diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..f5e4a65be --- /dev/null +++ b/.clang-format @@ -0,0 +1,106 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: DontAlign +AlignOperands: true +AlignTrailingComments: false +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: AfterColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: AfterColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 0 +# CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +#ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +StatementMacros: + - SerializableClassNameGetter + - SerializableOverrideMethods + - ClassInfoGetters +IncludeBlocks: Preserve +IndentCaseLabels: true +IndentGotoLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 6000 +PointerAlignment: Left +ReflowComments: false +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: c++17 +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: ForIndentation +... + diff --git a/.github/scripts/run-clang-format.py b/.github/scripts/run-clang-format.py new file mode 100755 index 000000000..6db70c2d4 --- /dev/null +++ b/.github/scripts/run-clang-format.py @@ -0,0 +1,408 @@ +#!/usr/bin/env python +"""A wrapper script around clang-format, suitable for linting multiple files +and to use for continuous integration. + +This is an alternative API for the clang-format command line. +It runs over multiple files and directories in parallel. +A diff output is produced and a sensible exit code is returned. + +""" + +from __future__ import print_function, unicode_literals + +import argparse +import codecs +import difflib +import fnmatch +import io +import errno +import multiprocessing +import os +import signal +import subprocess +import sys +import traceback + +from functools import partial + +try: + from subprocess import DEVNULL # py3k +except ImportError: + DEVNULL = open(os.devnull, "wb") + + +DEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx' +DEFAULT_CLANG_FORMAT_IGNORE = '.clang-format-ignore' + + +class ExitStatus: + SUCCESS = 0 + DIFF = 1 + TROUBLE = 2 + +def excludes_from_file(ignore_file): + excludes = [] + try: + with io.open(ignore_file, 'r', encoding='utf-8') as f: + for line in f: + if line.startswith('#'): + # ignore comments + continue + pattern = line.rstrip() + if not pattern: + # allow empty lines + continue + excludes.append(pattern) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + raise + return excludes; + +def list_files(files, recursive=False, extensions=None, exclude=None): + if extensions is None: + extensions = [] + if exclude is None: + exclude = [] + + out = [] + for file in files: + if recursive and os.path.isdir(file): + for dirpath, dnames, fnames in os.walk(file): + fpaths = [os.path.join(dirpath, fname) for fname in fnames] + for pattern in exclude: + # os.walk() supports trimming down the dnames list + # by modifying it in-place, + # to avoid unnecessary directory listings. + dnames[:] = [ + x for x in dnames + if + not fnmatch.fnmatch(os.path.join(dirpath, x), pattern) + ] + fpaths = [ + x for x in fpaths if not fnmatch.fnmatch(x, pattern) + ] + for f in fpaths: + ext = os.path.splitext(f)[1][1:] + if ext in extensions: + out.append(f) + else: + out.append(file) + return out + + +def make_diff(file, original, reformatted): + return list( + difflib.unified_diff( + original, + reformatted, + fromfile='{}\t(original)'.format(file), + tofile='{}\t(reformatted)'.format(file), + n=3)) + + +class DiffError(Exception): + def __init__(self, message, errs=None): + super(DiffError, self).__init__(message) + self.errs = errs or [] + + +class UnexpectedError(Exception): + def __init__(self, message, exc=None): + super(UnexpectedError, self).__init__(message) + self.formatted_traceback = traceback.format_exc() + self.exc = exc + + +def run_clang_format_diff_wrapper(args, file): + try: + ret = run_clang_format_diff(args, file) + return ret + except DiffError: + raise + except Exception as e: + raise UnexpectedError('{}: {}: {}'.format(file, e.__class__.__name__, + e), e) + + +def run_clang_format_diff(args, file): + try: + with io.open(file, 'r', encoding='utf-8') as f: + original = f.readlines() + except IOError as exc: + raise DiffError(str(exc)) + + if args.in_place: + invocation = [args.clang_format_executable, '-i', file] + else: + invocation = [args.clang_format_executable, file] + + if args.style: + invocation.extend(['--style', args.style]) + + if args.dry_run: + print(" ".join(invocation)) + return [], [] + + # Use of utf-8 to decode the process output. + # + # Hopefully, this is the correct thing to do. + # + # It's done due to the following assumptions (which may be incorrect): + # - clang-format will returns the bytes read from the files as-is, + # without conversion, and it is already assumed that the files use utf-8. + # - if the diagnostics were internationalized, they would use utf-8: + # > Adding Translations to Clang + # > + # > Not possible yet! + # > Diagnostic strings should be written in UTF-8, + # > the client can translate to the relevant code page if needed. + # > Each translation completely replaces the format string + # > for the diagnostic. + # > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation + # + # It's not pretty, due to Python 2 & 3 compatibility. + encoding_py3 = {} + if sys.version_info[0] >= 3: + encoding_py3['encoding'] = 'utf-8' + + try: + proc = subprocess.Popen( + invocation, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + **encoding_py3) + except OSError as exc: + raise DiffError( + "Command '{}' failed to start: {}".format( + subprocess.list2cmdline(invocation), exc + ) + ) + proc_stdout = proc.stdout + proc_stderr = proc.stderr + if sys.version_info[0] < 3: + # make the pipes compatible with Python 3, + # reading lines should output unicode + encoding = 'utf-8' + proc_stdout = codecs.getreader(encoding)(proc_stdout) + proc_stderr = codecs.getreader(encoding)(proc_stderr) + # hopefully the stderr pipe won't get full and block the process + outs = list(proc_stdout.readlines()) + errs = list(proc_stderr.readlines()) + proc.wait() + if proc.returncode: + raise DiffError( + "Command '{}' returned non-zero exit status {}".format( + subprocess.list2cmdline(invocation), proc.returncode + ), + errs, + ) + if args.in_place: + return [], errs + return make_diff(file, original, outs), errs + + +def bold_red(s): + return '\x1b[1m\x1b[31m' + s + '\x1b[0m' + + +def colorize(diff_lines): + def bold(s): + return '\x1b[1m' + s + '\x1b[0m' + + def cyan(s): + return '\x1b[36m' + s + '\x1b[0m' + + def green(s): + return '\x1b[32m' + s + '\x1b[0m' + + def red(s): + return '\x1b[31m' + s + '\x1b[0m' + + for line in diff_lines: + if line[:4] in ['--- ', '+++ ']: + yield bold(line) + elif line.startswith('@@ '): + yield cyan(line) + elif line.startswith('+'): + yield green(line) + elif line.startswith('-'): + yield red(line) + else: + yield line + + +def print_diff(diff_lines, use_color): + if use_color: + diff_lines = colorize(diff_lines) + if sys.version_info[0] < 3: + sys.stdout.writelines((l.encode('utf-8') for l in diff_lines)) + else: + sys.stdout.writelines(diff_lines) + + +def print_trouble(prog, message, use_colors): + error_text = 'error:' + if use_colors: + error_text = bold_red(error_text) + print("{}: {} {}".format(prog, error_text, message), file=sys.stderr) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + '--clang-format-executable', + metavar='EXECUTABLE', + help='path to the clang-format executable', + default='clang-format') + parser.add_argument( + '--extensions', + help='comma separated list of file extensions (default: {})'.format( + DEFAULT_EXTENSIONS), + default=DEFAULT_EXTENSIONS) + parser.add_argument( + '-r', + '--recursive', + action='store_true', + help='run recursively over directories') + parser.add_argument( + '-d', + '--dry-run', + action='store_true', + help='just print the list of files') + parser.add_argument( + '-i', + '--in-place', + action='store_true', + help='format file instead of printing differences') + parser.add_argument('files', metavar='file', nargs='+') + parser.add_argument( + '-q', + '--quiet', + action='store_true', + help="disable output, useful for the exit code") + parser.add_argument( + '-j', + metavar='N', + type=int, + default=0, + help='run N clang-format jobs in parallel' + ' (default number of cpus + 1)') + parser.add_argument( + '--color', + default='auto', + choices=['auto', 'always', 'never'], + help='show colored diff (default: auto)') + parser.add_argument( + '-e', + '--exclude', + metavar='PATTERN', + action='append', + default=[], + help='exclude paths matching the given glob-like pattern(s)' + ' from recursive search') + parser.add_argument( + '--style', + help='formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)') + + args = parser.parse_args() + + # use default signal handling, like diff return SIGINT value on ^C + # https://bugs.python.org/issue14229#msg156446 + signal.signal(signal.SIGINT, signal.SIG_DFL) + try: + signal.SIGPIPE + except AttributeError: + # compatibility, SIGPIPE does not exist on Windows + pass + else: + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + colored_stdout = False + colored_stderr = False + if args.color == 'always': + colored_stdout = True + colored_stderr = True + elif args.color == 'auto': + colored_stdout = sys.stdout.isatty() + colored_stderr = sys.stderr.isatty() + + version_invocation = [args.clang_format_executable, str("--version")] + try: + subprocess.check_call(version_invocation, stdout=DEVNULL) + except subprocess.CalledProcessError as e: + print_trouble(parser.prog, str(e), use_colors=colored_stderr) + return ExitStatus.TROUBLE + except OSError as e: + print_trouble( + parser.prog, + "Command '{}' failed to start: {}".format( + subprocess.list2cmdline(version_invocation), e + ), + use_colors=colored_stderr, + ) + return ExitStatus.TROUBLE + + retcode = ExitStatus.SUCCESS + + excludes = excludes_from_file(DEFAULT_CLANG_FORMAT_IGNORE) + excludes.extend(args.exclude) + + files = list_files( + args.files, + recursive=args.recursive, + exclude=excludes, + extensions=args.extensions.split(',')) + + if not files: + return + + njobs = args.j + if njobs == 0: + njobs = multiprocessing.cpu_count() + 1 + njobs = min(len(files), njobs) + + if njobs == 1: + # execute directly instead of in a pool, + # less overhead, simpler stacktraces + it = (run_clang_format_diff_wrapper(args, file) for file in files) + pool = None + else: + pool = multiprocessing.Pool(njobs) + it = pool.imap_unordered( + partial(run_clang_format_diff_wrapper, args), files) + pool.close() + while True: + try: + outs, errs = next(it) + except StopIteration: + break + except DiffError as e: + print_trouble(parser.prog, str(e), use_colors=colored_stderr) + retcode = ExitStatus.TROUBLE + sys.stderr.writelines(e.errs) + except UnexpectedError as e: + print_trouble(parser.prog, str(e), use_colors=colored_stderr) + sys.stderr.write(e.formatted_traceback) + retcode = ExitStatus.TROUBLE + # stop at the first unexpected error, + # something could be very wrong, + # don't process all files unnecessarily + if pool: + pool.terminate() + break + else: + sys.stderr.writelines(errs) + if outs == []: + continue + if not args.quiet: + print_diff(outs, use_color=colored_stdout) + if retcode == ExitStatus.SUCCESS: + retcode = ExitStatus.DIFF + if pool: + pool.join() + return retcode + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 854fcecb8..a864d14b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,3 +23,5 @@ jobs: msbuild: uses: ./.github/workflows/msbuild.yml + format: + uses: ./.github/workflows/clang-format.yml diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 000000000..8ff45b6f7 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,44 @@ +name: clang-format + +on: + # Triggers the workflow when called by a top-level workflow + workflow_call: + inputs: + upload_artefacts: + type: boolean + required: false + default: false + build_type: # "release" | "debug" + type: string + required: false + default: "release" + debug_level: # "full" | "minimal" | "release" + type: string + required: false + default: "release" + new_release_version: + type: string + required: false + +jobs: + clang-format: + runs-on: ubuntu-latest + name: Format sources + + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + + - name: Install dependencies + run: sudo apt-get install -y clang-format + + - name: Run clang-format + run: | + .github/scripts/run-clang-format.py -r Source Data/Base.rte/Shaders \ + --exclude Source/System/Base64 \ + --exclude Source/System/BitMask \ + --exclude Source/System/glad \ + --exclude Source/System/MicroPather \ + --exclude Source/System/Semver200 \ + --exclude Source/System/StackWalker diff --git a/Data/Base.rte/Shaders/Blit8.frag b/Data/Base.rte/Shaders/Blit8.frag index 6970c7ad7..ba4cd7b7a 100644 --- a/Data/Base.rte/Shaders/Blit8.frag +++ b/Data/Base.rte/Shaders/Blit8.frag @@ -1,4 +1,4 @@ -//Blit8.frag +// Blit8.frag #version 330 core in vec2 textureUV; @@ -8,8 +8,7 @@ out vec4 FragColor; uniform sampler2D rteTexture; uniform sampler1D rtePalette; -void main() -{ +void main() { float colorIndex = texture(rteTexture, vec2(textureUV.x, -textureUV.y)).r; FragColor = texture(rtePalette, colorIndex); } diff --git a/Data/Base.rte/Shaders/Blit8.vert b/Data/Base.rte/Shaders/Blit8.vert index f7859242f..652a81e18 100644 --- a/Data/Base.rte/Shaders/Blit8.vert +++ b/Data/Base.rte/Shaders/Blit8.vert @@ -1,7 +1,7 @@ #version 330 core -layout (location = 0) in vec2 rteVertexPosition; -layout (location = 1) in vec2 rteTexUV; +layout(location = 0) in vec2 rteVertexPosition; +layout(location = 1) in vec2 rteTexUV; out vec2 textureUV; @@ -10,6 +10,6 @@ uniform mat4 rteProjection; uniform mat4 rteUVTransform; void main() { - gl_Position = rteProjection * rteTransform * vec4(rteVertexPosition, 0.0, 1.0); - textureUV = (rteUVTransform * vec4(rteTexUV, 0.0, 1.0)).xy; + gl_Position = rteProjection * rteTransform * vec4(rteVertexPosition, 0.0, 1.0); + textureUV = (rteUVTransform * vec4(rteTexUV, 0.0, 1.0)).xy; } diff --git a/Data/Base.rte/Shaders/PostProcess.frag b/Data/Base.rte/Shaders/PostProcess.frag index 964752655..56227308e 100644 --- a/Data/Base.rte/Shaders/PostProcess.frag +++ b/Data/Base.rte/Shaders/PostProcess.frag @@ -7,7 +7,6 @@ out vec4 FragColor; uniform sampler2D rteTexture; uniform vec4 rteColor; - -void main() { - FragColor = texture(rteTexture, textureUV) * rteColor; +void main() { + FragColor = texture(rteTexture, textureUV) * rteColor; } diff --git a/Data/Base.rte/Shaders/PostProcess.vert b/Data/Base.rte/Shaders/PostProcess.vert index 647212dd0..ac9f28d0e 100644 --- a/Data/Base.rte/Shaders/PostProcess.vert +++ b/Data/Base.rte/Shaders/PostProcess.vert @@ -1,15 +1,14 @@ #version 330 core -layout (location = 0) in vec2 rteVertexPosition; -layout (location = 1) in vec2 rteTexUV; +layout(location = 0) in vec2 rteVertexPosition; +layout(location = 1) in vec2 rteTexUV; out vec2 textureUV; uniform mat4 rteTransform; uniform mat4 rteProjection; - void main() { - gl_Position = rteProjection * rteTransform * vec4(rteVertexPosition, 0.0, 1.0); - textureUV = vec2(rteTexUV.x, -rteTexUV.y); + gl_Position = rteProjection * rteTransform * vec4(rteVertexPosition, 0.0, 1.0); + textureUV = vec2(rteTexUV.x, -rteTexUV.y); } diff --git a/Data/Base.rte/Shaders/ScreenBlit.frag b/Data/Base.rte/Shaders/ScreenBlit.frag index 7c4097a17..30b2e1223 100644 --- a/Data/Base.rte/Shaders/ScreenBlit.frag +++ b/Data/Base.rte/Shaders/ScreenBlit.frag @@ -8,17 +8,17 @@ uniform sampler2D rteTexture; uniform sampler2D rteGUITexture; vec4 texture2DAA(sampler2D tex, vec2 uv) { - vec2 texsize = vec2(textureSize(tex,0)); - vec2 uv_texspace = uv*texsize; - vec2 seam = floor(uv_texspace+.5); - uv_texspace = (uv_texspace-seam)/fwidth(uv_texspace)+seam; - uv_texspace = clamp(uv_texspace, seam-.5, seam+.5); - return texture(tex, uv_texspace/texsize); + vec2 texsize = vec2(textureSize(tex, 0)); + vec2 uv_texspace = uv * texsize; + vec2 seam = floor(uv_texspace + .5); + uv_texspace = (uv_texspace - seam) / fwidth(uv_texspace) + seam; + uv_texspace = clamp(uv_texspace, seam - .5, seam + .5); + return texture(tex, uv_texspace / texsize); } void main() { - vec4 guiColor = texture2DAA(rteGUITexture, textureUV); - float guiSolid = step(0.00000001, guiColor.r + guiColor.g + guiColor.b); - float blendRatio = max(guiColor.a, guiSolid); - FragColor = (texture2DAA(rteTexture, textureUV) * (1- blendRatio)) + guiColor * blendRatio; + vec4 guiColor = texture2DAA(rteGUITexture, textureUV); + float guiSolid = step(0.00000001, guiColor.r + guiColor.g + guiColor.b); + float blendRatio = max(guiColor.a, guiSolid); + FragColor = (texture2DAA(rteTexture, textureUV) * (1 - blendRatio)) + guiColor * blendRatio; } diff --git a/Data/Base.rte/Shaders/ScreenBlit.vert b/Data/Base.rte/Shaders/ScreenBlit.vert index 54132ce0d..8cb4be28c 100644 --- a/Data/Base.rte/Shaders/ScreenBlit.vert +++ b/Data/Base.rte/Shaders/ScreenBlit.vert @@ -1,7 +1,7 @@ #version 330 core -layout (location = 0) in vec2 rteVertexPosition; -layout (location = 1) in vec2 rteTexUV; +layout(location = 0) in vec2 rteVertexPosition; +layout(location = 1) in vec2 rteTexUV; out vec2 textureUV; @@ -9,6 +9,6 @@ uniform mat4 rteTransform; uniform mat4 rteProjection; void main() { - gl_Position = rteProjection * rteTransform * vec4(rteVertexPosition.xy, 0.0, 1.0); - textureUV = rteTexUV; -} \ No newline at end of file + gl_Position = rteProjection * rteTransform * vec4(rteVertexPosition.xy, 0.0, 1.0); + textureUV = rteTexUV; +} diff --git a/Source/Activities/ActorEditor.cpp b/Source/Activities/ActorEditor.cpp index a6baf32f7..40a3e5101 100644 --- a/Source/Activities/ActorEditor.cpp +++ b/Source/Activities/ActorEditor.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -34,335 +33,297 @@ namespace RTE { -ConcreteClassInfo(ActorEditor, EditorActivity, 0); + ConcreteClassInfo(ActorEditor, EditorActivity, 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ActorEditor, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ActorEditor, effectively -// resetting the members of this abstraction level only. + void ActorEditor::Clear() { + m_pEditedActor = 0; + m_pPicker = 0; + } -void ActorEditor::Clear() -{ - m_pEditedActor = 0; - m_pPicker = 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ActorEditor object ready for use. + int ActorEditor::Create() { + if (EditorActivity::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ActorEditor object ready for use. + m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", "Actor Editor Pie Menu")->Clone())); -int ActorEditor::Create() -{ - if (EditorActivity::Create() < 0) - return -1; + return 0; + } - m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", "Actor Editor Pie Menu")->Clone())); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ActorEditor to be identical to another, by deep copy. - return 0; -} + int ActorEditor::Create(const ActorEditor& reference) { + if (EditorActivity::Create(reference) < 0) + return -1; + if (m_Description.empty()) + m_Description = "Load and edit Actors."; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ActorEditor to be identical to another, by deep copy. + return 0; + } -int ActorEditor::Create(const ActorEditor &reference) -{ - if (EditorActivity::Create(reference) < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int ActorEditor::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); + /* + MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + */ + EndPropertyList; + } - if (m_Description.empty()) - m_Description = "Load and edit Actors."; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this ActorEditor with a Writer for + // later recreation with Create(Reader &reader); - return 0; -} + int ActorEditor::Save(Writer& writer) const { + EditorActivity::Save(writer); + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ActorEditor object. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int ActorEditor::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); -/* - MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); -*/ - EndPropertyList; -} + void ActorEditor::Destroy(bool notInherited) { + delete m_pEditedActor; + delete m_pPicker; + if (!notInherited) + EditorActivity::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this ActorEditor with a Writer for -// later recreation with Create(Reader &reader); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. -int ActorEditor::Save(Writer &writer) const { - EditorActivity::Save(writer); - return 0; -} + int ActorEditor::Start() { + int error = EditorActivity::Start(); + ////////////////////////////////////////////// + // Allocate and (re)create the picker GUI -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ActorEditor object. + if (m_pPicker) + m_pPicker->Reset(); + else + m_pPicker = new ObjectPickerGUI; + m_pPicker->Create(&(m_PlayerController[0]), -1, "Actor"); -void ActorEditor::Destroy(bool notInherited) -{ - delete m_pEditedActor; - delete m_pPicker; + m_PieMenu->SetMenuController(&m_PlayerController[0]); - if (!notInherited) - EditorActivity::Destroy(); - Clear(); -} + m_EditorMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + return error; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + + void ActorEditor::SetPaused(bool pause) { + // Override the pause + m_Paused = false; + } -int ActorEditor::Start() -{ - int error = EditorActivity::Start(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. - ////////////////////////////////////////////// - // Allocate and (re)create the picker GUI + void ActorEditor::End() { + EditorActivity::End(); - if (m_pPicker) - m_pPicker->Reset(); - else - m_pPicker = new ObjectPickerGUI; - m_pPicker->Create(&(m_PlayerController[0]), -1, "Actor"); + m_ActivityState = ActivityState::Over; + } - m_PieMenu->SetMenuController(&m_PlayerController[0]); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActorEditor. Supposed to be done every frame + // before drawing. + + void ActorEditor::Update() { + // And object hasn't been loaded yet, so get the loading picker going + if (!m_pEditedActor) { + m_NeedSave = false; + m_HasEverBeenSaved = false; + // Show the picker dialog to select an object to load + m_pPicker->SetEnabled(true); + // Scroll to center of scene + g_CameraMan.SetScrollTarget(g_SceneMan.GetSceneDim() * 0.5); + m_EditorMode = m_PreviousMode = EditorActivity::LOADDIALOG; + m_ModeChange = true; + } - m_EditorMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; + // Mode switching etc - don't need for this yet + // EditorActivity::Update(); + // Update the player controller since we're not calling parent update + m_PlayerController[0].Update(); - return error; -} + if (!g_SceneMan.GetScene()) + return; + ///////////////////////////////////////////////////// + // Update the edited Actor -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + if (m_pEditedActor) { + m_pEditedActor->SetPos(g_SceneMan.GetSceneDim() * 0.5); + m_pEditedActor->FullUpdate(); + g_CameraMan.SetScrollTarget(m_pEditedActor->GetPos()); + } -void ActorEditor::SetPaused(bool pause) -{ - // Override the pause - m_Paused = false; -} + ///////////////////////////////////////////////////// + // Picker logic + // Enable or disable the picker + m_pPicker->SetEnabled(m_EditorMode == EditorActivity::LOADDIALOG); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. + // Update the picker GUI + m_pPicker->Update(); -void ActorEditor::End() -{ - EditorActivity::End(); + // Set the screen occlusion situation + if (!m_pPicker->IsVisible()) + g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(Players::PlayerOne)); + // Picking something to load into the editor + if (m_EditorMode == EditorActivity::LOADDIALOG) { + g_FrameMan.ClearScreenText(); + g_FrameMan.SetScreenText("Select an Actor to LOAD into the editor ->", 0, 333); + // Picked something! + if (m_pPicker->ObjectPicked() && !m_pPicker->IsEnabled()) { + // Load the picked Actor into the editor + LoadActor(m_pPicker->ObjectPicked()); + } + } else { + g_FrameMan.ClearScreenText(); + g_FrameMan.SetScreenText("Control the actor to see how he moves. Reload data with the pie menu.", 0, 0, 5000); + } - m_ActivityState = ActivityState::Over; -} + ////////////////////////////////////////////// + // Pie menu logic + if (m_pEditedActor) { + PieMenu* editedActorPieMenu = m_pEditedActor->GetPieMenu(); + editedActorPieMenu->SetEnabled(m_PlayerController[0].IsState(ControlState::PIE_MENU_ACTIVE) && m_EditorMode != EditorActivity::LOADDIALOG); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActorEditor. Supposed to be done every frame -// before drawing. - -void ActorEditor::Update() -{ - // And object hasn't been loaded yet, so get the loading picker going - if (!m_pEditedActor) - { - m_NeedSave = false; - m_HasEverBeenSaved = false; - // Show the picker dialog to select an object to load - m_pPicker->SetEnabled(true); - // Scroll to center of scene - g_CameraMan.SetScrollTarget(g_SceneMan.GetSceneDim() * 0.5); - m_EditorMode = m_PreviousMode = EditorActivity::LOADDIALOG; - m_ModeChange = true; - } - - // Mode switching etc - don't need for this yet -// EditorActivity::Update(); - // Update the player controller since we're not calling parent update - m_PlayerController[0].Update(); - - if (!g_SceneMan.GetScene()) - return; - - ///////////////////////////////////////////////////// - // Update the edited Actor - - if (m_pEditedActor) - { - m_pEditedActor->SetPos(g_SceneMan.GetSceneDim() * 0.5); - m_pEditedActor->FullUpdate(); - g_CameraMan.SetScrollTarget(m_pEditedActor->GetPos()); - } - - ///////////////////////////////////////////////////// - // Picker logic - - // Enable or disable the picker - m_pPicker->SetEnabled(m_EditorMode == EditorActivity::LOADDIALOG); - - // Update the picker GUI - m_pPicker->Update(); - - // Set the screen occlusion situation - if (!m_pPicker->IsVisible()) - g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(Players::PlayerOne)); - - // Picking something to load into the editor - if (m_EditorMode == EditorActivity::LOADDIALOG) - { - g_FrameMan.ClearScreenText(); - g_FrameMan.SetScreenText("Select an Actor to LOAD into the editor ->", 0, 333); - - // Picked something! - if (m_pPicker->ObjectPicked() && !m_pPicker->IsEnabled()) - { - // Load the picked Actor into the editor - LoadActor(m_pPicker->ObjectPicked()); - } - } - else - { - g_FrameMan.ClearScreenText(); - g_FrameMan.SetScreenText("Control the actor to see how he moves. Reload data with the pie menu.", 0, 0, 5000); - } - - ////////////////////////////////////////////// - // Pie menu logic - - if (m_pEditedActor) { - PieMenu *editedActorPieMenu = m_pEditedActor->GetPieMenu(); - editedActorPieMenu->SetEnabled(m_PlayerController[0].IsState(ControlState::PIE_MENU_ACTIVE) && m_EditorMode != EditorActivity::LOADDIALOG); - - if (editedActorPieMenu->GetPieCommand() == PieSlice::SliceType::EditorLoad) { - ReloadActorData(); - } else if (editedActorPieMenu->GetPieCommand() == PieSlice::SliceType::EditorPick) { - m_EditorMode = EditorActivity::LOADDIALOG; - m_ModeChange = true; + if (editedActorPieMenu->GetPieCommand() == PieSlice::SliceType::EditorLoad) { + ReloadActorData(); + } else if (editedActorPieMenu->GetPieCommand() == PieSlice::SliceType::EditorPick) { + m_EditorMode = EditorActivity::LOADDIALOG; + m_ModeChange = true; + } } } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. + void ActorEditor::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + // Draw the edited actor and pie menu + if (m_pEditedActor) { + m_pEditedActor->Draw(pTargetBitmap, targetPos, g_DrawColor); + m_pEditedActor->GetPieMenu()->Draw(pTargetBitmap, targetPos); + } -void ActorEditor::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - // Draw the edited actor and pie menu - if (m_pEditedActor) - { - m_pEditedActor->Draw(pTargetBitmap, targetPos, g_DrawColor); - m_pEditedActor->GetPieMenu()->Draw(pTargetBitmap, targetPos); - } + // Clear out annoying blooms + // TODO: Figure out if this needs a button or piemenu toggle for some edge case + // g_PostProcessMan.ClearScenePostEffects(); - // Clear out annoying blooms - // TODO: Figure out if this needs a button or piemenu toggle for some edge case - //g_PostProcessMan.ClearScenePostEffects(); + m_pPicker->Draw(pTargetBitmap); - m_pPicker->Draw(pTargetBitmap); + EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); + } - EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActorEditor's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + void ActorEditor::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + EditorActivity::Draw(pTargetBitmap, targetPos); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActorEditor's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the Actor itself and sets up the pie menu to match its setup. -void ActorEditor::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) -{ - EditorActivity::Draw(pTargetBitmap, targetPos); -} + bool ActorEditor::LoadActor(const Entity* pActorToLoad) { + if (!pActorToLoad) + return false; + // Replace the old one + if (MovableObject* asMo = dynamic_cast(m_pEditedActor)) { + asMo->DestroyScriptState(); + } + delete m_pEditedActor; + // Make a copy of the picked object reference + m_pEditedActor = dynamic_cast(pActorToLoad->Clone()); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the Actor itself and sets up the pie menu to match its setup. - -bool ActorEditor::LoadActor(const Entity *pActorToLoad) -{ - if (!pActorToLoad) - return false; - - // Replace the old one - if (MovableObject* asMo = dynamic_cast(m_pEditedActor)) { - asMo->DestroyScriptState(); - } - delete m_pEditedActor; - // Make a copy of the picked object reference - m_pEditedActor = dynamic_cast(pActorToLoad->Clone()); - - if (m_pEditedActor) - { - // Set up the editor for the new actor - m_pEditedActor->SetControllerMode(Controller::CIM_PLAYER, Players::PlayerOne); - - for (const PieSlice *pieSlice : m_PieMenu->GetPieSlices()) { - m_pEditedActor->GetPieMenu()->AddPieSlice(dynamic_cast(pieSlice->Clone()), this); + if (m_pEditedActor) { + // Set up the editor for the new actor + m_pEditedActor->SetControllerMode(Controller::CIM_PLAYER, Players::PlayerOne); + + for (const PieSlice* pieSlice: m_PieMenu->GetPieSlices()) { + m_pEditedActor->GetPieMenu()->AddPieSlice(dynamic_cast(pieSlice->Clone()), this); + } + + m_EditorMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } else { + g_FrameMan.ClearScreenText(); + g_FrameMan.SetScreenText("There's something wrong with that picked Actor!?", 0, 333, 2000); + return false; } - m_EditorMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - else - { - g_FrameMan.ClearScreenText(); - g_FrameMan.SetScreenText("There's something wrong with that picked Actor!?", 0, 333, 2000); - return false; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool ActorEditor::ReloadActorData() { - if (m_pEditedActor) { - std::string presetName = m_pEditedActor->GetPresetName(); - std::string className = m_pEditedActor->GetClassName(); - std::string moduleName = g_PresetMan.GetDataModuleName(m_pEditedActor->GetModuleID()); - g_PresetMan.ReloadEntityPreset(presetName, className, moduleName, false); - LoadActor(g_PresetMan.GetEntityPreset(className, presetName, moduleName)); - return m_pEditedActor != nullptr; + return true; } - return false; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool ActorEditor::ReloadActorData() { + if (m_pEditedActor) { + std::string presetName = m_pEditedActor->GetPresetName(); + std::string className = m_pEditedActor->GetClassName(); + std::string moduleName = g_PresetMan.GetDataModuleName(m_pEditedActor->GetModuleID()); + g_PresetMan.ReloadEntityPreset(presetName, className, moduleName, false); + LoadActor(g_PresetMan.GetEntityPreset(className, presetName, moduleName)); + return m_pEditedActor != nullptr; + } + return false; + } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/ActorEditor.h b/Source/Activities/ActorEditor.h index 715799bf7..676276ab8 100644 --- a/Source/Activities/ActorEditor.h +++ b/Source/Activities/ActorEditor.h @@ -10,254 +10,230 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "RTETools.h" #include "EditorActivity.h" -namespace RTE -{ - -class Actor; -class ObjectPickerGUI; -class PieMenu; -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUIComboBox; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: ActorEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activity for testing and quickly iterating on Actor data definitions. -// Parent(s): EditorActivity. -// Class history: 10/08/2007 ActorEditor Created. - -class ActorEditor : public EditorActivity { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(ActorEditor); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: ActorEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a ActorEditor object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - ActorEditor() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~ActorEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a ActorEditor object before deletion -// from system memory. -// Arguments: None. - - ~ActorEditor() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ActorEditor object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ActorEditor to be identical to another, by deep copy. -// Arguments: A reference to the ActorEditor to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const ActorEditor &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire ActorEditor, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); EditorActivity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ActorEditor object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the Actor itself and sets up the pie menu to match its setup. -// Arguments: An Entity Preset of the Actor to load into the editor. OWNERSHIP IS NOT TRANSFERRED! -// Return value: Whether the Actor was loaded successfully from the PresetMan. - - bool LoadActor(const Entity *pActorToLoad); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReloadActorData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the ini with the currently edited Actor's definitions. -// Arguments: None. -// Return value: Whether the data file was successfully read. - - bool ReloadActorData(); - - - // Member variables - static Entity::ClassInfo m_sClass; - - // The loaded MOSR of which we are editing. Owned by this. - Actor *m_pEditedActor; - // The picker for selecting which object to load - ObjectPickerGUI *m_pPicker; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class Actor; + class ObjectPickerGUI; + class PieMenu; + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUIComboBox; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: ActorEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activity for testing and quickly iterating on Actor data definitions. + // Parent(s): EditorActivity. + // Class history: 10/08/2007 ActorEditor Created. + + class ActorEditor : public EditorActivity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(ActorEditor); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: ActorEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a ActorEditor object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + ActorEditor() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~ActorEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a ActorEditor object before deletion + // from system memory. + // Arguments: None. + + ~ActorEditor() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ActorEditor object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ActorEditor to be identical to another, by deep copy. + // Arguments: A reference to the ActorEditor to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const ActorEditor& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire ActorEditor, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + EditorActivity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ActorEditor object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the Actor itself and sets up the pie menu to match its setup. + // Arguments: An Entity Preset of the Actor to load into the editor. OWNERSHIP IS NOT TRANSFERRED! + // Return value: Whether the Actor was loaded successfully from the PresetMan. + + bool LoadActor(const Entity* pActorToLoad); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReloadActorData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the ini with the currently edited Actor's definitions. + // Arguments: None. + // Return value: Whether the data file was successfully read. + + bool ReloadActorData(); + + // Member variables + static Entity::ClassInfo m_sClass; + + // The loaded MOSR of which we are editing. Owned by this. + Actor* m_pEditedActor; + // The picker for selecting which object to load + ObjectPickerGUI* m_pPicker; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/AreaEditor.cpp b/Source/Activities/AreaEditor.cpp index 102342622..0c7a02238 100644 --- a/Source/Activities/AreaEditor.cpp +++ b/Source/Activities/AreaEditor.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -41,717 +40,633 @@ namespace RTE { -ConcreteClassInfo(AreaEditor, EditorActivity, 0); + ConcreteClassInfo(AreaEditor, EditorActivity, 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AreaEditor, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AreaEditor, effectively -// resetting the members of this abstraction level only. + void AreaEditor::Clear() { + m_pEditorGUI = 0; + m_pNewAreaName = 0; + } -void AreaEditor::Clear() -{ - m_pEditorGUI = 0; - m_pNewAreaName = 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AreaEditor object ready for use. + int AreaEditor::Create() { + if (EditorActivity::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AreaEditor object ready for use. + return 0; + } -int AreaEditor::Create() -{ - if (EditorActivity::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AreaEditor to be identical to another, by deep copy. + int AreaEditor::Create(const AreaEditor& reference) { + if (EditorActivity::Create(reference) < 0) + return -1; - return 0; -} + if (m_Description.empty()) + m_Description = "Define and edit Areas on this Scene."; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AreaEditor to be identical to another, by deep copy. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int AreaEditor::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); + /* + MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + */ + EndPropertyList; + } -int AreaEditor::Create(const AreaEditor &reference) -{ - if (EditorActivity::Create(reference) < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this AreaEditor with a Writer for + // later recreation with Create(Reader &reader); - if (m_Description.empty()) - m_Description = "Define and edit Areas on this Scene."; + int AreaEditor::Save(Writer& writer) const { + EditorActivity::Save(writer); + return 0; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AreaEditor object. + void AreaEditor::Destroy(bool notInherited) { + delete m_pEditorGUI; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int AreaEditor::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); -/* - MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); -*/ - EndPropertyList; -} + if (!notInherited) + EditorActivity::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this AreaEditor with a Writer for -// later recreation with Create(Reader &reader); + int AreaEditor::Start() { + int error = EditorActivity::Start(); -int AreaEditor::Save(Writer &writer) const { - EditorActivity::Save(writer); - return 0; -} + ////////////////////////////////////////////// + // Allocate and (re)create the Editor GUI + if (m_pEditorGUI) + m_pEditorGUI->Destroy(); + else + m_pEditorGUI = new AreaEditorGUI; + m_pEditorGUI->Create(&(m_PlayerController[0]), true); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AreaEditor object. + ////////////////////////////////////////////////////////////// + // Hooking up directly to the controls defined in the GUI ini -void AreaEditor::Destroy(bool notInherited) -{ - delete m_pEditorGUI; + m_pGUIController->Load("Base.rte/GUIs/AreaEditorGUI.ini"); - if (!notInherited) - EditorActivity::Destroy(); - Clear(); -} + // Resize the invisible root container so it matches the screen rez + GUICollectionBox* pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); + if (pRootBox) + pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of + if (!m_pNewDialogBox) { + m_pNewDialogBox = dynamic_cast(m_pGUIController->GetControl("NewDialogBox")); + // m_pNewDialogBox->SetDrawType(GUICollectionBox::Color); + m_pNewDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pNewDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pNewDialogBox->GetHeight() / 2)); + m_pNewDialogBox->SetVisible(false); + } + m_pNewAreaName = dynamic_cast(m_pGUIController->GetControl("NewAreaNameTB")); + m_pNewButton = dynamic_cast(m_pGUIController->GetControl("NewAreaButton")); + m_pNewCancel = dynamic_cast(m_pGUIController->GetControl("NewCancelButton")); + + // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of + if (!m_pLoadDialogBox) { + m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); + // m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); + m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); + m_pLoadDialogBox->SetVisible(false); + } + m_pLoadNameCombo = dynamic_cast(m_pGUIController->GetControl("LoadSceneCB")); + m_pLoadNameCombo->SetDropHeight(std::min(m_pLoadNameCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); + m_pLoadDialogBox->SetSize(m_pLoadDialogBox->GetWidth(), m_pLoadDialogBox->GetHeight() + m_pLoadNameCombo->GetDropHeight()); // Make sure the dropdown can fit, no matter how tall it is. + m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadSceneButton")); + m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); + + if (!m_pSaveDialogBox) { + m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); + + // Set the background image of the parent collection box + // ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); + // m_pSaveDialogBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); + // m_pSaveDialogBox->SetDrawBackground(true); + // m_pSaveDialogBox->SetDrawType(GUICollectionBox::Image); + // m_pSaveDialogBox->SetDrawType(GUICollectionBox::Color); + m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); + m_pSaveDialogBox->SetVisible(false); + } + m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveSceneNameTB")); + m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); + m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveSceneButton")); + m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); + + if (!m_pChangesDialogBox) { + m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); + m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); + m_pChangesDialogBox->SetVisible(false); + } + m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); + m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); + m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); + + if (!m_pOverwriteDialogBox) { + m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); + m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); + m_pOverwriteDialogBox->SetVisible(false); + } + m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); + m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); + m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int AreaEditor::Start() -{ - int error = EditorActivity::Start(); - - ////////////////////////////////////////////// - // Allocate and (re)create the Editor GUI - - if (m_pEditorGUI) - m_pEditorGUI->Destroy(); - else - m_pEditorGUI = new AreaEditorGUI; - m_pEditorGUI->Create(&(m_PlayerController[0]), true); - - ////////////////////////////////////////////////////////////// - // Hooking up directly to the controls defined in the GUI ini - - m_pGUIController->Load("Base.rte/GUIs/AreaEditorGUI.ini"); - - // Resize the invisible root container so it matches the screen rez - GUICollectionBox *pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); - if (pRootBox) - pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); - - // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of - if (!m_pNewDialogBox) - { - m_pNewDialogBox = dynamic_cast(m_pGUIController->GetControl("NewDialogBox")); -// m_pNewDialogBox->SetDrawType(GUICollectionBox::Color); - m_pNewDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pNewDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pNewDialogBox->GetHeight() / 2)); - m_pNewDialogBox->SetVisible(false); - } - m_pNewAreaName = dynamic_cast(m_pGUIController->GetControl("NewAreaNameTB")); - m_pNewButton = dynamic_cast(m_pGUIController->GetControl("NewAreaButton")); - m_pNewCancel = dynamic_cast(m_pGUIController->GetControl("NewCancelButton")); - - // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of - if (!m_pLoadDialogBox) - { - m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); -// m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); - m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); - m_pLoadDialogBox->SetVisible(false); - } - m_pLoadNameCombo = dynamic_cast(m_pGUIController->GetControl("LoadSceneCB")); - m_pLoadNameCombo->SetDropHeight(std::min(m_pLoadNameCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); - m_pLoadDialogBox->SetSize(m_pLoadDialogBox->GetWidth(), m_pLoadDialogBox->GetHeight() + m_pLoadNameCombo->GetDropHeight()); // Make sure the dropdown can fit, no matter how tall it is. - m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadSceneButton")); - m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); - - if (!m_pSaveDialogBox) - { - m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); - - // Set the background image of the parent collection box -// ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); -// m_pSaveDialogBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); -// m_pSaveDialogBox->SetDrawBackground(true); -// m_pSaveDialogBox->SetDrawType(GUICollectionBox::Image); -// m_pSaveDialogBox->SetDrawType(GUICollectionBox::Color); - m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); - m_pSaveDialogBox->SetVisible(false); - } - m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveSceneNameTB")); - m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); - m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveSceneButton")); - m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); - - if (!m_pChangesDialogBox) - { - m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); - m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); - m_pChangesDialogBox->SetVisible(false); - } - m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); - m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); - m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); - - if (!m_pOverwriteDialogBox) - { - m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); - m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); - m_pOverwriteDialogBox->SetVisible(false); - } - m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); - m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); - m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); - - return error; -} + return error; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + void AreaEditor::SetPaused(bool pause) { + // Override the pause + m_Paused = false; + } -void AreaEditor::SetPaused(bool pause) -{ - // Override the pause - m_Paused = false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + void AreaEditor::End() { + EditorActivity::End(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. + m_ActivityState = ActivityState::Over; + } -void AreaEditor::End() -{ - EditorActivity::End(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this AreaEditor. Supposed to be done every frame + // before drawing. + void AreaEditor::Update() { + EditorActivity::Update(); + if (!g_SceneMan.GetScene()) + return; - m_ActivityState = ActivityState::Over; -} + Scene* pCurrentScene = g_SceneMan.GetScene(); + // Update the loaded objects of the loaded scene so they look right + pCurrentScene->UpdatePlacedObjects(Scene::PLACEONLOAD); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this AreaEditor. Supposed to be done every frame -// before drawing. - -void AreaEditor::Update() -{ - EditorActivity::Update(); - - if (!g_SceneMan.GetScene()) - return; - - Scene *pCurrentScene = g_SceneMan.GetScene(); - - // Update the loaded objects of the loaded scene so they look right - pCurrentScene->UpdatePlacedObjects(Scene::PLACEONLOAD); - - // If the scene has no Area:s yet, force the user to make a new one - if (pCurrentScene->m_AreaList.empty()) - m_EditorMode = EditorActivity::NEWDIALOG; - - // All dialog boxes are gone and we're editing the scene's Area:s - if (m_EditorMode == EditorActivity::EDITINGOBJECT) - { - if (m_ModeChange) - { - // Start in the add/move mode - m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::PREADDMOVEBOX); - // Hide the cursor for this layer of interface - m_pGUIController->EnableMouse(false); - m_ModeChange = false; - } - g_UInputMan.DisableKeys(false); - } - // We are doing something int he dialog boxes, so don't do anything in the editor interface or show any text messages - else - { - m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); - g_FrameMan.ClearScreenText(); - } - - - ///////////////////////////////////////////////////// - // Update the editor interface - - m_pEditorGUI->Update(); - - // Any edits made, dirtying the scene? - m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; - - // Get any mode change commands that the user gave the Editor GUI - if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::NEWDIALOG; - m_ModeChange = true; - // This is ahack so we don't get a 'save changes dialog' when we jsut want to create a new area. - // Will turn on dirtyness immediately as New button is pressed below - m_NeedSave = false; - } - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorLoad && m_EditorMode != LOADDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::LOADDIALOG; - m_ModeChange = true; - } - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - // Test the scene by starting a Skirmish Defense with it, after saving - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone || m_EditorMode == TESTINGOBJECT) - { - m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); - - if (m_NeedSave) - { - m_PreviousMode = EditorActivity::TESTINGOBJECT; - m_EditorMode = EditorActivity::CHANGESDIALOG; - m_ModeChange = true; -/* - if (m_HasEverBeenSaved) - SaveScene(pCurrentScene->GetPresetName()); - else - { - m_PreviousMode = TESTINGOBJECT; - m_EditorMode = SAVEDIALOG; - m_ModeChange = true; - } -*/ - } - else - { - g_SceneMan.SetSceneToLoad(pCurrentScene->GetPresetName()); - - const Activity *pActivityPreset = dynamic_cast(g_PresetMan.GetEntityPreset("GAScripted", "Skirmish Defense")); - Activity * pActivity = dynamic_cast(pActivityPreset->Clone()); - GameActivity *pTestGame = dynamic_cast(pActivity); - RTEAssert(pTestGame, "Couldn't find the \"Skirmish Defense\" GAScripted Activity! Has it been defined?"); - pTestGame->SetTeamOfPlayer(0, 0); - pTestGame->SetCPUTeam(1); - pTestGame->SetStartingGold(10000); - pTestGame->SetFogOfWarEnabled(false); - pTestGame->SetDifficulty(DifficultySetting::MediumDifficulty); - g_ActivityMan.SetStartActivity(pTestGame); - g_ActivityMan.SetRestartActivity(); - } - } - - //////////////////////////////////////////////////////// - // Handle events for mouse input on the controls - - GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { - // If we're not supposed to have mouse control, then ignore these messages -// Uh this is not right, editor always has mouse control so far -// if (!m_PlayerController[0].IsMouseControlled()) -// break; - - if (anEvent.GetType() == GUIEvent::Command) - { - ////////////////////////////////////////////////////////// - // NEW button pressed; create a Area in the current scene - - if (anEvent.GetControl() == m_pNewButton) - { - // Make sure we're not trying to create a noname area - if (!m_pNewAreaName->GetText().empty()) - { - // Check if name is already taken, and if so, select the taken one instead of creating a new - if (Scene::Area *pArea = pCurrentScene->GetArea(m_pNewAreaName->GetText())) - { - m_pEditorGUI->SetCurrentArea(pArea); - m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::PREADDMOVEBOX); - } - else - { - // Make and name new Area - Scene::Area newArea(m_pNewAreaName->GetText()); - pCurrentScene->m_AreaList.push_back(newArea); - // Set the new area as the active one in the GUI, note we're getting the correct one from the scene, it's a copy of the one passed in - m_pEditorGUI->SetCurrentArea(pCurrentScene->GetArea(newArea.GetName())); - // Update teh picker list of the GUI so we can mousewheel between all the Areas, incl the new one - m_pEditorGUI->UpdatePickerList(newArea.GetName()); - } - - // Change mode to start editing the new/newly selected Area - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - m_NeedSave = true; - } - else - { -// TODO: Play some error sound? - } - } - - ////////////////////////////////////////////////////////// - // LOAD button pressed; load the selected Scene - - if (anEvent.GetControl() == m_pLoadButton) - { - GUIListPanel::Item *pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - // Attempt to load the scene, without applying its placed objects - g_SceneMan.SetSceneToLoad(pItem->m_Name, false); - g_SceneMan.LoadScene(); - // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space - m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); - if (pCurrentScene) - { - m_pEditorGUI->Destroy(); - m_pEditorGUI->Create(&(m_PlayerController[0]), true); -// TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead - } - } - m_NeedSave = false; - m_HasEverBeenSaved = true; - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // SAVE button pressed; save the selected Scene - - if (anEvent.GetControl() == m_pSaveButton) - { - if (!m_pSaveNameBox->GetText().empty()) - { - // Save the scene to the name specified in the text box - if (SaveScene(m_pSaveNameBox->GetText())) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - // Should really leave dialog box open? - else - { - ; - } - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes YES pressed - - if (anEvent.GetControl() == m_pChangesYesButton) - { - if (m_HasEverBeenSaved) - { - if (SaveScene(pCurrentScene->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - } - // Open the save scene dialog to ask user where to save it then - else - { - m_PreviousMode = m_PreviousMode; - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes NO pressed - - if (anEvent.GetControl() == m_pChangesNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - m_NeedSave = false; - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene YES pressed - - if (anEvent.GetControl() == m_pOverwriteYesButton) - { - // Force overwrite - if (SaveScene(pCurrentScene->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode != EditorActivity::SAVEDIALOG ? m_PreviousMode : EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } -// TODO: Show overwrite error? - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene NO pressed - - if (anEvent.GetControl() == m_pOverwriteNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - - /////////////////////////////////////////////////////////////// - // CANCEL button pressed; exit any active dialog box - - if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) - { - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - } - - // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { -/* - /////////////////////////////////////// - // Clicks on the New Scene Module combo - - if (anEvent.GetControl() == m_pNewModuleCombo) - { - // Closed it, IE selected somehting - if(anEvent.GetMsg() == GUIComboBox::Closed) - UpdateNewDialog(); - } -*/ - } - } -} + // If the scene has no Area:s yet, force the user to make a new one + if (pCurrentScene->m_AreaList.empty()) + m_EditorMode = EditorActivity::NEWDIALOG; + // All dialog boxes are gone and we're editing the scene's Area:s + if (m_EditorMode == EditorActivity::EDITINGOBJECT) { + if (m_ModeChange) { + // Start in the add/move mode + m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::PREADDMOVEBOX); + // Hide the cursor for this layer of interface + m_pGUIController->EnableMouse(false); + m_ModeChange = false; + } + g_UInputMan.DisableKeys(false); + } + // We are doing something int he dialog boxes, so don't do anything in the editor interface or show any text messages + else { + m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); + g_FrameMan.ClearScreenText(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. + ///////////////////////////////////////////////////// + // Update the editor interface + + m_pEditorGUI->Update(); + + // Any edits made, dirtying the scene? + m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; + + // Get any mode change commands that the user gave the Editor GUI + if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) { + m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::NEWDIALOG; + m_ModeChange = true; + // This is ahack so we don't get a 'save changes dialog' when we jsut want to create a new area. + // Will turn on dirtyness immediately as New button is pressed below + m_NeedSave = false; + } else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorLoad && m_EditorMode != LOADDIALOG) { + m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::LOADDIALOG; + m_ModeChange = true; + } else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) { + m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + // Test the scene by starting a Skirmish Defense with it, after saving + else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone || m_EditorMode == TESTINGOBJECT) { + m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::INACTIVE); + + if (m_NeedSave) { + m_PreviousMode = EditorActivity::TESTINGOBJECT; + m_EditorMode = EditorActivity::CHANGESDIALOG; + m_ModeChange = true; + /* + if (m_HasEverBeenSaved) + SaveScene(pCurrentScene->GetPresetName()); + else + { + m_PreviousMode = TESTINGOBJECT; + m_EditorMode = SAVEDIALOG; + m_ModeChange = true; + } + */ + } else { + g_SceneMan.SetSceneToLoad(pCurrentScene->GetPresetName()); + + const Activity* pActivityPreset = dynamic_cast(g_PresetMan.GetEntityPreset("GAScripted", "Skirmish Defense")); + Activity* pActivity = dynamic_cast(pActivityPreset->Clone()); + GameActivity* pTestGame = dynamic_cast(pActivity); + RTEAssert(pTestGame, "Couldn't find the \"Skirmish Defense\" GAScripted Activity! Has it been defined?"); + pTestGame->SetTeamOfPlayer(0, 0); + pTestGame->SetCPUTeam(1); + pTestGame->SetStartingGold(10000); + pTestGame->SetFogOfWarEnabled(false); + pTestGame->SetDifficulty(DifficultySetting::MediumDifficulty); + g_ActivityMan.SetStartActivity(pTestGame); + g_ActivityMan.SetRestartActivity(); + } + } -void AreaEditor::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - m_pEditorGUI->Draw(pTargetBitmap, targetPos); + //////////////////////////////////////////////////////// + // Handle events for mouse input on the controls + + GUIEvent anEvent; + while (m_pGUIController->GetEvent(&anEvent)) { + // If we're not supposed to have mouse control, then ignore these messages + // Uh this is not right, editor always has mouse control so far + // if (!m_PlayerController[0].IsMouseControlled()) + // break; + + if (anEvent.GetType() == GUIEvent::Command) { + ////////////////////////////////////////////////////////// + // NEW button pressed; create a Area in the current scene + + if (anEvent.GetControl() == m_pNewButton) { + // Make sure we're not trying to create a noname area + if (!m_pNewAreaName->GetText().empty()) { + // Check if name is already taken, and if so, select the taken one instead of creating a new + if (Scene::Area* pArea = pCurrentScene->GetArea(m_pNewAreaName->GetText())) { + m_pEditorGUI->SetCurrentArea(pArea); + m_pEditorGUI->SetEditorGUIMode(AreaEditorGUI::PREADDMOVEBOX); + } else { + // Make and name new Area + Scene::Area newArea(m_pNewAreaName->GetText()); + pCurrentScene->m_AreaList.push_back(newArea); + // Set the new area as the active one in the GUI, note we're getting the correct one from the scene, it's a copy of the one passed in + m_pEditorGUI->SetCurrentArea(pCurrentScene->GetArea(newArea.GetName())); + // Update teh picker list of the GUI so we can mousewheel between all the Areas, incl the new one + m_pEditorGUI->UpdatePickerList(newArea.GetName()); + } - EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); -} + // Change mode to start editing the new/newly selected Area + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + m_NeedSave = true; + } else { + // TODO: Play some error sound? + } + } + ////////////////////////////////////////////////////////// + // LOAD button pressed; load the selected Scene + + if (anEvent.GetControl() == m_pLoadButton) { + GUIListPanel::Item* pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + // Attempt to load the scene, without applying its placed objects + g_SceneMan.SetSceneToLoad(pItem->m_Name, false); + g_SceneMan.LoadScene(); + // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space + m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); + if (pCurrentScene) { + m_pEditorGUI->Destroy(); + m_pEditorGUI->Create(&(m_PlayerController[0]), true); + // TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead + } + } + m_NeedSave = false; + m_HasEverBeenSaved = true; + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this AreaEditor's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + ////////////////////////////////////////////////////////// + // SAVE button pressed; save the selected Scene + + if (anEvent.GetControl() == m_pSaveButton) { + if (!m_pSaveNameBox->GetText().empty()) { + // Save the scene to the name specified in the text box + if (SaveScene(m_pSaveNameBox->GetText())) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + // Should really leave dialog box open? + else { + ; + } + } + } -void AreaEditor::Draw(BITMAP* pTargetBitmap, const Vector &targetPos) -{ - EditorActivity::Draw(pTargetBitmap, targetPos); -} + /////////////////////////////////////////////////////////////// + // Save Changes YES pressed + + if (anEvent.GetControl() == m_pChangesYesButton) { + if (m_HasEverBeenSaved) { + if (SaveScene(pCurrentScene->GetPresetName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + } + // Open the save scene dialog to ask user where to save it then + else { + m_PreviousMode = m_PreviousMode; + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////// + // Save Changes NO pressed -bool AreaEditor::SaveScene(const std::string &saveAsName, bool forceOverwrite) { - Scene *editedScene = g_SceneMan.GetScene(); - editedScene->SetPresetName(saveAsName); + if (anEvent.GetControl() == m_pChangesNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + m_NeedSave = false; + } - std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); - bool savingToUserScenesModule = (dataModuleName == c_UserScenesModuleName); + /////////////////////////////////////////////////////////////// + // Overwrite Scene YES pressed + + if (anEvent.GetControl() == m_pOverwriteYesButton) { + // Force overwrite + if (SaveScene(pCurrentScene->GetPresetName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode != EditorActivity::SAVEDIALOG ? m_PreviousMode : EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + // TODO: Show overwrite error? + } - std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); - std::string sceneSavePath; - std::string previewSavePath; + /////////////////////////////////////////////////////////////// + // Overwrite Scene NO pressed - if (savingToUserScenesModule) { - sceneSavePath = dataModuleFullPath + "/" + saveAsName + ".ini"; - previewSavePath = dataModuleFullPath + "/" + saveAsName + ".preview.png"; - } else { - sceneSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".ini"; - previewSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".preview.png"; - } + if (anEvent.GetControl() == m_pOverwriteNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } - if (g_PresetMan.AddEntityPreset(editedScene, m_ModuleSpaceID, forceOverwrite, sceneSavePath)) { - if (Writer sceneWriter(sceneSavePath, false); !sceneWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + sceneSavePath + "\n\nTHE EDITED SCENE PRESET WAS NOT SAVED!!!"); - } else { - // TODO: Check if the ini file already exists, and then ask if overwrite. - sceneWriter.NewPropertyWithValue("AddScene", editedScene); - sceneWriter.EndWrite(); - - editedScene->SavePreview(previewSavePath); - m_HasEverBeenSaved = true; - - if (!savingToUserScenesModule) { - // First find/create a Scenes.ini file to include the new .ini into. - std::string scenesFilePath(dataModuleFullPath + "/Scenes.ini"); - bool scenesFileExists = System::PathExistsCaseSensitive(scenesFilePath); - - if (Writer scenesFileWriter(scenesFilePath, true); !scenesFileWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + scenesFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); - } else { - scenesFileWriter.NewPropertyWithValue("IncludeFile", sceneSavePath); - scenesFileWriter.EndWrite(); - - // Append to the end of the modules' Index.ini to include the newly created Scenes.ini next startup. - // If it's somehow already included without actually existing, it doesn't matter, the definitions will just bounce the second time. - if (!scenesFileExists) { - std::string indexFilePath = dataModuleFullPath + "/Index.ini"; - - if (Writer indexWriter(indexFilePath, true); !indexWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + indexFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); - } else { - // Add extra tab since the DataModule has everything indented. - indexWriter.NewProperty("\tIncludeFile"); - indexWriter << scenesFilePath; - indexWriter.EndWrite(); - } - } + /////////////////////////////////////////////////////////////// + // CANCEL button pressed; exit any active dialog box + + if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) { + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; } } - return true; + + // Notifications + else if (anEvent.GetType() == GUIEvent::Notification) { + /* + /////////////////////////////////////// + // Clicks on the New Scene Module combo + + if (anEvent.GetControl() == m_pNewModuleCombo) + { + // Closed it, IE selected somehting + if(anEvent.GetMsg() == GUIComboBox::Closed) + UpdateNewDialog(); + } + */ + } } - } else { - // Got to ask if we can overwrite the existing preset. - m_PreviousMode = EditorMode::SAVEDIALOG; - m_EditorMode = EditorMode::OVERWRITEDIALOG; - m_ModeChange = true; } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. + void AreaEditor::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + m_pEditorGUI->Draw(pTargetBitmap, targetPos); -void AreaEditor::UpdateNewDialog() -{ - // Reset the new Area name text field - if (m_pNewAreaName->GetText().empty()) - m_pNewAreaName->SetText("Test Area 1"); -} + EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this AreaEditor's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. + void AreaEditor::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + EditorActivity::Draw(pTargetBitmap, targetPos); + } -void AreaEditor::UpdateLoadDialog() -{ - // Clear out the control - m_pLoadNameCombo->ClearList(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Get the list of all read in scenes - std::list sceneList; - g_PresetMan.GetAllOfType(sceneList, "Scene"); + bool AreaEditor::SaveScene(const std::string& saveAsName, bool forceOverwrite) { + Scene* editedScene = g_SceneMan.GetScene(); + editedScene->SetPresetName(saveAsName); - // Go through the list and add their names to the combo box - for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) - { - Scene * pScene = dynamic_cast(*itr); - if (pScene) - // Don't add the special "Editor Scene" or metascenes, users shouldn't be messing with them - if (pScene->GetPresetName() != "Editor Scene" && !pScene->IsMetagameInternal() && !pScene->IsSavedGameInternal() && (pScene->GetMetasceneParent() == "" || g_SettingsMan.ShowMetascenes())) - m_pLoadNameCombo->AddItem(pScene->GetPresetName()); - } + std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); + bool savingToUserScenesModule = (dataModuleName == c_UserScenesModuleName); - // Select the first one - m_pLoadNameCombo->SetSelectedIndex(0); -} + std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); + std::string sceneSavePath; + std::string previewSavePath; + if (savingToUserScenesModule) { + sceneSavePath = dataModuleFullPath + "/" + saveAsName + ".ini"; + previewSavePath = dataModuleFullPath + "/" + saveAsName + ".preview.png"; + } else { + sceneSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".ini"; + previewSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".preview.png"; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. + if (g_PresetMan.AddEntityPreset(editedScene, m_ModuleSpaceID, forceOverwrite, sceneSavePath)) { + if (Writer sceneWriter(sceneSavePath, false); !sceneWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + sceneSavePath + "\n\nTHE EDITED SCENE PRESET WAS NOT SAVED!!!"); + } else { + // TODO: Check if the ini file already exists, and then ask if overwrite. + sceneWriter.NewPropertyWithValue("AddScene", editedScene); + sceneWriter.EndWrite(); + + editedScene->SavePreview(previewSavePath); + m_HasEverBeenSaved = true; + + if (!savingToUserScenesModule) { + // First find/create a Scenes.ini file to include the new .ini into. + std::string scenesFilePath(dataModuleFullPath + "/Scenes.ini"); + bool scenesFileExists = System::PathExistsCaseSensitive(scenesFilePath); + + if (Writer scenesFileWriter(scenesFilePath, true); !scenesFileWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + scenesFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); + } else { + scenesFileWriter.NewPropertyWithValue("IncludeFile", sceneSavePath); + scenesFileWriter.EndWrite(); + + // Append to the end of the modules' Index.ini to include the newly created Scenes.ini next startup. + // If it's somehow already included without actually existing, it doesn't matter, the definitions will just bounce the second time. + if (!scenesFileExists) { + std::string indexFilePath = dataModuleFullPath + "/Index.ini"; + + if (Writer indexWriter(indexFilePath, true); !indexWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + indexFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); + } else { + // Add extra tab since the DataModule has everything indented. + indexWriter.NewProperty("\tIncludeFile"); + indexWriter << scenesFilePath; + indexWriter.EndWrite(); + } + } + } + } + return true; + } + } else { + // Got to ask if we can overwrite the existing preset. + m_PreviousMode = EditorMode::SAVEDIALOG; + m_EditorMode = EditorMode::OVERWRITEDIALOG; + m_ModeChange = true; + } + return false; + } -void AreaEditor::UpdateSaveDialog() -{ - m_pSaveNameBox->SetText((g_SceneMan.GetScene()->GetPresetName() == "None" || !m_HasEverBeenSaved) ? "New Scene" : g_SceneMan.GetScene()->GetPresetName()); - if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) - m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/"); - else - m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes"); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + void AreaEditor::UpdateNewDialog() { + // Reset the new Area name text field + if (m_pNewAreaName->GetText().empty()) + m_pNewAreaName->SetText("Test Area 1"); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. + + void AreaEditor::UpdateLoadDialog() { + // Clear out the control + m_pLoadNameCombo->ClearList(); + + // Get the list of all read in scenes + std::list sceneList; + g_PresetMan.GetAllOfType(sceneList, "Scene"); + + // Go through the list and add their names to the combo box + for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) { + Scene* pScene = dynamic_cast(*itr); + if (pScene) + // Don't add the special "Editor Scene" or metascenes, users shouldn't be messing with them + if (pScene->GetPresetName() != "Editor Scene" && !pScene->IsMetagameInternal() && !pScene->IsSavedGameInternal() && (pScene->GetMetasceneParent() == "" || g_SettingsMan.ShowMetascenes())) + m_pLoadNameCombo->AddItem(pScene->GetPresetName()); + } + + // Select the first one + m_pLoadNameCombo->SetSelectedIndex(0); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. -void AreaEditor::UpdateChangesDialog() -{ - if (m_HasEverBeenSaved) - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); + void AreaEditor::UpdateSaveDialog() { + m_pSaveNameBox->SetText((g_SceneMan.GetScene()->GetPresetName() == "None" || !m_HasEverBeenSaved) ? "New Scene" : g_SceneMan.GetScene()->GetPresetName()); if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) - m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); + m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/"); else - m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); - } - else - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Scene first?"); - m_pChangesNameLabel->SetText(""); - } -} + m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes"); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + + void AreaEditor::UpdateChangesDialog() { + if (m_HasEverBeenSaved) { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); + if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) + m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); + else + m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); + } else { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Scene first?"); + m_pChangesNameLabel->SetText(""); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. -void AreaEditor::UpdateOverwriteDialog() -{ - if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) - m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); - else - m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); -} + void AreaEditor::UpdateOverwriteDialog() { + if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) + m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); + else + m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); + } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/AreaEditor.h b/Source/Activities/AreaEditor.h index 900af5070..26378b247 100644 --- a/Source/Activities/AreaEditor.h +++ b/Source/Activities/AreaEditor.h @@ -10,293 +10,266 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "RTETools.h" #include "EditorActivity.h" -namespace RTE -{ - -class AreaEditorGUI; -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUIComboBox; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: AreaEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activity for editing Scene:s' Area:s. -// Parent(s): EditorActivity. -// Class history: 7/21/2008 AreaEditor created, based off SceneEditor - -class AreaEditor : public EditorActivity { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(AreaEditor); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: AreaEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a AreaEditor object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - AreaEditor() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~AreaEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a AreaEditor object before deletion -// from system memory. -// Arguments: None. - - ~AreaEditor() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AreaEditor object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AreaEditor to be identical to another, by deep copy. -// Arguments: A reference to the AreaEditor to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const AreaEditor &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire AreaEditor, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); EditorActivity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AreaEditor object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Saves the current Scene to an appropriate ini file, and asks user if they want to overwrite first if scene of this name exists. - /// - /// The name of the new Scene to be saved. - /// Whether to force any existing Scene of that name to be overwritten if it already exists. - /// Whether actually managed to save. Will return false both if a scene of this name already exists, or if other error. - bool SaveScene(const std::string &saveAsName, bool forceOverwrite = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateNewDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateLoadDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateSaveDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateChangesDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateOverwriteDialog() override; - - - // Member variables - static Entity::ClassInfo m_sClass; - - // The editor GUI - AreaEditorGUI *m_pEditorGUI; - - // The textbox for entering new Area names - GUITextBox *m_pNewAreaName; -// // Number which -// int m_NewAreaNumber; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class AreaEditorGUI; + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUIComboBox; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: AreaEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activity for editing Scene:s' Area:s. + // Parent(s): EditorActivity. + // Class history: 7/21/2008 AreaEditor created, based off SceneEditor + + class AreaEditor : public EditorActivity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(AreaEditor); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: AreaEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a AreaEditor object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + AreaEditor() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~AreaEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a AreaEditor object before deletion + // from system memory. + // Arguments: None. + + ~AreaEditor() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AreaEditor object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AreaEditor to be identical to another, by deep copy. + // Arguments: A reference to the AreaEditor to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const AreaEditor& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire AreaEditor, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + EditorActivity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AreaEditor object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Saves the current Scene to an appropriate ini file, and asks user if they want to overwrite first if scene of this name exists. + /// + /// The name of the new Scene to be saved. + /// Whether to force any existing Scene of that name to be overwritten if it already exists. + /// Whether actually managed to save. Will return false both if a scene of this name already exists, or if other error. + bool SaveScene(const std::string& saveAsName, bool forceOverwrite = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateNewDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateLoadDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateSaveDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateChangesDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateOverwriteDialog() override; + + // Member variables + static Entity::ClassInfo m_sClass; + + // The editor GUI + AreaEditorGUI* m_pEditorGUI; + + // The textbox for entering new Area names + GUITextBox* m_pNewAreaName; + // // Number which + // int m_NewAreaNumber; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/AssemblyEditor.cpp b/Source/Activities/AssemblyEditor.cpp index abf3a9dad..20677ef29 100644 --- a/Source/Activities/AssemblyEditor.cpp +++ b/Source/Activities/AssemblyEditor.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -41,775 +40,680 @@ namespace RTE { -ConcreteClassInfo(AssemblyEditor, EditorActivity, 0); + ConcreteClassInfo(AssemblyEditor, EditorActivity, 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AssemblyEditor, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AssemblyEditor, effectively -// resetting the members of this abstraction level only. + void AssemblyEditor::Clear() { + m_pEditorGUI = 0; + m_pModuleCombo = 0; + } -void AssemblyEditor::Clear() -{ - m_pEditorGUI = 0; - m_pModuleCombo = 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AssemblyEditor object ready for use. + int AssemblyEditor::Create() { + if (EditorActivity::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AssemblyEditor object ready for use. + return 0; + } -int AssemblyEditor::Create() -{ - if (EditorActivity::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AssemblyEditor to be identical to another, by deep copy. + int AssemblyEditor::Create(const AssemblyEditor& reference) { + if (EditorActivity::Create(reference) < 0) + return -1; - return 0; -} + if (m_Description.empty()) + m_Description = "Edit this Scene, including placement of all terrain objects and movable objects, AI blueprints, etc."; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AssemblyEditor to be identical to another, by deep copy. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int AssemblyEditor::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); + /* + MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + */ + EndPropertyList; + } -int AssemblyEditor::Create(const AssemblyEditor &reference) -{ - if (EditorActivity::Create(reference) < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this AssemblyEditor with a Writer for + // later recreation with Create(Reader &reader); - if (m_Description.empty()) - m_Description = "Edit this Scene, including placement of all terrain objects and movable objects, AI blueprints, etc."; + int AssemblyEditor::Save(Writer& writer) const { + EditorActivity::Save(writer); + return 0; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AssemblyEditor object. + void AssemblyEditor::Destroy(bool notInherited) { + delete m_pEditorGUI; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int AssemblyEditor::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); -/* - MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); -*/ - EndPropertyList; -} + if (!notInherited) + EditorActivity::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this AssemblyEditor with a Writer for -// later recreation with Create(Reader &reader); + int AssemblyEditor::Start() { + int error = EditorActivity::Start(); -int AssemblyEditor::Save(Writer &writer) const { - EditorActivity::Save(writer); - return 0; -} + ////////////////////////////////////////////// + // Allocate and (re)create the Editor GUI + if (m_pEditorGUI) + m_pEditorGUI->Destroy(); + else + m_pEditorGUI = new AssemblyEditorGUI; + m_pEditorGUI->Create(&(m_PlayerController[0]), AssemblyEditorGUI::ONLOADEDIT); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AssemblyEditor object. + ////////////////////////////////////////////////////////////// + // Hooking up directly to the controls defined in the GUI ini -void AssemblyEditor::Destroy(bool notInherited) -{ - delete m_pEditorGUI; + m_pGUIController->Load("Base.rte/GUIs/AssemblyEditorGUI.ini"); - if (!notInherited) - EditorActivity::Destroy(); - Clear(); -} + // Resize the invisible root container so it matches the screen rez + GUICollectionBox* pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); + if (pRootBox) + pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of + if (!m_pLoadDialogBox) { + m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); + // m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); + m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); + m_pLoadDialogBox->SetVisible(false); + } + m_pLoadNameCombo = dynamic_cast(m_pGUIController->GetControl("LoadSceneCB")); + m_pLoadNameCombo->SetDropHeight(std::min(m_pLoadNameCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); + m_pModuleCombo = dynamic_cast(m_pGUIController->GetControl("ModuleCB")); + m_pModuleCombo->SetDropHeight(std::min(m_pModuleCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); + m_pLoadDialogBox->SetSize(m_pLoadDialogBox->GetWidth(), m_pLoadDialogBox->GetHeight() + (std::max(m_pLoadNameCombo->GetDropHeight(), m_pModuleCombo->GetDropHeight()))); // Make sure the dropdowns can fit, no matter how tall they are. + m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadSceneButton")); + m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); + + if (!m_pSaveDialogBox) { + m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); + + // Set the background image of the parent collection box + m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); + m_pSaveDialogBox->SetVisible(false); + } + m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveSceneNameTB")); + m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); + m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveSceneButton")); + m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); + + if (!m_pChangesDialogBox) { + m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); + m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); + m_pChangesDialogBox->SetVisible(false); + } + m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); + m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); + m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); + + if (!m_pOverwriteDialogBox) { + m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); + m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); + m_pOverwriteDialogBox->SetVisible(false); + } + m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); + m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); + m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int AssemblyEditor::Start() -{ - int error = EditorActivity::Start(); - - ////////////////////////////////////////////// - // Allocate and (re)create the Editor GUI - - if (m_pEditorGUI) - m_pEditorGUI->Destroy(); - else - m_pEditorGUI = new AssemblyEditorGUI; - m_pEditorGUI->Create(&(m_PlayerController[0]), AssemblyEditorGUI::ONLOADEDIT); - - ////////////////////////////////////////////////////////////// - // Hooking up directly to the controls defined in the GUI ini - - m_pGUIController->Load("Base.rte/GUIs/AssemblyEditorGUI.ini"); - - // Resize the invisible root container so it matches the screen rez - GUICollectionBox *pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); - if (pRootBox) - pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); - - // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of - if (!m_pLoadDialogBox) - { - m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); -// m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); - m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); - m_pLoadDialogBox->SetVisible(false); - } - m_pLoadNameCombo = dynamic_cast(m_pGUIController->GetControl("LoadSceneCB")); - m_pLoadNameCombo->SetDropHeight(std::min(m_pLoadNameCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); - m_pModuleCombo = dynamic_cast(m_pGUIController->GetControl("ModuleCB")); - m_pModuleCombo->SetDropHeight(std::min(m_pModuleCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); - m_pLoadDialogBox->SetSize(m_pLoadDialogBox->GetWidth(), m_pLoadDialogBox->GetHeight() + (std::max(m_pLoadNameCombo->GetDropHeight(), m_pModuleCombo->GetDropHeight()))); // Make sure the dropdowns can fit, no matter how tall they are. - m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadSceneButton")); - m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); - - if (!m_pSaveDialogBox) - { - m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); - - // Set the background image of the parent collection box - m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); - m_pSaveDialogBox->SetVisible(false); - } - m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveSceneNameTB")); - m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); - m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveSceneButton")); - m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); - - if (!m_pChangesDialogBox) - { - m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); - m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); - m_pChangesDialogBox->SetVisible(false); - } - m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); - m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); - m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); - - if (!m_pOverwriteDialogBox) - { - m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); - m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); - m_pOverwriteDialogBox->SetVisible(false); - } - m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); - m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); - m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); - - return error; -} + return error; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + void AssemblyEditor::SetPaused(bool pause) { + // Override the pause + m_Paused = false; + } -void AssemblyEditor::SetPaused(bool pause) -{ - // Override the pause - m_Paused = false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + void AssemblyEditor::End() { + EditorActivity::End(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. + m_ActivityState = ActivityState::Over; + } -void AssemblyEditor::End() -{ - EditorActivity::End(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this AssemblyEditor. Supposed to be done every frame + // before drawing. + + void AssemblyEditor::Update() { + EditorActivity::Update(); + + if (!g_SceneMan.GetScene()) + return; + + // Update the loaded objects of the loaded scene so they look right + g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::PLACEONLOAD); + + // All dialog boxes are gone and we're editing the scene + if (m_EditorMode == EditorActivity::EDITINGOBJECT) { + if (m_ModeChange) { + // Open the picker depending on whetehr there's somehting in the cursor hand or not + m_pEditorGUI->SetEditorGUIMode(m_pEditorGUI->GetCurrentObject() ? AssemblyEditorGUI::ADDINGOBJECT : AssemblyEditorGUI::PICKINGOBJECT); + // Hide the cursor for this layer of interface + m_pGUIController->EnableMouse(false); + m_ModeChange = false; + } + g_UInputMan.DisableKeys(false); + } + // We are doing something int he dialog boxes, so don't do anything in the editor interface + else + m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); + + ///////////////////////////////////////////////////// + // Update the editor interface + + m_pEditorGUI->Update(); + + // Any edits made, dirtying the scene? + m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; + + // Get any mode change commands that the user gave the Editor GUI + if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) { + m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::NEWDIALOG; + m_ModeChange = true; + } else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorLoad && m_EditorMode != LOADDIALOG) { + m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::LOADDIALOG; + m_ModeChange = true; + } else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) { + m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + //////////////////////////////////////////////////////// + // Handle events for mouse input on the controls + GUIEvent anEvent; + while (m_pGUIController->GetEvent(&anEvent)) { + // If we're not supposed to have mouse control, then ignore these messages + // Uh this is not right, editor always has mouse control so far + // if (!m_PlayerController[0].IsMouseControlled()) + // break; - m_ActivityState = ActivityState::Over; -} + if (anEvent.GetType() == GUIEvent::Command) { + ////////////////////////////////////////////////////////// + // LOAD TO NEW button pressed; go from the load to the new dialog + if (anEvent.GetControl() == m_pLoadToNewButton) { + m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::NEWDIALOG; + m_ModeChange = true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this AssemblyEditor. Supposed to be done every frame -// before drawing. - -void AssemblyEditor::Update() -{ - EditorActivity::Update(); - - if (!g_SceneMan.GetScene()) - return; - - // Update the loaded objects of the loaded scene so they look right - g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::PLACEONLOAD); - - // All dialog boxes are gone and we're editing the scene - if (m_EditorMode == EditorActivity::EDITINGOBJECT) - { - if (m_ModeChange) - { - // Open the picker depending on whetehr there's somehting in the cursor hand or not - m_pEditorGUI->SetEditorGUIMode(m_pEditorGUI->GetCurrentObject() ? AssemblyEditorGUI::ADDINGOBJECT : AssemblyEditorGUI::PICKINGOBJECT); - // Hide the cursor for this layer of interface - m_pGUIController->EnableMouse(false); - m_ModeChange = false; - } - g_UInputMan.DisableKeys(false); - } - // We are doing something int he dialog boxes, so don't do anything in the editor interface - else - m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); - - - ///////////////////////////////////////////////////// - // Update the editor interface - - m_pEditorGUI->Update(); - - // Any edits made, dirtying the scene? - m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; - - // Get any mode change commands that the user gave the Editor GUI - if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::NEWDIALOG; - m_ModeChange = true; - } - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorLoad && m_EditorMode != LOADDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::LOADDIALOG; - m_ModeChange = true; - } - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - - //////////////////////////////////////////////////////// - // Handle events for mouse input on the controls - - GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { - // If we're not supposed to have mouse control, then ignore these messages -// Uh this is not right, editor always has mouse control so far -// if (!m_PlayerController[0].IsMouseControlled()) -// break; - - if (anEvent.GetType() == GUIEvent::Command) - { - ////////////////////////////////////////////////////////// - // LOAD TO NEW button pressed; go from the load to the new dialog - - if (anEvent.GetControl() == m_pLoadToNewButton) - { - m_pEditorGUI->SetEditorGUIMode(AssemblyEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::NEWDIALOG; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // LOAD button pressed; load the selected Scene - - if (anEvent.GetControl() == m_pLoadButton) - { - GUIListPanel::Item *pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - // Attempt to load the scene, without applying its placed objects - g_SceneMan.SetSceneToLoad(pItem->m_Name, false); - g_SceneMan.LoadScene(); - // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space - if (g_SceneMan.GetScene()) - { - //m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); - m_ModuleSpaceID = g_PresetMan.GetModuleID(m_pModuleCombo->GetSelectedItem()->m_Name); - RTEAssert(m_ModuleSpaceID >= 0, "Loaded Scene's DataModule ID is negative? Should always be a specific one.."); - m_pEditorGUI->Destroy(); - if (m_ModuleSpaceID == g_PresetMan.GetModuleID(c_UserScenesModuleName)) - m_pEditorGUI->Create(&(m_PlayerController[0]), AssemblyEditorGUI::ONLOADEDIT, -1); - else - m_pEditorGUI->Create(&(m_PlayerController[0]), AssemblyEditorGUI::ONLOADEDIT, m_ModuleSpaceID); -// TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead - } - } - m_NeedSave = false; - m_HasEverBeenSaved = true; - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // SAVE button pressed; save the selected Scene - if (anEvent.GetControl() == m_pSaveButton) - { - if (!m_pSaveNameBox->GetText().empty()) - { - // Save the scene to the name specified in the text box - if (SaveAssembly(m_pSaveNameBox->GetText())) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - // Should really leave dialog box open? - else - { - ; - } - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes YES pressed - - if (anEvent.GetControl() == m_pChangesYesButton) - { - if (m_HasEverBeenSaved) - { - if (SaveAssembly(m_pEditorGUI->GetCurrentAssemblyName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - } - // Open the save scene dialog to ask user where to save it then - else - { - m_PreviousMode = m_PreviousMode; - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes NO pressed - - if (anEvent.GetControl() == m_pChangesNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - m_NeedSave = false; - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene YES pressed - - if (anEvent.GetControl() == m_pOverwriteYesButton) - { - // Force overwrite - if (SaveAssembly(m_pEditorGUI->GetCurrentAssemblyName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene - m_EditorMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene NO pressed - - if (anEvent.GetControl() == m_pOverwriteNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - - /////////////////////////////////////////////////////////////// - // CANCEL button pressed; exit any active dialog box - - if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) - { - // Don't allow canceling out of diags if we're still in the special "Editor Scene", don't allow users to edit it! - // Just exit the whole editor into the main menu - if (g_SceneMan.GetScene()->GetPresetName() == "Editor Scene") - { - g_ActivityMan.PauseActivity(); - } - // Just do normal cancel of the dialog and go back to editing - else - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - - m_ModeChange = true; - } - } - - // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { - /////////////////////////////////////// - // Clicks on the New Scene Module combo - - if (anEvent.GetControl() == m_pNewModuleCombo) - { - // Closed it, IE selected somehting - if(anEvent.GetMsg() == GUIComboBox::Closed) - UpdateNewDialog(); - } - } - } -} + ////////////////////////////////////////////////////////// + // LOAD button pressed; load the selected Scene + + if (anEvent.GetControl() == m_pLoadButton) { + GUIListPanel::Item* pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + // Attempt to load the scene, without applying its placed objects + g_SceneMan.SetSceneToLoad(pItem->m_Name, false); + g_SceneMan.LoadScene(); + // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space + if (g_SceneMan.GetScene()) { + // m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); + m_ModuleSpaceID = g_PresetMan.GetModuleID(m_pModuleCombo->GetSelectedItem()->m_Name); + RTEAssert(m_ModuleSpaceID >= 0, "Loaded Scene's DataModule ID is negative? Should always be a specific one.."); + m_pEditorGUI->Destroy(); + if (m_ModuleSpaceID == g_PresetMan.GetModuleID(c_UserScenesModuleName)) + m_pEditorGUI->Create(&(m_PlayerController[0]), AssemblyEditorGUI::ONLOADEDIT, -1); + else + m_pEditorGUI->Create(&(m_PlayerController[0]), AssemblyEditorGUI::ONLOADEDIT, m_ModuleSpaceID); + // TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead + } + } + m_NeedSave = false; + m_HasEverBeenSaved = true; + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + ////////////////////////////////////////////////////////// + // SAVE button pressed; save the selected Scene + if (anEvent.GetControl() == m_pSaveButton) { + if (!m_pSaveNameBox->GetText().empty()) { + // Save the scene to the name specified in the text box + if (SaveAssembly(m_pSaveNameBox->GetText())) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + // Should really leave dialog box open? + else { + ; + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. + /////////////////////////////////////////////////////////////// + // Save Changes YES pressed + + if (anEvent.GetControl() == m_pChangesYesButton) { + if (m_HasEverBeenSaved) { + if (SaveAssembly(m_pEditorGUI->GetCurrentAssemblyName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + } + // Open the save scene dialog to ask user where to save it then + else { + m_PreviousMode = m_PreviousMode; + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + } -void AssemblyEditor::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - m_pEditorGUI->Draw(pTargetBitmap, targetPos); + /////////////////////////////////////////////////////////////// + // Save Changes NO pressed - EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); -} + if (anEvent.GetControl() == m_pChangesNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + m_NeedSave = false; + } + /////////////////////////////////////////////////////////////// + // Overwrite Scene YES pressed + + if (anEvent.GetControl() == m_pOverwriteYesButton) { + // Force overwrite + if (SaveAssembly(m_pEditorGUI->GetCurrentAssemblyName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene + m_EditorMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this AssemblyEditor's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + /////////////////////////////////////////////////////////////// + // Overwrite Scene NO pressed -void AssemblyEditor::Draw(BITMAP* pTargetBitmap, const Vector &targetPos) -{ - EditorActivity::Draw(pTargetBitmap, targetPos); -} + if (anEvent.GetControl() == m_pOverwriteNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + /////////////////////////////////////////////////////////////// + // CANCEL button pressed; exit any active dialog box + if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) { + // Don't allow canceling out of diags if we're still in the special "Editor Scene", don't allow users to edit it! + // Just exit the whole editor into the main menu + if (g_SceneMan.GetScene()->GetPresetName() == "Editor Scene") { + g_ActivityMan.PauseActivity(); + } + // Just do normal cancel of the dialog and go back to editing + else + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildAssembly -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and builds assembly which fits currently selected scheme and returns -// it's pointer. Owhership IS transfered. - -BunkerAssembly * AssemblyEditor::BuildAssembly(std::string saveAsName) -{ - // Create new bunker assembly to save - BunkerAssembly *pBA = new BunkerAssembly(); - pBA->Create(m_pEditorGUI->GetCurrentAssemblyScheme()); - - // Retreive some properties if we're overwriting existing bunker assembly - const BunkerAssembly * pExistingBA = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssembly", saveAsName, m_ModuleSpaceID)); - if (pExistingBA) - { - pBA->SetSymmetricAssemblyName(pExistingBA->GetSymmetricAssemblyName()); - } + m_ModeChange = true; + } + } - pBA->SetPresetName(saveAsName); - m_pEditorGUI->SetCurrentAssemblyName(saveAsName); + // Notifications + else if (anEvent.GetType() == GUIEvent::Notification) { + /////////////////////////////////////// + // Clicks on the New Scene Module combo - const std::list *pSceneObjectList = 0; - pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); - for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr) - { - //Check if object fits the assembly box - bool skip = true; + if (anEvent.GetControl() == m_pNewModuleCombo) { + // Closed it, IE selected somehting + if (anEvent.GetMsg() == GUIComboBox::Closed) + UpdateNewDialog(); + } + } + } + } - Vector pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset(); - Vector finalPos = pos; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. - if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && - (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) - skip = false; + void AssemblyEditor::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + m_pEditorGUI->Draw(pTargetBitmap, targetPos); - // Try to move scene object across seams and see if it fits into assembly box - if (g_SceneMan.GetScene()->WrapsX()) - { - pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() + Vector(g_SceneMan.GetScene()->GetWidth(), 0); + EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); + } - if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && - (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) - { - skip = false; - finalPos = pos; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this AssemblyEditor's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. - pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() - Vector(g_SceneMan.GetScene()->GetWidth(), 0); + void AssemblyEditor::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + EditorActivity::Draw(pTargetBitmap, targetPos); + } - if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && - (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) - { - skip = false; - finalPos = pos; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildAssembly + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and builds assembly which fits currently selected scheme and returns + // it's pointer. Owhership IS transfered. + + BunkerAssembly* AssemblyEditor::BuildAssembly(std::string saveAsName) { + // Create new bunker assembly to save + BunkerAssembly* pBA = new BunkerAssembly(); + pBA->Create(m_pEditorGUI->GetCurrentAssemblyScheme()); + + // Retreive some properties if we're overwriting existing bunker assembly + const BunkerAssembly* pExistingBA = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssembly", saveAsName, m_ModuleSpaceID)); + if (pExistingBA) { + pBA->SetSymmetricAssemblyName(pExistingBA->GetSymmetricAssemblyName()); } - if (g_SceneMan.GetScene()->WrapsY()) - { - pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() + Vector(0, g_SceneMan.GetScene()->GetHeight()); + pBA->SetPresetName(saveAsName); + m_pEditorGUI->SetCurrentAssemblyName(saveAsName); - if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && - (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) - { - skip = false; - finalPos = pos; - } + const std::list* pSceneObjectList = 0; + pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); + for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr) { + // Check if object fits the assembly box + bool skip = true; - pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() - Vector(0, g_SceneMan.GetScene()->GetHeight()); + Vector pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset(); + Vector finalPos = pos; if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && - (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) - { + (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) skip = false; - finalPos = pos; - } - } - if (!skip) - { - SceneObject *pNewSO = dynamic_cast((*itr)->Clone()); + // Try to move scene object across seams and see if it fits into assembly box + if (g_SceneMan.GetScene()->WrapsX()) { + pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() + Vector(g_SceneMan.GetScene()->GetWidth(), 0); - //Set position relative to this Bunker Assembly - //pNewSO->SetPos(pNewSO->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset()); - pNewSO->SetPos(finalPos); - pBA->AddPlacedObject(pNewSO); - } - } + if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && + (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) { + skip = false; + finalPos = pos; + } + + pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() - Vector(g_SceneMan.GetScene()->GetWidth(), 0); + + if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && + (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) { + skip = false; + finalPos = pos; + } + } - return pBA; -} + if (g_SceneMan.GetScene()->WrapsY()) { + pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() + Vector(0, g_SceneMan.GetScene()->GetHeight()); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && + (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) { + skip = false; + finalPos = pos; + } -bool AssemblyEditor::SaveAssembly(const std::string &saveAsName, bool forceOverwrite) { - std::unique_ptr editedAssembly(BuildAssembly(saveAsName)); + pos = (*itr)->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset() - Vector(0, g_SceneMan.GetScene()->GetHeight()); - std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); - bool savingToUserScenesModule = (dataModuleName == c_UserScenesModuleName); + if ((pos.m_X >= 0) && (pos.m_X < pBA->GetBitmapWidth()) && + (pos.m_Y >= 0) && (pos.m_Y < pBA->GetBitmapHeight())) { + skip = false; + finalPos = pos; + } + } - std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); - std::string assemblySavePath; + if (!skip) { + SceneObject* pNewSO = dynamic_cast((*itr)->Clone()); - if (savingToUserScenesModule) { - assemblySavePath = dataModuleFullPath + "/" + saveAsName + ".ini"; - } else { - if (dataModuleName == "Base.rte") { - assemblySavePath = dataModuleFullPath + "/Scenes/Objects/Bunkers/BunkerAssemblies/" + saveAsName + ".ini"; - } else { - System::MakeDirectory((dataModuleFullPath + "/BunkerAssemblies").c_str()); - assemblySavePath = dataModuleFullPath + "/BunkerAssemblies/" + saveAsName + ".ini"; + // Set position relative to this Bunker Assembly + // pNewSO->SetPos(pNewSO->GetPos() - pBA->GetPos() - pBA->GetBitmapOffset()); + pNewSO->SetPos(finalPos); + pBA->AddPlacedObject(pNewSO); + } } + + return pBA; } - if (g_PresetMan.AddEntityPreset(editedAssembly.get(), m_ModuleSpaceID, forceOverwrite, assemblySavePath)) { - if (Writer assemblyWriter(assemblySavePath, false); !assemblyWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + assemblySavePath + "\n\nTHE EDITED BUNKER ASSEMBLY PRESET WAS NOT SAVED!!!"); - } else { - // TODO: Check if the ini file already exists, and then ask if overwrite. - assemblyWriter.NewPropertyWithValue("AddBunkerAssembly", editedAssembly.get()); - assemblyWriter.EndWrite(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - m_HasEverBeenSaved = true; + bool AssemblyEditor::SaveAssembly(const std::string& saveAsName, bool forceOverwrite) { + std::unique_ptr editedAssembly(BuildAssembly(saveAsName)); - if (!savingToUserScenesModule) { - // First find/create a BunkerAssemblies.ini file to include the new .ini into. - std::string assembliesFilePath = dataModuleFullPath + ((dataModuleName == "Base.rte") ? "/Scenes/Objects/Bunkers/BunkerAssemblies/BunkerAssemblies.ini" : "/BunkerAssemblies/BunkerAssemblies.ini"); - bool assembliesFileExists = System::PathExistsCaseSensitive(assembliesFilePath); + std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); + bool savingToUserScenesModule = (dataModuleName == c_UserScenesModuleName); - if (Writer assembliesFileWriter(assembliesFilePath, true); !assembliesFileWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + assembliesFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); - } else { - assembliesFileWriter.NewPropertyWithValue("IncludeFile", assemblySavePath); - assembliesFileWriter.EndWrite(); - - // Append to the end of the modules' Index.ini to include the newly created Scenes.ini next startup. - // If it's somehow already included without actually existing, it doesn't matter, the definitions will just bounce the second time. - if (!assembliesFileExists) { - std::string indexFilePath = dataModuleFullPath + "/Index.ini"; - - if (Writer indexWriter(indexFilePath, true); !indexWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + indexFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); - } else { - // Add extra tab since the DataModule has everything indented. - indexWriter.NewProperty("\tIncludeFile"); - indexWriter << assembliesFilePath; - indexWriter.EndWrite(); + std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); + std::string assemblySavePath; + + if (savingToUserScenesModule) { + assemblySavePath = dataModuleFullPath + "/" + saveAsName + ".ini"; + } else { + if (dataModuleName == "Base.rte") { + assemblySavePath = dataModuleFullPath + "/Scenes/Objects/Bunkers/BunkerAssemblies/" + saveAsName + ".ini"; + } else { + System::MakeDirectory((dataModuleFullPath + "/BunkerAssemblies").c_str()); + assemblySavePath = dataModuleFullPath + "/BunkerAssemblies/" + saveAsName + ".ini"; + } + } + + if (g_PresetMan.AddEntityPreset(editedAssembly.get(), m_ModuleSpaceID, forceOverwrite, assemblySavePath)) { + if (Writer assemblyWriter(assemblySavePath, false); !assemblyWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + assemblySavePath + "\n\nTHE EDITED BUNKER ASSEMBLY PRESET WAS NOT SAVED!!!"); + } else { + // TODO: Check if the ini file already exists, and then ask if overwrite. + assemblyWriter.NewPropertyWithValue("AddBunkerAssembly", editedAssembly.get()); + assemblyWriter.EndWrite(); + + m_HasEverBeenSaved = true; + + if (!savingToUserScenesModule) { + // First find/create a BunkerAssemblies.ini file to include the new .ini into. + std::string assembliesFilePath = dataModuleFullPath + ((dataModuleName == "Base.rte") ? "/Scenes/Objects/Bunkers/BunkerAssemblies/BunkerAssemblies.ini" : "/BunkerAssemblies/BunkerAssemblies.ini"); + bool assembliesFileExists = System::PathExistsCaseSensitive(assembliesFilePath); + + if (Writer assembliesFileWriter(assembliesFilePath, true); !assembliesFileWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + assembliesFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); + } else { + assembliesFileWriter.NewPropertyWithValue("IncludeFile", assemblySavePath); + assembliesFileWriter.EndWrite(); + + // Append to the end of the modules' Index.ini to include the newly created Scenes.ini next startup. + // If it's somehow already included without actually existing, it doesn't matter, the definitions will just bounce the second time. + if (!assembliesFileExists) { + std::string indexFilePath = dataModuleFullPath + "/Index.ini"; + + if (Writer indexWriter(indexFilePath, true); !indexWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + indexFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); + } else { + // Add extra tab since the DataModule has everything indented. + indexWriter.NewProperty("\tIncludeFile"); + indexWriter << assembliesFilePath; + indexWriter.EndWrite(); + } } } } + return true; } - return true; + } else { + // Got to ask if we can overwrite the existing preset. + m_PreviousMode = EditorMode::SAVEDIALOG; + m_EditorMode = EditorMode::OVERWRITEDIALOG; + m_ModeChange = true; } - } else { - // Got to ask if we can overwrite the existing preset. - m_PreviousMode = EditorMode::SAVEDIALOG; - m_EditorMode = EditorMode::OVERWRITEDIALOG; - m_ModeChange = true; + return false; } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. + void AssemblyEditor::UpdateNewDialog() { + } -void AssemblyEditor::UpdateNewDialog() -{ + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. -} + void AssemblyEditor::UpdateLoadDialog() { + int scenesIndex = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. - -void AssemblyEditor::UpdateLoadDialog() -{ - int scenesIndex = 0; - - if (m_pModuleCombo->GetCount() <= 0) - { - for (int module = 0; module < g_PresetMan.GetTotalModuleCount(); ++module) - { - // Cut-off vanilla modules except Base.rte - bool isValid = false; - - // If metascenes are visible then allow to save assemblies to Base.rte - if (g_SettingsMan.ShowMetascenes()) - { - if ((module == 0 || module > 8) && g_PresetMan.GetDataModule(module)->GetFileName() != c_UserConquestSavesModuleName - && g_PresetMan.GetDataModule(module)->GetFileName() != "Missions.rte") - isValid = true; - } else { - if (module > 8 && g_PresetMan.GetDataModule(module)->GetFileName() != c_UserConquestSavesModuleName - && g_PresetMan.GetDataModule(module)->GetFileName() != "Missions.rte" && g_PresetMan.GetDataModule(module)->GetFileName() != c_UserScriptedSavesModuleName) - isValid = true; - } + if (m_pModuleCombo->GetCount() <= 0) { + for (int module = 0; module < g_PresetMan.GetTotalModuleCount(); ++module) { + // Cut-off vanilla modules except Base.rte + bool isValid = false; - // If Saving to Base.rte is enabled, every module is valid for saving - if (g_SettingsMan.AllowSavingToBase()) - isValid = true; - - if (isValid) - { - m_pModuleCombo->AddItem(g_PresetMan.GetDataModule(module)->GetFileName()); + // If metascenes are visible then allow to save assemblies to Base.rte + if (g_SettingsMan.ShowMetascenes()) { + if ((module == 0 || module > 8) && g_PresetMan.GetDataModule(module)->GetFileName() != c_UserConquestSavesModuleName && g_PresetMan.GetDataModule(module)->GetFileName() != "Missions.rte") + isValid = true; + } else { + if (module > 8 && g_PresetMan.GetDataModule(module)->GetFileName() != c_UserConquestSavesModuleName && g_PresetMan.GetDataModule(module)->GetFileName() != "Missions.rte" && g_PresetMan.GetDataModule(module)->GetFileName() != c_UserScriptedSavesModuleName) + isValid = true; + } + // If Saving to Base.rte is enabled, every module is valid for saving if (g_SettingsMan.AllowSavingToBase()) - { - // If editors are in dev-mode then select Base.rte as default module to save stuff - if (g_PresetMan.GetDataModule(module)->GetFileName() == "Base.rte") - scenesIndex = m_pModuleCombo->GetCount() - 1; - } - else - { - if (g_PresetMan.GetDataModule(module)->GetFileName() == c_UserScenesModuleName) - scenesIndex = m_pModuleCombo->GetCount() - 1; - } - } - } + isValid = true; - m_pModuleCombo->SetDropHeight(std::min({ m_pModuleCombo->GetListPanel()->GetStackHeight() + 4, m_pModuleCombo->GetDropHeight(), g_WindowMan.GetResY() / 2 })); - // Select the user scenes module - m_pModuleCombo->SetSelectedIndex(scenesIndex); - } + if (isValid) { + m_pModuleCombo->AddItem(g_PresetMan.GetDataModule(module)->GetFileName()); - // Clear out the control - m_pLoadNameCombo->ClearList(); + if (g_SettingsMan.AllowSavingToBase()) { + // If editors are in dev-mode then select Base.rte as default module to save stuff + if (g_PresetMan.GetDataModule(module)->GetFileName() == "Base.rte") + scenesIndex = m_pModuleCombo->GetCount() - 1; + } else { + if (g_PresetMan.GetDataModule(module)->GetFileName() == c_UserScenesModuleName) + scenesIndex = m_pModuleCombo->GetCount() - 1; + } + } + } - // Get the list of all read in scenes - std::list sceneList; - g_PresetMan.GetAllOfType(sceneList, "Scene"); + m_pModuleCombo->SetDropHeight(std::min({m_pModuleCombo->GetListPanel()->GetStackHeight() + 4, m_pModuleCombo->GetDropHeight(), g_WindowMan.GetResY() / 2})); + // Select the user scenes module + m_pModuleCombo->SetSelectedIndex(scenesIndex); + } - // Go through the list and add their names to the combo box - for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) - { - Scene * pScene = dynamic_cast(*itr); - if (pScene) - // Don't add the special "Editor Scene" or metascenes, users shouldn't be messing with them - if (pScene->GetPresetName() != "Editor Scene" && !pScene->IsMetagameInternal() && !pScene->IsSavedGameInternal() && (pScene->GetMetasceneParent() == "" || g_SettingsMan.ShowMetascenes())) - m_pLoadNameCombo->AddItem(pScene->GetPresetName()); - } + // Clear out the control + m_pLoadNameCombo->ClearList(); - // Select the first one - m_pLoadNameCombo->SetSelectedIndex(0); -} + // Get the list of all read in scenes + std::list sceneList; + g_PresetMan.GetAllOfType(sceneList, "Scene"); + // Go through the list and add their names to the combo box + for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) { + Scene* pScene = dynamic_cast(*itr); + if (pScene) + // Don't add the special "Editor Scene" or metascenes, users shouldn't be messing with them + if (pScene->GetPresetName() != "Editor Scene" && !pScene->IsMetagameInternal() && !pScene->IsSavedGameInternal() && (pScene->GetMetasceneParent() == "" || g_SettingsMan.ShowMetascenes())) + m_pLoadNameCombo->AddItem(pScene->GetPresetName()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. + // Select the first one + m_pLoadNameCombo->SetSelectedIndex(0); + } -void AssemblyEditor::UpdateSaveDialog() -{ - std::string defaultName = ""; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. - BunkerAssemblyScheme *pScheme = m_pEditorGUI->GetCurrentAssemblyScheme(); - if (pScheme) - defaultName = pScheme->GetPresetName() + " - "; + void AssemblyEditor::UpdateSaveDialog() { + std::string defaultName = ""; - m_pSaveNameBox->SetText(m_pEditorGUI->GetCurrentAssemblyName() == "" ? defaultName : m_pEditorGUI->GetCurrentAssemblyName()); - m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName()); -} + BunkerAssemblyScheme* pScheme = m_pEditorGUI->GetCurrentAssemblyScheme(); + if (pScheme) + defaultName = pScheme->GetPresetName() + " - "; + m_pSaveNameBox->SetText(m_pEditorGUI->GetCurrentAssemblyName() == "" ? defaultName : m_pEditorGUI->GetCurrentAssemblyName()); + m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. - -void AssemblyEditor::UpdateChangesDialog() -{ - if (m_HasEverBeenSaved) - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); - m_pChangesNameLabel->SetText(m_pEditorGUI->GetCurrentAssemblyName()); - } - else - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Assembly first?"); - m_pChangesNameLabel->SetText(m_pEditorGUI->GetCurrentAssemblyName()); - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + void AssemblyEditor::UpdateChangesDialog() { + if (m_HasEverBeenSaved) { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); + m_pChangesNameLabel->SetText(m_pEditorGUI->GetCurrentAssemblyName()); + } else { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Assembly first?"); + m_pChangesNameLabel->SetText(m_pEditorGUI->GetCurrentAssemblyName()); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. -void AssemblyEditor::UpdateOverwriteDialog() -{ - m_pOverwriteNameLabel->SetText(m_pEditorGUI->GetCurrentAssemblyName()); -} + void AssemblyEditor::UpdateOverwriteDialog() { + m_pOverwriteNameLabel->SetText(m_pEditorGUI->GetCurrentAssemblyName()); + } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/AssemblyEditor.h b/Source/Activities/AssemblyEditor.h index de2d6bb7c..37e714b7c 100644 --- a/Source/Activities/AssemblyEditor.h +++ b/Source/Activities/AssemblyEditor.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -18,295 +17,268 @@ #include "EditorActivity.h" #include "BunkerAssembly.h" -namespace RTE -{ - -class AssemblyEditorGUI; -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUIComboBox; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: AssemblyEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activity for editing scenes. -// Parent(s): EditorActivity. -// Class history: 8/30/2007 AssemblyEditor created, inheriting directly from Activity. -// 9/17/2007 Spliced out and made to derive from EditorActivty - -class AssemblyEditor : public EditorActivity { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(AssemblyEditor); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: AssemblyEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a AssemblyEditor object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - AssemblyEditor() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~AssemblyEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a AssemblyEditor object before deletion -// from system memory. -// Arguments: None. - - ~AssemblyEditor() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AssemblyEditor object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AssemblyEditor to be identical to another, by deep copy. -// Arguments: A reference to the AssemblyEditor to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const AssemblyEditor &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire AssemblyEditor, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); EditorActivity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AssemblyEditor object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildAssembly -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and builds assembly which fits currently selected scheme and returns -// it's pointer. Owhership IS transfered. -// Arguments: New assembly name. -// Return value: Built BunkerAssembly - - BunkerAssembly *BuildAssembly(std::string saveAsName); - - - /// - /// Saves the current BunkerAssembly to an appropriate ini file, and asks user if they want to overwrite first if a BunkerAssembly of this name exists. - /// - /// The name of the new BunkerAssembly to be saved. - /// Whether to force any existing BunkerAssembly of that name to be overwritten if it already exists. - /// Whether actually managed to save. Will return false both if a BunkerAssembly of this name already exists, or if other error. - bool SaveAssembly(const std::string &saveAsName, bool forceOverwrite = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateNewDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateLoadDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateSaveDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateChangesDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateOverwriteDialog() override; - - - // Member variables - static Entity::ClassInfo m_sClass; - - // The editor GUI - AssemblyEditorGUI *m_pEditorGUI; - - GUIComboBox *m_pModuleCombo; - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class AssemblyEditorGUI; + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUIComboBox; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: AssemblyEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activity for editing scenes. + // Parent(s): EditorActivity. + // Class history: 8/30/2007 AssemblyEditor created, inheriting directly from Activity. + // 9/17/2007 Spliced out and made to derive from EditorActivty + + class AssemblyEditor : public EditorActivity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(AssemblyEditor); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: AssemblyEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a AssemblyEditor object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + AssemblyEditor() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~AssemblyEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a AssemblyEditor object before deletion + // from system memory. + // Arguments: None. + + ~AssemblyEditor() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AssemblyEditor object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AssemblyEditor to be identical to another, by deep copy. + // Arguments: A reference to the AssemblyEditor to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const AssemblyEditor& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire AssemblyEditor, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + EditorActivity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AssemblyEditor object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildAssembly + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and builds assembly which fits currently selected scheme and returns + // it's pointer. Owhership IS transfered. + // Arguments: New assembly name. + // Return value: Built BunkerAssembly + + BunkerAssembly* BuildAssembly(std::string saveAsName); + + /// + /// Saves the current BunkerAssembly to an appropriate ini file, and asks user if they want to overwrite first if a BunkerAssembly of this name exists. + /// + /// The name of the new BunkerAssembly to be saved. + /// Whether to force any existing BunkerAssembly of that name to be overwritten if it already exists. + /// Whether actually managed to save. Will return false both if a BunkerAssembly of this name already exists, or if other error. + bool SaveAssembly(const std::string& saveAsName, bool forceOverwrite = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateNewDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateLoadDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateSaveDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateChangesDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateOverwriteDialog() override; + + // Member variables + static Entity::ClassInfo m_sClass; + + // The editor GUI + AssemblyEditorGUI* m_pEditorGUI; + + GUIComboBox* m_pModuleCombo; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/BaseEditor.cpp b/Source/Activities/BaseEditor.cpp index 1fb53e401..c533311d3 100644 --- a/Source/Activities/BaseEditor.cpp +++ b/Source/Activities/BaseEditor.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -36,361 +35,330 @@ namespace RTE { -ConcreteClassInfo(BaseEditor, Activity, 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this BaseEditor, effectively -// resetting the members of this abstraction level only. - -void BaseEditor::Clear() -{ - m_pEditorGUI = 0; - m_NeedSave = false; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BaseEditor object ready for use. - -int BaseEditor::Create() -{ - if (Activity::Create() < 0) - return -1; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a BaseEditor to be identical to another, by deep copy. - -int BaseEditor::Create(const BaseEditor &reference) -{ - if (Activity::Create(reference) < 0) - return -1; - - if (m_Description.empty()) - m_Description = "Build or Edit a base on this Scene."; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int BaseEditor::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Activity::ReadProperty(propName, reader)); -/* - MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); -*/ - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this BaseEditor with a Writer for -// later recreation with Create(Reader &reader); - -int BaseEditor::Save(Writer &writer) const { - Activity::Save(writer); - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the BaseEditor object. - -void BaseEditor::Destroy(bool notInherited) -{ - delete m_pEditorGUI; - - if (!notInherited) - Activity::Destroy(); - Clear(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int BaseEditor::Start() -{ - // Set the split screen config before the Scene (and it SceneLayers, specifially) are loaded - g_FrameMan.ResetSplitScreens(false, false); -// Too diff -// int error = Activity::Start(); - int error = 0; - - m_ActivityState = ActivityState::Running; - m_Paused = false; - - // Reset the mousemoving so that it won't trap the mouse if the window isn't in focus (common after loading) - g_UInputMan.DisableMouseMoving(true); - g_UInputMan.DisableMouseMoving(false); - - // Enable keys again - g_UInputMan.DisableKeys(false); - - // Load the scene now - error = g_SceneMan.LoadScene(); - if (error < 0) - return error; - - // Open all doors so we can pathfind past them for brain placement - g_MovableMan.OpenAllDoors(true, Teams::NoTeam); - - /////////////////////////////////////// - // Set up player - ONLY ONE ever in a base building activity - - // Figure which player is editing this base.. the first active one we find - int editingPlayer = Players::PlayerOne; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - if (m_IsActive[player]) - editingPlayer = player; -// TODO: support multiple coop players editing the same base?? - A: NO, silly - -// for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) -// { -// if (!m_IsActive[player]) -// continue; - m_ViewState[editingPlayer] = ViewState::Normal; - g_FrameMan.ClearScreenText(ScreenOfPlayer(editingPlayer)); - // Set the team associations with the first screen so that the correct unseen are shows up - g_CameraMan.SetScreenTeam(m_Team[editingPlayer], ScreenOfPlayer(editingPlayer)); - g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(editingPlayer)); - - m_PlayerController[editingPlayer].Reset(); - m_PlayerController[editingPlayer].Create(Controller::CIM_PLAYER, editingPlayer); - m_PlayerController[editingPlayer].SetTeam(m_Team[editingPlayer]); - - m_MessageTimer[editingPlayer].Reset(); -// } - - // Kill off any actors not of this player's team.. they're not supposed to be here - g_MovableMan.KillAllEnemyActors(GetTeamOfPlayer(editingPlayer)); - - ////////////////////////////////////////////// - // Allocate and (re)create the Editor GUI - - if (m_pEditorGUI) - m_pEditorGUI->Destroy(); - else - m_pEditorGUI = new SceneEditorGUI; - m_pEditorGUI->Create(&(m_PlayerController[editingPlayer]), SceneEditorGUI::BLUEPRINTEDIT); - - // See if we are playing a metagame and which metaplayer this would be editing in this activity - if (g_MetaMan.GameInProgress()) - { - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(editingPlayer); - if (pMetaPlayer) - { - // Set the appropriate modifiers to the prices etc of this editor - m_pEditorGUI->SetNativeTechModule(pMetaPlayer->GetNativeTechModule()); - m_pEditorGUI->SetForeignCostMultiplier(pMetaPlayer->GetForeignCostMultiplier()); - } - } - - // Set the view to scroll to the brain of the editing player, if there is any - if (g_SceneMan.GetScene()->GetResidentBrain(editingPlayer)) - m_pEditorGUI->SetCursorPos(g_SceneMan.GetScene()->GetResidentBrain(editingPlayer)->GetPos()); - - // Test if the resident brain is still in a valid spot, after potentially building it into a tomb since last round - m_pEditorGUI->TestBrainResidence(); - - //////////////////////////////// - // Set up teams - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - m_FundsChanged[team] = false; - m_TeamDeaths[team] = 0; - } - - // Move any brains resident in the Scene to the MovableMan -// Nope - these are manipulated by the SceneEditorGUI directly where they are in the resident lists -// g_SceneMan.GetScene()->PlaceResidentBrains(*this); - - // The get a list of all the placed objects in the Scene and set them to not kick around - const std::list *pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::BLUEPRINT); - for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr) - { - Actor *pActor = dynamic_cast(*itr); - if (pActor) - { - pActor->SetStatus(Actor::INACTIVE); - pActor->GetController()->SetDisabled(true); - } - } - - // Update all blueprints so they look right after load - g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::BLUEPRINT); - - return error; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. - -void BaseEditor::SetPaused(bool pause) -{ - // Override the pause - m_Paused = false; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. - -void BaseEditor::End() -{ - Activity::End(); - - m_ActivityState = ActivityState::Over; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this BaseEditor. Supposed to be done every frame -// before drawing. - -void BaseEditor::Update() -{ - Activity::Update(); - - if (!g_SceneMan.GetScene()) - return; - - // Update the loaded objects of the loaded scene so they look right - g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::BLUEPRINT); - - ///////////////////////////////////////////////////// - // Update the editor interface - - m_pEditorGUI->Update(); - - // Any edits made, dirtying the scene? - m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; - - // Get any mode change commands that the user gave the Editor GUI - // Done with editing for now; save and return to campaign screen - if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone) - { - m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); - - if (m_NeedSave) - SaveScene(g_SceneMan.GetScene()->GetPresetName()); - - // Quit to metagame view - g_ActivityMan.PauseActivity(); - } -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. - -void BaseEditor::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - m_pEditorGUI->Draw(pTargetBitmap, targetPos); - - Activity::DrawGUI(pTargetBitmap, targetPos, which); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this BaseEditor's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. - -void BaseEditor::Draw(BITMAP* pTargetBitmap, const Vector &targetPos) -{ - Activity::Draw(pTargetBitmap, targetPos); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the current scene to an appropriate ini file, and asks user if -// they want to overwrite first if scene of this name exists. - -bool BaseEditor::SaveScene(std::string saveAsName, bool forceOverwrite) -{ -/* - // Set the name of the current scene in effect - g_SceneMan.GetScene()->SetPresetName(saveAsName); - // Try to save to the data module - string sceneFilePath(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + saveAsName + ".ini"); - if (g_PresetMan.AddEntityPreset(g_SceneMan.GetScene(), m_ModuleSpaceID, forceOverwrite, sceneFilePath)) - { - // Does ini already exist? If yes, then no need to add it to a scenes.ini etc - bool sceneFileExisted = System::PathExistsCaseSensitive(sceneFilePath.c_str()); - // Create the writer - Writer sceneWriter(sceneFilePath.c_str(), false); - sceneWriter.NewProperty("AddScene"); -// TODO: Check if the ini file already exists, and then ask if overwrite - // Write the scene out to the new ini - sceneWriter << g_SceneMan.GetScene(); - - if (!sceneFileExisted) - { - // First find/create a .rte/Scenes.ini file to include the new .ini into - string scenesFilePath(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes.ini"); - bool scenesFileExisted = System::PathExistsCaseSensitive(scenesFilePath.c_str()); - Writer scenesWriter(scenesFilePath.c_str(), true); - scenesWriter.NewProperty("\nIncludeFile"); - scenesWriter << sceneFilePath; - - // Also add a line to the end of the modules' Index.ini to include the newly created Scenes.ini next startup - // If it's already included, it doens't matter, the definitions will just bounce the second time - if (!scenesFileExisted) - { - string indexFilePath(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Index.ini"); - Writer indexWriter(indexFilePath.c_str(), true); - // Add extra tab since the DataModule has everything indented - indexWriter.NewProperty("\tIncludeFile"); - indexWriter << scenesFilePath; - } - } - return m_HasEverBeenSaved = true; - } -*/ - return false; -} - -} // namespace RTE \ No newline at end of file + ConcreteClassInfo(BaseEditor, Activity, 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this BaseEditor, effectively + // resetting the members of this abstraction level only. + + void BaseEditor::Clear() { + m_pEditorGUI = 0; + m_NeedSave = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BaseEditor object ready for use. + + int BaseEditor::Create() { + if (Activity::Create() < 0) + return -1; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a BaseEditor to be identical to another, by deep copy. + + int BaseEditor::Create(const BaseEditor& reference) { + if (Activity::Create(reference) < 0) + return -1; + + if (m_Description.empty()) + m_Description = "Build or Edit a base on this Scene."; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int BaseEditor::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Activity::ReadProperty(propName, reader)); + /* + MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + */ + EndPropertyList; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this BaseEditor with a Writer for + // later recreation with Create(Reader &reader); + + int BaseEditor::Save(Writer& writer) const { + Activity::Save(writer); + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the BaseEditor object. + + void BaseEditor::Destroy(bool notInherited) { + delete m_pEditorGUI; + + if (!notInherited) + Activity::Destroy(); + Clear(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. + + int BaseEditor::Start() { + // Set the split screen config before the Scene (and it SceneLayers, specifially) are loaded + g_FrameMan.ResetSplitScreens(false, false); + // Too diff + // int error = Activity::Start(); + int error = 0; + + m_ActivityState = ActivityState::Running; + m_Paused = false; + + // Reset the mousemoving so that it won't trap the mouse if the window isn't in focus (common after loading) + g_UInputMan.DisableMouseMoving(true); + g_UInputMan.DisableMouseMoving(false); + + // Enable keys again + g_UInputMan.DisableKeys(false); + + // Load the scene now + error = g_SceneMan.LoadScene(); + if (error < 0) + return error; + + // Open all doors so we can pathfind past them for brain placement + g_MovableMan.OpenAllDoors(true, Teams::NoTeam); + + /////////////////////////////////////// + // Set up player - ONLY ONE ever in a base building activity + + // Figure which player is editing this base.. the first active one we find + int editingPlayer = Players::PlayerOne; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) + if (m_IsActive[player]) + editingPlayer = player; + // TODO: support multiple coop players editing the same base?? - A: NO, silly + + // for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) + // { + // if (!m_IsActive[player]) + // continue; + m_ViewState[editingPlayer] = ViewState::Normal; + g_FrameMan.ClearScreenText(ScreenOfPlayer(editingPlayer)); + // Set the team associations with the first screen so that the correct unseen are shows up + g_CameraMan.SetScreenTeam(m_Team[editingPlayer], ScreenOfPlayer(editingPlayer)); + g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(editingPlayer)); + + m_PlayerController[editingPlayer].Reset(); + m_PlayerController[editingPlayer].Create(Controller::CIM_PLAYER, editingPlayer); + m_PlayerController[editingPlayer].SetTeam(m_Team[editingPlayer]); + + m_MessageTimer[editingPlayer].Reset(); + // } + + // Kill off any actors not of this player's team.. they're not supposed to be here + g_MovableMan.KillAllEnemyActors(GetTeamOfPlayer(editingPlayer)); + + ////////////////////////////////////////////// + // Allocate and (re)create the Editor GUI + + if (m_pEditorGUI) + m_pEditorGUI->Destroy(); + else + m_pEditorGUI = new SceneEditorGUI; + m_pEditorGUI->Create(&(m_PlayerController[editingPlayer]), SceneEditorGUI::BLUEPRINTEDIT); + + // See if we are playing a metagame and which metaplayer this would be editing in this activity + if (g_MetaMan.GameInProgress()) { + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(editingPlayer); + if (pMetaPlayer) { + // Set the appropriate modifiers to the prices etc of this editor + m_pEditorGUI->SetNativeTechModule(pMetaPlayer->GetNativeTechModule()); + m_pEditorGUI->SetForeignCostMultiplier(pMetaPlayer->GetForeignCostMultiplier()); + } + } + + // Set the view to scroll to the brain of the editing player, if there is any + if (g_SceneMan.GetScene()->GetResidentBrain(editingPlayer)) + m_pEditorGUI->SetCursorPos(g_SceneMan.GetScene()->GetResidentBrain(editingPlayer)->GetPos()); + + // Test if the resident brain is still in a valid spot, after potentially building it into a tomb since last round + m_pEditorGUI->TestBrainResidence(); + + //////////////////////////////// + // Set up teams + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + m_FundsChanged[team] = false; + m_TeamDeaths[team] = 0; + } + + // Move any brains resident in the Scene to the MovableMan + // Nope - these are manipulated by the SceneEditorGUI directly where they are in the resident lists + // g_SceneMan.GetScene()->PlaceResidentBrains(*this); + + // The get a list of all the placed objects in the Scene and set them to not kick around + const std::list* pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::BLUEPRINT); + for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr) { + Actor* pActor = dynamic_cast(*itr); + if (pActor) { + pActor->SetStatus(Actor::INACTIVE); + pActor->GetController()->SetDisabled(true); + } + } + + // Update all blueprints so they look right after load + g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::BLUEPRINT); + + return error; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + + void BaseEditor::SetPaused(bool pause) { + // Override the pause + m_Paused = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + + void BaseEditor::End() { + Activity::End(); + + m_ActivityState = ActivityState::Over; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this BaseEditor. Supposed to be done every frame + // before drawing. + + void BaseEditor::Update() { + Activity::Update(); + + if (!g_SceneMan.GetScene()) + return; + + // Update the loaded objects of the loaded scene so they look right + g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::BLUEPRINT); + + ///////////////////////////////////////////////////// + // Update the editor interface + + m_pEditorGUI->Update(); + + // Any edits made, dirtying the scene? + m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; + + // Get any mode change commands that the user gave the Editor GUI + // Done with editing for now; save and return to campaign screen + if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone) { + m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); + + if (m_NeedSave) + SaveScene(g_SceneMan.GetScene()->GetPresetName()); + + // Quit to metagame view + g_ActivityMan.PauseActivity(); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + + void BaseEditor::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + m_pEditorGUI->Draw(pTargetBitmap, targetPos); + + Activity::DrawGUI(pTargetBitmap, targetPos, which); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this BaseEditor's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + + void BaseEditor::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + Activity::Draw(pTargetBitmap, targetPos); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the current scene to an appropriate ini file, and asks user if + // they want to overwrite first if scene of this name exists. + + bool BaseEditor::SaveScene(std::string saveAsName, bool forceOverwrite) { + /* + // Set the name of the current scene in effect + g_SceneMan.GetScene()->SetPresetName(saveAsName); + // Try to save to the data module + string sceneFilePath(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + saveAsName + ".ini"); + if (g_PresetMan.AddEntityPreset(g_SceneMan.GetScene(), m_ModuleSpaceID, forceOverwrite, sceneFilePath)) + { + // Does ini already exist? If yes, then no need to add it to a scenes.ini etc + bool sceneFileExisted = System::PathExistsCaseSensitive(sceneFilePath.c_str()); + // Create the writer + Writer sceneWriter(sceneFilePath.c_str(), false); + sceneWriter.NewProperty("AddScene"); + // TODO: Check if the ini file already exists, and then ask if overwrite + // Write the scene out to the new ini + sceneWriter << g_SceneMan.GetScene(); + + if (!sceneFileExisted) + { + // First find/create a .rte/Scenes.ini file to include the new .ini into + string scenesFilePath(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes.ini"); + bool scenesFileExisted = System::PathExistsCaseSensitive(scenesFilePath.c_str()); + Writer scenesWriter(scenesFilePath.c_str(), true); + scenesWriter.NewProperty("\nIncludeFile"); + scenesWriter << sceneFilePath; + + // Also add a line to the end of the modules' Index.ini to include the newly created Scenes.ini next startup + // If it's already included, it doens't matter, the definitions will just bounce the second time + if (!scenesFileExisted) + { + string indexFilePath(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Index.ini"); + Writer indexWriter(indexFilePath.c_str(), true); + // Add extra tab since the DataModule has everything indented + indexWriter.NewProperty("\tIncludeFile"); + indexWriter << scenesFilePath; + } + } + return m_HasEverBeenSaved = true; + } + */ + return false; + } + +} // namespace RTE diff --git a/Source/Activities/BaseEditor.h b/Source/Activities/BaseEditor.h index 7417cc7d7..555004ab7 100644 --- a/Source/Activities/BaseEditor.h +++ b/Source/Activities/BaseEditor.h @@ -10,228 +10,207 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "RTETools.h" #include "EditorActivity.h" -namespace RTE -{ - -class SceneEditorGUI; -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUIComboBox; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: BaseEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activity for editing designs only for the bases of each scene in a -// Campaign metagame. Doesn't need all the document-model dlg boxes. -// Parent(s): Activity. -// Class history: 04/30/2010 Created BaseEditor for the campaign base blueprint editing. - -class BaseEditor : public Activity { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(BaseEditor); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: BaseEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a BaseEditor object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - BaseEditor() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~BaseEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a BaseEditor object before deletion -// from system memory. -// Arguments: None. - - ~BaseEditor() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BaseEditor object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a BaseEditor to be identical to another, by deep copy. -// Arguments: A reference to the BaseEditor to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const BaseEditor &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire BaseEditor, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Activity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the BaseEditor object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the current scene to an appropriate ini file, and asks user if -// they want to overwrite first if scene of this name exists. -// Arguments: The name of the new scene to be saved. -// Whetehr to force any existing Scene of that name to be overwritten if -// it already exists. -// Return value: Whether actually managed to save. Will return false both if a scene -// of this name already exists, or if other error. - - bool SaveScene(std::string saveAsName, bool forceOverwrite = false); - - - // Member variables - static Entity::ClassInfo m_sClass; - - // The editor GUI - SceneEditorGUI *m_pEditorGUI; - - // Dirty Scene? - bool m_NeedSave; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class SceneEditorGUI; + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUIComboBox; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: BaseEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activity for editing designs only for the bases of each scene in a + // Campaign metagame. Doesn't need all the document-model dlg boxes. + // Parent(s): Activity. + // Class history: 04/30/2010 Created BaseEditor for the campaign base blueprint editing. + + class BaseEditor : public Activity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(BaseEditor); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: BaseEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a BaseEditor object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + BaseEditor() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~BaseEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a BaseEditor object before deletion + // from system memory. + // Arguments: None. + + ~BaseEditor() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BaseEditor object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a BaseEditor to be identical to another, by deep copy. + // Arguments: A reference to the BaseEditor to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const BaseEditor& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire BaseEditor, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Activity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the BaseEditor object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the current scene to an appropriate ini file, and asks user if + // they want to overwrite first if scene of this name exists. + // Arguments: The name of the new scene to be saved. + // Whetehr to force any existing Scene of that name to be overwritten if + // it already exists. + // Return value: Whether actually managed to save. Will return false both if a scene + // of this name already exists, or if other error. + + bool SaveScene(std::string saveAsName, bool forceOverwrite = false); + + // Member variables + static Entity::ClassInfo m_sClass; + + // The editor GUI + SceneEditorGUI* m_pEditorGUI; + + // Dirty Scene? + bool m_NeedSave; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/EditorActivity.cpp b/Source/Activities/EditorActivity.cpp index 4a152e6b4..3bc587479 100644 --- a/Source/Activities/EditorActivity.cpp +++ b/Source/Activities/EditorActivity.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -33,597 +32,550 @@ #include "GUIControlManager.h" #include "GUICollectionBox.h" - namespace RTE { -AbstractClassInfo(EditorActivity, Activity); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this EditorActivity, effectively -// resetting the members of this abstraction level only. - -void EditorActivity::Clear() -{ - // Most editors are single player affairs - m_MaxPlayerSupport = 1; - m_MinTeamsRequired = 1; - m_EditorMode = NEWDIALOG; - m_PreviousMode = EDITINGOBJECT; - m_ModeChange = false; - m_ModuleSpaceID = 0; - m_NeedSave = false; - m_HasEverBeenSaved = false; - m_PieMenu = nullptr; - m_pGUIScreen = 0; - m_pGUIInput = 0; - m_pGUIController = 0; - m_pNewDialogBox = 0; - m_pNewModuleCombo = 0; - m_pNewButton = 0; - m_pNewCancel = 0; - m_pLoadDialogBox = 0; - m_pLoadNameCombo = 0; - m_pLoadToNewButton = 0; - m_pLoadButton = 0; - m_pLoadCancel = 0; - m_pSaveDialogBox = 0; - m_pSaveNameBox = 0; - m_pSaveModuleLabel = 0; - m_pSaveButton = 0; - m_pSaveCancel = 0; - m_pChangesDialogBox = 0; - m_pChangesNameLabel = 0; - m_pChangesYesButton = 0; - m_pChangesNoButton = 0; - m_pOverwriteDialogBox = 0; - m_pOverwriteNameLabel = 0; - m_pOverwriteYesButton = 0; - m_pOverwriteNoButton = 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the EditorActivity object ready for use. - -int EditorActivity::Create() -{ - if (Activity::Create() < 0) - return -1; - - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a EditorActivity to be identical to another, by deep copy. - -int EditorActivity::Create(const EditorActivity &reference) -{ - if (Activity::Create(reference) < 0) - return -1; - -// m_Description = "No description defined for this Activity!"; - - m_EditorMode = reference.m_EditorMode; - m_ModuleSpaceID = reference.m_ModuleSpaceID; - m_NeedSave = reference.m_NeedSave; - if (reference.m_PieMenu) { m_PieMenu = std::unique_ptr(dynamic_cast(reference.m_PieMenu->Clone())); } - - return 0; -} - + AbstractClassInfo(EditorActivity, Activity); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this EditorActivity, effectively + // resetting the members of this abstraction level only. + + void EditorActivity::Clear() { + // Most editors are single player affairs + m_MaxPlayerSupport = 1; + m_MinTeamsRequired = 1; + m_EditorMode = NEWDIALOG; + m_PreviousMode = EDITINGOBJECT; + m_ModeChange = false; + m_ModuleSpaceID = 0; + m_NeedSave = false; + m_HasEverBeenSaved = false; + m_PieMenu = nullptr; + m_pGUIScreen = 0; + m_pGUIInput = 0; + m_pGUIController = 0; + m_pNewDialogBox = 0; + m_pNewModuleCombo = 0; + m_pNewButton = 0; + m_pNewCancel = 0; + m_pLoadDialogBox = 0; + m_pLoadNameCombo = 0; + m_pLoadToNewButton = 0; + m_pLoadButton = 0; + m_pLoadCancel = 0; + m_pSaveDialogBox = 0; + m_pSaveNameBox = 0; + m_pSaveModuleLabel = 0; + m_pSaveButton = 0; + m_pSaveCancel = 0; + m_pChangesDialogBox = 0; + m_pChangesNameLabel = 0; + m_pChangesYesButton = 0; + m_pChangesNoButton = 0; + m_pOverwriteDialogBox = 0; + m_pOverwriteNameLabel = 0; + m_pOverwriteYesButton = 0; + m_pOverwriteNoButton = 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int EditorActivity::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(Activity::ReadProperty(propName, reader)); -/* - MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); -*/ - EndPropertyList; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the EditorActivity object ready for use. + int EditorActivity::Create() { + if (Activity::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this EditorActivity with a Writer for -// later recreation with Create(Reader &reader); - -int EditorActivity::Save(Writer &writer) const { - Activity::Save(writer); - return 0; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a EditorActivity to be identical to another, by deep copy. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the EditorActivity object. + int EditorActivity::Create(const EditorActivity& reference) { + if (Activity::Create(reference) < 0) + return -1; -void EditorActivity::Destroy(bool notInherited) -{ - delete m_pGUIController; - delete m_pGUIInput; - delete m_pGUIScreen; + // m_Description = "No description defined for this Activity!"; - if (!notInherited) - Activity::Destroy(); - Clear(); -} + m_EditorMode = reference.m_EditorMode; + m_ModuleSpaceID = reference.m_ModuleSpaceID; + m_NeedSave = reference.m_NeedSave; + if (reference.m_PieMenu) { + m_PieMenu = std::unique_ptr(dynamic_cast(reference.m_PieMenu->Clone())); + } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int EditorActivity::Start() -{ - int error = 0; -// Don't, too different -// Activity::Start(); - - // Load the scene now - error = g_SceneMan.LoadScene(); - if (error < 0) - return error; - - // Clear the post effects - g_PostProcessMan.ClearScenePostEffects(); - - // Clear the screen messages - g_FrameMan.ClearScreenText(); - - // Reset the mousemoving so that it won't trap the mouse if the window isn't in focus (common after loading) - g_UInputMan.DisableMouseMoving(true); - g_UInputMan.DisableMouseMoving(false); - - m_ActivityState = ActivityState::Editing; - m_Paused = true; -// g_TimerMan.PauseSim(true); - m_ModeChange = true; - - // Play editing music - g_AudioMan.ClearMusicQueue(); - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/ccambient4.ogg"); - - // Force the split screen config to just be one big screen for editing - g_FrameMan.ResetSplitScreens(false, false); - - /////////////////////////// - // GUI manager setup - - if (!m_pGUIScreen) - m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer8()); - if (!m_pGUIInput) - m_pGUIInput = new GUIInputWrapper(-1, true); - if (!m_pGUIController) - m_pGUIController = new GUIControlManager(); - if (!m_pGUIController->Create(m_pGUIScreen, m_pGUIInput, "Base.rte/GUIs/Skins", "DefaultSkin.ini")) { - RTEAbort("Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/DefaultSkin.ini"); + return 0; } - return error; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int EditorActivity::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(Activity::ReadProperty(propName, reader)); + /* + MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + */ + EndPropertyList; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this EditorActivity with a Writer for + // later recreation with Create(Reader &reader); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + int EditorActivity::Save(Writer& writer) const { + Activity::Save(writer); + return 0; + } -void EditorActivity::SetPaused(bool pause) -{ - // Override the pause - m_Paused = false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the EditorActivity object. + void EditorActivity::Destroy(bool notInherited) { + delete m_pGUIController; + delete m_pGUIInput; + delete m_pGUIScreen; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. + if (!notInherited) + Activity::Destroy(); + Clear(); + } -void EditorActivity::End() -{ - Activity::End(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. + + int EditorActivity::Start() { + int error = 0; + // Don't, too different + // Activity::Start(); + + // Load the scene now + error = g_SceneMan.LoadScene(); + if (error < 0) + return error; + + // Clear the post effects + g_PostProcessMan.ClearScenePostEffects(); + + // Clear the screen messages + g_FrameMan.ClearScreenText(); + + // Reset the mousemoving so that it won't trap the mouse if the window isn't in focus (common after loading) + g_UInputMan.DisableMouseMoving(true); + g_UInputMan.DisableMouseMoving(false); + + m_ActivityState = ActivityState::Editing; + m_Paused = true; + // g_TimerMan.PauseSim(true); + m_ModeChange = true; + + // Play editing music + g_AudioMan.ClearMusicQueue(); + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/ccambient4.ogg"); + + // Force the split screen config to just be one big screen for editing + g_FrameMan.ResetSplitScreens(false, false); + + /////////////////////////// + // GUI manager setup + + if (!m_pGUIScreen) + m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer8()); + if (!m_pGUIInput) + m_pGUIInput = new GUIInputWrapper(-1, true); + if (!m_pGUIController) + m_pGUIController = new GUIControlManager(); + if (!m_pGUIController->Create(m_pGUIScreen, m_pGUIInput, "Base.rte/GUIs/Skins", "DefaultSkin.ini")) { + RTEAbort("Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/DefaultSkin.ini"); + } + + return error; + } - + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. - m_ActivityState = ActivityState::Over; -} + void EditorActivity::SetPaused(bool pause) { + // Override the pause + m_Paused = false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this EditorActivity. Supposed to be done every frame -// before drawing. - -void EditorActivity::Update() -{ - // Always show teh messages of the editor - m_MessageTimer[0].Reset(); - - Activity::Update(); - - if (!g_SceneMan.GetScene()) - return; - - // Hide all dialog boxes if mode changes, one will reappear below - if (m_ModeChange) - { - if (m_pNewDialogBox) - m_pNewDialogBox->SetVisible(false); - m_pLoadDialogBox->SetVisible(false); - m_pSaveDialogBox->SetVisible(false); - m_pChangesDialogBox->SetVisible(false); - m_pOverwriteDialogBox->SetVisible(false); - } - - if (m_EditorMode == NEWDIALOG) - { - if (m_ModeChange) - { - if (m_NeedSave) - { - m_PreviousMode = NEWDIALOG; - m_EditorMode = CHANGESDIALOG; - m_ModeChange = true; - } - else - { - UpdateNewDialog(); - // Set the mouse cursor free - m_pGUIController->EnableMouse(true); - g_UInputMan.TrapMousePos(false, 0); - // Show/hide relevant GUI elements - m_pNewDialogBox->SetVisible(true); - m_ModeChange = false; - } - } - } - else if (m_EditorMode == LOADDIALOG) - { - if (m_ModeChange) - { - if (m_NeedSave) - { - m_PreviousMode = LOADDIALOG; - m_EditorMode = CHANGESDIALOG; - m_ModeChange = true; - } - else - { - UpdateLoadDialog(); - // Set the mouse cursor free - m_pGUIController->EnableMouse(true); - g_UInputMan.TrapMousePos(false, 0); - // Show/hide relevant GUI elements - m_pLoadDialogBox->SetVisible(true); - m_ModeChange = false; - } - } - } - else if (m_EditorMode == SAVEDIALOG) - { - if (m_ModeChange) - { - UpdateSaveDialog(); - // Temporarily disable the UInput from reading regular keypresses so we can type - g_UInputMan.DisableKeys(true); - // Set the mouse cursor free - m_pGUIController->EnableMouse(true); - g_UInputMan.TrapMousePos(false, 0); - // Show/hide relevant GUI elements - m_pSaveDialogBox->SetVisible(true); - m_ModeChange = false; - } - } - else if (m_EditorMode == CHANGESDIALOG) - { - if (m_ModeChange) - { - UpdateChangesDialog(); - // Set the mouse cursor free - m_pGUIController->EnableMouse(true); - g_UInputMan.TrapMousePos(false, 0); - // Show/hide relevant GUI elements - m_pChangesDialogBox->SetVisible(true); - m_ModeChange = false; - } - } - else if (m_EditorMode == OVERWRITEDIALOG) - { - if (m_ModeChange) - { - UpdateOverwriteDialog(); - // Set the mouse cursor free - m_pGUIController->EnableMouse(true); - g_UInputMan.TrapMousePos(false, 0); - // Show/hide relevant GUI elements - m_pOverwriteDialogBox->SetVisible(true); - m_ModeChange = false; - } - } -/* Let this be handled by derived class - // Quit all dialog boxes - else - { - if (m_ModeChange) - { - // Hide the cursor for this layer of interface - m_pGUIController->EnableMouse(false); - m_ModeChange = false; - } - g_UInputMan.DisableKeys(false); - } -*/ - ////////////////////////////////////////// - // Update the ControlManager - - m_pGUIController->Update(); - -/* Do this in derived classes - //////////////////////////////////////////////////////// - // Handle events for mouse input on the controls - - GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { - // If we're not supposed to have mouse control, then ignore these messages -// Uh this is not right, editor always has mouse control so far -// if (!m_PlayerController[0].IsMouseControlled()) -// break; - - if (anEvent.GetType() == GUIEvent::Command) - { - ////////////////////////////////////////////////////////// - // NEW button pressed; create a new scene - - if (anEvent.GetControl() == m_pNewButton) - { - // Get the selected Module - GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - m_ModuleSpaceID = g_PresetMan.GetModuleID(pItem->m_Name); - - // Allocate Scene - Scene *pNewScene = new Scene(); - // Get the selected Terrain and create the Scene using it - pItem = m_pNewTerrainCombo->GetItem(m_pNewTerrainCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SLTerrain *pNewTerrain = dynamic_cast(g_PresetMan.GetEntityPreset("SLTerrain", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewTerrain, "No SLTerrain of that name defined!"); - pNewScene->Create(pNewTerrain); - } - - // Add specified scene layers - pItem = m_pNewBG1Combo->GetItem(m_pNewBG1Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SceneLayer of the name set as BG1 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - pItem = m_pNewBG2Combo->GetItem(m_pNewBG2Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SceneLayer of the name set as BG2 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - pItem = m_pNewBG3Combo->GetItem(m_pNewBG3Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SceneLayer of the name set as BG3 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - - // Actually load the scene's data and set it up as the current scene - g_SceneMan.LoadScene(pNewScene); - - // Reset the rest of the editor GUI - m_pEditorGUI->Destroy(); - m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, m_ModuleSpaceID); - } - - m_NeedSave = false; - m_HasEverBeenSaved = false; - m_EditorMode = m_PreviousMode = EDITINGOBJECT; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // LOAD button pressed; load the selected Scene - - if (anEvent.GetControl() == m_pLoadButton) - { - GUIListPanel::Item *pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - // Attempt to load the scene, without applying its placed objects - g_SceneMan.LoadScene(pItem->m_Name, false); - // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space - if (g_SceneMan.GetScene()) - { - m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); - RTEAssert(m_ModuleSpaceID >= 0, "Loaded Scene's DataModule ID is negative? Should always be a specific one.."); - m_pEditorGUI->Destroy(); - m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, m_ModuleSpaceID); -// TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead - } - } - m_NeedSave = false; - m_HasEverBeenSaved = true; - m_EditorMode = m_PreviousMode = EDITINGOBJECT; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // SAVE button pressed; save the selected Scene - - if (anEvent.GetControl() == m_pSaveButton) - { - if (!m_pSaveNameBox->GetText().empty()) - { - // Save the scene to the name specified in the text box - if (SaveScene(m_pSaveNameBox->GetText())) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - // Should really leave dialog box open? - else - { - ; - } - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes YES pressed - - if (anEvent.GetControl() == m_pChangesYesButton) - { - if (m_HasEverBeenSaved) - { - if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - } - // Open the save scene dialog to ask user where to save it then - else - { - m_PreviousMode = m_PreviousMode; - m_EditorMode = SAVEDIALOG; - m_ModeChange = true; - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes NO pressed - - if (anEvent.GetControl() == m_pChangesNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - m_NeedSave = false; - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene YES pressed - - if (anEvent.GetControl() == m_pOverwriteYesButton) - { - // Force overwrite - if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode != SAVEDIALOG ? m_PreviousMode : EDITINGOBJECT; - m_ModeChange = true; - } -// TODO: Show overwrite error? - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene NO pressed - - if (anEvent.GetControl() == m_pOverwriteNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - - /////////////////////////////////////////////////////////////// - // CANCEL button pressed; exit any active dialog box - - if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) - { - m_EditorMode = m_PreviousMode = EDITINGOBJECT; - m_ModeChange = true; - } - } - - // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { - /////////////////////////////////////// - // Clicks on the New Scene Module combo - - if (anEvent.GetControl() == m_pNewModuleCombo) - { - // Closed it, IE selected somehting - if(anEvent.GetMsg() == GUIComboBox::Closed) - UpdateNewDialog(); - } - - } - } -*/ -} + void EditorActivity::End() { + Activity::End(); + m_ActivityState = ActivityState::Over; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this EditorActivity. Supposed to be done every frame + // before drawing. + + void EditorActivity::Update() { + // Always show teh messages of the editor + m_MessageTimer[0].Reset(); + + Activity::Update(); + + if (!g_SceneMan.GetScene()) + return; + + // Hide all dialog boxes if mode changes, one will reappear below + if (m_ModeChange) { + if (m_pNewDialogBox) + m_pNewDialogBox->SetVisible(false); + m_pLoadDialogBox->SetVisible(false); + m_pSaveDialogBox->SetVisible(false); + m_pChangesDialogBox->SetVisible(false); + m_pOverwriteDialogBox->SetVisible(false); + } + + if (m_EditorMode == NEWDIALOG) { + if (m_ModeChange) { + if (m_NeedSave) { + m_PreviousMode = NEWDIALOG; + m_EditorMode = CHANGESDIALOG; + m_ModeChange = true; + } else { + UpdateNewDialog(); + // Set the mouse cursor free + m_pGUIController->EnableMouse(true); + g_UInputMan.TrapMousePos(false, 0); + // Show/hide relevant GUI elements + m_pNewDialogBox->SetVisible(true); + m_ModeChange = false; + } + } + } else if (m_EditorMode == LOADDIALOG) { + if (m_ModeChange) { + if (m_NeedSave) { + m_PreviousMode = LOADDIALOG; + m_EditorMode = CHANGESDIALOG; + m_ModeChange = true; + } else { + UpdateLoadDialog(); + // Set the mouse cursor free + m_pGUIController->EnableMouse(true); + g_UInputMan.TrapMousePos(false, 0); + // Show/hide relevant GUI elements + m_pLoadDialogBox->SetVisible(true); + m_ModeChange = false; + } + } + } else if (m_EditorMode == SAVEDIALOG) { + if (m_ModeChange) { + UpdateSaveDialog(); + // Temporarily disable the UInput from reading regular keypresses so we can type + g_UInputMan.DisableKeys(true); + // Set the mouse cursor free + m_pGUIController->EnableMouse(true); + g_UInputMan.TrapMousePos(false, 0); + // Show/hide relevant GUI elements + m_pSaveDialogBox->SetVisible(true); + m_ModeChange = false; + } + } else if (m_EditorMode == CHANGESDIALOG) { + if (m_ModeChange) { + UpdateChangesDialog(); + // Set the mouse cursor free + m_pGUIController->EnableMouse(true); + g_UInputMan.TrapMousePos(false, 0); + // Show/hide relevant GUI elements + m_pChangesDialogBox->SetVisible(true); + m_ModeChange = false; + } + } else if (m_EditorMode == OVERWRITEDIALOG) { + if (m_ModeChange) { + UpdateOverwriteDialog(); + // Set the mouse cursor free + m_pGUIController->EnableMouse(true); + g_UInputMan.TrapMousePos(false, 0); + // Show/hide relevant GUI elements + m_pOverwriteDialogBox->SetVisible(true); + m_ModeChange = false; + } + } + /* Let this be handled by derived class + // Quit all dialog boxes + else + { + if (m_ModeChange) + { + // Hide the cursor for this layer of interface + m_pGUIController->EnableMouse(false); + m_ModeChange = false; + } + g_UInputMan.DisableKeys(false); + } + */ + ////////////////////////////////////////// + // Update the ControlManager + + m_pGUIController->Update(); + + /* Do this in derived classes + //////////////////////////////////////////////////////// + // Handle events for mouse input on the controls + + GUIEvent anEvent; + while(m_pGUIController->GetEvent(&anEvent)) + { + // If we're not supposed to have mouse control, then ignore these messages + // Uh this is not right, editor always has mouse control so far + // if (!m_PlayerController[0].IsMouseControlled()) + // break; + + if (anEvent.GetType() == GUIEvent::Command) + { + ////////////////////////////////////////////////////////// + // NEW button pressed; create a new scene + + if (anEvent.GetControl() == m_pNewButton) + { + // Get the selected Module + GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + m_ModuleSpaceID = g_PresetMan.GetModuleID(pItem->m_Name); + + // Allocate Scene + Scene *pNewScene = new Scene(); + // Get the selected Terrain and create the Scene using it + pItem = m_pNewTerrainCombo->GetItem(m_pNewTerrainCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SLTerrain *pNewTerrain = dynamic_cast(g_PresetMan.GetEntityPreset("SLTerrain", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewTerrain, "No SLTerrain of that name defined!"); + pNewScene->Create(pNewTerrain); + } + + // Add specified scene layers + pItem = m_pNewBG1Combo->GetItem(m_pNewBG1Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SceneLayer of the name set as BG1 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + pItem = m_pNewBG2Combo->GetItem(m_pNewBG2Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SceneLayer of the name set as BG2 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + pItem = m_pNewBG3Combo->GetItem(m_pNewBG3Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SceneLayer of the name set as BG3 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + + // Actually load the scene's data and set it up as the current scene + g_SceneMan.LoadScene(pNewScene); + + // Reset the rest of the editor GUI + m_pEditorGUI->Destroy(); + m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, m_ModuleSpaceID); + } + + m_NeedSave = false; + m_HasEverBeenSaved = false; + m_EditorMode = m_PreviousMode = EDITINGOBJECT; + m_ModeChange = true; + } + + ////////////////////////////////////////////////////////// + // LOAD button pressed; load the selected Scene + + if (anEvent.GetControl() == m_pLoadButton) + { + GUIListPanel::Item *pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + // Attempt to load the scene, without applying its placed objects + g_SceneMan.LoadScene(pItem->m_Name, false); + // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space + if (g_SceneMan.GetScene()) + { + m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); + RTEAssert(m_ModuleSpaceID >= 0, "Loaded Scene's DataModule ID is negative? Should always be a specific one.."); + m_pEditorGUI->Destroy(); + m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, m_ModuleSpaceID); + // TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead + } + } + m_NeedSave = false; + m_HasEverBeenSaved = true; + m_EditorMode = m_PreviousMode = EDITINGOBJECT; + m_ModeChange = true; + } + + ////////////////////////////////////////////////////////// + // SAVE button pressed; save the selected Scene + + if (anEvent.GetControl() == m_pSaveButton) + { + if (!m_pSaveNameBox->GetText().empty()) + { + // Save the scene to the name specified in the text box + if (SaveScene(m_pSaveNameBox->GetText())) + { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + // Should really leave dialog box open? + else + { + ; + } + } + } + + /////////////////////////////////////////////////////////////// + // Save Changes YES pressed + + if (anEvent.GetControl() == m_pChangesYesButton) + { + if (m_HasEverBeenSaved) + { + if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) + { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + } + // Open the save scene dialog to ask user where to save it then + else + { + m_PreviousMode = m_PreviousMode; + m_EditorMode = SAVEDIALOG; + m_ModeChange = true; + } + } + + /////////////////////////////////////////////////////////////// + // Save Changes NO pressed + + if (anEvent.GetControl() == m_pChangesNoButton) + { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + m_NeedSave = false; + } + + /////////////////////////////////////////////////////////////// + // Overwrite Scene YES pressed + + if (anEvent.GetControl() == m_pOverwriteYesButton) + { + // Force overwrite + if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) + { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode != SAVEDIALOG ? m_PreviousMode : EDITINGOBJECT; + m_ModeChange = true; + } + // TODO: Show overwrite error? + } + + /////////////////////////////////////////////////////////////// + // Overwrite Scene NO pressed + + if (anEvent.GetControl() == m_pOverwriteNoButton) + { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + + /////////////////////////////////////////////////////////////// + // CANCEL button pressed; exit any active dialog box + + if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) + { + m_EditorMode = m_PreviousMode = EDITINGOBJECT; + m_ModeChange = true; + } + } + + // Notifications + else if (anEvent.GetType() == GUIEvent::Notification) + { + /////////////////////////////////////// + // Clicks on the New Scene Module combo + + if (anEvent.GetControl() == m_pNewModuleCombo) + { + // Closed it, IE selected somehting + if(anEvent.GetMsg() == GUIComboBox::Closed) + UpdateNewDialog(); + } + + } + } + */ + } -void EditorActivity::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - AllegroScreen drawScreen(pTargetBitmap); - m_pGUIController->Draw(&drawScreen); - if (m_EditorMode != EDITINGOBJECT) - m_pGUIController->DrawMouse(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + void EditorActivity::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + AllegroScreen drawScreen(pTargetBitmap); + m_pGUIController->Draw(&drawScreen); + if (m_EditorMode != EDITINGOBJECT) + m_pGUIController->DrawMouse(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this EditorActivity's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this EditorActivity's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. -void EditorActivity::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) -{ - -} + void EditorActivity::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/EditorActivity.h b/Source/Activities/EditorActivity.h index a98edf963..aaf129e3a 100644 --- a/Source/Activities/EditorActivity.h +++ b/Source/Activities/EditorActivity.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,351 +19,324 @@ #include "PostProcessMan.h" #include "PieMenu.h" -namespace RTE -{ - -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUIComboBox; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: EditorActivity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activity for editing things; owns and manages all the dialog boxes -// etc for docuemnt model, ie new, load, save, etc. -// Parent(s): Activity. -// Class history: 9/17/2007 EditorActivity created. - -class EditorActivity : public Activity { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableOverrideMethods; - ClassInfoGetters; - - // Different modes of this editor - enum EditorMode - { - NEWDIALOG = 0, - LOADDIALOG, - SAVEDIALOG, - CHANGESDIALOG, - OVERWRITEDIALOG, - EDITINGOBJECT, - TESTINGOBJECT, - EDITORMODECOUNT - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: EditorActivity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a EditorActivity object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - EditorActivity() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~EditorActivity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a EditorActivity object before deletion -// from system memory. -// Arguments: None. - - ~EditorActivity() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the EditorActivity object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a EditorActivity to be identical to another, by deep copy. -// Arguments: A reference to the EditorActivity to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const EditorActivity &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire EditorActivity, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Activity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the EditorActivity object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorMode(EditorMode newMode) { m_EditorMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorMode GetEditorMode() const { return m_EditorMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - virtual void UpdateNewDialog() {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - virtual void UpdateLoadDialog() {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - virtual void UpdateSaveDialog() {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - virtual void UpdateChangesDialog() {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - virtual void UpdateOverwriteDialog() {} - - - // Member variables - static Entity::ClassInfo m_sClass; - // The current mode of the whole editor. See EditorGUIMode enum. - EditorMode m_EditorMode; - // Indicates the previous mode before a confirm dialog box was shown - EditorMode m_PreviousMode; - // Whether the mode has been changed - bool m_ModeChange; - // The DataModule space that we are editing within; can only place objects defined in the official modules plus this one - int m_ModuleSpaceID; - // Whether the edited object has been changed since last save - bool m_NeedSave; - // Whether this thing has ever been saved (or loaded). Will be true of new until it is saved - bool m_HasEverBeenSaved; - - std::unique_ptr m_PieMenu; //!< The pie menu this EditorActivity should use, if any. - - // GUI Screen for use by the GUI dialog boxes. Owned - GUIScreen *m_pGUIScreen; - // Input controller for he dialog box gui. Owned - GUIInput *m_pGUIInput; - // The control manager which holds all the gui elements for the dialog boxes. Owned - GUIControlManager *m_pGUIController; - - // New Dialog box - GUICollectionBox *m_pNewDialogBox; - // The combobox which lists all the DataModules that the new Entity can belong to - GUIComboBox *m_pNewModuleCombo; - // The button for asking for new Entity - GUIButton *m_pNewButton; - // The button for canceling new Entity dialog - GUIButton *m_pNewCancel; - - // Load Dialog box - GUICollectionBox *m_pLoadDialogBox; - // The combobox which lists all the Entities that can be loaded - GUIComboBox *m_pLoadNameCombo; - // The button for going to new dialog instead - GUIButton *m_pLoadToNewButton; - // The button for confirming Entity load - GUIButton *m_pLoadButton; - // The button for canceling load dialog - GUIButton *m_pLoadCancel; - - // Save Dialog box - GUICollectionBox *m_pSaveDialogBox; - // Textbox for entering the name of the thing to save. - GUITextBox *m_pSaveNameBox; - // The label which shows which DataModule this Scene is set to be saved to - GUILabel *m_pSaveModuleLabel; - // The button for confirming save - GUIButton *m_pSaveButton; - // The button for canceling save dialog - GUIButton *m_pSaveCancel; - - // Changes Dialog box - GUICollectionBox *m_pChangesDialogBox; - // The label for showing where it'll be saved - GUILabel *m_pChangesNameLabel; - // The button for confirming save changes - GUIButton *m_pChangesYesButton; - // The button for No resposnes to save changes - GUIButton *m_pChangesNoButton; - - // Overwrite Dialog box - GUICollectionBox *m_pOverwriteDialogBox; - // The label for showing what is about to be overwritten - GUILabel *m_pOverwriteNameLabel; - // The button for confirming overwrite existing - GUIButton *m_pOverwriteYesButton; - // The button for No resposnes to overwrite - GUIButton *m_pOverwriteNoButton; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUIComboBox; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: EditorActivity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activity for editing things; owns and manages all the dialog boxes + // etc for docuemnt model, ie new, load, save, etc. + // Parent(s): Activity. + // Class history: 9/17/2007 EditorActivity created. + + class EditorActivity : public Activity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableOverrideMethods; + ClassInfoGetters; + + // Different modes of this editor + enum EditorMode { + NEWDIALOG = 0, + LOADDIALOG, + SAVEDIALOG, + CHANGESDIALOG, + OVERWRITEDIALOG, + EDITINGOBJECT, + TESTINGOBJECT, + EDITORMODECOUNT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: EditorActivity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a EditorActivity object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + EditorActivity() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~EditorActivity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a EditorActivity object before deletion + // from system memory. + // Arguments: None. + + ~EditorActivity() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the EditorActivity object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a EditorActivity to be identical to another, by deep copy. + // Arguments: A reference to the EditorActivity to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const EditorActivity& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire EditorActivity, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Activity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the EditorActivity object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorMode(EditorMode newMode) { m_EditorMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorMode GetEditorMode() const { return m_EditorMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + virtual void UpdateNewDialog() {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + virtual void UpdateLoadDialog() {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + virtual void UpdateSaveDialog() {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + virtual void UpdateChangesDialog() {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + virtual void UpdateOverwriteDialog() {} + + // Member variables + static Entity::ClassInfo m_sClass; + // The current mode of the whole editor. See EditorGUIMode enum. + EditorMode m_EditorMode; + // Indicates the previous mode before a confirm dialog box was shown + EditorMode m_PreviousMode; + // Whether the mode has been changed + bool m_ModeChange; + // The DataModule space that we are editing within; can only place objects defined in the official modules plus this one + int m_ModuleSpaceID; + // Whether the edited object has been changed since last save + bool m_NeedSave; + // Whether this thing has ever been saved (or loaded). Will be true of new until it is saved + bool m_HasEverBeenSaved; + + std::unique_ptr m_PieMenu; //!< The pie menu this EditorActivity should use, if any. + + // GUI Screen for use by the GUI dialog boxes. Owned + GUIScreen* m_pGUIScreen; + // Input controller for he dialog box gui. Owned + GUIInput* m_pGUIInput; + // The control manager which holds all the gui elements for the dialog boxes. Owned + GUIControlManager* m_pGUIController; + + // New Dialog box + GUICollectionBox* m_pNewDialogBox; + // The combobox which lists all the DataModules that the new Entity can belong to + GUIComboBox* m_pNewModuleCombo; + // The button for asking for new Entity + GUIButton* m_pNewButton; + // The button for canceling new Entity dialog + GUIButton* m_pNewCancel; + + // Load Dialog box + GUICollectionBox* m_pLoadDialogBox; + // The combobox which lists all the Entities that can be loaded + GUIComboBox* m_pLoadNameCombo; + // The button for going to new dialog instead + GUIButton* m_pLoadToNewButton; + // The button for confirming Entity load + GUIButton* m_pLoadButton; + // The button for canceling load dialog + GUIButton* m_pLoadCancel; + + // Save Dialog box + GUICollectionBox* m_pSaveDialogBox; + // Textbox for entering the name of the thing to save. + GUITextBox* m_pSaveNameBox; + // The label which shows which DataModule this Scene is set to be saved to + GUILabel* m_pSaveModuleLabel; + // The button for confirming save + GUIButton* m_pSaveButton; + // The button for canceling save dialog + GUIButton* m_pSaveCancel; + + // Changes Dialog box + GUICollectionBox* m_pChangesDialogBox; + // The label for showing where it'll be saved + GUILabel* m_pChangesNameLabel; + // The button for confirming save changes + GUIButton* m_pChangesYesButton; + // The button for No resposnes to save changes + GUIButton* m_pChangesNoButton; + + // Overwrite Dialog box + GUICollectionBox* m_pOverwriteDialogBox; + // The label for showing what is about to be overwritten + GUILabel* m_pOverwriteNameLabel; + // The button for confirming overwrite existing + GUIButton* m_pOverwriteYesButton; + // The button for No resposnes to overwrite + GUIButton* m_pOverwriteNoButton; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/GAScripted.cpp b/Source/Activities/GAScripted.cpp index aab6f8d33..ece23f7c4 100644 --- a/Source/Activities/GAScripted.cpp +++ b/Source/Activities/GAScripted.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -39,546 +38,531 @@ namespace RTE { -ConcreteClassInfo(GAScripted, GameActivity, 0); + ConcreteClassInfo(GAScripted, GameActivity, 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this GAScripted, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this GAScripted, effectively -// resetting the members of this abstraction level only. + void GAScripted::Clear() { + m_ScriptPath.clear(); + m_LuaClassName.clear(); + m_RequiredAreas.clear(); + m_PieSlicesToAdd.clear(); + } -void GAScripted::Clear() { - m_ScriptPath.clear(); - m_LuaClassName.clear(); - m_RequiredAreas.clear(); - m_PieSlicesToAdd.clear(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GAScripted object ready for use. + int GAScripted::Create() { + if (GameActivity::Create() < 0) { + return -1; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GAScripted object ready for use. + if (m_Description.empty()) { + m_Description = "A scripted activity without a description yet. Tell the creator to write one."; + } -int GAScripted::Create() { - if (GameActivity::Create() < 0) { - return -1; - } + // Gotto have a script file path and lua class names defined to Create + if (m_ScriptPath.empty() || m_LuaClassName.empty()) { + return -1; + } - if (m_Description.empty()) { - m_Description = "A scripted activity without a description yet. Tell the creator to write one."; - } + // Scan the script file for any mentions/uses of Areas. + CollectRequiredAreas(); - // Gotto have a script file path and lua class names defined to Create - if (m_ScriptPath.empty() || m_LuaClassName.empty()) { - return -1; - } + // If the GAScripted has a OnSave() function, we assume it can be saved by default + ReloadScripts(); + m_AllowsUserSaving = HasSaveFunction(); - // Scan the script file for any mentions/uses of Areas. - CollectRequiredAreas(); + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GAScripted to be identical to another, by deep copy. - // If the GAScripted has a OnSave() function, we assume it can be saved by default - ReloadScripts(); - m_AllowsUserSaving = HasSaveFunction(); + int GAScripted::Create(const GAScripted& reference) { + if (GameActivity::Create(reference) < 0) { + return -1; + } - return 0; -} + m_ScriptPath = reference.m_ScriptPath; + m_LuaClassName = reference.m_LuaClassName; + for (const std::string& referenceRequiredArea: reference.m_RequiredAreas) { + m_RequiredAreas.emplace(referenceRequiredArea); + } + for (const std::unique_ptr& referencePieSliceToAdd: reference.m_PieSlicesToAdd) { + m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(referencePieSliceToAdd->Clone()))); + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GAScripted to be identical to another, by deep copy. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int GAScripted::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return GameActivity::ReadProperty(propName, reader)); + + MatchProperty("ScriptPath", { + m_ScriptPath = g_PresetMan.GetFullModulePath(reader.ReadPropValue()); + }); + MatchProperty("LuaClassName", { + reader >> m_LuaClassName; + }); + MatchProperty("AddPieSlice", { + m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)))); + }); + + EndPropertyList; + } -int GAScripted::Create(const GAScripted &reference) { - if (GameActivity::Create(reference) < 0) { - return -1; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this GAScripted with a Writer for + // later recreation with Create(Reader &reader); - m_ScriptPath = reference.m_ScriptPath; - m_LuaClassName = reference.m_LuaClassName; - for (const std::string &referenceRequiredArea : reference.m_RequiredAreas) { - m_RequiredAreas.emplace(referenceRequiredArea); - } - for (const std::unique_ptr &referencePieSliceToAdd : reference.m_PieSlicesToAdd) { - m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(referencePieSliceToAdd->Clone()))); - } + int GAScripted::Save(Writer& writer) const { + // Hmm. We should probably be calling this prior to the writer Save, instead of const-casting. + const_cast(this)->RunLuaFunction("OnSave"); - return 0; -} + GameActivity::Save(writer); + writer.NewPropertyWithValue("ScriptPath", m_ScriptPath); + writer.NewPropertyWithValue("LuaClassName", m_LuaClassName); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int GAScripted::ReadProperty(const std::string_view &propName, Reader &reader) { - StartPropertyList(return GameActivity::ReadProperty(propName, reader)); - - MatchProperty("ScriptPath", { - m_ScriptPath = g_PresetMan.GetFullModulePath(reader.ReadPropValue()); - }); - MatchProperty("LuaClassName", { - reader >> m_LuaClassName; - }); - MatchProperty("AddPieSlice", { - m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)))); - }); - - EndPropertyList; -} + for (const std::unique_ptr& pieSliceToAdd: m_PieSlicesToAdd) { + writer.NewPropertyWithValue("AddPieSlice", pieSliceToAdd.get()); + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this GAScripted with a Writer for -// later recreation with Create(Reader &reader); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GAScripted object. -int GAScripted::Save(Writer &writer) const { - // Hmm. We should probably be calling this prior to the writer Save, instead of const-casting. - const_cast(this)->RunLuaFunction("OnSave"); + void GAScripted::Destroy(bool notInherited) { + // Delete global scripts + for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { + delete (*sItr); + } - GameActivity::Save(writer); + m_GlobalScriptsList.clear(); - writer.NewPropertyWithValue("ScriptPath", m_ScriptPath); - writer.NewPropertyWithValue("LuaClassName", m_LuaClassName); + if (!notInherited) { + GameActivity::Destroy(); + } - for (const std::unique_ptr &pieSliceToAdd : m_PieSlicesToAdd) { - writer.NewPropertyWithValue("AddPieSlice", pieSliceToAdd.get()); + Clear(); } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReloadScripts + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the preset scripts of this object, from the same script file + // path as was originally defined. This will also update the original + // preset in the PresetMan with the updated scripts so future objects + // spawned will use the new scripts. + + int GAScripted::ReloadScripts() { + if (m_ScriptPath.empty()) { + return 0; + } + int error = 0; + CollectRequiredAreas(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GAScripted object. + // If it hasn't been yet, run the file that specifies the Lua functions for this' operating logic (including the scene test function) + if (!g_LuaMan.GetMasterScriptState().GlobalIsDefined(m_LuaClassName)) { + // Temporarily store this Activity so the Lua state can access it + g_LuaMan.GetMasterScriptState().SetTempEntity(this); -void GAScripted::Destroy(bool notInherited) { - // Delete global scripts - for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { - delete (*sItr); - } + // Define the var that will hold the script file definitions + if ((error = g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGameActivity(LuaMan.TempEntity);")) < 0) { + return error; + } + } - m_GlobalScriptsList.clear(); + if ((error = g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath, true, false)) < 0) { + return error; + } - if (!notInherited) { - GameActivity::Destroy(); - } + RefreshActivityFunctions(); - Clear(); -} + return 0; + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReloadScripts -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the preset scripts of this object, from the same script file -// path as was originally defined. This will also update the original -// preset in the PresetMan with the updated scripts so future objects -// spawned will use the new scripts. + void GAScripted::RefreshActivityFunctions() { + m_ScriptFunctions.clear(); + if (m_ScriptPath.empty()) { + return; + } -int GAScripted::ReloadScripts() { - if (m_ScriptPath.empty()) { - return 0; - } + // We use m_LuaClassName here, because we ran the script file in the global state instead of in an environment + std::unordered_map scriptFileFunctions; + g_LuaMan.GetMasterScriptState().RetrieveFunctions(m_LuaClassName, GetSupportedScriptFunctionNames(), scriptFileFunctions); - int error = 0; - CollectRequiredAreas(); + for (const auto& [functionName, functionObject]: scriptFileFunctions) { + m_ScriptFunctions[functionName] = std::unique_ptr(functionObject); + } + } - // If it hasn't been yet, run the file that specifies the Lua functions for this' operating logic (including the scene test function) - if (!g_LuaMan.GetMasterScriptState().GlobalIsDefined(m_LuaClassName)) { - // Temporarily store this Activity so the Lua state can access it - g_LuaMan.GetMasterScriptState().SetTempEntity(this); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Define the var that will hold the script file definitions - if ((error = g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGameActivity(LuaMan.TempEntity);")) < 0) { - return error; - } - } + bool GAScripted::HasSaveFunction() const { + return m_ScriptFunctions.find("OnSave") != m_ScriptFunctions.end(); + } - if ((error = g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath, true, false)) < 0) { - return error; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - RefreshActivityFunctions(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SceneIsCompatible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells if a particular Scene supports this specific Activity on it. + // Usually that means certain Area:s need to be defined in the Scene. - return 0; -} + bool GAScripted::SceneIsCompatible(Scene* pScene, int teams) { + if (!GameActivity::SceneIsCompatible(pScene, teams)) { + return false; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Check if all Areas required by this are defined in the Scene + for (std::set::iterator itr = m_RequiredAreas.begin(); itr != m_RequiredAreas.end(); ++itr) { + // If Area is missing, this Scene is not up to par + if (!pScene->HasArea(*itr)) { + return false; + } + } -void GAScripted::RefreshActivityFunctions() { - m_ScriptFunctions.clear(); - if (m_ScriptPath.empty()) { - return; - } + // Temporarily store the scene so the Lua state can access it and check for the necessary Areas etc. + g_LuaMan.GetMasterScriptState().SetTempEntity(pScene); + // Cast the test scene it to a Scene object in Lua + if (g_LuaMan.GetMasterScriptState().RunScriptString("TestScene = ToScene(LuaMan.TempEntity);") < 0) { + return false; + } - // We use m_LuaClassName here, because we ran the script file in the global state instead of in an environment - std::unordered_map scriptFileFunctions; - g_LuaMan.GetMasterScriptState().RetrieveFunctions(m_LuaClassName, GetSupportedScriptFunctionNames(), scriptFileFunctions); + // If it hasn't been yet, run the file that specifies the Lua functions for this' operating logic (including the scene test function) + if (!g_LuaMan.GetMasterScriptState().GlobalIsDefined(m_LuaClassName)) { + // Temporarily store this Activity so the Lua state can access it + g_LuaMan.GetMasterScriptState().SetTempEntity(this); + // Define the var that will hold the script file definitions.. + // it's OK if the script fails, then the scene is still deemed compatible + if (g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGameActivity(LuaMan.TempEntity);") < 0) { + return true; + } + // Load and run the file, defining all the scripted functions of this Activity + if (g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath) < 0) { + return true; + } + } - for (const auto& [functionName, functionObject] : scriptFileFunctions) { - m_ScriptFunctions[functionName] = std::unique_ptr(functionObject); - } -} + // Call the defined function, but only after first checking if it exists + g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".SceneTest then " + m_LuaClassName + ":SceneTest(); end"); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // If the test left the Scene pointer still set, it means it passed the test + return g_LuaMan.GetMasterScriptState().GlobalIsDefined("TestScene"); + } -bool GAScripted::HasSaveFunction() const { - return m_ScriptFunctions.find("OnSave") != m_ScriptFunctions.end(); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void GAScripted::HandleCraftEnteringOrbit(ACraft* orbitedCraft) { + GameActivity::HandleCraftEnteringOrbit(orbitedCraft); + if (orbitedCraft && g_MovableMan.IsActor(orbitedCraft)) { + g_LuaMan.GetMasterScriptState().RunScriptFunctionString(m_LuaClassName + ".CraftEnteredOrbit", m_LuaClassName, {m_LuaClassName, m_LuaClassName + ".CraftEnteredOrbit"}, {orbitedCraft}); + for (GlobalScript* globalScript: m_GlobalScriptsList) { + globalScript->HandleCraftEnteringOrbit(orbitedCraft); + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SceneIsCompatible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells if a particular Scene supports this specific Activity on it. -// Usually that means certain Area:s need to be defined in the Scene. - -bool GAScripted::SceneIsCompatible(Scene *pScene, int teams) { - if (!GameActivity::SceneIsCompatible(pScene, teams)) { - return false; - } - - // Check if all Areas required by this are defined in the Scene - for (std::set::iterator itr = m_RequiredAreas.begin(); itr != m_RequiredAreas.end(); ++itr) { - // If Area is missing, this Scene is not up to par - if (!pScene->HasArea(*itr)) { - return false; - } - } - - // Temporarily store the scene so the Lua state can access it and check for the necessary Areas etc. - g_LuaMan.GetMasterScriptState().SetTempEntity(pScene); - // Cast the test scene it to a Scene object in Lua - if (g_LuaMan.GetMasterScriptState().RunScriptString("TestScene = ToScene(LuaMan.TempEntity);") < 0) { - return false; - } - - // If it hasn't been yet, run the file that specifies the Lua functions for this' operating logic (including the scene test function) - if (!g_LuaMan.GetMasterScriptState().GlobalIsDefined(m_LuaClassName)) { - // Temporarily store this Activity so the Lua state can access it - g_LuaMan.GetMasterScriptState().SetTempEntity(this); - // Define the var that will hold the script file definitions.. - // it's OK if the script fails, then the scene is still deemed compatible - if (g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGameActivity(LuaMan.TempEntity);") < 0) { - return true; - } - // Load and run the file, defining all the scripted functions of this Activity - if (g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath) < 0) { - return true; - } - } - - // Call the defined function, but only after first checking if it exists - g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".SceneTest then " + m_LuaClassName + ":SceneTest(); end"); - - // If the test left the Scene pointer still set, it means it passed the test - return g_LuaMan.GetMasterScriptState().GlobalIsDefined("TestScene"); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void GAScripted::HandleCraftEnteringOrbit(ACraft *orbitedCraft) { - GameActivity::HandleCraftEnteringOrbit(orbitedCraft); - - if (orbitedCraft && g_MovableMan.IsActor(orbitedCraft)) { - g_LuaMan.GetMasterScriptState().RunScriptFunctionString(m_LuaClassName + ".CraftEnteredOrbit", m_LuaClassName, {m_LuaClassName, m_LuaClassName + ".CraftEnteredOrbit"}, {orbitedCraft}); - for (GlobalScript *globalScript : m_GlobalScriptsList) { - globalScript->HandleCraftEnteringOrbit(orbitedCraft); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. -int GAScripted::Start() { - ActivityState initialActivityState = m_ActivityState; + int GAScripted::Start() { + ActivityState initialActivityState = m_ActivityState; - int error = GameActivity::Start(); - if (error < 0) { - return error; - } + int error = GameActivity::Start(); + if (error < 0) { + return error; + } - // Temporarily store this Activity so the Lua state can access it - g_LuaMan.GetMasterScriptState().SetTempEntity(this); + // Temporarily store this Activity so the Lua state can access it + g_LuaMan.GetMasterScriptState().SetTempEntity(this); - // Define the var that will hold the script file definitions - if ((error = g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGameActivity(LuaMan.TempEntity);")) < 0) { - return error; - } + // Define the var that will hold the script file definitions + if ((error = g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGameActivity(LuaMan.TempEntity);")) < 0) { + return error; + } - // Run the file that specifies the Lua functions for this' operating logic - if ((error = ReloadScripts()) < 0) { - return error; - } + // Run the file that specifies the Lua functions for this' operating logic + if ((error = ReloadScripts()) < 0) { + return error; + } - // Call the create function - if ((error = RunLuaFunction("StartActivity", {}, { initialActivityState == ActivityState::NotStarted ? "true" : "false" }, {})) < 0) { - return error; - } + // Call the create function + if ((error = RunLuaFunction("StartActivity", {}, {initialActivityState == ActivityState::NotStarted ? "true" : "false"}, {})) < 0) { + return error; + } - // Clear active global scripts - for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { - delete (*sItr); - } + // Clear active global scripts + for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { + delete (*sItr); + } - m_GlobalScriptsList.clear(); + m_GlobalScriptsList.clear(); - // Get all global scripts and add to execution list - std::list globalScripts; - g_PresetMan.GetAllOfType(globalScripts, "GlobalScript"); + // Get all global scripts and add to execution list + std::list globalScripts; + g_PresetMan.GetAllOfType(globalScripts, "GlobalScript"); - for (std::list::iterator sItr = globalScripts.begin(); sItr != globalScripts.end(); ++sItr) { - m_GlobalScriptsList.push_back(dynamic_cast((*sItr)->Clone())); - } + for (std::list::iterator sItr = globalScripts.begin(); sItr != globalScripts.end(); ++sItr) { + m_GlobalScriptsList.push_back(dynamic_cast((*sItr)->Clone())); + } - // Start all global scripts - for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { - (*sItr)->Start(); + // Start all global scripts + for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { + (*sItr)->Start(); + } + + return error; } - return error; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + void GAScripted::SetPaused(bool pause) { + GameActivity::SetPaused(pause); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + RunLuaFunction("PauseActivity", {}, {pause ? "true" : "false"}, {}); -void GAScripted::SetPaused(bool pause) { - GameActivity::SetPaused(pause); + // Pause all global scripts + for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { + (*sItr)->Pause(pause); + } + } - RunLuaFunction("PauseActivity", {}, { pause ? "true" : "false" }, {}); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. - // Pause all global scripts - for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { - (*sItr)->Pause(pause); - } -} + void GAScripted::End() { + GameActivity::End(); + RunLuaFunction("EndActivity"); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. + // End all global scripts + for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { + (*sItr)->End(); + } -void GAScripted::End() { - GameActivity::End(); + // Delete all global scripts, in case destructor is not called when activity restarts + for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { + delete (*sItr); + } - RunLuaFunction("EndActivity"); + m_GlobalScriptsList.clear(); + } - // End all global scripts - for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { - (*sItr)->End(); - } + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateEditing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: This is a special update step for when any player is still editing the + // scene. - // Delete all global scripts, in case destructor is not called when activity restarts - for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { - delete (*sItr); - } + void GAScripted::UpdateEditing() { + GameActivity::UpdateEditing(); + } + */ - m_GlobalScriptsList.clear(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this GAScripted. Supposed to be done every frame + // before drawing. -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateEditing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: This is a special update step for when any player is still editing the -// scene. + void GAScripted::Update() { + GameActivity::Update(); -void GAScripted::UpdateEditing() { - GameActivity::UpdateEditing(); -} -*/ + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) { + continue; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this GAScripted. Supposed to be done every frame -// before drawing. + // The current player's team + int team = m_Team[player]; + if (team == Teams::NoTeam) { + continue; + } + } + + // If the game didn't end, keep updating activity + if (m_ActivityState != ActivityState::Over) { + AddPieSlicesToActiveActorPieMenus(); -void GAScripted::Update() { - GameActivity::Update(); + // Need to call this continually unfortunately, as something might change due to dofile() + RefreshActivityFunctions(); - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - if (!(m_IsActive[player] && m_IsHuman[player])) { - continue; - } + RunLuaFunction("UpdateActivity"); - // The current player's team - int team = m_Team[player]; - if (team == Teams::NoTeam) { - continue; - } - } + UpdateGlobalScripts(false); + } + } - // If the game didn't end, keep updating activity - if (m_ActivityState != ActivityState::Over) { - AddPieSlicesToActiveActorPieMenus(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateGlobalScripts + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates globals scripts loaded with this activity. - // Need to call this continually unfortunately, as something might change due to dofile() - RefreshActivityFunctions(); + void GAScripted::UpdateGlobalScripts(bool lateUpdate) { + ZoneScoped; - RunLuaFunction("UpdateActivity"); + // Update all global scripts + for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { + if ((*sItr)->ShouldLateUpdate() == lateUpdate) { + (*sItr)->Update(); + } + } + } - UpdateGlobalScripts(false); - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + void GAScripted::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + GameActivity::DrawGUI(pTargetBitmap, targetPos, which); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateGlobalScripts -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates globals scripts loaded with this activity. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this GAScripted's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. -void GAScripted::UpdateGlobalScripts(bool lateUpdate) { - ZoneScoped; + void GAScripted::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + GameActivity::Draw(pTargetBitmap, targetPos); + } - // Update all global scripts - for (std::vector::iterator sItr = m_GlobalScriptsList.begin(); sItr < m_GlobalScriptsList.end(); ++sItr) { - if ((*sItr)->ShouldLateUpdate() == lateUpdate) { - (*sItr)->Update(); - } - } -} + int GAScripted::RunLuaFunction(const std::string& functionName, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments, const std::vector& functionObjectArguments) { + // Call the defined function, but only after first checking if it exists + auto funcItr = m_ScriptFunctions.find(functionName); + if (funcItr == m_ScriptFunctions.end()) { + return 0; + } + int error = g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(funcItr->second.get(), "_G", m_LuaClassName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. + return error; + } -void GAScripted::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) { - GameActivity::DrawGUI(pTargetBitmap, targetPos, which); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollectRequiredAreas + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through the script file and checks for any mentions and uses of + // Area:s that are required for this Activity to run in a Scene. + + void GAScripted::CollectRequiredAreas() { + // Open the script file so we can check it out + std::ifstream scriptFile = std::ifstream(g_PresetMan.GetFullModulePath(m_ScriptPath.c_str())); + if (!scriptFile.good()) { + return; + } + // Harvest the required Area:s from the file + m_RequiredAreas.clear(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this GAScripted's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + bool blockCommented = false; -void GAScripted::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) { - GameActivity::Draw(pTargetBitmap, targetPos); -} + while (!scriptFile.eof()) { + // Go through the script file, line by line + char rawLine[512]; + scriptFile.getline(rawLine, 512); + std::string line = rawLine; + std::string::size_type pos = 0; + std::string::size_type endPos = 0; + std::string::size_type commentPos = std::string::npos; -int GAScripted::RunLuaFunction(const std::string& functionName, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments, const std::vector& functionObjectArguments) { - // Call the defined function, but only after first checking if it exists - auto funcItr = m_ScriptFunctions.find(functionName); - if (funcItr == m_ScriptFunctions.end()) { - return 0; - } + // Check for block comments + if (!blockCommented && (commentPos = line.find("--[[", 0)) != std::string::npos) { + blockCommented = true; + } - int error = g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(funcItr->second.get(), "_G", m_LuaClassName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + // Find the end of the block comment + if (blockCommented) { + if ((commentPos = line.find("]]", commentPos == std::string::npos ? 0 : commentPos)) != std::string::npos) { + blockCommented = false; + pos = commentPos; + } + } - return error; -} + // Process the line as usual + if (!blockCommented) { + // See if this line is commented out anywhere + commentPos = line.find("--", 0); + do { + // Find the beginning of a mentioned Area name + pos = line.find(":GetArea(\"", pos); + if (pos != std::string::npos && pos < commentPos) { + // Move position forward to the actual Area name + pos += 10; + // Find the end of the Area name + endPos = line.find_first_of('"', pos); + // Copy it out and put into the list + if (endPos != std::string::npos) { + m_RequiredAreas.insert(line.substr(pos, endPos - pos)); + } + } + } while (pos != std::string::npos && pos < commentPos); + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollectRequiredAreas -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through the script file and checks for any mentions and uses of -// Area:s that are required for this Activity to run in a Scene. - -void GAScripted::CollectRequiredAreas() { - // Open the script file so we can check it out - std::ifstream scriptFile = std::ifstream(g_PresetMan.GetFullModulePath(m_ScriptPath.c_str())); - if (!scriptFile.good()) { - return; - } - - // Harvest the required Area:s from the file - m_RequiredAreas.clear(); - - bool blockCommented = false; - - while (!scriptFile.eof()) { - // Go through the script file, line by line - char rawLine[512]; - scriptFile.getline(rawLine, 512); - std::string line = rawLine; - std::string::size_type pos = 0; - std::string::size_type endPos = 0; - std::string::size_type commentPos = std::string::npos; - - // Check for block comments - if (!blockCommented && (commentPos = line.find("--[[", 0)) != std::string::npos) { - blockCommented = true; - } - - // Find the end of the block comment - if (blockCommented) { - if ((commentPos = line.find("]]", commentPos == std::string::npos ? 0 : commentPos)) != std::string::npos) { - blockCommented = false; - pos = commentPos; - } - } - - // Process the line as usual - if (!blockCommented) { - // See if this line is commented out anywhere - commentPos = line.find("--", 0); - do { - // Find the beginning of a mentioned Area name - pos = line.find(":GetArea(\"", pos); - if (pos != std::string::npos && pos < commentPos) { - // Move position forward to the actual Area name - pos += 10; - // Find the end of the Area name - endPos = line.find_first_of('"', pos); - // Copy it out and put into the list - if (endPos != std::string::npos) { - m_RequiredAreas.insert(line.substr(pos, endPos - pos)); - } - } - } while(pos != std::string::npos && pos < commentPos); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void GAScripted::AddPieSlicesToActiveActorPieMenus() { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - if (m_IsActive[player] && m_IsHuman[player] && m_ControlledActor[player] && m_ViewState[player] != ViewState::DeathWatch && m_ViewState[player] != ViewState::ActorSelect && m_ViewState[player] != ViewState::AIGoToPoint && m_ViewState[player] != ViewState::UnitSelectCircle) { - PieMenu *controlledActorPieMenu = m_ControlledActor[player]->GetPieMenu(); - if (controlledActorPieMenu && m_ControlledActor[player]->GetController()->IsState(PIE_MENU_ACTIVE) && controlledActorPieMenu->IsEnabling()) { - for (const std::unique_ptr &pieSlice : m_PieSlicesToAdd) { - controlledActorPieMenu->AddPieSliceIfPresetNameIsUnique(pieSlice.get(), this, true); - } - for (const GlobalScript *globalScript : m_GlobalScriptsList) { - for (const std::unique_ptr &pieSlice : globalScript->GetPieSlicesToAdd()) { - controlledActorPieMenu->AddPieSliceIfPresetNameIsUnique(pieSlice.get(), globalScript, true); + void GAScripted::AddPieSlicesToActiveActorPieMenus() { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (m_IsActive[player] && m_IsHuman[player] && m_ControlledActor[player] && m_ViewState[player] != ViewState::DeathWatch && m_ViewState[player] != ViewState::ActorSelect && m_ViewState[player] != ViewState::AIGoToPoint && m_ViewState[player] != ViewState::UnitSelectCircle) { + PieMenu* controlledActorPieMenu = m_ControlledActor[player]->GetPieMenu(); + if (controlledActorPieMenu && m_ControlledActor[player]->GetController()->IsState(PIE_MENU_ACTIVE) && controlledActorPieMenu->IsEnabling()) { + for (const std::unique_ptr& pieSlice: m_PieSlicesToAdd) { + controlledActorPieMenu->AddPieSliceIfPresetNameIsUnique(pieSlice.get(), this, true); + } + for (const GlobalScript* globalScript: m_GlobalScriptsList) { + for (const std::unique_ptr& pieSlice: globalScript->GetPieSlicesToAdd()) { + controlledActorPieMenu->AddPieSliceIfPresetNameIsUnique(pieSlice.get(), globalScript, true); + } } } } } } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/GAScripted.h b/Source/Activities/GAScripted.h index e756588ec..080dc6e17 100644 --- a/Source/Activities/GAScripted.h +++ b/Source/Activities/GAScripted.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,309 +19,289 @@ #include "LuabindObjectWrapper.h" -namespace RTE -{ - -class ACraft; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: GAScripted -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Scripted activity -// Parent(s): GameActivity. -// Class history: 07/03/2008 GAScripted created. - -class GAScripted : public GameActivity { - - friend class LuaMan; - friend class ActivityMan; - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - -ScriptFunctionNames("StartActivity", "UpdateActivity", "PauseActivity", "EndActivity", "OnSave", "CraftEnteredOrbit", "OnMessage", "OnGlobalMessage"); - -// Concrete allocation and cloning definitions -EntityAllocation(GAScripted); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GAScripted -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GAScripted object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - GAScripted() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~GAScripted -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a GAScripted object before deletion -// from system memory. -// Arguments: None. - - ~GAScripted() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GAScripted object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GAScripted object ready for use. -// Arguments: The filepath to the script that defines this' Lua-defined derivation -// of this class. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(std::string scriptPath, std::string scriptClassName) { m_ScriptPath = scriptPath; m_LuaClassName = scriptClassName; return Create(); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GAScripted to be identical to another, by deep copy. -// Arguments: A reference to the GAScripted to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const GAScripted &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire GAScripted, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Activity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GAScripted object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReloadScripts -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the preset scripts of this object, from the same script file -// path as was originally defined. This will also update the original -// preset in the PresetMan with the updated scripts so future objects -// spawned will use the new scripts. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int ReloadScripts() override; - - /// - /// Refreshes our activity functions to find any changes from script. - /// - void RefreshActivityFunctions(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLuaClassName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the class name of the Lua-derived class defined in this' script. -// Arguments: None. -// Return value: A string with the friendly-formatted Lua type name of this object. - - const std::string & GetLuaClassName() const { return m_LuaClassName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SceneIsCompatible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells if a particular Scene supports this specific Activity on it. -// Usually that means certain Area:s need to be defined in the Scene. -// Arguments: The Scene to check if it supports this Activiy. Ownership IS NOT TRANSFERRED! -// How many teams we're checking for. Some scenes may support and activity -// but only for a limited number of teams. If -1, not applicable. -// Return value: Whether the Scene has the right stuff. - - bool SceneIsCompatible(Scene *pScene, int teams = -1) override; - - - /// - /// Handles when an ACraft has left the game scene and entered orbit, though does not delete it. Ownership is NOT transferred, as the ACraft's inventory is just 'unloaded'. - /// - /// The ACraft instance that entered orbit. Ownership is NOT transferred! - void HandleCraftEnteringOrbit(ACraft *orbitedCraft) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateGlobalScripts -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates globals scripts loaded with this activity. -// Arguments: Whether it's an early update, during Activity update, or late update, after MovableMan -// Return value: None. - - void UpdateGlobalScripts(bool lateUpdate); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector& targetPos = Vector()) override; - - int RunLuaFunction(const std::string& functionName, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector(), const std::vector& functionObjectArguments = std::vector()); - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CollectRequiredAreas -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through the script file and checks for any mentions and uses of -// Area:s that are required for this Activity to run in a Scene. -// Arguments: None. -// Return value: None. - - void CollectRequiredAreas(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: InitAIs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does nothing - we do this in script! Just overrides the base behaviour. -// Arguments: None. -// Return value: None. - - void InitAIs() override {}; - - - // Member variables - static Entity::ClassInfo m_sClass; - - // The path to the lua script file that defines this' behaviors with overrides of its virtual functions - std::string m_ScriptPath; - // The name of the class (table) defining the logic of this in Lua, as specified in the script file - std::string m_LuaClassName; - // The list of Area:s required in a Scene to play this Activity on it - std::set m_RequiredAreas; - std::vector> m_PieSlicesToAdd; //!< A vector of PieSlices that should be added to any PieMenus opened while this GAScripted is running. - // The list of global scripts allowed to run during this activity - std::vector m_GlobalScriptsList; - - std::unordered_map> m_ScriptFunctions; //!< A map of LuabindObjectWrappers that hold Lua functions. Used to maintain script execution order and avoid extraneous Lua calls. - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - /// - /// Returns whether this GAScripted has an OnSave function, to act as a default for whether saving is allowed or not. - /// - /// Whether this GAScripted has an OnSave function - bool HasSaveFunction() const; - - /// - /// Adds this GAScripted's PieSlices, and any active GlobalScripts' PieSlices, to any active PieMenus. - /// - void AddPieSlicesToActiveActorPieMenus(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class ACraft; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: GAScripted + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Scripted activity + // Parent(s): GameActivity. + // Class history: 07/03/2008 GAScripted created. + + class GAScripted : public GameActivity { + + friend class LuaMan; + friend class ActivityMan; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + ScriptFunctionNames("StartActivity", "UpdateActivity", "PauseActivity", "EndActivity", "OnSave", "CraftEnteredOrbit", "OnMessage", "OnGlobalMessage"); + + // Concrete allocation and cloning definitions + EntityAllocation(GAScripted); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GAScripted + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GAScripted object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + GAScripted() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~GAScripted + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a GAScripted object before deletion + // from system memory. + // Arguments: None. + + ~GAScripted() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GAScripted object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GAScripted object ready for use. + // Arguments: The filepath to the script that defines this' Lua-defined derivation + // of this class. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(std::string scriptPath, std::string scriptClassName) { + m_ScriptPath = scriptPath; + m_LuaClassName = scriptClassName; + return Create(); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GAScripted to be identical to another, by deep copy. + // Arguments: A reference to the GAScripted to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const GAScripted& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire GAScripted, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Activity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GAScripted object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReloadScripts + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the preset scripts of this object, from the same script file + // path as was originally defined. This will also update the original + // preset in the PresetMan with the updated scripts so future objects + // spawned will use the new scripts. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int ReloadScripts() override; + + /// + /// Refreshes our activity functions to find any changes from script. + /// + void RefreshActivityFunctions(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLuaClassName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the class name of the Lua-derived class defined in this' script. + // Arguments: None. + // Return value: A string with the friendly-formatted Lua type name of this object. + + const std::string& GetLuaClassName() const { return m_LuaClassName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SceneIsCompatible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells if a particular Scene supports this specific Activity on it. + // Usually that means certain Area:s need to be defined in the Scene. + // Arguments: The Scene to check if it supports this Activiy. Ownership IS NOT TRANSFERRED! + // How many teams we're checking for. Some scenes may support and activity + // but only for a limited number of teams. If -1, not applicable. + // Return value: Whether the Scene has the right stuff. + + bool SceneIsCompatible(Scene* pScene, int teams = -1) override; + + /// + /// Handles when an ACraft has left the game scene and entered orbit, though does not delete it. Ownership is NOT transferred, as the ACraft's inventory is just 'unloaded'. + /// + /// The ACraft instance that entered orbit. Ownership is NOT transferred! + void HandleCraftEnteringOrbit(ACraft* orbitedCraft) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateGlobalScripts + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates globals scripts loaded with this activity. + // Arguments: Whether it's an early update, during Activity update, or late update, after MovableMan + // Return value: None. + + void UpdateGlobalScripts(bool lateUpdate); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + int RunLuaFunction(const std::string& functionName, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector(), const std::vector& functionObjectArguments = std::vector()); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CollectRequiredAreas + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through the script file and checks for any mentions and uses of + // Area:s that are required for this Activity to run in a Scene. + // Arguments: None. + // Return value: None. + + void CollectRequiredAreas(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: InitAIs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does nothing - we do this in script! Just overrides the base behaviour. + // Arguments: None. + // Return value: None. + + void InitAIs() override{}; + + // Member variables + static Entity::ClassInfo m_sClass; + + // The path to the lua script file that defines this' behaviors with overrides of its virtual functions + std::string m_ScriptPath; + // The name of the class (table) defining the logic of this in Lua, as specified in the script file + std::string m_LuaClassName; + // The list of Area:s required in a Scene to play this Activity on it + std::set m_RequiredAreas; + std::vector> m_PieSlicesToAdd; //!< A vector of PieSlices that should be added to any PieMenus opened while this GAScripted is running. + // The list of global scripts allowed to run during this activity + std::vector m_GlobalScriptsList; + + std::unordered_map> m_ScriptFunctions; //!< A map of LuabindObjectWrappers that hold Lua functions. Used to maintain script execution order and avoid extraneous Lua calls. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + /// + /// Returns whether this GAScripted has an OnSave function, to act as a default for whether saving is allowed or not. + /// + /// Whether this GAScripted has an OnSave function + bool HasSaveFunction() const; + + /// + /// Adds this GAScripted's PieSlices, and any active GlobalScripts' PieSlices, to any active PieMenus. + /// + void AddPieSlicesToActiveActorPieMenus(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/GATutorial.cpp b/Source/Activities/GATutorial.cpp index b287ce70b..cdc004f1a 100644 --- a/Source/Activities/GATutorial.cpp +++ b/Source/Activities/GATutorial.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -37,1038 +36,954 @@ namespace RTE { -ConcreteClassInfo(GATutorial, GameActivity, 0); + ConcreteClassInfo(GATutorial, GameActivity, 0); + GATutorial::TutStep::TutStep(std::string text, int stepDuration, std::string screensPath, int frameCount, int frameDuration) { + m_Text = text; + m_Duration = stepDuration; + m_FrameDuration = frameDuration; -GATutorial::TutStep::TutStep(std::string text, int stepDuration, std::string screensPath, int frameCount, int frameDuration) -{ - m_Text = text; - m_Duration = stepDuration; - m_FrameDuration = frameDuration; + if (!screensPath.empty()) { + ContentFile(screensPath.c_str()).GetAsAnimation(m_pScreens, frameCount); + } + } - if (!screensPath.empty()) - { - ContentFile(screensPath.c_str()).GetAsAnimation(m_pScreens, frameCount); - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this GATutorial, effectively + // resetting the members of this abstraction level only. + + void GATutorial::Clear() { + m_TutorialPlayer = Players::PlayerOne; + + for (int area = 0; area < AREACOUNT; ++area) { + m_TriggerBoxes[area].Reset(); + m_ScreenPositions[area].Reset(); + m_ScreenStates[area] = SCREENOFF; + m_TextOffsets[area].Reset(); + m_TutAreaSteps[area].clear(); + } + for (int room = 0; room < ROOMCOUNT; ++room) { + m_RoomSignPositions[room].Reset(); + m_aapRoomSigns[room][UNLIT] = 0; + m_aapRoomSigns[room][LIT] = 0; + } + m_AreaTimer.Reset(); + m_StepTimer.Reset(); + m_CurrentArea = BRAINCHAMBER; + m_PrevArea = BRAINCHAMBER; + m_ScreenChange = false; + m_CurrentStep = 0; + m_CurrentFrame = 0; + m_CurrentRoom = ROOM0; + + for (int stage = 0; stage < FIGHTSTAGECOUNT; ++stage) + m_FightTriggers[stage].Reset(); + + m_EnemyCount = 0; + m_CurrentFightStage = NOFIGHT; + m_pCPUBrain = 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GATutorial object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this GATutorial, effectively -// resetting the members of this abstraction level only. - -void GATutorial::Clear() -{ - m_TutorialPlayer = Players::PlayerOne; - - for (int area = 0; area < AREACOUNT; ++area) - { - m_TriggerBoxes[area].Reset(); - m_ScreenPositions[area].Reset(); - m_ScreenStates[area] = SCREENOFF; - m_TextOffsets[area].Reset(); - m_TutAreaSteps[area].clear(); - } - for (int room = 0; room < ROOMCOUNT; ++room) - { - m_RoomSignPositions[room].Reset(); - m_aapRoomSigns[room][UNLIT] = 0; - m_aapRoomSigns[room][LIT] = 0; - } - m_AreaTimer.Reset(); - m_StepTimer.Reset(); - m_CurrentArea = BRAINCHAMBER; - m_PrevArea = BRAINCHAMBER; - m_ScreenChange = false; - m_CurrentStep = 0; - m_CurrentFrame = 0; - m_CurrentRoom = ROOM0; - - for (int stage = 0; stage < FIGHTSTAGECOUNT; ++stage) - m_FightTriggers[stage].Reset(); - - m_EnemyCount = 0; - m_CurrentFightStage = NOFIGHT; - m_pCPUBrain = 0; -} + int GATutorial::Create() { + if (GameActivity::Create() < 0) + return -1; + m_Description = "A tutorial for learning how to play Cortex Command. A good place to start!"; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GATutorial object ready for use. + return 0; + } -int GATutorial::Create() -{ - if (GameActivity::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GATutorial to be identical to another, by deep copy. + + int GATutorial::Create(const GATutorial& reference) { + if (GameActivity::Create(reference) < 0) + return -1; + + for (int area = 0; area < AREACOUNT; ++area) { + m_TriggerBoxes[area] = reference.m_TriggerBoxes[area]; + m_ScreenPositions[area] = reference.m_ScreenPositions[area]; + m_ScreenStates[area] = reference.m_ScreenStates[area]; + m_TextOffsets[area] = reference.m_TextOffsets[area]; + m_TutAreaSteps[area] = reference.m_TutAreaSteps[area]; + } + for (int room = 0; room < ROOMCOUNT; ++room) { + m_RoomSignPositions[room] = reference.m_RoomSignPositions[room]; + } + m_AreaTimer.Reset(); + m_StepTimer.Reset(); + m_CurrentArea = reference.m_CurrentArea; + m_PrevArea = reference.m_PrevArea; + m_CurrentStep = reference.m_CurrentStep; + m_CurrentFrame = reference.m_CurrentFrame; + m_CurrentRoom = reference.m_CurrentRoom; + + for (int stage = 0; stage < FIGHTSTAGECOUNT; ++stage) + m_FightTriggers[stage] = reference.m_FightTriggers[stage]; + + m_EnemyCount = reference.m_EnemyCount; + m_CurrentFightStage = reference.m_CurrentFightStage; + // DOn't, owned and need to make deep copy in that case + // m_pCPUBrain; + + return 0; + } - m_Description = "A tutorial for learning how to play Cortex Command. A good place to start!"; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int GATutorial::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return GameActivity::ReadProperty(propName, reader)); + /* + MatchProperty("SpawnIntervalEasiest", { reader >> m_SpawnIntervalEasiest; }); + MatchProperty("SpawnIntervalHardest", { reader >> m_SpawnIntervalHardest; }); + MatchProperty("AddAttackerSpawn", + Actor *pNewSpawn = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); + if (pNewSpawn) { m_AttackerSpawns.push_back(pNewSpawn); } ); + */ + EndPropertyList; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this GATutorial with a Writer for + // later recreation with Create(Reader &reader); + int GATutorial::Save(Writer& writer) const { + GameActivity::Save(writer); + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GATutorial to be identical to another, by deep copy. - -int GATutorial::Create(const GATutorial &reference) -{ - if (GameActivity::Create(reference) < 0) - return -1; - - for (int area = 0; area < AREACOUNT; ++area) - { - m_TriggerBoxes[area] = reference.m_TriggerBoxes[area]; - m_ScreenPositions[area] = reference.m_ScreenPositions[area]; - m_ScreenStates[area] = reference.m_ScreenStates[area]; - m_TextOffsets[area] = reference.m_TextOffsets[area]; - m_TutAreaSteps[area] = reference.m_TutAreaSteps[area]; - } - for (int room = 0; room < ROOMCOUNT; ++room) - { - m_RoomSignPositions[room] = reference.m_RoomSignPositions[room]; - } - m_AreaTimer.Reset(); - m_StepTimer.Reset(); - m_CurrentArea = reference.m_CurrentArea; - m_PrevArea = reference.m_PrevArea; - m_CurrentStep = reference.m_CurrentStep; - m_CurrentFrame = reference.m_CurrentFrame; - m_CurrentRoom = reference.m_CurrentRoom; - - for (int stage = 0; stage < FIGHTSTAGECOUNT; ++stage) - m_FightTriggers[stage] = reference.m_FightTriggers[stage]; - - m_EnemyCount = reference.m_EnemyCount; - m_CurrentFightStage = reference.m_CurrentFightStage; -// DOn't, owned and need to make deep copy in that case -// m_pCPUBrain; - - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GATutorial object. + void GATutorial::Destroy(bool notInherited) { + if (!notInherited) + GameActivity::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int GATutorial::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return GameActivity::ReadProperty(propName, reader)); -/* - MatchProperty("SpawnIntervalEasiest", { reader >> m_SpawnIntervalEasiest; }); - MatchProperty("SpawnIntervalHardest", { reader >> m_SpawnIntervalHardest; }); - MatchProperty("AddAttackerSpawn", - Actor *pNewSpawn = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); - if (pNewSpawn) { m_AttackerSpawns.push_back(pNewSpawn); } ); -*/ - EndPropertyList; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SceneIsCompatible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells if a particular Scene supports this specific Activity on it. + // Usually that means certain Area:s need to be defined in the Scene. + bool GATutorial::SceneIsCompatible(Scene* pScene, int teams) { + if (!GameActivity::SceneIsCompatible(pScene, teams)) + return false; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this GATutorial with a Writer for -// later recreation with Create(Reader &reader); + // Quick and dirty hardcoded hack.. only this scene is compatible anyway + if (pScene->GetPresetName() == "Tutorial Bunker") + return true; -int GATutorial::Save(Writer &writer) const { - GameActivity::Save(writer); - return 0; -} + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. + + int GATutorial::Start() { + int error = GameActivity::Start(); + + //////////////////////////////// + // Set up teams + + // Team 2 is always CPU + SetCPUTeam(Teams::TeamTwo); + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + + if (team == Teams::TeamOne) { + // See if there are specified landing zone areas defined in the scene + char str[64]; + std::snprintf(str, sizeof(str), "LZ Team %d", team + 1); + Scene::Area* pArea = g_SceneMan.GetScene()->GetArea(str); + // pArea = pArea ? pArea : g_SceneMan.GetScene()->GetArea("Landing Zone"); + // If area is defined, save a copy so we can lock the LZ selection to within its boxes + if (pArea && !pArea->HasNoArea()) + SetLZArea(team, *pArea); + } + + // If this is a CPU controlled team, then try to find a brain for them, or place one + if (team == m_CPUTeam && !m_pCPUBrain) { + // TODO: Make special CPU brain actor which will only appear in CPU brain fights, and have to be placed in the scenes + m_pCPUBrain = g_MovableMan.GetUnassignedBrain(team); + m_pCPUBrain = m_pCPUBrain ? m_pCPUBrain : g_MovableMan.GetFirstBrainActor(team); // Try getting our assigned brain + if (!m_pCPUBrain) { + // Couldn't find an available brain in the scene, so make one and place it + m_pCPUBrain = dynamic_cast(g_PresetMan.GetEntityPreset("Actor", "Brain Case")->Clone()); + if (m_pCPUBrain) { + Vector brainPos; + // Place opposite of the other team's brain + Actor* pOtherBrain = g_MovableMan.GetFirstOtherBrainActor(team); + if (pOtherBrain) { + brainPos = pOtherBrain->GetPos(); + brainPos.m_X += g_SceneMan.GetSceneWidth() / 2; + brainPos.m_Y = g_SceneMan.GetSceneHeight() - 200; + g_SceneMan.WrapPosition(brainPos); + } + // No brain found on other team... then just place somewhere in the ground, spaced out + else { + if (team == Teams::TeamOne) + brainPos.SetXY((float)g_SceneMan.GetSceneWidth() * 0.25, (float)g_SceneMan.GetSceneHeight() * 0.75); + if (team == Teams::TeamTwo) + brainPos.SetXY((float)g_SceneMan.GetSceneWidth() * 0.75, (float)g_SceneMan.GetSceneHeight() * 0.75); + } + m_pCPUBrain->SetPos(brainPos); + m_pCPUBrain->SetTeam(team); + // Transfer ownership here + g_MovableMan.AddActor(m_pCPUBrain); + pOtherBrain = 0; + } + } + m_EnemyCount = g_MovableMan.GetTeamRoster(m_CPUTeam)->size(); + } + // Give the player some scratch + else + m_TeamFunds[team] = this->GetStartingGold(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GATutorial object. + /////////////////////////////////////// + // Set up players + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + // Expand all modules to show the goods + m_pBuyGUI[player]->SetModuleExpanded(0); + + // No need for the LZ to follow the brain, the scene-set one is enough + SetBrainLZWidth(player, 0); + + // If we can't find an unassigned brain in the scene to give each player, then force to go into editing mode to place one + if (!m_Brain[player]) { + g_ConsoleMan.PrintString("ERROR: Can't find brain for tutorial game mode!"); + } + // Set the found brain to be the selected actor at start + else { + m_TutorialPlayer = player; + } + /* + if (m_ActivityState == ActivityState::Editing) + g_FrameMan.SetScreenText((player % 2 == 0) ? "Place your brain vault and build your bunker around it..." : "...then select \"DONE\" from the pie menu!", ScreenOfPlayer(player), 0); + else if (m_ActivityState == ActivityState::Running) + g_FrameMan.SetScreenText((player % 2 == 0) ? "Mine Gold and buy more firepower with the funds..." : "...then smash the competing brain to claim victory!", ScreenOfPlayer(player), 0); + */ + } -void GATutorial::Destroy(bool notInherited) -{ - if (!notInherited) - GameActivity::Destroy(); - Clear(); -} + ///////////////////////////////////////////// + // SET UP TUTORIAL + + // COMMON SCREENS + std::vector apScreens = ContentFile("Missions.rte/Objects/Tutorial/ScreenStatic.png").GetAsAnimation(3); + m_apCommonScreens[SCREENOFF] = apScreens[0]; + m_apCommonScreens[STATICLITTLE] = apScreens[1]; + m_apCommonScreens[STATICLARGE] = apScreens[2]; + + // ROOM SIGNS + ContentFile signFile; + for (int room = 0; room < ROOMCOUNT; ++room) { + if (room == ROOM0) + signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryA.png"); + else if (room == ROOM1) + signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryB.png"); + else if (room == ROOM2) + signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryC.png"); + else if (room == ROOM3) + signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryD.png"); + std::vector apSigns = signFile.GetAsAnimation(2); + m_aapRoomSigns[room][UNLIT] = apSigns[0]; + m_aapRoomSigns[room][LIT] = apSigns[1]; + } + m_RoomSignPositions[ROOM0].SetXY(744, 695); + m_RoomSignPositions[ROOM1].SetXY(888, 695); + m_RoomSignPositions[ROOM2].SetXY(888, 599); + m_RoomSignPositions[ROOM3].SetXY(888, 431); + m_CurrentRoom = ROOM3; + + ////////////////////////////////// + // Setup all the Tutorial Areas and their text instructions etc + + SetupAreas(); + + // Disable all enemy AIs so they dont attack prematurely + DisableAIs(true, Teams::TeamTwo); + + ////////////////////////////////// + // FIGHT TRIGGERS + + m_FightTriggers[DEFENDING].Create(Vector(1330, 0), 770, 400); + + // m_FightTriggerEast.Create(Vector(526, 0), 52, 840); + // m_FightTriggerWest.Create(Vector(1336, 0), 52, 840); + /* + // Start special tutorial playlist + g_AudioMan.ClearMusicQueue(); + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/ccambient4.ogg", 0); + g_AudioMan.QueueSilence(30); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); + g_AudioMan.QueueSilence(30); + g_AudioMan.QueueMusicStream("Base.rte/Music/Watts/Last Man.ogg"); + g_AudioMan.QueueSilence(30); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); + */ + return error; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SceneIsCompatible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells if a particular Scene supports this specific Activity on it. -// Usually that means certain Area:s need to be defined in the Scene. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. -bool GATutorial::SceneIsCompatible(Scene *pScene, int teams) -{ - if (!GameActivity::SceneIsCompatible(pScene, teams)) - return false; + void GATutorial::SetPaused(bool pause) { + GameActivity::SetPaused(pause); - // Quick and dirty hardcoded hack.. only this scene is compatible anyway - if (pScene->GetPresetName() == "Tutorial Bunker") - return true; + // Re-setup the ares with any updated control mappings that the player might have made in teh menu + if (!pause) + SetupAreas(); + } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + + void GATutorial::End() { + GameActivity::End(); + + bool playerWon = false; + // Show appropriate end game messages + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + if (m_Team[player] == m_WinnerTeam) { + playerWon = true; + // Set the winner's observation view to his controlled actors instead of his brain + if (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) + m_ObservationTarget[player] = m_ControlledActor[player]->GetPos(); + } + } + // Temp fix so music doesn't start playing if ending the Activity when changing resolution through the in-game settings. + if (!m_Paused) { + // Play the appropriate tune on player win/lose + if (playerWon) { + g_AudioMan.ClearMusicQueue(); + // Loop it twice, nice tune! + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/uwinfinal.ogg", 2); + g_AudioMan.QueueSilence(10); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); + } else { + g_AudioMan.ClearMusicQueue(); + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/udiedfinal.ogg", 0); + g_AudioMan.QueueSilence(10); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int GATutorial::Start() -{ - int error = GameActivity::Start(); - - //////////////////////////////// - // Set up teams - - // Team 2 is always CPU - SetCPUTeam(Teams::TeamTwo); - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - - if (team == Teams::TeamOne) - { - // See if there are specified landing zone areas defined in the scene - char str[64]; - std::snprintf(str, sizeof(str), "LZ Team %d", team + 1); - Scene::Area *pArea = g_SceneMan.GetScene()->GetArea(str); - // pArea = pArea ? pArea : g_SceneMan.GetScene()->GetArea("Landing Zone"); - // If area is defined, save a copy so we can lock the LZ selection to within its boxes - if (pArea && !pArea->HasNoArea()) - SetLZArea(team, *pArea); - } - - // If this is a CPU controlled team, then try to find a brain for them, or place one - if (team == m_CPUTeam && !m_pCPUBrain) - { -// TODO: Make special CPU brain actor which will only appear in CPU brain fights, and have to be placed in the scenes - m_pCPUBrain = g_MovableMan.GetUnassignedBrain(team); - m_pCPUBrain = m_pCPUBrain ? m_pCPUBrain : g_MovableMan.GetFirstBrainActor(team); // Try getting our assigned brain - if (!m_pCPUBrain) - { - // Couldn't find an available brain in the scene, so make one and place it - m_pCPUBrain = dynamic_cast(g_PresetMan.GetEntityPreset("Actor", "Brain Case")->Clone()); - if (m_pCPUBrain) - { - Vector brainPos; - // Place opposite of the other team's brain - Actor *pOtherBrain = g_MovableMan.GetFirstOtherBrainActor(team); - if (pOtherBrain) - { - brainPos = pOtherBrain->GetPos(); - brainPos.m_X += g_SceneMan.GetSceneWidth() / 2; - brainPos.m_Y = g_SceneMan.GetSceneHeight() - 200; - g_SceneMan.WrapPosition(brainPos); - } - // No brain found on other team... then just place somewhere in the ground, spaced out - else - { - if (team == Teams::TeamOne) - brainPos.SetXY((float)g_SceneMan.GetSceneWidth() * 0.25, (float)g_SceneMan.GetSceneHeight() * 0.75); - if (team == Teams::TeamTwo) - brainPos.SetXY((float)g_SceneMan.GetSceneWidth() * 0.75, (float)g_SceneMan.GetSceneHeight() * 0.75); - } - m_pCPUBrain->SetPos(brainPos); - m_pCPUBrain->SetTeam(team); - // Transfer ownership here - g_MovableMan.AddActor(m_pCPUBrain); - pOtherBrain = 0; - } - } - m_EnemyCount = g_MovableMan.GetTeamRoster(m_CPUTeam)->size(); - } - // Give the player some scratch - else - m_TeamFunds[team] = this->GetStartingGold(); - } - - /////////////////////////////////////// - // Set up players - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - // Expand all modules to show the goods - m_pBuyGUI[player]->SetModuleExpanded(0); - - // No need for the LZ to follow the brain, the scene-set one is enough - SetBrainLZWidth(player, 0); - - // If we can't find an unassigned brain in the scene to give each player, then force to go into editing mode to place one - if (!m_Brain[player]) - { - g_ConsoleMan.PrintString("ERROR: Can't find brain for tutorial game mode!"); - } - // Set the found brain to be the selected actor at start - else - { - m_TutorialPlayer = player; - } -/* - if (m_ActivityState == ActivityState::Editing) - g_FrameMan.SetScreenText((player % 2 == 0) ? "Place your brain vault and build your bunker around it..." : "...then select \"DONE\" from the pie menu!", ScreenOfPlayer(player), 0); - else if (m_ActivityState == ActivityState::Running) - g_FrameMan.SetScreenText((player % 2 == 0) ? "Mine Gold and buy more firepower with the funds..." : "...then smash the competing brain to claim victory!", ScreenOfPlayer(player), 0); -*/ - } - - - ///////////////////////////////////////////// - // SET UP TUTORIAL - - // COMMON SCREENS - std::vector apScreens = ContentFile("Missions.rte/Objects/Tutorial/ScreenStatic.png").GetAsAnimation(3); - m_apCommonScreens[SCREENOFF] = apScreens[0]; - m_apCommonScreens[STATICLITTLE] = apScreens[1]; - m_apCommonScreens[STATICLARGE] = apScreens[2]; - - // ROOM SIGNS - ContentFile signFile; - for (int room = 0; room < ROOMCOUNT; ++room) - { - if (room == ROOM0) - signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryA.png"); - else if (room == ROOM1) - signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryB.png"); - else if (room == ROOM2) - signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryC.png"); - else if (room == ROOM3) - signFile.SetDataPath("Missions.rte/Objects/Tutorial/TutEntryD.png"); - std::vector apSigns = signFile.GetAsAnimation(2); - m_aapRoomSigns[room][UNLIT] = apSigns[0]; - m_aapRoomSigns[room][LIT] = apSigns[1]; - } - - m_RoomSignPositions[ROOM0].SetXY(744, 695); - m_RoomSignPositions[ROOM1].SetXY(888, 695); - m_RoomSignPositions[ROOM2].SetXY(888, 599); - m_RoomSignPositions[ROOM3].SetXY(888, 431); - m_CurrentRoom = ROOM3; - - ////////////////////////////////// - // Setup all the Tutorial Areas and their text instructions etc - - SetupAreas(); - - // Disable all enemy AIs so they dont attack prematurely - DisableAIs(true, Teams::TeamTwo); - - ////////////////////////////////// - // FIGHT TRIGGERS - - m_FightTriggers[DEFENDING].Create(Vector(1330, 0), 770, 400); - -// m_FightTriggerEast.Create(Vector(526, 0), 52, 840); -// m_FightTriggerWest.Create(Vector(1336, 0), 52, 840); -/* - // Start special tutorial playlist - g_AudioMan.ClearMusicQueue(); - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/ccambient4.ogg", 0); - g_AudioMan.QueueSilence(30); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); - g_AudioMan.QueueSilence(30); - g_AudioMan.QueueMusicStream("Base.rte/Music/Watts/Last Man.ogg"); - g_AudioMan.QueueSilence(30); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); -*/ - return error; -} + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateEditing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: This is a special update step for when any player is still editing the + // scene. + void GATutorial::UpdateEditing() + { + GameActivity::UpdateEditing(); + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this GATutorial. Supposed to be done every frame + // before drawing. + + void GATutorial::Update() { + // Avoid game logic when we're editing + if (m_ActivityState == ActivityState::Editing) { + UpdateEditing(); + return; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + GameActivity::Update(); + + // Clear all objective markers, they get re-added each frame + ClearObjectivePoints(); + + /////////////////////////////////////////// + // Iterate through all human players + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + // The current player's team + int team = m_Team[player]; + if (team == Teams::NoTeam) + continue; + + // Make sure the game is not already ending + if (m_ActivityState != ActivityState::Over) { + // Check if any player's brain is dead + if (!g_MovableMan.IsActor(m_Brain[player])) { + m_Brain[player] = 0; + g_FrameMan.SetScreenText("Your brain has been destroyed!", ScreenOfPlayer(player), 333); + + // Now see if all brains are dead of this player's team, and if so, end the game + if (!g_MovableMan.GetFirstBrainActor(team)) { + m_WinnerTeam = OtherTeam(team); + End(); + } + + m_MessageTimer[player].Reset(); + } + // Mark the player brain to be protected when the fight happens + else if (m_CurrentFightStage >= DEFENDING) { + // Update the observation target to the brain, so that if/when it dies, the view flies to it in observation mode + // SetObservationTarget(m_Brain[player]->GetPos(), player); + // Mark the player's brain to be protected by his team + AddObjectivePoint("Protect!", m_Brain[player]->GetPos() + Vector(0, 10), team, GameActivity::ARROWUP); + // Mark the CPU brain for desctruction too + if (g_MovableMan.IsActor(m_pCPUBrain)) + AddObjectivePoint("Destroy!", m_pCPUBrain->GetPos() + Vector(0, 12), team, GameActivity::ARROWUP); + } + } + // Game over, show the appropriate messages until a certain time + else if (!m_GameOverTimer.IsPastSimMS(m_GameOverPeriod)) { + // TODO: make more appropriate messages here for run out of funds endings + if (m_Team[player] == m_WinnerTeam) + g_FrameMan.SetScreenText("You destroyed the dummy CPU!\nPress [SPACE] or [START] to continue", ScreenOfPlayer(player)); + else + g_FrameMan.SetScreenText("Your brain has been destroyed!", ScreenOfPlayer(player)); + } + } -void GATutorial::SetPaused(bool pause) -{ - GameActivity::SetPaused(pause); + /////////////////////////////////////////// + // Iterate through all teams + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + ///////////////////////////////////////// + // Attacking CPU team logic + /* + if (team == m_CPUTeam) + { + // Spawn the CPU team's attacking forces + if (m_SpawnTimer.IsPastSimMS(m_SpawnInterval) && m_ActivityState != ActivityState::Over) + { + if (!m_AttackerSpawns.empty()) + { + int whichSpawn = std::floor(m_AttackerSpawns.size() * RandomNum()); + Actor *pSpawn = dynamic_cast(m_AttackerSpawns[whichSpawn]->Clone()); + if (pSpawn) + { + Vector landingZone; + Actor *pEnemyBrain = g_MovableMan.GetFirstOtherBrainActor(team); + + // Don't land right on top of player team's base + if (pEnemyBrain) + { + // Get player team's base pos + landingZone = pEnemyBrain->GetPos(); + // Get the opposite side + landingZone.m_X += g_SceneMan.GetSceneWidth() / 2; + // Now give the zone width + landingZone.m_X += (g_SceneMan.GetSceneWidth() / 2) * 0.75 * NormalRand(); + // Wrap + g_SceneMan.WrapPosition(landingZone); + } + else + { + landingZone.m_X = g_SceneMan.GetSceneWidth() * RandomNum(); + } + Vector dropStart(landingZone.m_X, -50); + pSpawn->SetPos(dropStart); + pSpawn->SetTeam(team); + pSpawn->SetControllerMode(Controller::CIM_AI); + // Let the spawn into the world, passing ownership + g_MovableMan.AddActor(pSpawn); + pSpawn = 0; + } + } + m_SpawnTimer.Reset(); + } + } + */ + /////////////////////////////////////////// + // Check for victory conditions + + // Make sure the game is not already ending + if (m_ActivityState != ActivityState::Over && team != m_CPUTeam) { + // TODO: Gotto have budget restrictions in this activity! + /* + // Check for bankruptcy + // TODO Don't hardcode the rocket cost! + if (m_TeamFunds[team] < 0)//&& Only brain is left of actors) + { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) + { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + if (m_Team[player] == team) + g_FrameMan.SetScreenText("Your team can't afford any more transportation!", ScreenOfPlayer(player)); + else + { + g_FrameMan.SetScreenText("Your competition is bankrupt!", ScreenOfPlayer(player)); + m_WinnerTeam = m_Team[player]; + } + m_MessageTimer[player].Reset(); + } + End(); + } + */ + } + } - // Re-setup the ares with any updated control mappings that the player might have made in teh menu - if (!pause) - SetupAreas(); -} + /////////////////////////////////////////// + // TUTORIAL LOGIC + + // Detect the player going into new areas + if (m_ControlledActor[m_TutorialPlayer]) { + for (int area = 0; area < AREACOUNT; ++area) { + // Switch if within the trigger box of a new area + if (area != m_CurrentArea && m_TriggerBoxes[area].IsWithinBox(m_ControlledActor[m_TutorialPlayer]->GetPos())) { + // Change to the new area + m_PrevArea = m_CurrentArea; + m_CurrentArea = (TutorialArea)area; + m_CurrentStep = 0; + m_ScreenChange = true; + m_AreaTimer.Reset(); + m_StepTimer.Reset(); + } + } + /* + // Fight stage triggers + for (int stage = 0; stage < FIGHTSTAGECOUNT; ++stage) + { + + // Switch if within the trigger box of a new area + if (area != m_CurrentArea && m_TriggerBoxes[area].IsWithinBox(m_ControlledActor[m_TutorialPlayer]->GetPos())) + { + + if (m_FightTriggers[stage].Reset(); + } + */ + } + // Cycle through the steps of the current area + if (m_StepTimer.IsPastRealMS(m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration)) { + // Go to next step, looping around to the first if necessary + if (++m_CurrentStep == m_TutAreaSteps[m_CurrentArea].size()) + m_CurrentStep = 0; + m_ScreenChange = true; + // Start timing the new step + m_StepTimer.Reset(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. - -void GATutorial::End() -{ - GameActivity::End(); - - bool playerWon = false; - // Show appropriate end game messages - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - if (m_Team[player] == m_WinnerTeam) - { - playerWon = true; - // Set the winner's observation view to his controlled actors instead of his brain - if (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) - m_ObservationTarget[player] = m_ControlledActor[player]->GetPos(); - } - } - - // Temp fix so music doesn't start playing if ending the Activity when changing resolution through the in-game settings. - if (!m_Paused) { - // Play the appropriate tune on player win/lose - if (playerWon) { - g_AudioMan.ClearMusicQueue(); - // Loop it twice, nice tune! - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/uwinfinal.ogg", 2); - g_AudioMan.QueueSilence(10); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); - } else { - g_AudioMan.ClearMusicQueue(); - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/udiedfinal.ogg", 0); - g_AudioMan.QueueSilence(10); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); + // Only mess with animation if there are more than one frame for this step and the frameduration is set to something + int frameCount = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_pScreens.size(); + if (frameCount > 0 && m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_FrameDuration > 0) { + int newFrame = ((long)m_StepTimer.GetElapsedRealTimeMS() / m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_FrameDuration) % frameCount; + // Clamp the frame + newFrame = newFrame < 0 ? 0 : (newFrame >= frameCount ? frameCount - 1 : newFrame); + if (newFrame != m_CurrentFrame) { + m_CurrentFrame = newFrame; + m_ScreenChange = true; + } } - } -} -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateEditing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: This is a special update step for when any player is still editing the -// scene. + /* Draw this manually over the current screen in DrawGUI + // Take over control of screen messages + m_MessageTimer[m_TutorialPlayer].Reset(); + // Display the text of the current step + // g_FrameMan.ClearScreenText(); + g_FrameMan.SetScreenText(m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text, 0, 500, -1, true);//, m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration); + */ + // Draw the correct current screens + BITMAP* pScreen = 0; + + // Turn ON the screen of the CURRENT area, animating the static-y frames and drawing them to the scene + // Then show the current step image + if (m_ScreenStates[m_CurrentArea] != SHOWINGSTEP || m_ScreenChange) { + // Figure out if to draw static or the step screen + m_ScreenStates[m_CurrentArea] = m_AreaTimer.IsPastRealMS(200) ? SHOWINGSTEP : (m_AreaTimer.IsPastRealMS(100) ? STATICLARGE : STATICLITTLE); + + pScreen = 0; + // Showing step image or a static screen? + if (m_ScreenStates[m_CurrentArea] == SHOWINGSTEP) { + if (m_CurrentFrame < frameCount) + pScreen = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_pScreens[m_CurrentFrame]; + } else + pScreen = m_apCommonScreens[(int)(m_ScreenStates[m_CurrentArea])]; + + // Draw to the scene bg layer + if (pScreen) + blit(pScreen, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_ScreenPositions[m_CurrentArea].GetFloorIntX(), m_ScreenPositions[m_CurrentArea].GetFloorIntY(), pScreen->w, pScreen->h); + + m_ScreenChange = false; + } -void GATutorial::UpdateEditing() -{ - GameActivity::UpdateEditing(); -} -*/ + // Turn OFF the screen of all the other areas, animating the static-y frames and drawing them to the scene + for (int area = 0; area < AREACOUNT; ++area) { + pScreen = 0; + // Turn off all other areas + if (area != m_CurrentArea && m_ScreenStates[area] != SCREENOFF) { + m_ScreenStates[area] = m_AreaTimer.IsPastRealMS(200) ? SCREENOFF : (m_AreaTimer.IsPastRealMS(100) ? STATICLITTLE : STATICLARGE); + pScreen = m_apCommonScreens[(int)(m_ScreenStates[area])]; + if (pScreen) + blit(pScreen, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_ScreenPositions[area].GetFloorIntX(), m_ScreenPositions[area].GetFloorIntY(), pScreen->w, pScreen->h); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this GATutorial. Supposed to be done every frame -// before drawing. - -void GATutorial::Update() -{ - // Avoid game logic when we're editing - if (m_ActivityState == ActivityState::Editing) - { - UpdateEditing(); - return; - } - - GameActivity::Update(); - - // Clear all objective markers, they get re-added each frame - ClearObjectivePoints(); - - /////////////////////////////////////////// - // Iterate through all human players - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - // The current player's team - int team = m_Team[player]; - if (team == Teams::NoTeam) - continue; - - // Make sure the game is not already ending - if (m_ActivityState != ActivityState::Over) - { - // Check if any player's brain is dead - if (!g_MovableMan.IsActor(m_Brain[player])) - { - m_Brain[player] = 0; - g_FrameMan.SetScreenText("Your brain has been destroyed!", ScreenOfPlayer(player), 333); - - // Now see if all brains are dead of this player's team, and if so, end the game - if (!g_MovableMan.GetFirstBrainActor(team)) - { - m_WinnerTeam = OtherTeam(team); - End(); - } - - m_MessageTimer[player].Reset(); - } - // Mark the player brain to be protected when the fight happens - else if (m_CurrentFightStage >= DEFENDING) - { - // Update the observation target to the brain, so that if/when it dies, the view flies to it in observation mode -// SetObservationTarget(m_Brain[player]->GetPos(), player); - // Mark the player's brain to be protected by his team - AddObjectivePoint("Protect!", m_Brain[player]->GetPos() + Vector(0, 10), team, GameActivity::ARROWUP); - // Mark the CPU brain for desctruction too - if (g_MovableMan.IsActor(m_pCPUBrain)) - AddObjectivePoint("Destroy!", m_pCPUBrain->GetPos() + Vector(0, 12), team, GameActivity::ARROWUP); - } - } - // Game over, show the appropriate messages until a certain time - else if (!m_GameOverTimer.IsPastSimMS(m_GameOverPeriod)) - { -// TODO: make more appropriate messages here for run out of funds endings - if (m_Team[player] == m_WinnerTeam) - g_FrameMan.SetScreenText("You destroyed the dummy CPU!\nPress [SPACE] or [START] to continue", ScreenOfPlayer(player)); - else - g_FrameMan.SetScreenText("Your brain has been destroyed!", ScreenOfPlayer(player)); - } - } - - /////////////////////////////////////////// - // Iterate through all teams - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - ///////////////////////////////////////// - // Attacking CPU team logic -/* - if (team == m_CPUTeam) - { - // Spawn the CPU team's attacking forces - if (m_SpawnTimer.IsPastSimMS(m_SpawnInterval) && m_ActivityState != ActivityState::Over) - { - if (!m_AttackerSpawns.empty()) - { - int whichSpawn = std::floor(m_AttackerSpawns.size() * RandomNum()); - Actor *pSpawn = dynamic_cast(m_AttackerSpawns[whichSpawn]->Clone()); - if (pSpawn) - { - Vector landingZone; - Actor *pEnemyBrain = g_MovableMan.GetFirstOtherBrainActor(team); - - // Don't land right on top of player team's base - if (pEnemyBrain) - { - // Get player team's base pos - landingZone = pEnemyBrain->GetPos(); - // Get the opposite side - landingZone.m_X += g_SceneMan.GetSceneWidth() / 2; - // Now give the zone width - landingZone.m_X += (g_SceneMan.GetSceneWidth() / 2) * 0.75 * NormalRand(); - // Wrap - g_SceneMan.WrapPosition(landingZone); - } - else - { - landingZone.m_X = g_SceneMan.GetSceneWidth() * RandomNum(); - } - Vector dropStart(landingZone.m_X, -50); - pSpawn->SetPos(dropStart); - pSpawn->SetTeam(team); - pSpawn->SetControllerMode(Controller::CIM_AI); - // Let the spawn into the world, passing ownership - g_MovableMan.AddActor(pSpawn); - pSpawn = 0; - } - } - m_SpawnTimer.Reset(); - } - } -*/ - /////////////////////////////////////////// - // Check for victory conditions - - // Make sure the game is not already ending - if (m_ActivityState != ActivityState::Over && team != m_CPUTeam) - { -// TODO: Gotto have budget restrictions in this activity! -/* - // Check for bankruptcy -// TODO Don't hardcode the rocket cost! - if (m_TeamFunds[team] < 0)//&& Only brain is left of actors) - { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - if (m_Team[player] == team) - g_FrameMan.SetScreenText("Your team can't afford any more transportation!", ScreenOfPlayer(player)); - else - { - g_FrameMan.SetScreenText("Your competition is bankrupt!", ScreenOfPlayer(player)); - m_WinnerTeam = m_Team[player]; - } - m_MessageTimer[player].Reset(); - } - End(); - } -*/ - } - } - - /////////////////////////////////////////// - // TUTORIAL LOGIC - - // Detect the player going into new areas - if (m_ControlledActor[m_TutorialPlayer]) - { - for (int area = 0; area < AREACOUNT; ++area) - { - // Switch if within the trigger box of a new area - if (area != m_CurrentArea && m_TriggerBoxes[area].IsWithinBox(m_ControlledActor[m_TutorialPlayer]->GetPos())) - { - // Change to the new area - m_PrevArea = m_CurrentArea; - m_CurrentArea = (TutorialArea)area; - m_CurrentStep = 0; - m_ScreenChange = true; - m_AreaTimer.Reset(); - m_StepTimer.Reset(); - } - } -/* - // Fight stage triggers - for (int stage = 0; stage < FIGHTSTAGECOUNT; ++stage) - { - - // Switch if within the trigger box of a new area - if (area != m_CurrentArea && m_TriggerBoxes[area].IsWithinBox(m_ControlledActor[m_TutorialPlayer]->GetPos())) - { - - if (m_FightTriggers[stage].Reset(); - } -*/ - } - - // Cycle through the steps of the current area - if (m_StepTimer.IsPastRealMS(m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration)) - { - // Go to next step, looping around to the first if necessary - if (++m_CurrentStep == m_TutAreaSteps[m_CurrentArea].size()) - m_CurrentStep = 0; - m_ScreenChange = true; - // Start timing the new step - m_StepTimer.Reset(); - } - - // Only mess with animation if there are more than one frame for this step and the frameduration is set to something - int frameCount = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_pScreens.size(); - if (frameCount > 0 && m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_FrameDuration > 0) - { - int newFrame = ((long)m_StepTimer.GetElapsedRealTimeMS() / m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_FrameDuration) % frameCount; - // Clamp the frame - newFrame = newFrame < 0 ? 0 : (newFrame >= frameCount ? frameCount - 1 : newFrame); - if (newFrame != m_CurrentFrame) - { - m_CurrentFrame = newFrame; - m_ScreenChange = true; - } - } - -/* Draw this manually over the current screen in DrawGUI - // Take over control of screen messages - m_MessageTimer[m_TutorialPlayer].Reset(); - // Display the text of the current step -// g_FrameMan.ClearScreenText(); - g_FrameMan.SetScreenText(m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text, 0, 500, -1, true);//, m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration); -*/ - // Draw the correct current screens - BITMAP *pScreen = 0; - - // Turn ON the screen of the CURRENT area, animating the static-y frames and drawing them to the scene - // Then show the current step image - if (m_ScreenStates[m_CurrentArea] != SHOWINGSTEP || m_ScreenChange) - { - // Figure out if to draw static or the step screen - m_ScreenStates[m_CurrentArea] = m_AreaTimer.IsPastRealMS(200) ? SHOWINGSTEP : (m_AreaTimer.IsPastRealMS(100) ? STATICLARGE : STATICLITTLE); - - pScreen = 0; - // Showing step image or a static screen? - if (m_ScreenStates[m_CurrentArea] == SHOWINGSTEP) - { - if (m_CurrentFrame < frameCount) - pScreen = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_pScreens[m_CurrentFrame]; - } - else - pScreen = m_apCommonScreens[(int)(m_ScreenStates[m_CurrentArea])]; - - // Draw to the scene bg layer - if (pScreen) - blit(pScreen, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_ScreenPositions[m_CurrentArea].GetFloorIntX(), m_ScreenPositions[m_CurrentArea].GetFloorIntY(), pScreen->w, pScreen->h); - - m_ScreenChange = false; - } - - // Turn OFF the screen of all the other areas, animating the static-y frames and drawing them to the scene - for (int area = 0; area < AREACOUNT; ++area) - { - pScreen = 0; - // Turn off all other areas - if (area != m_CurrentArea && m_ScreenStates[area] != SCREENOFF) - { - m_ScreenStates[area] = m_AreaTimer.IsPastRealMS(200) ? SCREENOFF : (m_AreaTimer.IsPastRealMS(100) ? STATICLITTLE : STATICLARGE); - pScreen = m_apCommonScreens[(int)(m_ScreenStates[area])]; - if (pScreen) - blit(pScreen, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_ScreenPositions[area].GetFloorIntX(), m_ScreenPositions[area].GetFloorIntY(), pScreen->w, pScreen->h); - } - } - - //////////////////////// - // ROOM SIGNS - - // Translate current area to a room - TutorialRoom prevRoom = m_CurrentRoom; - if (m_CurrentArea == BRAINCHAMBER) - m_CurrentRoom = ROOM0; - else if (m_CurrentArea == BODYSTORAGE) - m_CurrentRoom = ROOM1; - else if (m_CurrentArea == OBSTACLECOURSE) - m_CurrentRoom = ROOM2; - else if (m_CurrentArea == FIRINGRANGE) - m_CurrentRoom = ROOM3; - - // Draw the correct currently lit or blinking signs - BITMAP *pSign = 0; - if (prevRoom != m_CurrentRoom) - { - pSign = m_aapRoomSigns[ROOM0][m_CurrentRoom >= ROOM0 ? LIT : UNLIT]; - blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM0].GetFloorIntX(), m_RoomSignPositions[ROOM0].GetFloorIntY(), pSign->w, pSign->h); - pSign = m_aapRoomSigns[ROOM1][m_CurrentRoom >= ROOM1 ? LIT : UNLIT]; - blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM1].GetFloorIntX(), m_RoomSignPositions[ROOM1].GetFloorIntY(), pSign->w, pSign->h); - pSign = m_aapRoomSigns[ROOM2][m_CurrentRoom >= ROOM2 ? LIT : UNLIT]; - blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM2].GetFloorIntX(), m_RoomSignPositions[ROOM2].GetFloorIntY(), pSign->w, pSign->h); - pSign = m_aapRoomSigns[ROOM3][m_CurrentRoom >= ROOM3 ? LIT : UNLIT]; - blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM3].GetFloorIntX(), m_RoomSignPositions[ROOM3].GetFloorIntY(), pSign->w, pSign->h); - } - // Blink the next room's sign - if (m_CurrentRoom < ROOM3) - { - pSign = m_aapRoomSigns[m_CurrentRoom + 1][m_AreaTimer.AlternateReal(200) ? LIT : UNLIT]; - blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[m_CurrentRoom + 1].GetFloorIntX(), m_RoomSignPositions[m_CurrentRoom + 1].GetFloorIntY(), pSign->w, pSign->h); - } - - //////////////////////// - // FIGHT LOGIC - - // Triggered defending stage - if (m_CurrentFightStage == NOFIGHT && ((m_ControlledActor[m_TutorialPlayer] && m_FightTriggers[DEFENDING].IsWithinBox(m_ControlledActor[m_TutorialPlayer]->GetPos())) || g_MovableMan.GetTeamRoster(m_CPUTeam)->size() < m_EnemyCount)) { - // Take over control of screen messages - m_MessageTimer[m_TutorialPlayer].Reset(); - // Display the text of the current step - g_FrameMan.ClearScreenText(ScreenOfPlayer(m_TutorialPlayer)); - g_FrameMan.SetScreenText("DEFEND YOUR BRAIN AGAINST THE INCOMING FORCES!", ScreenOfPlayer(m_TutorialPlayer), 500, 8000, true); - // This will make all the enemy team AI's go into brain hunt mode - GameActivity::InitAIs(); - DisableAIs(false, Teams::TeamTwo); - - // Advance the stage - m_CurrentFightStage = DEFENDING; - } - - /////////////////////////////////////////// - // Check for victory conditions - - // Check if the CPU brain is dead, if we're playing against the CPU - if (!g_MovableMan.IsActor(m_pCPUBrain) && m_ActivityState != ActivityState::Over) - { - m_pCPUBrain = 0; - // Proclaim player winner and end - m_WinnerTeam = Teams::TeamOne; - // Finito! - End(); - } - - // After a while of game over and we won, exit to the campaign menu automatically - if (m_ActivityState == ActivityState::Over && m_WinnerTeam == Teams::TeamOne) - { - if (m_GameOverTimer.IsPastSimMS(m_GameOverPeriod)) - { - g_FrameMan.ClearScreenText(ScreenOfPlayer(m_TutorialPlayer)); - g_FrameMan.SetScreenText("Press [SPACE] or [START] to continue!", ScreenOfPlayer(m_TutorialPlayer), 750); - } - - if (m_GameOverTimer.IsPastSimMS(54000) || g_UInputMan.AnyStartPress()) - { - g_ActivityMan.EndActivity(); - g_ActivityMan.SetInActivity(false); - } - } -} + //////////////////////// + // ROOM SIGNS + + // Translate current area to a room + TutorialRoom prevRoom = m_CurrentRoom; + if (m_CurrentArea == BRAINCHAMBER) + m_CurrentRoom = ROOM0; + else if (m_CurrentArea == BODYSTORAGE) + m_CurrentRoom = ROOM1; + else if (m_CurrentArea == OBSTACLECOURSE) + m_CurrentRoom = ROOM2; + else if (m_CurrentArea == FIRINGRANGE) + m_CurrentRoom = ROOM3; + + // Draw the correct currently lit or blinking signs + BITMAP* pSign = 0; + if (prevRoom != m_CurrentRoom) { + pSign = m_aapRoomSigns[ROOM0][m_CurrentRoom >= ROOM0 ? LIT : UNLIT]; + blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM0].GetFloorIntX(), m_RoomSignPositions[ROOM0].GetFloorIntY(), pSign->w, pSign->h); + pSign = m_aapRoomSigns[ROOM1][m_CurrentRoom >= ROOM1 ? LIT : UNLIT]; + blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM1].GetFloorIntX(), m_RoomSignPositions[ROOM1].GetFloorIntY(), pSign->w, pSign->h); + pSign = m_aapRoomSigns[ROOM2][m_CurrentRoom >= ROOM2 ? LIT : UNLIT]; + blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM2].GetFloorIntX(), m_RoomSignPositions[ROOM2].GetFloorIntY(), pSign->w, pSign->h); + pSign = m_aapRoomSigns[ROOM3][m_CurrentRoom >= ROOM3 ? LIT : UNLIT]; + blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[ROOM3].GetFloorIntX(), m_RoomSignPositions[ROOM3].GetFloorIntY(), pSign->w, pSign->h); + } + // Blink the next room's sign + if (m_CurrentRoom < ROOM3) { + pSign = m_aapRoomSigns[m_CurrentRoom + 1][m_AreaTimer.AlternateReal(200) ? LIT : UNLIT]; + blit(pSign, g_SceneMan.GetTerrain()->GetBGColorBitmap(), 0, 0, m_RoomSignPositions[m_CurrentRoom + 1].GetFloorIntX(), m_RoomSignPositions[m_CurrentRoom + 1].GetFloorIntY(), pSign->w, pSign->h); + } + //////////////////////// + // FIGHT LOGIC + + // Triggered defending stage + if (m_CurrentFightStage == NOFIGHT && ((m_ControlledActor[m_TutorialPlayer] && m_FightTriggers[DEFENDING].IsWithinBox(m_ControlledActor[m_TutorialPlayer]->GetPos())) || g_MovableMan.GetTeamRoster(m_CPUTeam)->size() < m_EnemyCount)) { + // Take over control of screen messages + m_MessageTimer[m_TutorialPlayer].Reset(); + // Display the text of the current step + g_FrameMan.ClearScreenText(ScreenOfPlayer(m_TutorialPlayer)); + g_FrameMan.SetScreenText("DEFEND YOUR BRAIN AGAINST THE INCOMING FORCES!", ScreenOfPlayer(m_TutorialPlayer), 500, 8000, true); + // This will make all the enemy team AI's go into brain hunt mode + GameActivity::InitAIs(); + DisableAIs(false, Teams::TeamTwo); + + // Advance the stage + m_CurrentFightStage = DEFENDING; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. - -void GATutorial::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - GameActivity::DrawGUI(pTargetBitmap, targetPos, which); - - if (IsRunning())// && (m_AreaTimer.AlternateReal(500) || m_AreaTimer.AlternateReal(250) || m_AreaTimer.AlternateReal(125))) - { - AllegroBitmap pBitmapInt(pTargetBitmap); - Vector screenTextPos = m_ScreenPositions[m_CurrentArea] + m_TextOffsets[m_CurrentArea] - targetPos; - // How long the revealing of the text period will be, clamped, and plus three for the last three dots added later - float revealPeriod = (m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text.size() + 3) * 30; - if (revealPeriod > m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration * 0.85) - revealPeriod = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration * 0.85; - // The normalized reveal control - float revealed = m_StepTimer.GetElapsedRealTimeMS() / revealPeriod; - if (revealed > 1.0) - revealed = 1.0; - std::string revealText = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text.substr(0, (m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text.size() + 3) * revealed); - // Dot blinking logic - if (revealed == 1.0) - { - int timePhase = (int)m_AreaTimer.GetElapsedRealTimeMS() % 1200; - revealText = revealText + (timePhase > 900 ? "..." : (timePhase > 600 ? ".. " : (timePhase > 300 ? ". " : " "))); - } - g_FrameMan.GetSmallFont()->DrawAligned(&pBitmapInt, screenTextPos.m_X, screenTextPos.m_Y, revealText.c_str(), GUIFont::Centre); - } -} + /////////////////////////////////////////// + // Check for victory conditions + + // Check if the CPU brain is dead, if we're playing against the CPU + if (!g_MovableMan.IsActor(m_pCPUBrain) && m_ActivityState != ActivityState::Over) { + m_pCPUBrain = 0; + // Proclaim player winner and end + m_WinnerTeam = Teams::TeamOne; + // Finito! + End(); + } + // After a while of game over and we won, exit to the campaign menu automatically + if (m_ActivityState == ActivityState::Over && m_WinnerTeam == Teams::TeamOne) { + if (m_GameOverTimer.IsPastSimMS(m_GameOverPeriod)) { + g_FrameMan.ClearScreenText(ScreenOfPlayer(m_TutorialPlayer)); + g_FrameMan.SetScreenText("Press [SPACE] or [START] to continue!", ScreenOfPlayer(m_TutorialPlayer), 750); + } + + if (m_GameOverTimer.IsPastSimMS(54000) || g_UInputMan.AnyStartPress()) { + g_ActivityMan.EndActivity(); + g_ActivityMan.SetInActivity(false); + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this GATutorial's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + + void GATutorial::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + GameActivity::DrawGUI(pTargetBitmap, targetPos, which); + + if (IsRunning()) // && (m_AreaTimer.AlternateReal(500) || m_AreaTimer.AlternateReal(250) || m_AreaTimer.AlternateReal(125))) + { + AllegroBitmap pBitmapInt(pTargetBitmap); + Vector screenTextPos = m_ScreenPositions[m_CurrentArea] + m_TextOffsets[m_CurrentArea] - targetPos; + // How long the revealing of the text period will be, clamped, and plus three for the last three dots added later + float revealPeriod = (m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text.size() + 3) * 30; + if (revealPeriod > m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration * 0.85) + revealPeriod = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Duration * 0.85; + // The normalized reveal control + float revealed = m_StepTimer.GetElapsedRealTimeMS() / revealPeriod; + if (revealed > 1.0) + revealed = 1.0; + std::string revealText = m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text.substr(0, (m_TutAreaSteps[m_CurrentArea][m_CurrentStep].m_Text.size() + 3) * revealed); + // Dot blinking logic + if (revealed == 1.0) { + int timePhase = (int)m_AreaTimer.GetElapsedRealTimeMS() % 1200; + revealText = revealText + (timePhase > 900 ? "..." : (timePhase > 600 ? ".. " : (timePhase > 300 ? ". " : " "))); + } + g_FrameMan.GetSmallFont()->DrawAligned(&pBitmapInt, screenTextPos.m_X, screenTextPos.m_Y, revealText.c_str(), GUIFont::Centre); + } + } -void GATutorial::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) -{ - GameActivity::Draw(pTargetBitmap, targetPos); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this GATutorial's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + void GATutorial::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + GameActivity::Draw(pTargetBitmap, targetPos); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: InitAIs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through all Actor:s currently in the MovableMan and gives each -// one not controlled by a Controller a CAI and appropriate AIMode setting -// based on team and CPU team. - -void GATutorial::InitAIs() -{ - Actor *pActor = 0; - Actor *pFirstActor = 0; - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - // Get the first one - pFirstActor = pActor = g_MovableMan.GetNextTeamActor(team); - - do - { - // Set up AI controller if currently not player controlled - if (pActor && !pActor->GetController()->IsPlayerControlled()) - { - pActor->SetControllerMode(Controller::CIM_AI); - - // If human, set appropriate AI mode - if (dynamic_cast(pActor) || dynamic_cast(pActor)) - { - // Sentry default - if (team == m_CPUTeam) - pActor->SetAIMode(AHuman::AIMODE_SENTRY); - else if (team >= 0) - pActor->SetAIMode(AHuman::AIMODE_SENTRY); - // Let the non team actors be (the wildlife) - else - ; - } - } - - // Next! - pActor = g_MovableMan.GetNextTeamActor(team, pActor); - } - while (pActor && pActor != pFirstActor); - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: InitAIs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through all Actor:s currently in the MovableMan and gives each + // one not controlled by a Controller a CAI and appropriate AIMode setting + // based on team and CPU team. + + void GATutorial::InitAIs() { + Actor* pActor = 0; + Actor* pFirstActor = 0; + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + // Get the first one + pFirstActor = pActor = g_MovableMan.GetNextTeamActor(team); + + do { + // Set up AI controller if currently not player controlled + if (pActor && !pActor->GetController()->IsPlayerControlled()) { + pActor->SetControllerMode(Controller::CIM_AI); + + // If human, set appropriate AI mode + if (dynamic_cast(pActor) || dynamic_cast(pActor)) { + // Sentry default + if (team == m_CPUTeam) + pActor->SetAIMode(AHuman::AIMODE_SENTRY); + else if (team >= 0) + pActor->SetAIMode(AHuman::AIMODE_SENTRY); + // Let the non team actors be (the wildlife) + else + ; + } + } + + // Next! + pActor = g_MovableMan.GetNextTeamActor(team, pActor); + } while (pActor && pActor != pFirstActor); + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetupAreas + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets up or resets the Tutorial Areas to show the current control + // mappings etc. + + void GATutorial::SetupAreas() { + int device = g_UInputMan.GetControlScheme(m_TutorialPlayer)->GetDevice(); + int preset = g_UInputMan.GetControlScheme(m_TutorialPlayer)->GetPreset(); + + // Adjust for special commands when using the keyboard-only setup + std::string JumpName = MAPNAME(INPUT_L_UP); + std::string CrouchName = MAPNAME(INPUT_L_DOWN); + if (device == DEVICE_KEYB_ONLY) { + JumpName = MAPNAME(INPUT_JUMP); + CrouchName = MAPNAME(INPUT_CROUCH); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetupAreas -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets up or resets the Tutorial Areas to show the current control -// mappings etc. - -void GATutorial::SetupAreas() -{ - int device = g_UInputMan.GetControlScheme(m_TutorialPlayer)->GetDevice(); - int preset = g_UInputMan.GetControlScheme(m_TutorialPlayer)->GetPreset(); - - // Adjust for special commands when using the keyboard-only setup - std::string JumpName = MAPNAME(INPUT_L_UP); - std::string CrouchName = MAPNAME(INPUT_L_DOWN); - if (device == DEVICE_KEYB_ONLY) - { - JumpName = MAPNAME(INPUT_JUMP); - CrouchName = MAPNAME(INPUT_CROUCH); - } - - // If no preset, adjust the pie menu and fire names when using the defaults on a gamepad.. otherwise it'll show up as an unhelpful "Joystick" - std::string PieName = MAPNAME(INPUT_PIEMENU_ANALOG); - if (PieName == "") - { - PieName = MAPNAME(INPUT_PIEMENU_DIGITAL); - } - - std::string FireName = MAPNAME(INPUT_FIRE); - if (device >= DEVICE_GAMEPAD_1 && preset == InputScheme::InputPreset::NoPreset) - { - PieName = "Pie Menu Trigger"; - FireName = "Fire Trigger"; - } - - // BRAINCHAMBER - // Set up the trigger area - m_TriggerBoxes[BRAINCHAMBER].SetCorner(Vector(631, 608)); - m_TriggerBoxes[BRAINCHAMBER].SetWidth(137); - m_TriggerBoxes[BRAINCHAMBER].SetHeight(155); - // Screen position - m_ScreenPositions[BRAINCHAMBER].SetXY(673, 688); - // Text offset from screen position - m_TextOffsets[BRAINCHAMBER].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); - // Set up the steps - m_TutAreaSteps[BRAINCHAMBER].clear(); - m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("Welcome to Cortex Command", 4000, "Missions.rte/Objects/Tutorial/CCLogo.png", 2)); - m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("Above is your disembodied brain", 4000, "Missions.rte/Objects/Tutorial/ArrowUp.png", 2)); - m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("With it, you can remotely control other bodies", 4000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); - m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("Switch to one now by using [" + MAPNAME(INPUT_PREV) + "] or [" + MAPNAME(INPUT_NEXT) + "]", 4000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); - m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("If you haven't set up your controls yet, hit [Esc] and do so", 8000, "Missions.rte/Objects/Tutorial/Joystick.png", 2)); - - // BODYSTORAGE - // Set up the trigger area - m_TriggerBoxes[BODYSTORAGE].SetCorner(Vector(911, 662)); - m_TriggerBoxes[BODYSTORAGE].SetWidth(397); - m_TriggerBoxes[BODYSTORAGE].SetHeight(98); - // Screen position - m_ScreenPositions[BODYSTORAGE].SetXY(961, 688); - // Text offset from screen position - m_TextOffsets[BODYSTORAGE].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); - // Set up the steps - m_TutAreaSteps[BODYSTORAGE].clear(); - m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Here are some dummy bodies for practice", 4000, "Missions.rte/Objects/Tutorial/BodyHop.png", 2)); - m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Quickly switch control between them left and right with [" + MAPNAME(INPUT_PREV) + "] and [" + MAPNAME(INPUT_NEXT) + "]", 6000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); - m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Or hold down either [" + MAPNAME(INPUT_PREV) + "] or [" + MAPNAME(INPUT_NEXT) + "] to get a selection cursor", 6000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); - m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Switch to the leftmost body and walk it out of the room with [" + MAPNAME(INPUT_L_LEFT) + "]", 8000, "Missions.rte/Objects/Tutorial/ArrowLeft.png", 2)); - - // SHAFT - // Set up the trigger area - m_TriggerBoxes[SHAFT].SetCorner(Vector(772, 385)); - m_TriggerBoxes[SHAFT].SetWidth(135); - m_TriggerBoxes[SHAFT].SetHeight(380); - // Screen position - m_ScreenPositions[SHAFT].SetXY(817, 688); - // Text offset from screen position - m_TextOffsets[SHAFT].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); - // Set up the steps - m_TutAreaSteps[SHAFT].clear(); - m_TutAreaSteps[SHAFT].push_back(TutStep("Use [" + JumpName + "] to activate jetpack", 4000, "Missions.rte/Objects/Tutorial/ArrowUp.png", 2)); - m_TutAreaSteps[SHAFT].push_back(TutStep("Fire jetpack in bursts for better control", 4000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); - m_TutAreaSteps[SHAFT].push_back(TutStep("Adjust the jet direction by aiming or looking", 4000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); - m_TutAreaSteps[SHAFT].push_back(TutStep("Jump height is affected by the body's total weight", 4000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); - m_TutAreaSteps[SHAFT].push_back(TutStep("So the more you carry, the less you can jump", 8000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); - - // OBSTACLECOURSE - // Set up the trigger area - m_TriggerBoxes[OBSTACLECOURSE].SetCorner(Vector(915, 492)); - m_TriggerBoxes[OBSTACLECOURSE].SetWidth(395); - m_TriggerBoxes[OBSTACLECOURSE].SetHeight(167); - // Screen position - m_ScreenPositions[OBSTACLECOURSE].SetXY(961, 592); - // Text offset from screen position - m_TextOffsets[OBSTACLECOURSE].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); - // Set up the steps - m_TutAreaSteps[OBSTACLECOURSE].clear(); - m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("Obstacle course", 2000, "Missions.rte/Objects/Tutorial/BodyHop.png", 2)); - m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("Climb obstacles by holding [" + MAPNAME(INPUT_L_RIGHT) + "]", 4000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); - m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("Even climb ladders by simply moving toward them", 8000, "Missions.rte/Objects/Tutorial/BodyClimb.png", 2)); - m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("You can also crouch and crawl with [" + CrouchName + "]", 6000, "Missions.rte/Objects/Tutorial/BodyCrawl.png", 2)); - m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("In tight spaces, you may need to angle your head down to get through", 8000, "Missions.rte/Objects/Tutorial/BodyCrawl.png", 2)); - - // FIRINGRANGE - // Set up the trigger area - m_TriggerBoxes[FIRINGRANGE].SetCorner(Vector(913, 394)); - m_TriggerBoxes[FIRINGRANGE].SetWidth(389); - m_TriggerBoxes[FIRINGRANGE].SetHeight(97); - // Screen position - m_ScreenPositions[FIRINGRANGE].SetXY(961, 424); - // Text offset from screen position - m_TextOffsets[FIRINGRANGE].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); - // Set up the steps - m_TutAreaSteps[FIRINGRANGE].clear(); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Firing range", 2000, "Missions.rte/Objects/Tutorial/FireTarget.png", 1)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Pick up the weapon by first standing over it", 4000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("And then hold down [" + PieName + "]", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 1, 500)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Point up to 'Pick Up'", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 2, 500)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Release [" + PieName + "] to complete the command", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 1)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("If you aim continuously toward your target", 4000, "Missions.rte/Objects/Tutorial/BodyAim.png", 3)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("It improves your accuracy and view distance", 4000, "Missions.rte/Objects/Tutorial/BodyAim.png", 3)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Use [" + FireName + "] to Fire!", 4000, "Missions.rte/Objects/Tutorial/BodyFire.png", 2)); - m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Reload manually with [" + PieName + "] + up", 8000, "Missions.rte/Objects/Tutorial/BodyFire.png", 2)); - - // ROOFTOP - // Set up the trigger area - m_TriggerBoxes[ROOFTOP].SetCorner(Vector(732, 176)); - m_TriggerBoxes[ROOFTOP].SetWidth(356); - m_TriggerBoxes[ROOFTOP].SetHeight(210); - // Screen position - m_ScreenPositions[ROOFTOP].SetXY(961, 316); - // Text offset from screen position - m_TextOffsets[ROOFTOP].SetXY(m_apCommonScreens[0]->w / 2, -16); - // Set up the steps - m_TutAreaSteps[ROOFTOP].clear(); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Pick up the digging tool", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 2, 500)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Use it on the dirt here", 8000, "Missions.rte/Objects/Tutorial/DigPile.png", 2, 750)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("If you dig up gold, it is added to your team's funds", 4000, "Missions.rte/Objects/Tutorial/Funds.png", 2, 250)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Funds can be spent in the Buy Menu", 4000, "Missions.rte/Objects/Tutorial/Funds.png", 1, 333)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Which is opened through the Command Menu", 4000, "Missions.rte/Objects/Tutorial/MenuBuyMenu.png", 1, 500)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Hold [" + PieName + "] and point up and left to 'Buy Menu'", 6000, "Missions.rte/Objects/Tutorial/MenuBuyMenu.png", 2, 500)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("The Buy Menu works like a shopping cart", 6000, "Missions.rte/Objects/Tutorial/BuyMenuCargo.png", 1, 500)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Add to the Cargo list the items you want delivered", 6000, "Missions.rte/Objects/Tutorial/BuyMenuCargo.png", 2, 500)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Then use the BUY button, or click outside the menu", 4000, "Missions.rte/Objects/Tutorial/BuyMenuBuy.png", 2, 500)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Finally select a flat area where you want the goods delivered", 8000, "Missions.rte/Objects/Tutorial/BuyMenuBuy.png", 1, 500)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Next, you can go explore to the west to try flying and climbing in the wild", 6000, "Missions.rte/Objects/Tutorial/ArrowLeft.png", 2)); - m_TutAreaSteps[ROOFTOP].push_back(TutStep("Or, go to the east to learn about squads!", 8000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); - - // ROOFEAST - // Set up the trigger area - m_TriggerBoxes[ROOFEAST].SetCorner(Vector(1100, 176)); - m_TriggerBoxes[ROOFEAST].SetWidth(200); - m_TriggerBoxes[ROOFEAST].SetHeight(210); - // Screen position - m_ScreenPositions[ROOFEAST].SetXY(1201, 316); - // Text offset from screen position - m_TextOffsets[ROOFEAST].SetXY(m_apCommonScreens[0]->w / 2, -16); - // Set up the steps - m_TutAreaSteps[ROOFEAST].clear(); - m_TutAreaSteps[ROOFEAST].push_back(TutStep("Hold [" + PieName + "] and point down and right to 'Form Squad'", 4000, "Missions.rte/Objects/Tutorial/MenuTeam.png", 2, 500)); - m_TutAreaSteps[ROOFEAST].push_back(TutStep("Adjust selection circle to select nearby bodies", 4000, "Missions.rte/Objects/Tutorial/TeamSelect.png", 4, 500)); - m_TutAreaSteps[ROOFEAST].push_back(TutStep("All selected units will follow you, and engage on their own", 4000, "Missions.rte/Objects/Tutorial/TeamFollow.png", 2, 500)); - m_TutAreaSteps[ROOFEAST].push_back(TutStep("Units with similar weapons will fire in unison with the leader", 4000, "Missions.rte/Objects/Tutorial/TeamFollow.png", 2, 500)); - m_TutAreaSteps[ROOFEAST].push_back(TutStep("Hold [" + PieName + "] and point down and right again to disband squad", 4000, "Missions.rte/Objects/Tutorial/MenuTeam.png", 2, 500)); - m_TutAreaSteps[ROOFEAST].push_back(TutStep("Next, you can head east for a TRIAL BATTLE!", 8000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); - - m_AreaTimer.Reset(); - m_StepTimer.Reset(); -} + // If no preset, adjust the pie menu and fire names when using the defaults on a gamepad.. otherwise it'll show up as an unhelpful "Joystick" + std::string PieName = MAPNAME(INPUT_PIEMENU_ANALOG); + if (PieName == "") { + PieName = MAPNAME(INPUT_PIEMENU_DIGITAL); + } + + std::string FireName = MAPNAME(INPUT_FIRE); + if (device >= DEVICE_GAMEPAD_1 && preset == InputScheme::InputPreset::NoPreset) { + PieName = "Pie Menu Trigger"; + FireName = "Fire Trigger"; + } + + // BRAINCHAMBER + // Set up the trigger area + m_TriggerBoxes[BRAINCHAMBER].SetCorner(Vector(631, 608)); + m_TriggerBoxes[BRAINCHAMBER].SetWidth(137); + m_TriggerBoxes[BRAINCHAMBER].SetHeight(155); + // Screen position + m_ScreenPositions[BRAINCHAMBER].SetXY(673, 688); + // Text offset from screen position + m_TextOffsets[BRAINCHAMBER].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); + // Set up the steps + m_TutAreaSteps[BRAINCHAMBER].clear(); + m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("Welcome to Cortex Command", 4000, "Missions.rte/Objects/Tutorial/CCLogo.png", 2)); + m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("Above is your disembodied brain", 4000, "Missions.rte/Objects/Tutorial/ArrowUp.png", 2)); + m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("With it, you can remotely control other bodies", 4000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); + m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("Switch to one now by using [" + MAPNAME(INPUT_PREV) + "] or [" + MAPNAME(INPUT_NEXT) + "]", 4000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); + m_TutAreaSteps[BRAINCHAMBER].push_back(TutStep("If you haven't set up your controls yet, hit [Esc] and do so", 8000, "Missions.rte/Objects/Tutorial/Joystick.png", 2)); + + // BODYSTORAGE + // Set up the trigger area + m_TriggerBoxes[BODYSTORAGE].SetCorner(Vector(911, 662)); + m_TriggerBoxes[BODYSTORAGE].SetWidth(397); + m_TriggerBoxes[BODYSTORAGE].SetHeight(98); + // Screen position + m_ScreenPositions[BODYSTORAGE].SetXY(961, 688); + // Text offset from screen position + m_TextOffsets[BODYSTORAGE].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); + // Set up the steps + m_TutAreaSteps[BODYSTORAGE].clear(); + m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Here are some dummy bodies for practice", 4000, "Missions.rte/Objects/Tutorial/BodyHop.png", 2)); + m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Quickly switch control between them left and right with [" + MAPNAME(INPUT_PREV) + "] and [" + MAPNAME(INPUT_NEXT) + "]", 6000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); + m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Or hold down either [" + MAPNAME(INPUT_PREV) + "] or [" + MAPNAME(INPUT_NEXT) + "] to get a selection cursor", 6000, "Missions.rte/Objects/Tutorial/BodyZap.png", 2)); + m_TutAreaSteps[BODYSTORAGE].push_back(TutStep("Switch to the leftmost body and walk it out of the room with [" + MAPNAME(INPUT_L_LEFT) + "]", 8000, "Missions.rte/Objects/Tutorial/ArrowLeft.png", 2)); + + // SHAFT + // Set up the trigger area + m_TriggerBoxes[SHAFT].SetCorner(Vector(772, 385)); + m_TriggerBoxes[SHAFT].SetWidth(135); + m_TriggerBoxes[SHAFT].SetHeight(380); + // Screen position + m_ScreenPositions[SHAFT].SetXY(817, 688); + // Text offset from screen position + m_TextOffsets[SHAFT].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); + // Set up the steps + m_TutAreaSteps[SHAFT].clear(); + m_TutAreaSteps[SHAFT].push_back(TutStep("Use [" + JumpName + "] to activate jetpack", 4000, "Missions.rte/Objects/Tutorial/ArrowUp.png", 2)); + m_TutAreaSteps[SHAFT].push_back(TutStep("Fire jetpack in bursts for better control", 4000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); + m_TutAreaSteps[SHAFT].push_back(TutStep("Adjust the jet direction by aiming or looking", 4000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); + m_TutAreaSteps[SHAFT].push_back(TutStep("Jump height is affected by the body's total weight", 4000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); + m_TutAreaSteps[SHAFT].push_back(TutStep("So the more you carry, the less you can jump", 8000, "Missions.rte/Objects/Tutorial/BodyJetpack.png", 2)); + + // OBSTACLECOURSE + // Set up the trigger area + m_TriggerBoxes[OBSTACLECOURSE].SetCorner(Vector(915, 492)); + m_TriggerBoxes[OBSTACLECOURSE].SetWidth(395); + m_TriggerBoxes[OBSTACLECOURSE].SetHeight(167); + // Screen position + m_ScreenPositions[OBSTACLECOURSE].SetXY(961, 592); + // Text offset from screen position + m_TextOffsets[OBSTACLECOURSE].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); + // Set up the steps + m_TutAreaSteps[OBSTACLECOURSE].clear(); + m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("Obstacle course", 2000, "Missions.rte/Objects/Tutorial/BodyHop.png", 2)); + m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("Climb obstacles by holding [" + MAPNAME(INPUT_L_RIGHT) + "]", 4000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); + m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("Even climb ladders by simply moving toward them", 8000, "Missions.rte/Objects/Tutorial/BodyClimb.png", 2)); + m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("You can also crouch and crawl with [" + CrouchName + "]", 6000, "Missions.rte/Objects/Tutorial/BodyCrawl.png", 2)); + m_TutAreaSteps[OBSTACLECOURSE].push_back(TutStep("In tight spaces, you may need to angle your head down to get through", 8000, "Missions.rte/Objects/Tutorial/BodyCrawl.png", 2)); + + // FIRINGRANGE + // Set up the trigger area + m_TriggerBoxes[FIRINGRANGE].SetCorner(Vector(913, 394)); + m_TriggerBoxes[FIRINGRANGE].SetWidth(389); + m_TriggerBoxes[FIRINGRANGE].SetHeight(97); + // Screen position + m_ScreenPositions[FIRINGRANGE].SetXY(961, 424); + // Text offset from screen position + m_TextOffsets[FIRINGRANGE].SetXY(m_apCommonScreens[0]->w / 2, m_apCommonScreens[0]->h + 4); + // Set up the steps + m_TutAreaSteps[FIRINGRANGE].clear(); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Firing range", 2000, "Missions.rte/Objects/Tutorial/FireTarget.png", 1)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Pick up the weapon by first standing over it", 4000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("And then hold down [" + PieName + "]", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 1, 500)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Point up to 'Pick Up'", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 2, 500)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Release [" + PieName + "] to complete the command", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 1)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("If you aim continuously toward your target", 4000, "Missions.rte/Objects/Tutorial/BodyAim.png", 3)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("It improves your accuracy and view distance", 4000, "Missions.rte/Objects/Tutorial/BodyAim.png", 3)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Use [" + FireName + "] to Fire!", 4000, "Missions.rte/Objects/Tutorial/BodyFire.png", 2)); + m_TutAreaSteps[FIRINGRANGE].push_back(TutStep("Reload manually with [" + PieName + "] + up", 8000, "Missions.rte/Objects/Tutorial/BodyFire.png", 2)); + + // ROOFTOP + // Set up the trigger area + m_TriggerBoxes[ROOFTOP].SetCorner(Vector(732, 176)); + m_TriggerBoxes[ROOFTOP].SetWidth(356); + m_TriggerBoxes[ROOFTOP].SetHeight(210); + // Screen position + m_ScreenPositions[ROOFTOP].SetXY(961, 316); + // Text offset from screen position + m_TextOffsets[ROOFTOP].SetXY(m_apCommonScreens[0]->w / 2, -16); + // Set up the steps + m_TutAreaSteps[ROOFTOP].clear(); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Pick up the digging tool", 4000, "Missions.rte/Objects/Tutorial/MenuPickUp.png", 2, 500)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Use it on the dirt here", 8000, "Missions.rte/Objects/Tutorial/DigPile.png", 2, 750)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("If you dig up gold, it is added to your team's funds", 4000, "Missions.rte/Objects/Tutorial/Funds.png", 2, 250)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Funds can be spent in the Buy Menu", 4000, "Missions.rte/Objects/Tutorial/Funds.png", 1, 333)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Which is opened through the Command Menu", 4000, "Missions.rte/Objects/Tutorial/MenuBuyMenu.png", 1, 500)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Hold [" + PieName + "] and point up and left to 'Buy Menu'", 6000, "Missions.rte/Objects/Tutorial/MenuBuyMenu.png", 2, 500)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("The Buy Menu works like a shopping cart", 6000, "Missions.rte/Objects/Tutorial/BuyMenuCargo.png", 1, 500)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Add to the Cargo list the items you want delivered", 6000, "Missions.rte/Objects/Tutorial/BuyMenuCargo.png", 2, 500)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Then use the BUY button, or click outside the menu", 4000, "Missions.rte/Objects/Tutorial/BuyMenuBuy.png", 2, 500)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Finally select a flat area where you want the goods delivered", 8000, "Missions.rte/Objects/Tutorial/BuyMenuBuy.png", 1, 500)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Next, you can go explore to the west to try flying and climbing in the wild", 6000, "Missions.rte/Objects/Tutorial/ArrowLeft.png", 2)); + m_TutAreaSteps[ROOFTOP].push_back(TutStep("Or, go to the east to learn about squads!", 8000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); + + // ROOFEAST + // Set up the trigger area + m_TriggerBoxes[ROOFEAST].SetCorner(Vector(1100, 176)); + m_TriggerBoxes[ROOFEAST].SetWidth(200); + m_TriggerBoxes[ROOFEAST].SetHeight(210); + // Screen position + m_ScreenPositions[ROOFEAST].SetXY(1201, 316); + // Text offset from screen position + m_TextOffsets[ROOFEAST].SetXY(m_apCommonScreens[0]->w / 2, -16); + // Set up the steps + m_TutAreaSteps[ROOFEAST].clear(); + m_TutAreaSteps[ROOFEAST].push_back(TutStep("Hold [" + PieName + "] and point down and right to 'Form Squad'", 4000, "Missions.rte/Objects/Tutorial/MenuTeam.png", 2, 500)); + m_TutAreaSteps[ROOFEAST].push_back(TutStep("Adjust selection circle to select nearby bodies", 4000, "Missions.rte/Objects/Tutorial/TeamSelect.png", 4, 500)); + m_TutAreaSteps[ROOFEAST].push_back(TutStep("All selected units will follow you, and engage on their own", 4000, "Missions.rte/Objects/Tutorial/TeamFollow.png", 2, 500)); + m_TutAreaSteps[ROOFEAST].push_back(TutStep("Units with similar weapons will fire in unison with the leader", 4000, "Missions.rte/Objects/Tutorial/TeamFollow.png", 2, 500)); + m_TutAreaSteps[ROOFEAST].push_back(TutStep("Hold [" + PieName + "] and point down and right again to disband squad", 4000, "Missions.rte/Objects/Tutorial/MenuTeam.png", 2, 500)); + m_TutAreaSteps[ROOFEAST].push_back(TutStep("Next, you can head east for a TRIAL BATTLE!", 8000, "Missions.rte/Objects/Tutorial/ArrowRight.png", 2)); + + m_AreaTimer.Reset(); + m_StepTimer.Reset(); + } } // namespace RTE diff --git a/Source/Activities/GATutorial.h b/Source/Activities/GATutorial.h index a24197943..f5379470a 100644 --- a/Source/Activities/GATutorial.h +++ b/Source/Activities/GATutorial.h @@ -10,334 +10,305 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "GameActivity.h" #include "Box.h" -namespace RTE -{ - -class Actor; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: GATutorial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tutorial mission with lots of special triggering logic. -// Parent(s): GameActivity. -// Class history: 10/13/2007 GATutorial created. - -class GATutorial : public GameActivity { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(GATutorial); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GATutorial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GATutorial object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - GATutorial() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~GATutorial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a GATutorial object before deletion -// from system memory. -// Arguments: None. - - ~GATutorial() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GATutorial object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GATutorial to be identical to another, by deep copy. -// Arguments: A reference to the GATutorial to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const GATutorial &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire GATutorial, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Activity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GATutorial object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SceneIsCompatible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells if a particular Scene supports this specific Activity on it. -// Usually that means certain Area:s need to be defined in the Scene. -// Arguments: The Scene to check if it supports this Activiy. Ownership IS NOT TRANSFERRED! -// How many teams we're checking for. Some scenes may support and activity -// but only for a limited number of teams. If -1, not applicable. -// Return value: Whether the Scene has the right stuff. - - bool SceneIsCompatible(Scene *pScene, int teams = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: InitAIs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through all Actor:s currently in the MovableMan and sets each -// one not controlled by a player to be AI controlled and AIMode setting -// based on team and CPU team. -// Arguments: None. -// Return value: None. - - void InitAIs() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetupAreas -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets up or resets the Tutorial Areas to show the current control -// mappings etc. -// Arguments: None. -// Return value: None. - - void SetupAreas(); - - - enum TutorialArea - { - BRAINCHAMBER = 0, - BODYSTORAGE, - SHAFT, - OBSTACLECOURSE, - FIRINGRANGE, - ROOFTOP, - ROOFEAST, - AREACOUNT - }; - - enum TutorialRoom - { - ROOM0 = 0, - ROOM1, - ROOM2, - ROOM3, - ROOMCOUNT - }; - - enum LitState - { - UNLIT = 0, - LIT, - LITSTATECOUNT - }; - - enum ScreenState - { - SCREENOFF = 0, - STATICLITTLE, - STATICLARGE, - SHOWINGSTEP, - SREENSTATECOUNT - }; - - enum FightStage - { - NOFIGHT = 0, - DEFENDING, - ATTACK, - FIGHTSTAGECOUNT - }; - - struct TutStep - { - // Text of this step - std::string m_Text; - // Duration of the whole step - int m_Duration; - // BITMAPs not owned here - std::vector m_pScreens; - // The duration of one frame - int m_FrameDuration; - - TutStep(std::string text, int stepDuration, std::string screensPath = "", int frameCount = 1, int frameDuration = 250); - }; - - // Member variables - static Entity::ClassInfo m_sClass; - - // The player which is actually playing the tut - int m_TutorialPlayer; - // The areas that trigger specific sets of steps to be shown - Box m_TriggerBoxes[AREACOUNT]; - // Positions of the screens for each area - Vector m_ScreenPositions[AREACOUNT]; - // The current state of the all the different areas' screens - ScreenState m_ScreenStates[AREACOUNT]; - // Offsets of the center of the text line from the screen position - Vector m_TextOffsets[AREACOUNT]; - // Screen bitmaps common to all areas.. off, static etc - BITMAP *m_apCommonScreens[STATICLARGE + 1]; - // The steps themselves; cycles through for each area - std::vector m_TutAreaSteps[AREACOUNT]; - // Positions of the numbered room signs - Vector m_RoomSignPositions[ROOMCOUNT]; - // Room sign bitmaps, unlit and lit - BITMAP *m_aapRoomSigns[ROOMCOUNT][LITSTATECOUNT]; - // The timer which keeps track of how long each area has been showing - Timer m_AreaTimer; - // The timer which keeps track of how long each step should be shown - Timer m_StepTimer; - // Which are the player-controlled actor is within - TutorialArea m_CurrentArea; - // Which are the player-controlled actor was in last - TutorialArea m_PrevArea; - // If teh screen has just changed and needs to be redrawn - bool m_ScreenChange; - // Which tutorial step of the current area currently being played back - int m_CurrentStep; - // Which frame of the current step's animation are we on? - int m_CurrentFrame; - // Current room - TutorialRoom m_CurrentRoom; - // Trigger box for the subsequent fight - Box m_FightTriggers[FIGHTSTAGECOUNT]; - int m_EnemyCount; //!< The amount of enemy actors at the start of the activity. - // The current fight stage - FightStage m_CurrentFightStage; - // The CPU opponent brain; not owned! - Actor *m_pCPUBrain; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class Actor; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: GATutorial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tutorial mission with lots of special triggering logic. + // Parent(s): GameActivity. + // Class history: 10/13/2007 GATutorial created. + + class GATutorial : public GameActivity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(GATutorial); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GATutorial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GATutorial object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + GATutorial() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~GATutorial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a GATutorial object before deletion + // from system memory. + // Arguments: None. + + ~GATutorial() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GATutorial object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GATutorial to be identical to another, by deep copy. + // Arguments: A reference to the GATutorial to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const GATutorial& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire GATutorial, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Activity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GATutorial object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SceneIsCompatible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells if a particular Scene supports this specific Activity on it. + // Usually that means certain Area:s need to be defined in the Scene. + // Arguments: The Scene to check if it supports this Activiy. Ownership IS NOT TRANSFERRED! + // How many teams we're checking for. Some scenes may support and activity + // but only for a limited number of teams. If -1, not applicable. + // Return value: Whether the Scene has the right stuff. + + bool SceneIsCompatible(Scene* pScene, int teams = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: InitAIs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through all Actor:s currently in the MovableMan and sets each + // one not controlled by a player to be AI controlled and AIMode setting + // based on team and CPU team. + // Arguments: None. + // Return value: None. + + void InitAIs() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetupAreas + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets up or resets the Tutorial Areas to show the current control + // mappings etc. + // Arguments: None. + // Return value: None. + + void SetupAreas(); + + enum TutorialArea { + BRAINCHAMBER = 0, + BODYSTORAGE, + SHAFT, + OBSTACLECOURSE, + FIRINGRANGE, + ROOFTOP, + ROOFEAST, + AREACOUNT + }; + + enum TutorialRoom { + ROOM0 = 0, + ROOM1, + ROOM2, + ROOM3, + ROOMCOUNT + }; + + enum LitState { + UNLIT = 0, + LIT, + LITSTATECOUNT + }; + + enum ScreenState { + SCREENOFF = 0, + STATICLITTLE, + STATICLARGE, + SHOWINGSTEP, + SREENSTATECOUNT + }; + + enum FightStage { + NOFIGHT = 0, + DEFENDING, + ATTACK, + FIGHTSTAGECOUNT + }; + + struct TutStep { + // Text of this step + std::string m_Text; + // Duration of the whole step + int m_Duration; + // BITMAPs not owned here + std::vector m_pScreens; + // The duration of one frame + int m_FrameDuration; + + TutStep(std::string text, int stepDuration, std::string screensPath = "", int frameCount = 1, int frameDuration = 250); + }; + + // Member variables + static Entity::ClassInfo m_sClass; + + // The player which is actually playing the tut + int m_TutorialPlayer; + // The areas that trigger specific sets of steps to be shown + Box m_TriggerBoxes[AREACOUNT]; + // Positions of the screens for each area + Vector m_ScreenPositions[AREACOUNT]; + // The current state of the all the different areas' screens + ScreenState m_ScreenStates[AREACOUNT]; + // Offsets of the center of the text line from the screen position + Vector m_TextOffsets[AREACOUNT]; + // Screen bitmaps common to all areas.. off, static etc + BITMAP* m_apCommonScreens[STATICLARGE + 1]; + // The steps themselves; cycles through for each area + std::vector m_TutAreaSteps[AREACOUNT]; + // Positions of the numbered room signs + Vector m_RoomSignPositions[ROOMCOUNT]; + // Room sign bitmaps, unlit and lit + BITMAP* m_aapRoomSigns[ROOMCOUNT][LITSTATECOUNT]; + // The timer which keeps track of how long each area has been showing + Timer m_AreaTimer; + // The timer which keeps track of how long each step should be shown + Timer m_StepTimer; + // Which are the player-controlled actor is within + TutorialArea m_CurrentArea; + // Which are the player-controlled actor was in last + TutorialArea m_PrevArea; + // If teh screen has just changed and needs to be redrawn + bool m_ScreenChange; + // Which tutorial step of the current area currently being played back + int m_CurrentStep; + // Which frame of the current step's animation are we on? + int m_CurrentFrame; + // Current room + TutorialRoom m_CurrentRoom; + // Trigger box for the subsequent fight + Box m_FightTriggers[FIGHTSTAGECOUNT]; + int m_EnemyCount; //!< The amount of enemy actors at the start of the activity. + // The current fight stage + FightStage m_CurrentFightStage; + // The CPU opponent brain; not owned! + Actor* m_pCPUBrain; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/GameActivity.cpp b/Source/Activities/GameActivity.cpp index 78402d756..8b60ff6de 100644 --- a/Source/Activities/GameActivity.cpp +++ b/Source/Activities/GameActivity.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -48,296 +47,274 @@ namespace RTE { -AbstractClassInfo(GameActivity, Activity); - + AbstractClassInfo(GameActivity, Activity); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this GameActivity, effectively + // resetting the members of this abstraction level only. + + void GameActivity::Clear() { + m_CPUTeam = -1; + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + m_ObservationTarget[player].Reset(); + m_DeathViewTarget[player].Reset(); + m_ActorSelectTimer[player].Reset(); + m_ActorCursor[player].Reset(); + m_pLastMarkedActor[player] = 0; + m_LandingZone[player].Reset(); + m_AIReturnCraft[player] = true; + m_StrategicModePieMenu.at(player) = nullptr; + m_LZCursorWidth[player] = 0; + m_InventoryMenuGUI[player] = nullptr; + m_pBuyGUI[player] = 0; + m_pEditorGUI[player] = 0; + m_LuaLockActor[player] = false; + m_LuaLockActorMode[player] = Controller::InputMode::CIM_AI; + m_pBannerRed[player] = 0; + m_pBannerYellow[player] = 0; + m_BannerRepeats[player] = 0; + m_ReadyToStart[player] = false; + m_PurchaseOverride[player].clear(); + m_BrainLZWidth[player] = BRAINLZWIDTHDEFAULT; + m_TeamTech[player] = ""; + m_NetworkPlayerNames[player] = ""; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this GameActivity, effectively -// resetting the members of this abstraction level only. - -void GameActivity::Clear() -{ - m_CPUTeam = -1; - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - m_ObservationTarget[player].Reset(); - m_DeathViewTarget[player].Reset(); - m_ActorSelectTimer[player].Reset(); - m_ActorCursor[player].Reset(); - m_pLastMarkedActor[player] = 0; - m_LandingZone[player].Reset(); - m_AIReturnCraft[player] = true; - m_StrategicModePieMenu.at(player) = nullptr; - m_LZCursorWidth[player] = 0; - m_InventoryMenuGUI[player] = nullptr; - m_pBuyGUI[player] = 0; - m_pEditorGUI[player] = 0; - m_LuaLockActor[player] = false; - m_LuaLockActorMode[player] = Controller::InputMode::CIM_AI; - m_pBannerRed[player] = 0; - m_pBannerYellow[player] = 0; - m_BannerRepeats[player] = 0; - m_ReadyToStart[player] = false; - m_PurchaseOverride[player].clear(); - m_BrainLZWidth[player] = BRAINLZWIDTHDEFAULT; - m_TeamTech[player] = ""; - m_NetworkPlayerNames[player] = ""; - } - - m_StartingGold = 0; - m_FogOfWarEnabled = false; - m_RequireClearPathToOrbit = false; - - m_DefaultFogOfWar = -1; - m_DefaultRequireClearPathToOrbit = -1; - m_DefaultDeployUnits = 1; - m_DefaultGoldCakeDifficulty = -1; - m_DefaultGoldEasyDifficulty = -1; - m_DefaultGoldMediumDifficulty = -1; - m_DefaultGoldHardDifficulty = -1; - m_DefaultGoldNutsDifficulty = -1; - m_DefaultGoldMaxDifficulty = -1; - m_FogOfWarSwitchEnabled = true; - m_DeployUnitsSwitchEnabled = false; - m_GoldSwitchEnabled = true; - m_RequireClearPathToOrbitSwitchEnabled = true; - m_BuyMenuEnabled = true; - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - m_Deliveries[team].clear(); - m_LandingZoneArea[team].Reset(); - m_aLZCursor[team].clear(); - m_aObjCursor[team].clear(); - } - - m_Objectives.clear(); - - m_DeliveryDelay = 4500; - m_CursorTimer.Reset(); - m_GameTimer.Reset(); - m_GameOverTimer.Reset(); - m_GameOverPeriod = 5000; - m_WinnerTeam = -1; -} + m_StartingGold = 0; + m_FogOfWarEnabled = false; + m_RequireClearPathToOrbit = false; + + m_DefaultFogOfWar = -1; + m_DefaultRequireClearPathToOrbit = -1; + m_DefaultDeployUnits = 1; + m_DefaultGoldCakeDifficulty = -1; + m_DefaultGoldEasyDifficulty = -1; + m_DefaultGoldMediumDifficulty = -1; + m_DefaultGoldHardDifficulty = -1; + m_DefaultGoldNutsDifficulty = -1; + m_DefaultGoldMaxDifficulty = -1; + m_FogOfWarSwitchEnabled = true; + m_DeployUnitsSwitchEnabled = false; + m_GoldSwitchEnabled = true; + m_RequireClearPathToOrbitSwitchEnabled = true; + m_BuyMenuEnabled = true; + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + m_Deliveries[team].clear(); + m_LandingZoneArea[team].Reset(); + m_aLZCursor[team].clear(); + m_aObjCursor[team].clear(); + } + m_Objectives.clear(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GameActivity object ready for use. + m_DeliveryDelay = 4500; + m_CursorTimer.Reset(); + m_GameTimer.Reset(); + m_GameOverTimer.Reset(); + m_GameOverPeriod = 5000; + m_WinnerTeam = -1; + } -int GameActivity::Create() -{ - if (Activity::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GameActivity object ready for use. -// m_Description = "Define and edit Areas on this Scene."; + int GameActivity::Create() { + if (Activity::Create() < 0) + return -1; - // Load banners - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - m_pBannerRed[player] = new GUIBanner(); - m_pBannerYellow[player] = new GUIBanner(); - } + // m_Description = "Define and edit Areas on this Scene."; - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - m_TeamIsCPU[team] = false; - } + // Load banners + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + m_pBannerRed[player] = new GUIBanner(); + m_pBannerYellow[player] = new GUIBanner(); + } - return 0; -} + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + m_TeamIsCPU[team] = false; + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GameActivity to be identical to another, by deep copy. - -int GameActivity::Create(const GameActivity &reference) -{ - if (Activity::Create(reference) < 0) - return -1; - - m_CPUTeam = reference.m_CPUTeam; - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - m_ObservationTarget[player] = reference.m_ObservationTarget[player]; - m_DeathViewTarget[player] = reference.m_DeathViewTarget[player]; - m_ActorCursor[player] = reference.m_ActorCursor[player]; - m_pLastMarkedActor[player] = reference.m_pLastMarkedActor[player]; - m_LandingZone[player] = reference.m_LandingZone[player]; - m_AIReturnCraft[player] = reference.m_AIReturnCraft[player]; - m_InventoryMenuGUI[player] = new InventoryMenuGUI; - m_pBuyGUI[player] = new BuyMenuGUI; - m_pEditorGUI[player] = new SceneEditorGUI; - m_LuaLockActor[player] = reference.m_LuaLockActor[player]; - m_LuaLockActorMode[player] = reference.m_LuaLockActorMode[player]; - m_pBannerRed[player] = new GUIBanner(); - m_pBannerYellow[player] = new GUIBanner(); - m_ReadyToStart[player] = reference.m_ReadyToStart[player]; - m_BrainLZWidth[player] = reference.m_BrainLZWidth[player]; - - m_NetworkPlayerNames[player] = reference.m_NetworkPlayerNames[player]; - } - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - m_LandingZoneArea[team] = reference.m_LandingZoneArea[team]; - m_TeamTech[team] = reference.m_TeamTech[team]; - m_TeamIsCPU[team] = reference.m_TeamIsCPU[team]; - } - - m_StartingGold = reference.m_StartingGold; - m_FogOfWarEnabled = reference.m_FogOfWarEnabled; - m_RequireClearPathToOrbit = reference.m_RequireClearPathToOrbit; - - m_DefaultFogOfWar = reference.m_DefaultFogOfWar; - m_DefaultRequireClearPathToOrbit = reference.m_DefaultRequireClearPathToOrbit; - m_DefaultDeployUnits = reference.m_DefaultDeployUnits; - m_DefaultGoldCakeDifficulty = reference.m_DefaultGoldCakeDifficulty; - m_DefaultGoldEasyDifficulty = reference.m_DefaultGoldEasyDifficulty; - m_DefaultGoldMediumDifficulty = reference.m_DefaultGoldMediumDifficulty; - m_DefaultGoldHardDifficulty = reference.m_DefaultGoldHardDifficulty; - m_DefaultGoldNutsDifficulty = reference.m_DefaultGoldNutsDifficulty; - m_DefaultGoldMaxDifficulty = reference.m_DefaultGoldMaxDifficulty; - m_FogOfWarSwitchEnabled = reference.m_FogOfWarSwitchEnabled; - m_DeployUnitsSwitchEnabled = reference.m_DeployUnitsSwitchEnabled; - m_GoldSwitchEnabled = reference.m_GoldSwitchEnabled; - m_RequireClearPathToOrbitSwitchEnabled = reference.m_RequireClearPathToOrbitSwitchEnabled; - m_BuyMenuEnabled = reference.m_BuyMenuEnabled; - - m_DeliveryDelay = reference.m_DeliveryDelay; -// m_CursorTimer = reference.m_CursorTimer; -// m_GameTimer = reference.m_GameTimer; -// m_GameOverTimer = reference.m_GameOverTimer; - m_GameOverPeriod = reference.m_GameOverPeriod; - m_WinnerTeam = reference.m_WinnerTeam; - - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GameActivity to be identical to another, by deep copy. + + int GameActivity::Create(const GameActivity& reference) { + if (Activity::Create(reference) < 0) + return -1; + + m_CPUTeam = reference.m_CPUTeam; + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + m_ObservationTarget[player] = reference.m_ObservationTarget[player]; + m_DeathViewTarget[player] = reference.m_DeathViewTarget[player]; + m_ActorCursor[player] = reference.m_ActorCursor[player]; + m_pLastMarkedActor[player] = reference.m_pLastMarkedActor[player]; + m_LandingZone[player] = reference.m_LandingZone[player]; + m_AIReturnCraft[player] = reference.m_AIReturnCraft[player]; + m_InventoryMenuGUI[player] = new InventoryMenuGUI; + m_pBuyGUI[player] = new BuyMenuGUI; + m_pEditorGUI[player] = new SceneEditorGUI; + m_LuaLockActor[player] = reference.m_LuaLockActor[player]; + m_LuaLockActorMode[player] = reference.m_LuaLockActorMode[player]; + m_pBannerRed[player] = new GUIBanner(); + m_pBannerYellow[player] = new GUIBanner(); + m_ReadyToStart[player] = reference.m_ReadyToStart[player]; + m_BrainLZWidth[player] = reference.m_BrainLZWidth[player]; + + m_NetworkPlayerNames[player] = reference.m_NetworkPlayerNames[player]; + } + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + m_LandingZoneArea[team] = reference.m_LandingZoneArea[team]; + m_TeamTech[team] = reference.m_TeamTech[team]; + m_TeamIsCPU[team] = reference.m_TeamIsCPU[team]; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int GameActivity::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Activity::ReadProperty(propName, reader)); - - MatchProperty("CPUTeam", - reader >> m_CPUTeam; - SetCPUTeam(m_CPUTeam); ); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); - MatchProperty("DefaultFogOfWar", { reader >> m_DefaultFogOfWar; }); - MatchProperty("DefaultRequireClearPathToOrbit", { reader >> m_DefaultRequireClearPathToOrbit; }); - MatchProperty("DefaultDeployUnits", { reader >> m_DefaultDeployUnits; }); - MatchProperty("DefaultGoldCakeDifficulty", { reader >> m_DefaultGoldCakeDifficulty; }); - MatchProperty("DefaultGoldEasyDifficulty", { reader >> m_DefaultGoldEasyDifficulty; }); - MatchProperty("DefaultGoldMediumDifficulty", { reader >> m_DefaultGoldMediumDifficulty; }); - MatchProperty("DefaultGoldHardDifficulty", { reader >> m_DefaultGoldHardDifficulty; }); - MatchProperty("DefaultGoldNutsDifficulty", { reader >> m_DefaultGoldNutsDifficulty; }); - MatchProperty("DefaultGoldMaxDifficulty", { reader >> m_DefaultGoldMaxDifficulty; }); - MatchProperty("FogOfWarSwitchEnabled", { reader >> m_FogOfWarSwitchEnabled; }); - MatchProperty("DeployUnitsSwitchEnabled", { reader >> m_DeployUnitsSwitchEnabled; }); - MatchProperty("GoldSwitchEnabled", { reader >> m_GoldSwitchEnabled; }); - MatchProperty("RequireClearPathToOrbitSwitchEnabled", { reader >> m_RequireClearPathToOrbitSwitchEnabled; }); - MatchProperty("BuyMenuEnabled", { reader >> m_BuyMenuEnabled; }); - MatchForwards("Team1Tech") - MatchForwards("Team2Tech") - MatchForwards("Team3Tech") - MatchProperty("Team4Tech", - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { - if (propName == "Team" + std::to_string(team + 1) + "Tech") { - std::string techName; - reader >> techName; - SetTeamTech(team, techName); - } - } ); - MatchProperty("SpecialBehaviour_StartingGold", { reader >> m_StartingGold; }); - MatchProperty("SpecialBehaviour_FogOfWarEnabled", { reader >> m_FogOfWarEnabled; }); + m_StartingGold = reference.m_StartingGold; + m_FogOfWarEnabled = reference.m_FogOfWarEnabled; + m_RequireClearPathToOrbit = reference.m_RequireClearPathToOrbit; + + m_DefaultFogOfWar = reference.m_DefaultFogOfWar; + m_DefaultRequireClearPathToOrbit = reference.m_DefaultRequireClearPathToOrbit; + m_DefaultDeployUnits = reference.m_DefaultDeployUnits; + m_DefaultGoldCakeDifficulty = reference.m_DefaultGoldCakeDifficulty; + m_DefaultGoldEasyDifficulty = reference.m_DefaultGoldEasyDifficulty; + m_DefaultGoldMediumDifficulty = reference.m_DefaultGoldMediumDifficulty; + m_DefaultGoldHardDifficulty = reference.m_DefaultGoldHardDifficulty; + m_DefaultGoldNutsDifficulty = reference.m_DefaultGoldNutsDifficulty; + m_DefaultGoldMaxDifficulty = reference.m_DefaultGoldMaxDifficulty; + m_FogOfWarSwitchEnabled = reference.m_FogOfWarSwitchEnabled; + m_DeployUnitsSwitchEnabled = reference.m_DeployUnitsSwitchEnabled; + m_GoldSwitchEnabled = reference.m_GoldSwitchEnabled; + m_RequireClearPathToOrbitSwitchEnabled = reference.m_RequireClearPathToOrbitSwitchEnabled; + m_BuyMenuEnabled = reference.m_BuyMenuEnabled; + + m_DeliveryDelay = reference.m_DeliveryDelay; + // m_CursorTimer = reference.m_CursorTimer; + // m_GameTimer = reference.m_GameTimer; + // m_GameOverTimer = reference.m_GameOverTimer; + m_GameOverPeriod = reference.m_GameOverPeriod; + m_WinnerTeam = reference.m_WinnerTeam; + + return 0; + } - EndPropertyList; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int GameActivity::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Activity::ReadProperty(propName, reader)); + + MatchProperty("CPUTeam", + reader >> m_CPUTeam; + SetCPUTeam(m_CPUTeam);); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + MatchProperty("DefaultFogOfWar", { reader >> m_DefaultFogOfWar; }); + MatchProperty("DefaultRequireClearPathToOrbit", { reader >> m_DefaultRequireClearPathToOrbit; }); + MatchProperty("DefaultDeployUnits", { reader >> m_DefaultDeployUnits; }); + MatchProperty("DefaultGoldCakeDifficulty", { reader >> m_DefaultGoldCakeDifficulty; }); + MatchProperty("DefaultGoldEasyDifficulty", { reader >> m_DefaultGoldEasyDifficulty; }); + MatchProperty("DefaultGoldMediumDifficulty", { reader >> m_DefaultGoldMediumDifficulty; }); + MatchProperty("DefaultGoldHardDifficulty", { reader >> m_DefaultGoldHardDifficulty; }); + MatchProperty("DefaultGoldNutsDifficulty", { reader >> m_DefaultGoldNutsDifficulty; }); + MatchProperty("DefaultGoldMaxDifficulty", { reader >> m_DefaultGoldMaxDifficulty; }); + MatchProperty("FogOfWarSwitchEnabled", { reader >> m_FogOfWarSwitchEnabled; }); + MatchProperty("DeployUnitsSwitchEnabled", { reader >> m_DeployUnitsSwitchEnabled; }); + MatchProperty("GoldSwitchEnabled", { reader >> m_GoldSwitchEnabled; }); + MatchProperty("RequireClearPathToOrbitSwitchEnabled", { reader >> m_RequireClearPathToOrbitSwitchEnabled; }); + MatchProperty("BuyMenuEnabled", { reader >> m_BuyMenuEnabled; }); + MatchForwards("Team1Tech") + MatchForwards("Team2Tech") + MatchForwards("Team3Tech") + MatchProperty( + "Team4Tech", + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { + if (propName == "Team" + std::to_string(team + 1) + "Tech") { + std::string techName; + reader >> techName; + SetTeamTech(team, techName); + } + }); + MatchProperty("SpecialBehaviour_StartingGold", { reader >> m_StartingGold; }); + MatchProperty("SpecialBehaviour_FogOfWarEnabled", { reader >> m_FogOfWarEnabled; }); + + EndPropertyList; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this GameActivity with a Writer for + // later recreation with Create(Reader &reader); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this GameActivity with a Writer for -// later recreation with Create(Reader &reader); + int GameActivity::Save(Writer& writer) const { + Activity::Save(writer); -int GameActivity::Save(Writer &writer) const { - Activity::Save(writer); + writer.NewPropertyWithValue("CPUTeam", m_CPUTeam); + writer.NewPropertyWithValue("DeliveryDelay", m_DeliveryDelay); + writer.NewPropertyWithValue("BuyMenuEnabled", m_BuyMenuEnabled); - writer.NewPropertyWithValue("CPUTeam", m_CPUTeam); - writer.NewPropertyWithValue("DeliveryDelay", m_DeliveryDelay); - writer.NewPropertyWithValue("BuyMenuEnabled", m_BuyMenuEnabled); + // Note - these special behaviour properties are for saving and loading. Normally these fields are set by the Activity config GUI. + writer.NewPropertyWithValue("SpecialBehaviour_StartingGold", m_StartingGold); + writer.NewPropertyWithValue("SpecialBehaviour_FogOfWarEnabled", m_FogOfWarEnabled); - // Note - these special behaviour properties are for saving and loading. Normally these fields are set by the Activity config GUI. - writer.NewPropertyWithValue("SpecialBehaviour_StartingGold", m_StartingGold); - writer.NewPropertyWithValue("SpecialBehaviour_FogOfWarEnabled", m_FogOfWarEnabled); + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { + writer.NewPropertyWithValue("Team" + std::to_string(team + 1) + "Tech", GetTeamTech(team)); + } - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { - writer.NewPropertyWithValue("Team" + std::to_string(team + 1) + "Tech", GetTeamTech(team)); + return 0; } - return 0; -} - + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GameActivity object. + + void GameActivity::Destroy(bool notInherited) { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + delete m_InventoryMenuGUI[player]; + delete m_pBuyGUI[player]; + delete m_pEditorGUI[player]; + delete m_pBannerRed[player]; + delete m_pBannerYellow[player]; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GameActivity object. - -void GameActivity::Destroy(bool notInherited) -{ - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - delete m_InventoryMenuGUI[player]; - delete m_pBuyGUI[player]; - delete m_pEditorGUI[player]; - delete m_pBannerRed[player]; - delete m_pBannerYellow[player]; - } - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { - delete itr->pCraft; - } - m_Deliveries[team].clear(); - } - - if (!notInherited) - Activity::Destroy(); - Clear(); -} + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { + delete itr->pCraft; + } + m_Deliveries[team].clear(); + } + if (!notInherited) + Activity::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTeamTech -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets tech module name for specified team. Module must set must be loaded. - void GameActivity::SetTeamTech(int team, std::string tech) - { - if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) - { + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTeamTech + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets tech module name for specified team. Module must set must be loaded. + void GameActivity::SetTeamTech(int team, std::string tech) { + if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { if (tech == "-All-" || tech == "-Random-") m_TeamTech[team] = tech; - else - { + else { int id = g_PresetMan.GetModuleID(tech); if (id != -1) m_TeamTech[team] = tech; @@ -347,2626 +324,2409 @@ void GameActivity::Destroy(bool notInherited) } } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCrabToHumanSpawnRatio -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns CrabToHumanSpawnRatio for specified module - float GameActivity::GetCrabToHumanSpawnRatio(int moduleid) - { - if (moduleid > -1) - { - const DataModule * pDataModule = g_PresetMan.GetDataModule(moduleid); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCrabToHumanSpawnRatio + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns CrabToHumanSpawnRatio for specified module + float GameActivity::GetCrabToHumanSpawnRatio(int moduleid) { + if (moduleid > -1) { + const DataModule* pDataModule = g_PresetMan.GetDataModule(moduleid); if (pDataModule) return pDataModule->GetCrabToHumanSpawnRatio(); } return 0.25; } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCPUTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current CPU-assisted team, if any (NoTeam) - LEGACY function + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCPUTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current CPU-assisted team, if any (NoTeam) - LEGACY function -void GameActivity::SetCPUTeam(int team) -{ - if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { - // Set the legacy var - m_CPUTeam = team; + void GameActivity::SetCPUTeam(int team) { + if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { + // Set the legacy var + m_CPUTeam = team; - m_TeamActive[team] = true; - m_TeamIsCPU[team] = true; - } + m_TeamActive[team] = true; + m_TeamIsCPU[team] = true; + } -/* whaaaa? - // Also set the newer human indicator flags - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - m_IsHuman[m_Team[player]] = m_IsActive[player] && m_Team[player] != team; -*/ -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool GameActivity::IsBuyGUIVisible(int which) const { - if (which == -1) { - for (short player = Players::PlayerOne; player < this->GetPlayerCount(); player++) { - if (this->GetBuyGUI(player)->IsVisible()) { - return true; - } - } - return false; - } - return this->GetBuyGUI(which)->IsVisible(); - -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool GameActivity::LockControlledActor(Players player, bool lock, Controller::InputMode lockToMode) { - if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { - bool prevLock = m_LuaLockActor[player]; - m_LuaLockActor[player] = lock; - m_LuaLockActorMode[player] = lockToMode; - return true; + /* whaaaa? + // Also set the newer human indicator flags + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) + m_IsHuman[m_Team[player]] = m_IsActive[player] && m_Team[player] != team; + */ } - return false; -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SwitchToActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the this to focus player control to a specific Actor for a -// specific team. OWNERSHIP IS NOT TRANSFERRED! + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool GameActivity::IsBuyGUIVisible(int which) const { + if (which == -1) { + for (short player = Players::PlayerOne; player < this->GetPlayerCount(); player++) { + if (this->GetBuyGUI(player)->IsVisible()) { + return true; + } + } + return false; + } + return this->GetBuyGUI(which)->IsVisible(); + } -bool GameActivity::SwitchToActor(Actor *pActor, int player, int team) -{ - // Computer players don't focus on any Actor - if (!m_IsHuman[player]) - return false; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (pActor && pActor->GetPieMenu()) { - pActor->GetPieMenu()->DoDisableAnimation(); + bool GameActivity::LockControlledActor(Players player, bool lock, Controller::InputMode lockToMode) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { + bool prevLock = m_LuaLockActor[player]; + m_LuaLockActor[player] = lock; + m_LuaLockActorMode[player] = lockToMode; + return true; + } + return false; } - m_InventoryMenuGUI[player]->SetEnabled(false); - // Disable the AI command mode since it's connected to the current actor - if (m_ViewState[player] == ViewState::AISentryPoint || m_ViewState[player] == ViewState::AIPatrolPoints || m_ViewState[player] == ViewState::AIGoldDigPoint || m_ViewState[player] == ViewState::AIGoToPoint || m_ViewState[player] == ViewState::UnitSelectCircle) - m_ViewState[player] = ViewState::Normal; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SwitchToActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the this to focus player control to a specific Actor for a + // specific team. OWNERSHIP IS NOT TRANSFERRED! - return Activity::SwitchToActor(pActor, player, team); -} + bool GameActivity::SwitchToActor(Actor* pActor, int player, int team) { + // Computer players don't focus on any Actor + if (!m_IsHuman[player]) + return false; + if (pActor && pActor->GetPieMenu()) { + pActor->GetPieMenu()->DoDisableAnimation(); + } + m_InventoryMenuGUI[player]->SetEnabled(false); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SwitchToNextActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the this to focus player control to the next Actor of a -// specific team, other than the current one focused on. + // Disable the AI command mode since it's connected to the current actor + if (m_ViewState[player] == ViewState::AISentryPoint || m_ViewState[player] == ViewState::AIPatrolPoints || m_ViewState[player] == ViewState::AIGoldDigPoint || m_ViewState[player] == ViewState::AIGoToPoint || m_ViewState[player] == ViewState::UnitSelectCircle) + m_ViewState[player] = ViewState::Normal; + + return Activity::SwitchToActor(pActor, player, team); + } -void GameActivity::SwitchToNextActor(int player, int team, Actor *pSkip) -{ - m_InventoryMenuGUI[player]->SetEnabled(false); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SwitchToNextActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the this to focus player control to the next Actor of a + // specific team, other than the current one focused on. - // Disable the AI command mode since it's connected to the current actor - if (m_ViewState[player] == ViewState::AISentryPoint || m_ViewState[player] == ViewState::AIPatrolPoints || m_ViewState[player] == ViewState::AIGoldDigPoint || m_ViewState[player] == ViewState::AIGoToPoint || m_ViewState[player] == ViewState::UnitSelectCircle) - m_ViewState[player] = ViewState::Normal; + void GameActivity::SwitchToNextActor(int player, int team, Actor* pSkip) { + m_InventoryMenuGUI[player]->SetEnabled(false); - Activity::SwitchToNextActor(player, team, pSkip); + // Disable the AI command mode since it's connected to the current actor + if (m_ViewState[player] == ViewState::AISentryPoint || m_ViewState[player] == ViewState::AIPatrolPoints || m_ViewState[player] == ViewState::AIGoldDigPoint || m_ViewState[player] == ViewState::AIGoToPoint || m_ViewState[player] == ViewState::UnitSelectCircle) + m_ViewState[player] = ViewState::Normal; - if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); - } -} + Activity::SwitchToNextActor(player, team, pSkip); + if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SwitchToPrevActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces this to focus player control to the previous Actor of a -// specific team, other than the current one focused on. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SwitchToPrevActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces this to focus player control to the previous Actor of a + // specific team, other than the current one focused on. -void GameActivity::SwitchToPrevActor(int player, int team, Actor *pSkip) -{ - m_InventoryMenuGUI[player]->SetEnabled(false); + void GameActivity::SwitchToPrevActor(int player, int team, Actor* pSkip) { + m_InventoryMenuGUI[player]->SetEnabled(false); - // Disable the AI command mode since it's connected to the current actor - if (m_ViewState[player] == ViewState::AISentryPoint || m_ViewState[player] == ViewState::AIPatrolPoints || m_ViewState[player] == ViewState::AIGoldDigPoint || m_ViewState[player] == ViewState::AIGoToPoint || m_ViewState[player] == ViewState::UnitSelectCircle) - m_ViewState[player] = ViewState::Normal; + // Disable the AI command mode since it's connected to the current actor + if (m_ViewState[player] == ViewState::AISentryPoint || m_ViewState[player] == ViewState::AIPatrolPoints || m_ViewState[player] == ViewState::AIGoldDigPoint || m_ViewState[player] == ViewState::AIGoToPoint || m_ViewState[player] == ViewState::UnitSelectCircle) + m_ViewState[player] = ViewState::Normal; - Activity::SwitchToPrevActor(player, team, pSkip); + Activity::SwitchToPrevActor(player, team, pSkip); - if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); + if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); + } } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddObjectivePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Created an objective point for one of the teams to show until cleared. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddObjectivePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Created an objective point for one of the teams to show until cleared. + void GameActivity::AddObjectivePoint(std::string description, Vector objPos, int whichTeam, ObjectiveArrowDir arrowDir) { + m_Objectives.push_back(ObjectivePoint(description, objPos, whichTeam, arrowDir)); + } -void GameActivity::AddObjectivePoint(std::string description, Vector objPos, int whichTeam, ObjectiveArrowDir arrowDir) -{ - m_Objectives.push_back(ObjectivePoint(description, objPos, whichTeam, arrowDir)); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: YSortObjectivePoints + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sorts all objective points according to their positions on the Y axis. + void GameActivity::YSortObjectivePoints() { + m_Objectives.sort(ObjPointYPosComparison()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: YSortObjectivePoints -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sorts all objective points according to their positions on the Y axis. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddOverridePurchase + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds somehting to the purchase list that will override what is set + // in the buy GUI next time CreateDelivery is called. + + int GameActivity::AddOverridePurchase(const SceneObject* pPurchase, int player) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { + // Add to purchase list if valid item + if (pPurchase) { + // Get the preset of this instance passed in, so we make sure we are only storing non-owned instances + const SceneObject* pPreset = dynamic_cast(g_PresetMan.GetEntityPreset(pPurchase->GetClassName(), pPurchase->GetPresetName(), pPurchase->GetModuleID())); + if (pPreset) + m_PurchaseOverride[player].push_back(pPreset); + } -void GameActivity::YSortObjectivePoints() -{ - m_Objectives.sort(ObjPointYPosComparison()); -} + // Take metaplayer tech modifiers into account + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); + } + // Calculate the total list cost for this player + int totalListCost = 0; + for (std::list::iterator itr = m_PurchaseOverride[player].begin(); itr != m_PurchaseOverride[player].end(); ++itr) + totalListCost += (*itr)->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddOverridePurchase -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds somehting to the purchase list that will override what is set -// in the buy GUI next time CreateDelivery is called. - -int GameActivity::AddOverridePurchase(const SceneObject *pPurchase, int player) -{ - if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) - { - // Add to purchase list if valid item - if (pPurchase) - { - // Get the preset of this instance passed in, so we make sure we are only storing non-owned instances - const SceneObject *pPreset = dynamic_cast(g_PresetMan.GetEntityPreset(pPurchase->GetClassName(), pPurchase->GetPresetName(), pPurchase->GetModuleID())); - if (pPreset) - m_PurchaseOverride[player].push_back(pPreset); + return totalListCost; } - // Take metaplayer tech modifiers into account - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - } + return 0; + } - // Calculate the total list cost for this player - int totalListCost = 0; - for (std::list::iterator itr = m_PurchaseOverride[player].begin(); itr != m_PurchaseOverride[player].end(); ++itr) - totalListCost += (*itr)->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOverridePurchaseList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: First clears and then adds all the stuff in a Loadout to the override + // purchase list. - return totalListCost; - } + int GameActivity::SetOverridePurchaseList(const Loadout* pLoadout, int player) { + // First clear out the list + ClearOverridePurchase(player); + + int finalListCost = 0; - return 0; -} + // Sanity check + if (!pLoadout) { + g_ConsoleMan.PrintString("ERROR: Tried to set an override purchase list based on a nonexistent Loadout!"); + return 0; + } + const ACraft* pCraftPreset = pLoadout->GetDeliveryCraft(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOverridePurchaseList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: First clears and then adds all the stuff in a Loadout to the override -// purchase list. - -int GameActivity::SetOverridePurchaseList(const Loadout *pLoadout, int player) -{ - // First clear out the list - ClearOverridePurchase(player); - - int finalListCost = 0; - - // Sanity check - if (!pLoadout) - { - g_ConsoleMan.PrintString("ERROR: Tried to set an override purchase list based on a nonexistent Loadout!"); - return 0; - } - - const ACraft *pCraftPreset = pLoadout->GetDeliveryCraft(); - - // Check if we even have a craft and substitute a default if we don't - if (!pCraftPreset) - { -// Too verbose for a recoverable error -// g_ConsoleMan.PrintString("ERROR: Tried to set an override purchase list with no delivery craft defined. Using a default instead."); - const Loadout *pDefault = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Default", -1)); - if (pDefault) - pCraftPreset = pDefault->GetDeliveryCraft(); - - // If still no go, then fuck it - if (!pCraftPreset) - { - g_ConsoleMan.PrintString("ERROR: Couldn't even find a \"Default\" Loadout in Base.rte! Aborting."); - return 0; - } - } - - // Add the delivery Craft - finalListCost = AddOverridePurchase(pCraftPreset, player); - - // Add the rest of the cargo list - std::list *pCargoList = const_cast(pLoadout)->GetCargoList(); - for (std::list::iterator itr = pCargoList->begin(); itr != pCargoList->end(); ++itr) - finalListCost = AddOverridePurchase(*itr, player); - - return finalListCost; -} + // Check if we even have a craft and substitute a default if we don't + if (!pCraftPreset) { + // Too verbose for a recoverable error + // g_ConsoleMan.PrintString("ERROR: Tried to set an override purchase list with no delivery craft defined. Using a default instead."); + const Loadout* pDefault = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Default", -1)); + if (pDefault) + pCraftPreset = pDefault->GetDeliveryCraft(); + + // If still no go, then fuck it + if (!pCraftPreset) { + g_ConsoleMan.PrintString("ERROR: Couldn't even find a \"Default\" Loadout in Base.rte! Aborting."); + return 0; + } + } + // Add the delivery Craft + finalListCost = AddOverridePurchase(pCraftPreset, player); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOverridePurchaseList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: First clears and then adds all the stuff in a Loadout to the override -// purchase list. + // Add the rest of the cargo list + std::list* pCargoList = const_cast(pLoadout)->GetCargoList(); + for (std::list::iterator itr = pCargoList->begin(); itr != pCargoList->end(); ++itr) + finalListCost = AddOverridePurchase(*itr, player); -int GameActivity::SetOverridePurchaseList(std::string loadoutName, int player) -{ - // Find out the native module of this player - int nativeModule = 0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - nativeModule = pMetaPlayer->GetNativeTechModule(); + return finalListCost; + } - // Find the Loadout that this Deployment is referring to - const Loadout *pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", loadoutName, nativeModule)); - if (pLoadout) - return SetOverridePurchaseList(pLoadout, player); - else - g_ConsoleMan.PrintString("ERROR: Tried to set an override purchase list based on a nonexistent Loadout!"); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOverridePurchaseList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: First clears and then adds all the stuff in a Loadout to the override + // purchase list. - return 0; -} + int GameActivity::SetOverridePurchaseList(std::string loadoutName, int player) { + // Find out the native module of this player + int nativeModule = 0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) + nativeModule = pMetaPlayer->GetNativeTechModule(); + // Find the Loadout that this Deployment is referring to + const Loadout* pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", loadoutName, nativeModule)); + if (pLoadout) + return SetOverridePurchaseList(pLoadout, player); + else + g_ConsoleMan.PrintString("ERROR: Tried to set an override purchase list based on a nonexistent Loadout!"); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateDelivery -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes the current order out of a player's buy GUI, creates a Delivery -// based off it, and stuffs it into that player's delivery queue. - -bool GameActivity::CreateDelivery(int player, int mode, Vector &waypoint, Actor * pTargetMO) -{ - int team = m_Team[player]; - if (team == Teams::NoTeam) - return false; - - // Prepare the Craft, stuff everything into it and add it to the queue - // Retrieve the ordered craft and its inventory - std::list purchaseList; - - ACraft *pDeliveryCraft = 0; - // If we have a list to purchase that overrides the buy GUI, then use it and clear it - if (!m_PurchaseOverride[player].empty()) - { - const ACraft *pCraftPreset = 0; - for (std::list::iterator itr = m_PurchaseOverride[player].begin(); itr != m_PurchaseOverride[player].end(); ++itr) - { - // Find the first craft to use as the delivery craft - pCraftPreset = dynamic_cast(*itr); - if (!pDeliveryCraft && pCraftPreset) - pDeliveryCraft = dynamic_cast((*itr)->Clone()); - else - purchaseList.push_back(*itr); - } - } - // Otherwise, use what's set in the buy GUI as usual - else - { - m_pBuyGUI[player]->GetOrderList(purchaseList); - pDeliveryCraft = dynamic_cast(m_pBuyGUI[player]->GetDeliveryCraftPreset()->Clone()); - // If we don't have any loadout presets in the menu, save the current config for later - if (m_pBuyGUI[player]->GetLoadoutPresets().empty()) - m_pBuyGUI[player]->SaveCurrentLoadout(); - } - - if (pDeliveryCraft && (!m_HadBrain[player] || m_Brain[player])) - { - // Take metaplayer tech modifiers into account when calculating costs of this delivery - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - } - // Start with counting the craft - float totalCost = 0; - - if (m_pBuyGUI[player]->GetOnlyShowOwnedItems()) - { - if (!m_pBuyGUI[player]->CommitPurchase(pDeliveryCraft->GetModuleAndPresetName())) - { - if (m_pBuyGUI[player]->IsAlwaysAllowedItem(pDeliveryCraft->GetModuleAndPresetName())) - totalCost = pDeliveryCraft->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateDelivery + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes the current order out of a player's buy GUI, creates a Delivery + // based off it, and stuffs it into that player's delivery queue. + + bool GameActivity::CreateDelivery(int player, int mode, Vector& waypoint, Actor* pTargetMO) { + int team = m_Team[player]; + if (team == Teams::NoTeam) + return false; + + // Prepare the Craft, stuff everything into it and add it to the queue + // Retrieve the ordered craft and its inventory + std::list purchaseList; + + ACraft* pDeliveryCraft = 0; + // If we have a list to purchase that overrides the buy GUI, then use it and clear it + if (!m_PurchaseOverride[player].empty()) { + const ACraft* pCraftPreset = 0; + for (std::list::iterator itr = m_PurchaseOverride[player].begin(); itr != m_PurchaseOverride[player].end(); ++itr) { + // Find the first craft to use as the delivery craft + pCraftPreset = dynamic_cast(*itr); + if (!pDeliveryCraft && pCraftPreset) + pDeliveryCraft = dynamic_cast((*itr)->Clone()); else - return false; + purchaseList.push_back(*itr); } } - else - { - if (!m_pBuyGUI[player]->CommitPurchase(pDeliveryCraft->GetModuleAndPresetName())) - totalCost = pDeliveryCraft->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + // Otherwise, use what's set in the buy GUI as usual + else { + m_pBuyGUI[player]->GetOrderList(purchaseList); + pDeliveryCraft = dynamic_cast(m_pBuyGUI[player]->GetDeliveryCraftPreset()->Clone()); + // If we don't have any loadout presets in the menu, save the current config for later + if (m_pBuyGUI[player]->GetLoadoutPresets().empty()) + m_pBuyGUI[player]->SaveCurrentLoadout(); } - // Go through the list of things ordered, and give any actors all the items that is present after them, - // until the next actor. Also, the first actor gets all stuff in the list above him. - MovableObject *pInventoryObject = 0; - Actor *pPassenger = 0; - Actor *pLastPassenger = 0; - std::list cargoItems; - - for (std::list::iterator itr = purchaseList.begin(); itr != purchaseList.end(); ++itr) - { - bool purchaseItem = true; - - // Add to the total cost tally - if (m_pBuyGUI[player]->GetOnlyShowOwnedItems()) - { - if (!m_pBuyGUI[player]->CommitPurchase((*itr)->GetModuleAndPresetName())) - { - if (m_pBuyGUI[player]->IsAlwaysAllowedItem((*itr)->GetModuleAndPresetName())) - totalCost += (*itr)->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + if (pDeliveryCraft && (!m_HadBrain[player] || m_Brain[player])) { + // Take metaplayer tech modifiers into account when calculating costs of this delivery + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); + } + // Start with counting the craft + float totalCost = 0; + + if (m_pBuyGUI[player]->GetOnlyShowOwnedItems()) { + if (!m_pBuyGUI[player]->CommitPurchase(pDeliveryCraft->GetModuleAndPresetName())) { + if (m_pBuyGUI[player]->IsAlwaysAllowedItem(pDeliveryCraft->GetModuleAndPresetName())) + totalCost = pDeliveryCraft->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); else - purchaseItem = false; + return false; } + } else { + if (!m_pBuyGUI[player]->CommitPurchase(pDeliveryCraft->GetModuleAndPresetName())) + totalCost = pDeliveryCraft->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); } - else - { - if (!m_pBuyGUI[player]->CommitPurchase((*itr)->GetModuleAndPresetName())) - totalCost += (*itr)->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); - } - if (purchaseItem) - { - // Make copy of the preset instance in the list - pInventoryObject = dynamic_cast((*itr)->Clone()); - // See if it's actually a passenger, as opposed to a regular item - pPassenger = dynamic_cast(pInventoryObject); - // If it's an actor, then set its team and add it to the Craft's inventory! - if (pPassenger) - { - if (dynamic_cast(pPassenger)) { - // If this is the first passenger, then give him all the shit found in the list before him - if (!pLastPassenger) { - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - pPassenger->AddInventoryItem(*iItr); + // Go through the list of things ordered, and give any actors all the items that is present after them, + // until the next actor. Also, the first actor gets all stuff in the list above him. + MovableObject* pInventoryObject = 0; + Actor* pPassenger = 0; + Actor* pLastPassenger = 0; + std::list cargoItems; + + for (std::list::iterator itr = purchaseList.begin(); itr != purchaseList.end(); ++itr) { + bool purchaseItem = true; + + // Add to the total cost tally + if (m_pBuyGUI[player]->GetOnlyShowOwnedItems()) { + if (!m_pBuyGUI[player]->CommitPurchase((*itr)->GetModuleAndPresetName())) { + if (m_pBuyGUI[player]->IsAlwaysAllowedItem((*itr)->GetModuleAndPresetName())) + totalCost += (*itr)->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + else + purchaseItem = false; + } + } else { + if (!m_pBuyGUI[player]->CommitPurchase((*itr)->GetModuleAndPresetName())) + totalCost += (*itr)->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + } + + if (purchaseItem) { + // Make copy of the preset instance in the list + pInventoryObject = dynamic_cast((*itr)->Clone()); + // See if it's actually a passenger, as opposed to a regular item + pPassenger = dynamic_cast(pInventoryObject); + // If it's an actor, then set its team and add it to the Craft's inventory! + if (pPassenger) { + if (dynamic_cast(pPassenger)) { + // If this is the first passenger, then give him all the shit found in the list before him + if (!pLastPassenger) { + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + pPassenger->AddInventoryItem(*iItr); + } + // This isn't the first passenger, so give the previous guy all the stuff that was found since processing him + else { + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + pLastPassenger->AddInventoryItem(*iItr); + } + + // Now set the current passenger as the 'last passenger' so he'll eventually get everything found after him. + pLastPassenger = pPassenger; + } else if (pLastPassenger) { + for (MovableObject* cargoItem: cargoItems) { + pLastPassenger->AddInventoryItem(cargoItem); + } + pLastPassenger = nullptr; } - // This isn't the first passenger, so give the previous guy all the stuff that was found since processing him - else { - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - pLastPassenger->AddInventoryItem(*iItr); + // Clear out the temporary cargo list since we've assign all the stuff in it to a passenger + cargoItems.clear(); + // Set the team etc for the current passenger and stuff him into the craft + pPassenger->SetTeam(team); + pPassenger->SetControllerMode(Controller::CIM_AI); + pPassenger->SetAIMode((Actor::AIMode)mode); + + if (pTargetMO != NULL) { + Actor* pTarget = dynamic_cast(pTargetMO); + if (pTarget) + pPassenger->AddAIMOWaypoint(pTarget); + } else if (waypoint.m_X > 0 && waypoint.m_Y > 0) { + pPassenger->AddAISceneWaypoint(waypoint); } - // Now set the current passenger as the 'last passenger' so he'll eventually get everything found after him. - pLastPassenger = pPassenger; - } else if (pLastPassenger) { - for (MovableObject *cargoItem : cargoItems) { - pLastPassenger->AddInventoryItem(cargoItem); - } - pLastPassenger = nullptr; + pDeliveryCraft->AddInventoryItem(pPassenger); } - // Clear out the temporary cargo list since we've assign all the stuff in it to a passenger - cargoItems.clear(); - // Set the team etc for the current passenger and stuff him into the craft - pPassenger->SetTeam(team); - pPassenger->SetControllerMode(Controller::CIM_AI); - pPassenger->SetAIMode((Actor::AIMode)mode); - - if (pTargetMO != NULL) - { - Actor * pTarget = dynamic_cast(pTargetMO); - if (pTarget) - pPassenger->AddAIMOWaypoint(pTarget); - } - else if (waypoint.m_X > 0 && waypoint.m_Y > 0) - { - pPassenger->AddAISceneWaypoint(waypoint); - } - - pDeliveryCraft->AddInventoryItem(pPassenger); + // If not, then add it to the temp list of items which will be added to the last passenger's inventory + else + cargoItems.push_back(pInventoryObject); } - // If not, then add it to the temp list of items which will be added to the last passenger's inventory - else - cargoItems.push_back(pInventoryObject); } - } - - pPassenger = 0; - - // If there was a last passenger and things after him, stuff all the items into his inventory - if (pLastPassenger) - { - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - pLastPassenger->AddInventoryItem(*iItr); - } - // Otherwise, stuff it all stuff directly into the craft instead - else - { - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - pDeliveryCraft->AddInventoryItem(*iItr); - } - - float spawnY = 0.0f; - if (g_SceneMan.GetTerrain() && g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { - spawnY = g_SceneMan.GetSceneHeight(); - } - - // Delivery craft appear straight over the selected LZ - pDeliveryCraft->SetPos(Vector(m_LandingZone[player].m_X, spawnY)); -// pDeliveryCraft->SetPos(Vector(m_LandingZone[player].m_X, 300)); - - pDeliveryCraft->SetTeam(team); -// TODO: The after-delivery AI mode needs to be set depending on what the user has set in teh LZ selection mode - pDeliveryCraft->SetControllerMode(Controller::CIM_AI); - pDeliveryCraft->SetAIMode(m_AIReturnCraft[player] ? Actor::AIMODE_DELIVER : Actor::AIMODE_STAY); - - // Prepare the Delivery struct and stuff the ready to go craft in there - Delivery newDelivery; - // Pass ownership of the craft to the new Delivery struct - newDelivery.pCraft = pDeliveryCraft; - newDelivery.orderedByPlayer = player; - newDelivery.landingZone = m_LandingZone[player]; - newDelivery.multiOrderYOffset = 0; - newDelivery.delay = m_DeliveryDelay * pDeliveryCraft->GetDeliveryDelayMultiplier(); - newDelivery.timer.Reset(); - - // Add the new Delivery to the queue - m_Deliveries[team].push_back(newDelivery); - - pDeliveryCraft = 0; - pLastPassenger = 0; - - // Deduct cost from team's funds - m_TeamFunds[team] -= totalCost; - - // Go 'ding!', but only if player is human, or it may be confusing - if (PlayerHuman(player)) - g_GUISound.ConfirmSound()->Play(player); - - // Clear out the override purchase list, whether anything was in there or not, it should not override twice. - m_PurchaseOverride[player].clear(); - - return true; - } - - return false; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetupPlayers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Precalculates the player-to-screen index map, counts the number of -// active players, teams etc. - -void GameActivity::SetupPlayers() -{ - Activity::SetupPlayers(); - - // Add the locked cpu team that can't have any players - if (m_CPUTeam != Teams::NoTeam && !m_TeamActive[m_CPUTeam]) { - m_TeamCount++; - // Also activate the CPU team - m_TeamActive[m_CPUTeam] = true; - } - - // Don't clear a CPU team's active status though - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { - if (m_TeamIsCPU[team] && !m_TeamActive[team]) { - m_TeamCount++; - m_TeamActive[team] = true; - } - } -} + pPassenger = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int GameActivity::Start() -{ - // Set the split screen config before the Scene (and it SceneLayers, specifially) are loaded - int humanCount = GetHumanCount(); - // Depending on the resolution aspect ratio, split first horizontally (if wide screen) - if (((float)g_WindowMan.GetResX() / (float)g_WindowMan.GetResY()) >= 1.6) - g_FrameMan.ResetSplitScreens(humanCount > 1, humanCount > 2); - // or vertically (if 4:3-ish) - else - g_FrameMan.ResetSplitScreens(humanCount > 2, humanCount > 1); - - int error = Activity::Start(); - if (error < 0) - return error; - - m_WinnerTeam = Teams::NoTeam; - - //////////////////////////////// - // Set up teams - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - - m_Deliveries[team].clear(); - - // Clear delivery queues - for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { - delete itr->pCraft; - } - - m_Deliveries[team].clear(); -/* This is taken care of by the individual Activity logic - // See if there are specified landing zone areas defined in the scene - char str[64]; - std::snprintf(str, sizeof(str), "LZ Team %d", team + 1); - Scene::Area *pArea = g_SceneMan.GetScene()->GetArea(str); - pArea = pArea ? pArea : g_SceneMan.GetScene()->GetArea("Landing Zone"); - // If area is defined, save a copy so we can lock the LZ selection to within its boxes - if (pArea && !pArea->HasNoArea()) - m_LandingZoneArea[team] = *pArea; -*/ - } - - /////////////////////////////////////// - // Set up human players - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - // Set the team associations with each screen displayed - g_CameraMan.SetScreenTeam(m_Team[player], ScreenOfPlayer(player)); - // And occlusion - g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(player)); - - // Allocate and (re)create the Inventory Menu GUIs - if (m_InventoryMenuGUI[player]) { - m_InventoryMenuGUI[player]->Destroy(); - } else { - m_InventoryMenuGUI[player] = new InventoryMenuGUI; - } - m_InventoryMenuGUI[player]->Create(&m_PlayerController[player]); - - // Allocate and (re)create the Editor GUIs - if (m_pEditorGUI[player]) - m_pEditorGUI[player]->Destroy(); - else - m_pEditorGUI[player] = new SceneEditorGUI; - m_pEditorGUI[player]->Create(&m_PlayerController[player]); - m_ReadyToStart[player] = false; - - // Allocate and (re)create the Buy GUIs - if (m_pBuyGUI[player]) - m_pBuyGUI[player]->Destroy(); - else - m_pBuyGUI[player] = new BuyMenuGUI; - m_pBuyGUI[player]->Create(&m_PlayerController[player]); - - // Load correct loadouts into buy menu if we're starting a non meta-game activity - if (m_pBuyGUI[player]->GetMetaPlayer() == Players::NoPlayer) { - int techModuleID = g_PresetMan.GetModuleID(GetTeamTech(GetTeamOfPlayer(player))); - - m_pBuyGUI[player]->SetNativeTechModule(techModuleID); - m_pBuyGUI[player]->SetForeignCostMultiplier(1.0); - m_pBuyGUI[player]->LoadAllLoadoutsFromFile(); - - // Change Editor GUI native tech module so it could load and show correct deployment prices - m_pEditorGUI[player]->SetNativeTechModule(techModuleID); - } + // If there was a last passenger and things after him, stuff all the items into his inventory + if (pLastPassenger) { + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + pLastPassenger->AddInventoryItem(*iItr); + } + // Otherwise, stuff it all stuff directly into the craft instead + else { + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + pDeliveryCraft->AddInventoryItem(*iItr); + } - //////////////////////////////////// - // GUI split screen setup - // If there are split screens, set up the GUIs to draw and their mouses to point correctly - if (g_FrameMan.IsInMultiplayerMode()) - { - m_pEditorGUI[player]->SetPosOnScreen(0, 0); - m_pBuyGUI[player]->SetPosOnScreen(0, 0); - } - else - { - if (g_FrameMan.GetScreenCount() > 1) - { - // Screen 1 Always upper left corner - if (ScreenOfPlayer(player) == 0) - { - m_pEditorGUI[player]->SetPosOnScreen(0, 0); - m_pBuyGUI[player]->SetPosOnScreen(0, 0); - } - else if (ScreenOfPlayer(player) == 1) - { - // If both splits, or just Vsplit, then in upper right quadrant - if ((g_FrameMan.GetVSplit() && !g_FrameMan.GetHSplit()) || (g_FrameMan.GetVSplit() && g_FrameMan.GetVSplit())) - { - m_pEditorGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, 0); - m_pBuyGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, 0); - } - // If only hsplit, then lower left quadrant - else - { - m_pEditorGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); - m_pBuyGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); - } - } - // Screen 3 is lower left quadrant - else if (ScreenOfPlayer(player) == 2) - { - m_pEditorGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); - m_pBuyGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); - } - // Screen 4 is lower right quadrant - else if (ScreenOfPlayer(player) == 3) - { - m_pEditorGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, g_WindowMan.GetResY() / 2); - m_pBuyGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, g_WindowMan.GetResY() / 2); - } + float spawnY = 0.0f; + if (g_SceneMan.GetTerrain() && g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { + spawnY = g_SceneMan.GetSceneHeight(); } - } - // Allocate and (re)create the banners - if (m_pBannerRed[player]) - m_pBannerRed[player]->Destroy(); - else - m_pBannerRed[player] = new GUIBanner; - m_pBannerRed[player]->Create("Base.rte/GUIs/Fonts/BannerFontRedReg.png", "Base.rte/GUIs/Fonts/BannerFontRedBlur.png", 8); - - // Allocate and (re)create the banners - if (m_pBannerYellow[player]) - m_pBannerYellow[player]->Destroy(); - else - m_pBannerYellow[player] = new GUIBanner; - m_pBannerYellow[player]->Create("Base.rte/GUIs/Fonts/BannerFontYellowReg.png", "Base.rte/GUIs/Fonts/BannerFontYellowBlur.png", 8); - - // Resetting the banner repeat counter - m_BannerRepeats[player] = 0; - - // Draw GO! game start notification, if it's a new game - if (m_ActivityState == ActivityState::NotStarted) { - m_pBannerYellow[player]->ShowText("GO!", GUIBanner::FLYBYLEFTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 500); - g_FrameMan.SetScreenText((player % 2 == 0) ? "Mine Gold and buy more firepower with the funds..." : "...then smash the competing brain to claim victory!", ScreenOfPlayer(player), 0); - } - - m_ActorCursor[player].Reset(); - m_LandingZone[player].Reset(); - - // Set the initial landing zones to be above the respective brains, but not for the observer player in a three player game - if (m_Brain[player] && !(m_PlayerCount == 3 && ScreenOfPlayer(player) == 3)) - { - // Also set the brain to be the selected actor at start - SwitchToActor(m_Brain[player], player, m_Team[player]); - m_ActorCursor[player] = m_Brain[player]->GetPos(); - m_LandingZone[player].m_X = m_Brain[player]->GetPos().m_X; - // Set the observation target to the brain, so that if/when it dies, the view flies to it in observation mode - m_ObservationTarget[player] = m_Brain[player]->GetPos(); - } - } - - // Set up the AI controllers for everyone - InitAIs(); - - // Start the game timer - m_GameTimer.Reset(); - - if (m_aLZCursor[0].empty()) - { - ContentFile cursorFile("Base.rte/GUIs/Indicators/LZArrowRedL.png"); - cursorFile.GetAsAnimation(m_aLZCursor[0], LZCURSORFRAMECOUNT); - cursorFile.SetDataPath("Base.rte/GUIs/Indicators/LZArrowGreenL.png"); - cursorFile.GetAsAnimation(m_aLZCursor[1], LZCURSORFRAMECOUNT); - cursorFile.SetDataPath("Base.rte/GUIs/Indicators/LZArrowBlueL.png"); - cursorFile.GetAsAnimation(m_aLZCursor[2], LZCURSORFRAMECOUNT); - cursorFile.SetDataPath("Base.rte/GUIs/Indicators/LZArrowYellowL.png"); - cursorFile.GetAsAnimation(m_aLZCursor[3], LZCURSORFRAMECOUNT); - } - - if (m_aObjCursor[0].empty()) - { - ContentFile cursorFile("Base.rte/GUIs/Indicators/ObjArrowRed.png"); - cursorFile.GetAsAnimation(m_aObjCursor[0], OBJARROWFRAMECOUNT); - cursorFile.SetDataPath("Base.rte/GUIs/Indicators/ObjArrowGreen.png"); - cursorFile.GetAsAnimation(m_aObjCursor[1], OBJARROWFRAMECOUNT); - cursorFile.SetDataPath("Base.rte/GUIs/Indicators/ObjArrowBlue.png"); - cursorFile.GetAsAnimation(m_aObjCursor[2], OBJARROWFRAMECOUNT); - cursorFile.SetDataPath("Base.rte/GUIs/Indicators/ObjArrowYellow.png"); - cursorFile.GetAsAnimation(m_aObjCursor[3], OBJARROWFRAMECOUNT); - } - - // Start the in-game music - g_AudioMan.ClearMusicQueue(); - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/cc2g.ogg", 0); - g_AudioMan.QueueSilence(30); - g_AudioMan.QueueMusicStream("Base.rte/Music/Watts/Last Man.ogg"); - g_AudioMan.QueueSilence(30); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); - - return error; -} + // Delivery craft appear straight over the selected LZ + pDeliveryCraft->SetPos(Vector(m_LandingZone[player].m_X, spawnY)); + // pDeliveryCraft->SetPos(Vector(m_LandingZone[player].m_X, 300)); + pDeliveryCraft->SetTeam(team); + // TODO: The after-delivery AI mode needs to be set depending on what the user has set in teh LZ selection mode + pDeliveryCraft->SetControllerMode(Controller::CIM_AI); + pDeliveryCraft->SetAIMode(m_AIReturnCraft[player] ? Actor::AIMODE_DELIVER : Actor::AIMODE_STAY); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + // Prepare the Delivery struct and stuff the ready to go craft in there + Delivery newDelivery; + // Pass ownership of the craft to the new Delivery struct + newDelivery.pCraft = pDeliveryCraft; + newDelivery.orderedByPlayer = player; + newDelivery.landingZone = m_LandingZone[player]; + newDelivery.multiOrderYOffset = 0; + newDelivery.delay = m_DeliveryDelay * pDeliveryCraft->GetDeliveryDelayMultiplier(); + newDelivery.timer.Reset(); -void GameActivity::SetPaused(bool pause) -{ - Activity::SetPaused(pause); -} + // Add the new Delivery to the queue + m_Deliveries[team].push_back(newDelivery); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. - -void GameActivity::End() -{ - Activity::End(); - - bool playerWon = false; - - // Disable control of actors.. will be handed over to the observation targets instead - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(player)); - - if (m_Team[player] == m_WinnerTeam) - { - playerWon = true; - // Set the winner's observation view to his controlled actors instead of his brain - if (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) - m_ObservationTarget[player] = m_ControlledActor[player]->GetPos(); - } - } - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { - if (MovableObject* asMo = dynamic_cast(itr->pCraft)) { - asMo->DestroyScriptState(); - } - delete itr->pCraft; - } - m_Deliveries[team].clear(); - } - - -/* Now controlled by the scripted activities - // Play the approriate tune on player win/lose - if (playerWon) - { -// Didn't work well, has gap between intro and loop tracks -// g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/uwinintro.ogg", 0); -// g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/uwinloop.ogg"); - g_AudioMan.ClearMusicQueue(); - // Loop it twice, nice tune! - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/uwinfinal.ogg", 2); - g_AudioMan.QueueSilence(10); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); - } - else - { - g_AudioMan.ClearMusicQueue(); - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/udiedfinal.ogg", 0); - g_AudioMan.QueueSilence(10); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); - } -*/ - - m_ActivityState = ActivityState::Over; - m_GameOverTimer.Reset(); -} + pDeliveryCraft = 0; + pLastPassenger = 0; + // Deduct cost from team's funds + m_TeamFunds[team] -= totalCost; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateEditing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: This is a special update step for when any player is still editing the -// scene. - -void GameActivity::UpdateEditing() -{ - // Editing the scene, just update the editor guis and see if players are ready to start or not - if (m_ActivityState != ActivityState::Editing) - return; - - /////////////////////////////////////////// - // Iterate through all human players - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - m_pEditorGUI[player]->Update(); - - // Set the team associations with each screen displayed - g_CameraMan.SetScreenTeam(m_Team[player], ScreenOfPlayer(player)); - - // Check if the player says he's done editing, and if so, make sure he really is good to go - if (m_pEditorGUI[player]->GetEditorGUIMode() == SceneEditorGUI::DONEEDITING) - { - // See if a brain has been placed yet by this player - IN A VALID LOCATION - if (!m_pEditorGUI[player]->TestBrainResidence()) - { - // Hm not ready yet without resident brain in the right spot, so let user know - m_ReadyToStart[player] = false; - const Entity *pBrain = g_PresetMan.GetEntityPreset("Actor", "Brain Case"); - if (pBrain) - m_pEditorGUI[player]->SetCurrentObject(dynamic_cast(pBrain->Clone())); - m_pEditorGUI[player]->SetEditorGUIMode(SceneEditorGUI::INSTALLINGBRAIN); - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - g_FrameMan.SetScreenText("PLACE YOUR BRAIN IN A VALID SPOT FIRST!", ScreenOfPlayer(player), 250, 3500); - m_MessageTimer[player].Reset(); - } - // Ready to start - else - { - m_ReadyToStart[player] = true; - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - g_FrameMan.SetScreenText("READY to start - wait for others to finish...", ScreenOfPlayer(player), 333); - m_pEditorGUI[player]->SetEditorGUIMode(SceneEditorGUI::ADDINGOBJECT); - } - } - - // Keep showing ready message - if (m_ReadyToStart[player]) - g_FrameMan.SetScreenText("READY to start - wait for others to finish...", ScreenOfPlayer(player), 333); - } - - // Have all players flagged themselves as ready to start the game? - bool allReady = true; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - if (!m_ReadyToStart[player]) - allReady = false; - } - - // YES, we are allegedly all ready to stop editing and start the game! - if (allReady) - { - // Make sure any players haven't moved or entombed their brains in the period after flagging themselves "done" - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - // See if a brain has been placed yet by this player - IN A VALID LOCATION - if (!m_pEditorGUI[player]->TestBrainResidence()) - { - // Hm not ready yet without resident brain in the right spot, so let user know - m_ReadyToStart[player] = false; - allReady = false; - const Entity *pBrain = g_PresetMan.GetEntityPreset("Actor", "Brain Case"); - if (pBrain) - m_pEditorGUI[player]->SetCurrentObject(dynamic_cast(pBrain->Clone())); - m_pEditorGUI[player]->SetEditorGUIMode(SceneEditorGUI::INSTALLINGBRAIN); - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - g_FrameMan.SetScreenText("PLACE YOUR BRAIN IN A VALID SPOT FIRST!", ScreenOfPlayer(player), 333, 3500); - m_MessageTimer[player].Reset(); - } - } - - // Still good to go?? - if (allReady) - { - // All resident brains are still in valid spots - place them into the simulation - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - // Place this player's resident brain into the simulation and set it as the player's assigned brain - g_SceneMan.GetScene()->PlaceResidentBrain(player, *this); - - // Still no brain of this player? Last ditch effort to find one and assign it to this player - if (!m_Brain[player]) - m_Brain[player] = g_MovableMan.GetUnassignedBrain(m_Team[player]); - // Um, something went wrong.. we're not done placing brains after all?? - if (!m_Brain[player]) - { - allReady = false; - // Get the brains back into residency so the players who are OK are still so - g_SceneMan.GetScene()->RetrieveResidentBrains(*this); - break; - } - - // Set the brain to be the selected actor at start - SwitchToActor(m_Brain[player], player, m_Team[player]); - m_ActorCursor[player] = m_Brain[player]->GetPos(); - m_LandingZone[player].m_X = m_Brain[player]->GetPos().m_X; - // Set the observation target to the brain, so that if/when it dies, the view flies to it in observation mode - m_ObservationTarget[player] = m_Brain[player]->GetPos(); - // CLear the messages before starting the game - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - // Reset the screen occlusion if any players are still in menus - g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(player)); - } - } - - // Still good to go?? then GO - if (allReady) - { - // START the game! - m_ActivityState = ActivityState::Running; - // Re-enable the AI's if we are done editing - DisableAIs(false); - InitAIs(); - // Reset the mouse value and pathfinding so it'll know about the newly placed stuff - g_UInputMan.SetMouseValueMagnitude(0); - g_SceneMan.GetScene()->ResetPathFinding(); - // Start the in-game track - g_AudioMan.ClearMusicQueue(); - g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/cc2g.ogg", 0); - g_AudioMan.QueueSilence(30); - g_AudioMan.QueueMusicStream("Base.rte/Music/Watts/Last Man.ogg"); - g_AudioMan.QueueSilence(30); - g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); - } - } -} + // Go 'ding!', but only if player is human, or it may be confusing + if (PlayerHuman(player)) + g_GUISound.ConfirmSound()->Play(player); + // Clear out the override purchase list, whether anything was in there or not, it should not override twice. + m_PurchaseOverride[player].clear(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this GameActivity. Supposed to be done every frame -// before drawing. - -void GameActivity::Update() -{ - Activity::Update(); - - // Avoid game logic when we're editing - if (m_ActivityState == ActivityState::Editing) - { - UpdateEditing(); - return; - } - - /////////////////////////////////////////// - // Iterate through all human players - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - // The current player's team - int team = m_Team[player]; - if (team == Teams::NoTeam) - continue; - - // Temporary hack to avoid teh buy menu buy button to be pressed immediately after selecting an LZ for a previous order - bool skipBuyUpdate = false; - - // Set the team associations with each screen displayed - g_CameraMan.SetScreenTeam(team, ScreenOfPlayer(player)); - - ////////////////////////////////////////////////////// - // Assure that Controlled Actor is a safe pointer - - // Only allow this if player's brain is intact - if (m_Brain[player] && !m_Brain[player]->IsDead() ) - { - // Note that we have now had a brain - m_HadBrain[player] = true; - - // Tracking normally - if (m_ViewState[player] == ViewState::Normal) - { - // Get a next actor if there isn't one - if (!m_ControlledActor[player]) - SwitchToNextActor(player, team); - - // Continually set the observation target to the brain during play, so that if/when it dies, the view flies to it in observation mode - if (m_ActivityState != ActivityState::Over && m_ViewState[player] != ViewState::Observe) - m_ObservationTarget[player] = m_Brain[player]->GetPos(); - - // Save the location of the currently controlled actor so we can know where to watch if he died on us - if (g_MovableMan.IsActor(m_ControlledActor[player])) - { - m_DeathViewTarget[player] = m_ControlledActor[player]->GetPos(); - m_DeathTimer[player].Reset(); - } - // Add delay after death before switching so the death comedy can be witnessed - // Died, so enter death watch mode - else - { - LoseControlOfActor(player); - } - } - // Ok, done watching death comedy, now automatically switch - else if (m_ViewState[player] == ViewState::DeathWatch && m_DeathTimer[player].IsPastSimMS(1500)) - { - // Get a next actor if there isn't one - if (!m_ControlledActor[player]) - SwitchToNextActor(player, team); - - // If currently focused actor died, get next one - if (!g_MovableMan.IsActor(m_ControlledActor[player])) - SwitchToNextActor(player, team); - - if (m_ViewState[player] != ViewState::ActorSelect) - m_ViewState[player] = ViewState::Normal; - } - // Any other viewing mode and the actor died... go to deathwatch - else if (m_ControlledActor[player] && !g_MovableMan.IsActor(m_ControlledActor[player])) - { - LoseControlOfActor(player); - } - } - // Player brain is now gone! Remove any control he may have had - else if (m_HadBrain[player]) - { - if (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) - m_ControlledActor[player]->SetControllerMode(Controller::CIM_AI); - m_ControlledActor[player] = 0; - m_ViewState[player] = ViewState::Observe; - } - // Never had a brain, and no actor is selected, so just select the first one we do have - else if (m_ViewState[player] != ViewState::Observe && !g_MovableMan.IsActor(m_ControlledActor[player])) - { - // Only try to switch if there's somehting to switch to - if (!g_MovableMan.GetTeamRoster(team)->empty()) - SwitchToNextActor(player, team); - else - m_ControlledActor[player] = 0; - } - - // Player-commanded actor switching - if (m_ViewState[player] != ViewState::Observe) { - // Switch to brain actor directly if the player wants to - if (m_PlayerController[player].IsState(ACTOR_BRAIN) && m_ViewState[player] != ViewState::ActorSelect) { - SwitchToActor(m_Brain[player], player, team); - m_ViewState[player] = ViewState::Normal; - } else if (m_PlayerController[player].IsState(ACTOR_NEXT) && m_ViewState[player] != ViewState::ActorSelect && !m_pBuyGUI[player]->IsVisible() && !m_LuaLockActor[player]) { - // Switch to next actor if the player wants to. Don't do it while the buy menu is open - if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->SetEnabled(false); - } - - SwitchToNextActor(player, team); - m_ViewState[player] = ViewState::Normal; - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - } - // Switch to prev actor if the player wants to. Don't do it while the buy menu is open - else if (m_PlayerController[player].IsState(ACTOR_PREV) && m_ViewState[player] != ViewState::ActorSelect && !m_pBuyGUI[player]->IsVisible()) { - if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->SetEnabled(false); - } - - SwitchToPrevActor(player, team); - m_ViewState[player] = ViewState::Normal; - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - } else if (m_ViewState[player] != ViewState::ActorSelect && !m_pBuyGUI[player]->IsVisible() && !m_LuaLockActor[player] && (m_PlayerController[player].IsState(ACTOR_NEXT_PREP) || m_PlayerController[player].IsState(ACTOR_PREV_PREP))) { - // Go into manual actor select mode if either actor switch buttons are held for a duration - if (m_ActorSelectTimer[player].IsPastRealMS(250)) { - // Set cursor to start at the head of controlled actor - if (m_ControlledActor[player]) { - // Give switched from actor an AI controller - m_ControlledActor[player]->SetControllerMode(Controller::CIM_AI); - m_ControlledActor[player]->GetController()->SetDisabled(false); - m_ActorCursor[player] = m_ControlledActor[player]->GetCPUPos(); - m_CursorTimer.Reset(); - } - - m_ViewState[player] = ViewState::ActorSelect; - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - } - } else { - m_ActorSelectTimer[player].Reset(); - } - } - - //////////////////////////////////// - // Update sceneman scroll targets - - if (m_ViewState[player] == ViewState::Observe) - { - // If we're observing game over state, freeze the view for a bit so the player's input doesn't ruin the focus - if (!(m_ActivityState == ActivityState::Over && !m_GameOverTimer.IsPastRealMS(1000))) - { - // Get cursor input - m_PlayerController[player].RelativeCursorMovement(m_ObservationTarget[player], 1.2f); - } - // Set the view to the observation position - g_SceneMan.ForceBounds(m_ObservationTarget[player]); - g_CameraMan.SetScrollTarget(m_ObservationTarget[player], 0.1, ScreenOfPlayer(player)); - } - - /////////////////////////////////////////////////// - // Manually selecting a new actor to switch to - - else if (m_ViewState[player] == ViewState::ActorSelect) - { - // Continuously display message - g_FrameMan.SetScreenText("Select a body to switch control to...", ScreenOfPlayer(player)); - // Get cursor input - m_PlayerController[player].RelativeCursorMovement(m_ActorCursor[player]); - - // Find the actor closest to the cursor, if any within the radius - Vector markedDistance; - Actor *pMarkedActor = g_MovableMan.GetClosestTeamActor(team, player, m_ActorCursor[player], g_SceneMan.GetSceneWidth(), markedDistance, true); -// Actor *pMarkedActor = g_MovableMan.GetClosestTeamActor(team, player, m_ActorCursor[player], g_FrameMan.GetPlayerScreenWidth() / 4); - - // Player canceled selection of actor - if (m_PlayerController[player].IsState(PRESS_SECONDARY)) { - // Reset the mouse so the actor doesn't change aim because mouse has been moved - if (m_PlayerController[player].IsMouseControlled()) { g_UInputMan.SetMouseValueMagnitude(0); } - - m_ViewState[player] = ViewState::Normal; - g_GUISound.UserErrorSound()->Play(player); - if (m_ControlledActor[player]) { - if (m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); - } - m_ControlledActor[player]->SetControllerMode(Controller::CIM_PLAYER, player); - } - if (pMarkedActor && pMarkedActor->GetPieMenu()) { - pMarkedActor->GetPieMenu()->DoDisableAnimation(); - } - } - // Player is done selecting new actor; switch to it if we have anything marked - else if (m_PlayerController[player].IsState(ACTOR_NEXT) || m_PlayerController[player].IsState(ACTOR_PREV) || m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) { - // Reset the mouse so the actor doesn't change aim because mouse has been moved - if (m_PlayerController[player].IsMouseControlled()) { g_UInputMan.SetMouseValueMagnitude(0); } + return true; + } - if (pMarkedActor) { - SwitchToActor(pMarkedActor, player, team); - } else { - g_GUISound.UserErrorSound()->Play(player); - } + return false; + } - m_ViewState[player] = ViewState::Normal; - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - // Flash the same actor, jsut to show the control went back to him - if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); - } - } - else if (pMarkedActor && pMarkedActor->GetPieMenu()) { - int quarterFrameBuffer = g_FrameMan.GetPlayerFrameBufferWidth(player) / 4; - if (markedDistance.MagnitudeIsGreaterThan(static_cast(quarterFrameBuffer))) { - pMarkedActor->GetPieMenu()->Wobble(); - } else { - pMarkedActor->GetPieMenu()->FreezeAtRadius(30); - } - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetupPlayers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Precalculates the player-to-screen index map, counts the number of + // active players, teams etc. - // Set the view to the cursor pos - g_SceneMan.ForceBounds(m_ActorCursor[player]); - g_CameraMan.SetScrollTarget(m_ActorCursor[player], 0.1, ScreenOfPlayer(player)); + void GameActivity::SetupPlayers() { + Activity::SetupPlayers(); - if (m_pLastMarkedActor[player]) { - if (!g_MovableMan.ValidMO(m_pLastMarkedActor[player])) { - m_pLastMarkedActor[player] = nullptr; - } else if (m_pLastMarkedActor[player] != pMarkedActor && m_pLastMarkedActor[player]->GetPieMenu()) { - m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); - } - } - if (pMarkedActor) { m_pLastMarkedActor[player] = pMarkedActor; } - } - - /////////////////////////////////////////////////// - // Selecting points on the scene for the AI to go to - - else if (m_ViewState[player] == ViewState::AIGoToPoint) - { - // Continuously display message - g_FrameMan.SetScreenText("Set waypoints for the AI to go to...", ScreenOfPlayer(player)); - // Get cursor input - m_PlayerController[player].RelativeCursorMovement(m_ActorCursor[player]); - - // If we are pointing to an actor to follow, then snap cursor to that actor's position - Actor *pTargetActor = 0; - Vector distance; - if (pTargetActor = g_MovableMan.GetClosestActor(m_ActorCursor[player], 40, distance, m_ControlledActor[player]); pTargetActor && pTargetActor->GetPieMenu()) { - if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { - m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); - } - pTargetActor->GetPieMenu()->FreezeAtRadius(15); - m_pLastMarkedActor[player] = pTargetActor; - } else if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { - m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); - } + // Add the locked cpu team that can't have any players + if (m_CPUTeam != Teams::NoTeam && !m_TeamActive[m_CPUTeam]) { + m_TeamCount++; + // Also activate the CPU team + m_TeamActive[m_CPUTeam] = true; + } - // Set the view to the cursor pos - g_SceneMan.ForceBounds(m_ActorCursor[player]); - g_CameraMan.SetScrollTarget(m_ActorCursor[player], 0.1, ScreenOfPlayer(player)); - - // Draw the actor's waypoints - m_ControlledActor[player]->DrawWaypoints(true); - - // Disable the actor's controller - m_ControlledActor[player]->GetController()->SetDisabled(true); - - // Player is done setting waypoints - if (m_PlayerController[player].IsState(PRESS_SECONDARY) || m_PlayerController[player].IsState(ACTOR_NEXT_PREP) || m_PlayerController[player].IsState(ACTOR_PREV_PREP)) { - // Stop drawing the waypoints -// m_ControlledActor[player]->DrawWaypoints(false); - // Update the player's move path now to the first waypoint set - m_ControlledActor[player]->UpdateMovePath(); - // Give player control back to actor - m_ControlledActor[player]->GetController()->SetDisabled(false); - // Switch back to normal view - m_ViewState[player] = ViewState::Normal; - // Stop displaying the message - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { - m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); - } - } - // Player set a new waypoint - else if (m_ControlledActor[player] && m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) - { -// TODO: Sound? - // If we are pointing to an actor to follow, tehn give that kind of waypoint command - if (pTargetActor) - m_ControlledActor[player]->AddAIMOWaypoint(pTargetActor); - // Just pointing into somewhere in the scene, so give that command - else - m_ControlledActor[player]->AddAISceneWaypoint(m_ActorCursor[player]); - // Update the player's move path now to the first waypoint set - m_ControlledActor[player]->UpdateMovePath(); - if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { - m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); - } - } - } - else if (m_ViewState[player] == ViewState::UnitSelectCircle) - { - // Continuously display message - g_FrameMan.SetScreenText("Select units to group...", ScreenOfPlayer(player)); - - m_PlayerController[player].RelativeCursorMovement(m_ActorCursor[player]); - - Vector relativeToActor = m_ActorCursor[player] - m_ControlledActor[player]->GetPos(); - - float sceneWidth = static_cast(g_SceneMan.GetSceneWidth()); - float seamMinimum = 350.0F; - - //Check if we crossed the seam - if (g_SceneMan.GetScene()->WrapsX()) { - float halfSceneWidth = sceneWidth * 0.5F; - if (relativeToActor.MagnitudeIsGreaterThan(std::max(halfSceneWidth, seamMinimum))) { - if (m_ActorCursor->m_X < halfSceneWidth) { - relativeToActor = m_ActorCursor[player] + Vector(sceneWidth, 0) - m_ControlledActor[player]->GetPos(); - } else { - relativeToActor = m_ActorCursor[player] - Vector(sceneWidth, 0) - m_ControlledActor[player]->GetPos(); - } - } + // Don't clear a CPU team's active status though + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (m_TeamIsCPU[team] && !m_TeamActive[team]) { + m_TeamCount++; + m_TeamActive[team] = true; } + } + } - // Limit selection range - relativeToActor = relativeToActor.CapMagnitude(seamMinimum); - m_ActorCursor[player] = m_ControlledActor[player]->GetPos() + relativeToActor; - - bool wrapped; - - // Set the view to the cursor pos - wrapped = g_SceneMan.ForceBounds(m_ActorCursor[player]); - //g_CameraMan.SetScrollTarget(m_ActorCursor[player], 0.1, wrapped, ScreenOfPlayer(player)); - - // Set the view to the actor pos - Vector scrollPos = Vector(m_ControlledActor[player]->GetPos()); - g_SceneMan.ForceBounds(scrollPos); - g_CameraMan.SetScrollTarget(scrollPos, 0.1, ScreenOfPlayer(player)); - - // Disable the actor's controller - m_ControlledActor[player]->GetController()->SetDisabled(true); - - // Player is done setting waypoints - if (m_PlayerController[player].IsState(PRESS_SECONDARY) || m_PlayerController[player].IsState(ACTOR_NEXT_PREP) || m_PlayerController[player].IsState(ACTOR_PREV_PREP)) { - // Give player control back to actor - m_ControlledActor[player]->GetController()->SetDisabled(false); - // Switch back to normal view - m_ViewState[player] = ViewState::Normal; - // Stop displaying the message - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - } - // Player set a new waypoint - else if (m_ControlledActor[player] && m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) - { - // m_ControlledActor[player]->AddAISceneWaypoint(m_ActorCursor[player]); - // Give player control back to actor - m_ControlledActor[player]->GetController()->SetDisabled(false); - // Switch back to normal view - m_ViewState[player] = ViewState::Normal; - // Stop displaying the message - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - - //Switch commander to sentry mode - m_ControlledActor[player]->SetAIMode(Actor::AIMODE_SENTRY); - - // Detect nearby actors and attach them to commander - float sqrRadius = g_SceneMan.ShortestDistance(m_ActorCursor[player],m_ControlledActor[player]->GetPos(), true).GetSqrMagnitude(); - - Actor *pActor = 0; - Actor *pFirstActor = 0; - - // Get the first one - pFirstActor = pActor = g_MovableMan.GetNextTeamActor(m_ControlledActor[player]->GetTeam()); - - do - { - // Set up commander if actor is not player controlled and not brain - if (pActor && !pActor->GetController()->IsPlayerControlled() && !pActor->IsInGroup("Brains")) - { - // If human, set appropriate AI mode - if (dynamic_cast(pActor) || dynamic_cast(pActor)) - if (g_SceneMan.ShortestDistance(m_ControlledActor[player]->GetPos(), pActor->GetPos(),true).GetSqrMagnitude() < sqrRadius) - { - pActor->FlashWhite(); - pActor->ClearAIWaypoints(); - pActor->SetAIMode(Actor::AIMODE_SQUAD); - pActor->AddAIMOWaypoint(m_ControlledActor[player]); - pActor->UpdateMovePath(); // Make sure pActor has m_ControlledActor registered as an AIMOWaypoint - } - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. + + int GameActivity::Start() { + // Set the split screen config before the Scene (and it SceneLayers, specifially) are loaded + int humanCount = GetHumanCount(); + // Depending on the resolution aspect ratio, split first horizontally (if wide screen) + if (((float)g_WindowMan.GetResX() / (float)g_WindowMan.GetResY()) >= 1.6) + g_FrameMan.ResetSplitScreens(humanCount > 1, humanCount > 2); + // or vertically (if 4:3-ish) + else + g_FrameMan.ResetSplitScreens(humanCount > 2, humanCount > 1); - // Next! - pActor = g_MovableMan.GetNextTeamActor(team, pActor); - } - while (pActor && pActor != pFirstActor); - } - } - /////////////////////////////////////////////////// - // Selecting LZ, a place for the craft to land - - else if (m_ViewState[player] == ViewState::LandingZoneSelect) - { - g_FrameMan.SetScreenText("Choose your landing zone... Hold UP or DOWN to place multiple orders", ScreenOfPlayer(player)); - - // Save the x pos so we can see which direction the user is moving it - float prevLZX = m_LandingZone[player].m_X; - - // See if there's analog input - if (m_PlayerController[player].GetAnalogMove().m_X > 0.1) - m_LandingZone[player].m_X += m_PlayerController[player].GetAnalogMove().m_X * 8; - // Try the mouse - else if (!m_PlayerController[player].GetMouseMovement().IsZero()) - m_LandingZone[player].m_X += m_PlayerController[player].GetMouseMovement().m_X; - // Digital movement - else - { - if (m_PlayerController[player].IsState(MOVE_RIGHT)) - m_LandingZone[player].m_X += 8; - else if (m_PlayerController[player].IsState(MOVE_LEFT)) - m_LandingZone[player].m_X -= 8; - } - - // Limit the LZ selection to the special LZ Area:s both specified in the derived Activity and moving with the brain - if (!m_LandingZoneArea[m_Team[player]].HasNoArea()) - { - // Add up the static LZ loaded from the Scene to the one(s) around the player's team's brains - Scene::Area totalLZ(m_LandingZoneArea[m_Team[player]]); -/* This whole concept kinda sucks - defensive AA robots are more fun way to go to prevent bumrushing the brain with craft - for (int p = Players::PlayerOne; p < Players::MaxPlayerCount; ++p) - { - if (!(m_IsActive[p] && m_IsHuman[p] && m_BrainLZWidth[p] > 0)) - continue; - // Same team as this player and has a brain - if (m_Brain[p] && m_Team[p] == m_Team[player]) - { - Box brainBox(Vector(0, 0), m_BrainLZWidth[p], 100); - // Center the brain LZ box aroud the player's brain - brainBox.SetCenter(m_Brain[p]->GetPos()); - // Add it to the total LZ - totalLZ.AddBox(brainBox); - } - } -*/ - // Move the actual LZ cursor to within the valid LZ Area. We pass in 0 for direction so it doesn't try to wrap around on wrapping maps. - totalLZ.MovePointInsideX(m_LandingZone[player].m_X, 0); - } - - // Interface for the craft AI post-delivery mode - if (m_PlayerController[player].IsState(PRESS_DOWN)) { - if (m_AIReturnCraft[player]) { g_GUISound.SelectionChangeSound()->Play(player); } - - m_AIReturnCraft[player] = false; - } else if (m_PlayerController[player].IsState(PRESS_UP)) { - if (!m_AIReturnCraft[player]) { g_GUISound.SelectionChangeSound()->Play(player); } - - m_AIReturnCraft[player] = true; - } + int error = Activity::Start(); + if (error < 0) + return error; - // Player canceled the order while selecting LZ - can't be done in pregame - if (m_PlayerController[player].IsState(PRESS_SECONDARY) && m_ActivityState != ActivityState::PreGame) - { - // Switch back to normal view - m_ViewState[player] = ViewState::Normal; - // Play err sound to indicate cancellation - g_FrameMan.SetScreenText("Order canceled!", ScreenOfPlayer(player), 333); - m_MessageTimer[player].Reset(); - g_GUISound.UserErrorSound()->Play(player); - // Flash the same actor, jsut to show the control went back to him - if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); - } - } else if (m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) { - m_LandingZone[player].m_Y = 0; - float lzOffsetY = 0; - // Holding up or down will allow the player to make multiple orders without exiting the delivery phase. TODO: this should probably have a cooldown? - if (!m_PlayerController[player].IsState(MOVE_UP) && !m_PlayerController[player].IsState(MOVE_DOWN)) { - m_LandingZone[player].m_Y = g_SceneMan.FindAltitude(m_LandingZone[player], g_SceneMan.GetSceneHeight(), 10, true); - if (!g_MovableMan.GetNextTeamActor(team)) { - m_ObservationTarget[player] = m_LandingZone[player]; - m_ViewState[player] = ViewState::Observe; - } else { - m_ViewState[player] = ViewState::Normal; - } - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { - m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); - } + m_WinnerTeam = Teams::NoTeam; - CreateDelivery(player); - } else { - // Place the new marker above the cursor so that they don't intersect with each other. - lzOffsetY += m_AIReturnCraft[player] ? -32.0F : 32.0F; - if (g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { - lzOffsetY *= -1.0f; - } + //////////////////////////////// + // Set up teams - m_LandingZone[player].m_Y = g_SceneMan.FindAltitude(m_LandingZone[player], g_SceneMan.GetSceneHeight(), 10, true) + lzOffsetY; + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; - if (m_pBuyGUI[player]->GetTotalOrderCost() > GetTeamFunds(team)) { - g_GUISound.UserErrorSound()->Play(player); - m_FundsChanged[team] = true; - if (!g_MovableMan.GetNextTeamActor(team)) { - m_ObservationTarget[player] = m_LandingZone[player]; - m_ViewState[player] = ViewState::Observe; - } else { - m_ViewState[player] = ViewState::Normal; - } - } else { - CreateDelivery(player); - m_Deliveries[team].rbegin()->multiOrderYOffset = lzOffsetY; - } - } - // Revert the Y offset so that the cursor doesn't flinch. - m_LandingZone[player].m_Y -= lzOffsetY; + m_Deliveries[team].clear(); + + // Clear delivery queues + for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { + delete itr->pCraft; } - g_SceneMan.ForceBounds(m_LandingZone[player]); - - // Interpolate the LZ altitude to the height of the highest terrain point at the player-chosen X - float prevHeight = m_LandingZone[player].m_Y; - - float viewOffset = g_FrameMan.GetPlayerScreenHeight() / 4; - m_LandingZone[player].m_Y = 0.0f; - if (g_SceneMan.GetTerrain() && g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { - m_LandingZone[player].m_Y = g_SceneMan.GetSceneHeight(); - viewOffset *= -1; - } - - m_LandingZone[player].m_Y = prevHeight + ((g_SceneMan.FindAltitude(m_LandingZone[player], g_SceneMan.GetSceneHeight(), 10, true) - prevHeight) * 0.2); - - // Set the view to a little above the LZ position - Vector viewTarget(m_LandingZone[player].m_X, m_LandingZone[player].m_Y - viewOffset); - g_CameraMan.SetScrollTarget(viewTarget, 0.1, ScreenOfPlayer(player)); - } - - //////////////////////////// - // Deathwatching - - else if (m_ViewState[player] == ViewState::DeathWatch) - { - // Continuously deathwatch message - g_FrameMan.SetScreenText("Lost control of remote body!", ScreenOfPlayer(player)); - // Don't move anything, just stay put watching the death funnies - g_CameraMan.SetScrollTarget(m_DeathViewTarget[player], 0.1, ScreenOfPlayer(player)); - } - - //////////////////////////////////////////////////// - // Normal scrolling to view the currently controlled Actor - // But only if we're not editing something, because editor will scroll the screen himself - // and double scrolling will cause CC gitch when we'll cross the seam - else if (m_ControlledActor[player] && m_ActivityState != ActivityState::Editing && m_ActivityState != ActivityState::PreGame) - { - g_CameraMan.SetScrollTarget(m_ControlledActor[player]->GetViewPoint(), 0.1, ScreenOfPlayer(player)); - } - - if (m_ControlledActor[player] && m_ViewState[player] != ViewState::DeathWatch && m_ViewState[player] != ViewState::ActorSelect && m_ViewState[player] != ViewState::AIGoToPoint && m_ViewState[player] != ViewState::UnitSelectCircle) { - PieMenu *controlledActorPieMenu = m_ControlledActor[player]->GetPieMenu(); - if (controlledActorPieMenu && m_ControlledActor[player]->GetController()->IsState(PIE_MENU_ACTIVE)) { - if (!m_BuyMenuEnabled && controlledActorPieMenu->IsEnabling()) { - controlledActorPieMenu->RemovePieSlicesByType(PieSlice::SliceType::BuyMenu); - } + m_Deliveries[team].clear(); + /* This is taken care of by the individual Activity logic + // See if there are specified landing zone areas defined in the scene + char str[64]; + std::snprintf(str, sizeof(str), "LZ Team %d", team + 1); + Scene::Area *pArea = g_SceneMan.GetScene()->GetArea(str); + pArea = pArea ? pArea : g_SceneMan.GetScene()->GetArea("Landing Zone"); + // If area is defined, save a copy so we can lock the LZ selection to within its boxes + if (pArea && !pArea->HasNoArea()) + m_LandingZoneArea[team] = *pArea; + */ + } - if (controlledActorPieMenu->IsEnabled() && controlledActorPieMenu->HasSubPieMenuOpen() && m_InventoryMenuGUI[player]->GetMenuMode() == InventoryMenuGUI::MenuMode::Carousel) { - m_InventoryMenuGUI[player]->SetEnabled(false); - } else if (m_InventoryMenuGUI[player]->GetMenuMode() == InventoryMenuGUI::MenuMode::Carousel || !m_InventoryMenuGUI[player]->IsVisible()) { - m_InventoryMenuGUI[player]->SetMenuMode(InventoryMenuGUI::MenuMode::Carousel); - m_InventoryMenuGUI[player]->EnableIfNotEmpty(); - } - } else if (!m_PlayerController[player].IsState(PIE_MENU_ACTIVE) && m_InventoryMenuGUI[player]->GetMenuMode() == InventoryMenuGUI::MenuMode::Carousel) { - m_InventoryMenuGUI[player]->SetEnabled(false); + /////////////////////////////////////// + // Set up human players + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + // Set the team associations with each screen displayed + g_CameraMan.SetScreenTeam(m_Team[player], ScreenOfPlayer(player)); + // And occlusion + g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(player)); + + // Allocate and (re)create the Inventory Menu GUIs + if (m_InventoryMenuGUI[player]) { + m_InventoryMenuGUI[player]->Destroy(); + } else { + m_InventoryMenuGUI[player] = new InventoryMenuGUI; } + m_InventoryMenuGUI[player]->Create(&m_PlayerController[player]); - if (PieSlice::SliceType command = controlledActorPieMenu->GetPieCommand(); command != PieSlice::SliceType::NoType) { - // AI mode commands that need extra points set in special view modes here - //TODO I don't think these viewstates are actually used?! - if (command == PieSlice::SliceType::Sentry) { - m_ViewState[player] = ViewState::AISentryPoint; - } else if (command == PieSlice::SliceType::Patrol) { - m_ViewState[player] = ViewState::AIPatrolPoints; - } else if (command == PieSlice::SliceType::GoldDig) { - m_ViewState[player] = ViewState::AIGoldDigPoint; - } else if (command == PieSlice::SliceType::GoTo) { - m_ViewState[player] = ViewState::AIGoToPoint; - m_ControlledActor[player]->ClearAIWaypoints(); - m_ActorCursor[player] = m_ControlledActor[player]->GetPos(); - m_ControlledActor[player]->GetController()->SetDisabled(true); - } else if (command == PieSlice::SliceType::FormSquad) { - //Find out if we have any connected units, and disconnect them - bool isCommander = false; - - Actor *pActor = 0; - Actor *pFirstActor = 0; + // Allocate and (re)create the Editor GUIs + if (m_pEditorGUI[player]) + m_pEditorGUI[player]->Destroy(); + else + m_pEditorGUI[player] = new SceneEditorGUI; + m_pEditorGUI[player]->Create(&m_PlayerController[player]); + m_ReadyToStart[player] = false; - pFirstActor = pActor = g_MovableMan.GetNextTeamActor(m_ControlledActor[player]->GetTeam()); + // Allocate and (re)create the Buy GUIs + if (m_pBuyGUI[player]) + m_pBuyGUI[player]->Destroy(); + else + m_pBuyGUI[player] = new BuyMenuGUI; + m_pBuyGUI[player]->Create(&m_PlayerController[player]); - // Reset commander if we have any subordinates - do { - if (pActor) { - // Set appropriate AI mode - if (dynamic_cast(pActor) || dynamic_cast(pActor)) - if (pActor->GetAIMOWaypointID() == m_ControlledActor[player]->GetID()) { - pActor->FlashWhite(); - pActor->ClearAIWaypoints(); - pActor->SetAIMode((Actor::AIMode)m_ControlledActor[player]->GetAIMode()); // Inherit the leader's AI mode - isCommander = true; - } - } - pActor = g_MovableMan.GetNextTeamActor(team, pActor); - } while (pActor && pActor != pFirstActor); + // Load correct loadouts into buy menu if we're starting a non meta-game activity + if (m_pBuyGUI[player]->GetMetaPlayer() == Players::NoPlayer) { + int techModuleID = g_PresetMan.GetModuleID(GetTeamTech(GetTeamOfPlayer(player))); - //Now turn on selection UI, if we didn't disconnect anyone - if (!isCommander) { - m_ViewState[player] = ViewState::UnitSelectCircle; - // Set cursor to the actor - m_ActorCursor[player] = m_ControlledActor[player]->GetPos() + Vector(50, -50); - // Disable Actor's controller while we set the waypoints - m_ControlledActor[player]->GetController()->SetDisabled(true); - if (controlledActorPieMenu) { - controlledActorPieMenu->SetEnabled(false); + m_pBuyGUI[player]->SetNativeTechModule(techModuleID); + m_pBuyGUI[player]->SetForeignCostMultiplier(1.0); + m_pBuyGUI[player]->LoadAllLoadoutsFromFile(); + + // Change Editor GUI native tech module so it could load and show correct deployment prices + m_pEditorGUI[player]->SetNativeTechModule(techModuleID); + } + + //////////////////////////////////// + // GUI split screen setup + // If there are split screens, set up the GUIs to draw and their mouses to point correctly + if (g_FrameMan.IsInMultiplayerMode()) { + m_pEditorGUI[player]->SetPosOnScreen(0, 0); + m_pBuyGUI[player]->SetPosOnScreen(0, 0); + } else { + if (g_FrameMan.GetScreenCount() > 1) { + // Screen 1 Always upper left corner + if (ScreenOfPlayer(player) == 0) { + m_pEditorGUI[player]->SetPosOnScreen(0, 0); + m_pBuyGUI[player]->SetPosOnScreen(0, 0); + } else if (ScreenOfPlayer(player) == 1) { + // If both splits, or just Vsplit, then in upper right quadrant + if ((g_FrameMan.GetVSplit() && !g_FrameMan.GetHSplit()) || (g_FrameMan.GetVSplit() && g_FrameMan.GetVSplit())) { + m_pEditorGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, 0); + m_pBuyGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, 0); + } + // If only hsplit, then lower left quadrant + else { + m_pEditorGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); + m_pBuyGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); } } - } else if (command == PieSlice::SliceType::BuyMenu) { - m_pBuyGUI[player]->SetEnabled(true); - skipBuyUpdate = true; - } else if (command == PieSlice::SliceType::FullInventory) { - controlledActorPieMenu->SetEnabled(false); - m_InventoryMenuGUI[player]->SetEnabled(false); - m_InventoryMenuGUI[player]->SetMenuMode(InventoryMenuGUI::MenuMode::Full); - m_InventoryMenuGUI[player]->SetEnabled(true); + // Screen 3 is lower left quadrant + else if (ScreenOfPlayer(player) == 2) { + m_pEditorGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); + m_pBuyGUI[player]->SetPosOnScreen(0, g_WindowMan.GetResY() / 2); + } + // Screen 4 is lower right quadrant + else if (ScreenOfPlayer(player) == 3) { + m_pEditorGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, g_WindowMan.GetResY() / 2); + m_pBuyGUI[player]->SetPosOnScreen(g_WindowMan.GetResX() / 2, g_WindowMan.GetResY() / 2); + } } - m_ControlledActor[player]->HandlePieCommand(command); } - m_InventoryMenuGUI[player]->SetInventoryActor(m_ControlledActor[player]); - m_InventoryMenuGUI[player]->Update(); - } + // Allocate and (re)create the banners + if (m_pBannerRed[player]) + m_pBannerRed[player]->Destroy(); + else + m_pBannerRed[player] = new GUIBanner; + m_pBannerRed[player]->Create("Base.rte/GUIs/Fonts/BannerFontRedReg.png", "Base.rte/GUIs/Fonts/BannerFontRedBlur.png", 8); - /////////////////////////////////////// - // Update Buy Menu GUIs - - // Enable or disable the Buy Menus if the brain is selected, Skip if an LZ selection button press was just performed - if (!skipBuyUpdate) - { -// m_pBuyGUI[player]->SetEnabled(m_ControlledActor[player] == m_Brain[player] && m_ViewState[player] != ViewState::LandingZoneSelect && m_ActivityState != ActivityState::Over); - m_pBuyGUI[player]->Update(); - } - - // Trap the mouse if we're in gameplay and not in menus - g_UInputMan.TrapMousePos(!m_pBuyGUI[player]->IsEnabled() && !m_InventoryMenuGUI[player]->IsEnabledAndNotCarousel() && !m_LuaLockActor[player], player); - - // Start LZ picking mode if a purchase was made - if (m_pBuyGUI[player]->PurchaseMade()) - { - m_LZCursorWidth[player] = std::min(m_pBuyGUI[player]->GetDeliveryWidth(), g_FrameMan.GetPlayerScreenWidth() - 24); - m_pBuyGUI[player]->SetEnabled(false); -// SwitchToPrevActor(player, team, m_Brain[player]); - // Start selecting the landing zone - m_ViewState[player] = ViewState::LandingZoneSelect; - - // Set this to zero so the cursor interpolates down from the sky - float landingSpot = 0.0f; - if (g_SceneMan.GetTerrain() && g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { - landingSpot = g_SceneMan.GetSceneHeight(); - } - - m_LandingZone[player].m_Y = landingSpot; - } - - // After a while of game over, change messages to the final one for everyone - if (m_ActivityState == ActivityState::Over && m_GameOverTimer.IsPastRealMS(m_GameOverPeriod)) - { - g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); - //g_FrameMan.SetScreenText("Press [Esc] to leave the battlefield", ScreenOfPlayer(player), 750); - if (g_FrameMan.IsInMultiplayerMode()) - g_FrameMan.SetScreenText("All players must press and hold [BACKSPACE] to continue!", ScreenOfPlayer(player), 750); + // Allocate and (re)create the banners + if (m_pBannerYellow[player]) + m_pBannerYellow[player]->Destroy(); else - g_FrameMan.SetScreenText("Press [SPACE] or [START] to continue!", ScreenOfPlayer(player), 750); - - // Actually end on space - if (m_GameOverTimer.IsPastSimMS(55000) || g_UInputMan.AnyStartPress()) - { - g_ActivityMan.EndActivity(); - g_ActivityMan.SetInActivity(false); - } - } - - /////////////////////////////////// - // Enable/disable controlled actors' AI as appropriate when in menus - - if (m_ControlledActor[player] && m_ControlledActor[player]->GetController()->GetPlayerRaw() == player) - { - // Don't disable when pie menu is active; it is done inside the Controller Update - if (m_pBuyGUI[player]->IsVisible() || m_ViewState[player] == ViewState::ActorSelect || m_ViewState[player] == ViewState::LandingZoneSelect || m_ViewState[player] == ViewState::Observe) { - m_ControlledActor[player]->GetController()->SetInputMode(Controller::CIM_AI); - } else if (m_InventoryMenuGUI[player]->IsEnabledAndNotCarousel()) { - m_ControlledActor[player]->GetController()->SetInputMode(Controller::CIM_DISABLED); - } else if (m_LuaLockActor[player]) { - m_ControlledActor[player]->GetController()->SetInputMode(m_LuaLockActorMode[player]); - } else { - m_ControlledActor[player]->GetController()->SetInputMode(Controller::CIM_PLAYER); - } - } - - /////////////////////////////////////// - // Configure banners to show when important things happen, like the game over or death of brain - - if (IsOver()) - { - // Override previous messages - if (m_pBannerRed[player]->IsVisible() && m_pBannerRed[player]->GetBannerText() != "FAIL") - m_pBannerRed[player]->HideText(2500, 0); - if (m_pBannerYellow[player]->IsVisible() && m_pBannerYellow[player]->GetBannerText() != "WIN") - m_pBannerYellow[player]->HideText(2500, 0); - - // Player on a winning team - if (GetWinnerTeam() == m_Team[player] && !m_pBannerYellow[player]->IsVisible()) - m_pBannerYellow[player]->ShowText("WIN", GUIBanner::FLYBYRIGHTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); - - // Loser player - if (GetWinnerTeam() != m_Team[player] && !m_pBannerRed[player]->IsVisible()) - m_pBannerRed[player]->ShowText("FAIL", GUIBanner::FLYBYLEFTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); - } - // If a player had a brain that is now dead, but his team is not yet done, show the dead banner on his screen - else if (m_ActivityState != ActivityState::Editing && m_ActivityState != ActivityState::Starting && m_HadBrain[player] && !m_Brain[player] && !m_pBannerRed[player]->IsVisible()) - { - // If repeated too many times, just let the banner stop at showing and not cycle - if (m_BannerRepeats[player]++ < 6) - m_pBannerRed[player]->ShowText("DEAD", GUIBanner::FLYBYLEFTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); - else - m_pBannerRed[player]->ShowText("DEAD", GUIBanner::FLYBYLEFTWARD, -1, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); - } - - /////////////////////////////////////// - // Update message banners - - m_pBannerRed[player]->Update(); - m_pBannerYellow[player]->Update(); - } - - /////////////////////////////////////////// - // Iterate through all teams - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - - // Pause deliveries if game hasn't started yet - if (m_ActivityState == ActivityState::PreGame) - { - for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) - (*itr).timer.Reset(); - } - - //////////////////////////////// - // Delivery status update - - if (!m_Deliveries[team].empty()) - { - int player = m_Deliveries[team].front().orderedByPlayer; - if (m_MessageTimer[player].IsPastSimMS(1000)) - { - char message[512]; - std::snprintf(message, sizeof(message), "Next delivery in %i secs", ((int)m_Deliveries[team].front().delay - (int)m_Deliveries[team].front().timer.GetElapsedSimTimeMS()) / 1000); - g_FrameMan.SetScreenText(message, ScreenOfPlayer(player)); - m_MessageTimer[player].Reset(); - } - } - - // Delivery has arrived! Unpack and put into the world - if (!m_Deliveries[team].empty() && m_Deliveries[team].front().timer.IsPastSimMS(m_Deliveries[team].front().delay)) - { - // This is transferring ownership of the craft instance from the Delivery struct - ACraft *pDeliveryCraft = m_Deliveries[team].front().pCraft; - int player = m_Deliveries[team].front().orderedByPlayer; - if (pDeliveryCraft) - { - g_FrameMan.SetScreenText("Your order has arrived!", ScreenOfPlayer(player), 333); - m_MessageTimer[player].Reset(); - - pDeliveryCraft->ResetAllTimers(); - pDeliveryCraft->Update(); - - // Add the delivery craft to the world, TRANSFERRING OWNERSHIP - g_MovableMan.AddActor(pDeliveryCraft); -/* - // If the player who ordered this seems stuck int he manu waiting for the delivery, give him direct control - if (m_ControlledActor[player] == m_Brain[player] && m_ViewState[player] != ViewState::LandingZoneSelect) - { - SwitchToActor(pDeliveryCraft, player, team); - } -*/ - } - m_Deliveries[team].pop_front(); - } - } - - /////////////////////////////////////////// - // Special observer mode for the FOURTH screen in a THREE player game -/* Problematic with new player scheme.. what if the fourth player is active?? - if (m_PlayerCount == 3) - { - // Update the controller of the observation view - m_PlayerController[Players::PlayerFour].Update(); - - // Observer user control override - if (m_PlayerController[Players::PlayerFour].RelativeCursorMovement(m_ObservationTarget[Players::PlayerFour], 1.2)) - m_DeathTimer[Players::PlayerFour].Reset(); - - // If no user input in a few seconds, start scrolling along the terrain - if (m_DeathTimer[Players::PlayerFour].IsPastSimMS(5000)) - { - // Make it scroll along - m_ObservationTarget[Players::PlayerFour].m_X += 0.5; - - // Make view follow the terrain - float prevHeight = m_ObservationTarget[Players::PlayerFour].m_Y; - m_ObservationTarget[Players::PlayerFour].m_Y = 0; - m_ObservationTarget[Players::PlayerFour].m_Y = prevHeight + ((g_SceneMan.FindAltitude(m_ObservationTarget[Players::PlayerFour], g_SceneMan.GetSceneHeight(), 20, true) - prevHeight) * 0.02); - } - - // Set the view to the observation position - g_CameraMan.SetScrollTarget(m_ObservationTarget[Players::PlayerFour], 0.1, g_SceneMan.ForceBounds(m_ObservationTarget[Players::PlayerFour]), ScreenOfPlayer(Players::PlayerFour)); - } -*/ -} + m_pBannerYellow[player] = new GUIBanner; + m_pBannerYellow[player]->Create("Base.rte/GUIs/Fonts/BannerFontYellowReg.png", "Base.rte/GUIs/Fonts/BannerFontYellowBlur.png", 8); + // Resetting the banner repeat counter + m_BannerRepeats[player] = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. - -void GameActivity::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - if (which < 0 || which >= c_MaxScreenCount) - return; - - char str[512]; - int yTextPos = 0; - int team = Teams::NoTeam; - int cursor = 0; - int PoS = PlayerOfScreen(which); - if (PoS < Players::PlayerOne || PoS >= Players::MaxPlayerCount) - return; - Box screenBox(targetPos, pTargetBitmap->w, pTargetBitmap->h); - GUIFont *pLargeFont = g_FrameMan.GetLargeFont(); - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); - AllegroBitmap pBitmapInt(pTargetBitmap); - int frame = ((int)m_CursorTimer.GetElapsedSimTimeMS() % 1000) / 250; - Vector landZone; - - // Iterate through all players, drawing each currently used LZ cursor. - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - if (m_ViewState[player] == ViewState::LandingZoneSelect) - { - int halfWidth = std::max(m_LZCursorWidth[player]/2, 36); - team = m_Team[player]; - if (team == Teams::NoTeam) - continue; - cursor = team; - landZone = m_LandingZone[player] - targetPos; - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); - pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 36, "and then", GUIFont::Centre); - pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); - // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap - if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) - { - // Wrap shit around and draw dupe on the other side - int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); - pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 36, "and then", GUIFont::Centre); - pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); - } - } - } - - // Iterate through all teams, drawing all pending delivery cursors - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - char str[64]; - cursor = team; - for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) - { - int halfWidth = 24; - landZone = itr->landingZone - targetPos; - bool anyPlayerOnTeamIsInLandingZoneSelectViewState = false; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - if (GetTeamOfPlayer(player) == team && m_ViewState[player] == ViewState::LandingZoneSelect) { - anyPlayerOnTeamIsInLandingZoneSelectViewState = true; - break; - } + // Draw GO! game start notification, if it's a new game + if (m_ActivityState == ActivityState::NotStarted) { + m_pBannerYellow[player]->ShowText("GO!", GUIBanner::FLYBYLEFTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 500); + g_FrameMan.SetScreenText((player % 2 == 0) ? "Mine Gold and buy more firepower with the funds..." : "...then smash the competing brain to claim victory!", ScreenOfPlayer(player), 0); } - if (!anyPlayerOnTeamIsInLandingZoneSelectViewState) { landZone.m_Y -= itr->multiOrderYOffset; } - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 38, "ETA:", GUIFont::Centre); - if (m_ActivityState == ActivityState::PreGame) - std::snprintf(str, sizeof(str), "???s"); - else - std::snprintf(str, sizeof(str), "%is", ((int)itr->delay - (int)itr->timer.GetElapsedSimTimeMS()) / 1000); - pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 32, str, GUIFont::Centre); - // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap - if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) - { - // Wrap shit around and draw dupe on the other side - int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 38, "ETA:", GUIFont::Centre); - pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 32, str, GUIFont::Centre); - } - } - } - - // The team of the screen - team = m_Team[PoS]; - if (team == Teams::NoTeam) - return; - - // None of the following player-specific GUI elements apply if this isn't a played human actor - if (!(m_IsActive[PoS] && m_IsHuman[PoS])) - return; - - // Get all possible wrapped boxes of the screen - std::list wrappedBoxes; - g_SceneMan.WrapBox(screenBox, wrappedBoxes); - Vector wrappingOffset, objScenePos, onScreenEdgePos; - float distance, shortestDist; - float sceneWidth = static_cast(g_SceneMan.GetSceneWidth()); - float halfScreenWidth = pTargetBitmap->w / 2; - float halfScreenHeight = pTargetBitmap->h / 2; - // THis is the max distance that is possible between a point inside the scene, but outside the screen box, and the screen box's outer edge closest to the point (taking wrapping into account) - float maxOffScreenSceneWidth = g_SceneMan.SceneWrapsX() ? ((sceneWidth / 2) - halfScreenWidth) : (sceneWidth - pTargetBitmap->w); - // These handle arranging the left and right stacks of arrows, so they don't pile up on top of each other - cursor = team; - float leftStackY = halfScreenHeight - m_aObjCursor[cursor][frame]->h * 2; - float rightStackY = leftStackY; - - // Draw the objective points this player should care about - for (std::list::iterator itr = m_Objectives.begin(); itr != m_Objectives.end(); ++itr) - { - // Only draw objectives of the same team as the current player - if (itr->m_Team == team) - { - // Iterate through the wrapped screen boxes - will only be one if there's no wrapping - // Try to the find one that contains the objective point - bool withinAny = false; - std::list::iterator nearestBoxItr = wrappedBoxes.begin(); - shortestDist = 1000000.0; - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - // See if we found the point to be within the screen or not - if (wItr->IsWithinBox((*itr).m_ScenePos)) - { - nearestBoxItr = wItr; - withinAny = true; - break; - } - // Well, which wrapped screen box is closest to the point? - distance = g_SceneMan.ShortestDistance(wItr->GetCenter(), (*itr).m_ScenePos).GetLargest(); - if (distance < shortestDist) - { - shortestDist = distance; - nearestBoxItr = wItr; - } - } - - // Get the difference that the wrapped screen has from the actual one - wrappingOffset = screenBox.GetCorner() - nearestBoxItr->GetCorner(); - // Apply that offet to the objective point's position - objScenePos = itr->m_ScenePos + wrappingOffset; - - // Objective is within the screen, so draw the set arrow over it - if (withinAny) - itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], objScenePos - targetPos, itr->m_ArrowDir); - // Outside the screen, so draw it at the edge of it - else - { - // Figure out which point is closest to the box, taking scene wrapping into account - objScenePos = nearestBoxItr->GetCenter() + g_SceneMan.ShortestDistance(nearestBoxItr->GetCenter(), objScenePos); - // Shortest distance from the edge of the screen box, not the center. - shortestDist -= halfScreenWidth; - - // Make the arrow point toward the edge of the screen - if (objScenePos.m_X >= nearestBoxItr->GetCorner().m_X + nearestBoxItr->GetWidth()) - { - // Make the edge position approach the center of the vertical edge of the screen the farther away the objective position is from the screen - onScreenEdgePos = nearestBoxItr->GetWithinBox(objScenePos) - targetPos; - // Double the EaseIn to make it even more exponential, want the arrow to stay close to the edge for a long time - onScreenEdgePos.m_Y = rightStackY + EaseIn(0, onScreenEdgePos.m_Y - rightStackY, EaseIn(0, 1.0, 1.0 - (shortestDist / maxOffScreenSceneWidth))); - itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], onScreenEdgePos, ARROWRIGHT); - // Stack cursor moves down an arrowheight - rightStackY += m_aObjCursor[cursor][frame]->h; - } - else if (objScenePos.m_X < nearestBoxItr->GetCorner().m_X) - { - // Make the edge position approach the center of the vertical edge of the screen the farther away the objective position is from the screen - onScreenEdgePos = nearestBoxItr->GetWithinBox(objScenePos) - targetPos; - // Double the EaseIn to make it even more exponential, want the arrow to stay close to the edge for a long time - onScreenEdgePos.m_Y = leftStackY + EaseIn(0, onScreenEdgePos.m_Y - leftStackY, EaseIn(0, 1.0, 1.0 - (shortestDist / maxOffScreenSceneWidth))); - itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], onScreenEdgePos, ARROWLEFT); - // Stack cursor moves down an arrowheight - leftStackY += m_aObjCursor[cursor][frame]->h; - } - else if (objScenePos.m_Y < nearestBoxItr->GetCorner().m_Y) - itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], nearestBoxItr->GetWithinBox(objScenePos) - targetPos, ARROWUP); - else - itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], nearestBoxItr->GetWithinBox(objScenePos) - targetPos, ARROWDOWN); - } - } - } - - // Team Icon up in the top left corner - const Icon *pIcon = GetTeamIcon(m_Team[PoS]); - if (pIcon) - draw_sprite(pTargetBitmap, pIcon->GetBitmaps8()[0], MAX(2, g_CameraMan.GetScreenOcclusion(which).m_X + 2), 2); - // Gold - std::snprintf(str, sizeof(str), "%c Funds: %.10g oz", TeamFundsChanged(which) ? -57 : -58, std::floor(GetTeamFunds(m_Team[PoS]))); - g_FrameMan.GetLargeFont()->DrawAligned(&pBitmapInt, MAX(16, g_CameraMan.GetScreenOcclusion(which).m_X + 16), yTextPos, str, GUIFont::Left); -/* Not applicable anymore to the 4-team games - // Body losses - std::snprintf(str, sizeof(str), "%c Losses: %c%i %c%i", -39, -62, GetTeamDeathCount(Teams::TeamOne), -59, GetTeamDeathCount(Teams::TeamTwo)); - g_FrameMan.GetLargeFont()->DrawAligned(&pBitmapInt, MIN(pTargetBitmap->w - 4, pTargetBitmap->w - 4 + g_CameraMan.GetScreenOcclusion(which).m_X), yTextPos, str, GUIFont::Right); -*/ - // Show the player's controller scheme icon in the upper right corner of his screen, but only for a minute - if (m_GameTimer.GetElapsedRealTimeS() < 30) - { -// TODO: Only blink if there hasn't been any input on a controller since start of game?? - // Blink them at first, but only if there's more than one human player - if (m_GameTimer.GetElapsedRealTimeS() > 4 || m_GameTimer.AlternateReal(150) || GetHumanCount() < 2) - { - pIcon = g_UInputMan.GetSchemeIcon(PoS); - if (pIcon) - { - draw_sprite(pTargetBitmap, pIcon->GetBitmaps8()[0], MIN(pTargetBitmap->w - pIcon->GetBitmaps8()[0]->w - 2, pTargetBitmap->w - pIcon->GetBitmaps8()[0]->w - 2 + g_CameraMan.GetScreenOcclusion(which).m_X), yTextPos); -// TODO: make a black Activity intro screen, saying "Player X, press any key/button to show that you are ready!, and display their controller icon, then fade into the scene" -// stretch_sprite(pTargetBitmap, pIcon->GetBitmaps8()[0], 10, 10, pIcon->GetBitmaps8()[0]->w * 4, pIcon->GetBitmaps8()[0]->h * 4); - } - } - } - - if (m_ActivityState == ActivityState::Running) { - if (m_InventoryMenuGUI[PoS] && m_InventoryMenuGUI[PoS]->IsVisible()) { m_InventoryMenuGUI[PoS]->Draw(pTargetBitmap, targetPos); } - if (m_pBuyGUI[PoS] && m_pBuyGUI[PoS]->IsVisible()) { m_pBuyGUI[PoS]->Draw(pTargetBitmap); } - } - - // Draw actor picking crosshairs if applicable - if (m_ViewState[PoS] == ViewState::ActorSelect && m_IsActive[PoS] && m_IsHuman[PoS]) - { - Vector center = m_ActorCursor[PoS] - targetPos; - circle(pTargetBitmap, center.m_X, center.m_Y, m_CursorTimer.AlternateReal(150) ? 6 : 8, g_YellowGlowColor); - // Add pixel glow area around it, in scene coordinates - g_PostProcessMan.RegisterGlowArea(m_ActorCursor[PoS], 10); -/* Crosshairs - putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); -*/ - } - // AI point commands cursor - else if (m_ViewState[PoS] == ViewState::AIGoToPoint) - { - Vector center = m_ActorCursor[PoS] - targetPos; - circle(pTargetBitmap, center.m_X, center.m_Y, m_CursorTimer.AlternateReal(150) ? 6 : 8, g_YellowGlowColor); - circlefill(pTargetBitmap, center.m_X, center.m_Y, 2, g_YellowGlowColor); -// putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); - // Add pixel glow area around it, in scene coordinates - g_PostProcessMan.RegisterGlowArea(m_ActorCursor[PoS], 10); - - // Draw a line from the last set waypoint to the cursor - if (m_ControlledActor[PoS] && g_MovableMan.IsActor(m_ControlledActor[PoS])) - g_FrameMan.DrawLine(pTargetBitmap, m_ControlledActor[PoS]->GetLastAIWaypoint() - targetPos, m_ActorCursor[PoS] - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); - } - // Group selection circle - else if (m_ViewState[PoS] == ViewState::UnitSelectCircle) - { - if (m_ControlledActor[PoS] && g_MovableMan.IsActor(m_ControlledActor[PoS])) - { - Vector cursorDrawPos = m_ActorCursor[PoS] - targetPos; - Vector actorPos = m_ControlledActor[PoS]->GetPos(); - Vector drawPos = actorPos - targetPos; - - //Fix cursor coordinates - if (!targetPos.IsZero()) - { - // Spans vertical scene seam - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) - { - if ((targetPos.m_X < 0) && (m_ActorCursor[PoS].m_X > (sceneWidth - pTargetBitmap->w))) - cursorDrawPos.m_X -= sceneWidth; - else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_ActorCursor[PoS].m_X < pTargetBitmap->w)) - cursorDrawPos.m_X += sceneWidth; - } - // Spans horizontal scene seam - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) - { - if ((targetPos.m_Y < 0) && (m_ActorCursor[PoS].m_Y > (sceneHeight - pTargetBitmap->h))) - cursorDrawPos.m_Y -= sceneHeight; - else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_ActorCursor[PoS].m_Y < pTargetBitmap->h)) - cursorDrawPos.m_Y += sceneHeight; - } + + m_ActorCursor[player].Reset(); + m_LandingZone[player].Reset(); + + // Set the initial landing zones to be above the respective brains, but not for the observer player in a three player game + if (m_Brain[player] && !(m_PlayerCount == 3 && ScreenOfPlayer(player) == 3)) { + // Also set the brain to be the selected actor at start + SwitchToActor(m_Brain[player], player, m_Team[player]); + m_ActorCursor[player] = m_Brain[player]->GetPos(); + m_LandingZone[player].m_X = m_Brain[player]->GetPos().m_X; + // Set the observation target to the brain, so that if/when it dies, the view flies to it in observation mode + m_ObservationTarget[player] = m_Brain[player]->GetPos(); } + } + // Set up the AI controllers for everyone + InitAIs(); + + // Start the game timer + m_GameTimer.Reset(); + + if (m_aLZCursor[0].empty()) { + ContentFile cursorFile("Base.rte/GUIs/Indicators/LZArrowRedL.png"); + cursorFile.GetAsAnimation(m_aLZCursor[0], LZCURSORFRAMECOUNT); + cursorFile.SetDataPath("Base.rte/GUIs/Indicators/LZArrowGreenL.png"); + cursorFile.GetAsAnimation(m_aLZCursor[1], LZCURSORFRAMECOUNT); + cursorFile.SetDataPath("Base.rte/GUIs/Indicators/LZArrowBlueL.png"); + cursorFile.GetAsAnimation(m_aLZCursor[2], LZCURSORFRAMECOUNT); + cursorFile.SetDataPath("Base.rte/GUIs/Indicators/LZArrowYellowL.png"); + cursorFile.GetAsAnimation(m_aLZCursor[3], LZCURSORFRAMECOUNT); + } - // Fix circle center coordinates - if (!targetPos.IsZero()) - { - // Spans vertical scene seam - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) - { - if ((targetPos.m_X < 0) && (actorPos.m_X > (sceneWidth - pTargetBitmap->w))) - drawPos.m_X -= sceneWidth; - else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (actorPos.m_X < pTargetBitmap->w)) - drawPos.m_X += sceneWidth; - } - // Spans horizontal scene seam - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) - { - if ((targetPos.m_Y < 0) && (actorPos.m_Y > (sceneHeight - pTargetBitmap->h))) - drawPos.m_Y -= sceneHeight; - else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (actorPos.m_Y < pTargetBitmap->h)) - drawPos.m_Y += sceneHeight; - } - } + if (m_aObjCursor[0].empty()) { + ContentFile cursorFile("Base.rte/GUIs/Indicators/ObjArrowRed.png"); + cursorFile.GetAsAnimation(m_aObjCursor[0], OBJARROWFRAMECOUNT); + cursorFile.SetDataPath("Base.rte/GUIs/Indicators/ObjArrowGreen.png"); + cursorFile.GetAsAnimation(m_aObjCursor[1], OBJARROWFRAMECOUNT); + cursorFile.SetDataPath("Base.rte/GUIs/Indicators/ObjArrowBlue.png"); + cursorFile.GetAsAnimation(m_aObjCursor[2], OBJARROWFRAMECOUNT); + cursorFile.SetDataPath("Base.rte/GUIs/Indicators/ObjArrowYellow.png"); + cursorFile.GetAsAnimation(m_aObjCursor[3], OBJARROWFRAMECOUNT); + } - float radius = g_SceneMan.ShortestDistance(m_ActorCursor[PoS], m_ControlledActor[PoS]->GetPos(), true).GetMagnitude(); + // Start the in-game music + g_AudioMan.ClearMusicQueue(); + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/cc2g.ogg", 0); + g_AudioMan.QueueSilence(30); + g_AudioMan.QueueMusicStream("Base.rte/Music/Watts/Last Man.ogg"); + g_AudioMan.QueueSilence(30); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); - circle(pTargetBitmap, cursorDrawPos.m_X, cursorDrawPos.m_Y, m_CursorTimer.AlternateReal(150) ? 6 : 8, g_YellowGlowColor); - circlefill(pTargetBitmap, cursorDrawPos.m_X, cursorDrawPos.m_Y, 2, g_YellowGlowColor); + return error; + } - Vector unwrappedPos; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. - //Check if we crossed the seam - if (g_SceneMan.GetScene()->WrapsX()) - { - //Calculate unwrapped cursor position, or it won't glow - unwrappedPos = m_ActorCursor[PoS] - m_ControlledActor[PoS]->GetPos(); - float halfSceneWidth = sceneWidth * 0.5F; - float seamMinimum = 350.0F; + void GameActivity::SetPaused(bool pause) { + Activity::SetPaused(pause); + } - if (unwrappedPos.MagnitudeIsGreaterThan(std::max(halfSceneWidth, seamMinimum))) - { - if (m_ActorCursor->m_X < halfSceneWidth) - unwrappedPos = m_ActorCursor[PoS] + Vector(sceneWidth , 0); - else - unwrappedPos = m_ActorCursor[PoS] - Vector(sceneWidth , 0); - g_PostProcessMan.RegisterGlowArea(unwrappedPos, 10); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + + void GameActivity::End() { + Activity::End(); + + bool playerWon = false; + + // Disable control of actors.. will be handed over to the observation targets instead + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(player)); + + if (m_Team[player] == m_WinnerTeam) { + playerWon = true; + // Set the winner's observation view to his controlled actors instead of his brain + if (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) + m_ObservationTarget[player] = m_ControlledActor[player]->GetPos(); } - else - unwrappedPos = m_ActorCursor[PoS]; + } - g_PostProcessMan.RegisterGlowArea(m_ActorCursor[PoS], 10); + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { + if (MovableObject* asMo = dynamic_cast(itr->pCraft)) { + asMo->DestroyScriptState(); + } + delete itr->pCraft; + } + m_Deliveries[team].clear(); + } - //Glowing dotted circle version - int dots = 2 * c_PI * radius / 25;//5 + (int)(radius / 10); - float radsperdot = 2 * 3.14159265359 / dots; + /* Now controlled by the scripted activities + // Play the approriate tune on player win/lose + if (playerWon) + { + // Didn't work well, has gap between intro and loop tracks + // g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/uwinintro.ogg", 0); + // g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/uwinloop.ogg"); + g_AudioMan.ClearMusicQueue(); + // Loop it twice, nice tune! + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/uwinfinal.ogg", 2); + g_AudioMan.QueueSilence(10); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); + } + else + { + g_AudioMan.ClearMusicQueue(); + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/udiedfinal.ogg", 0); + g_AudioMan.QueueSilence(10); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/ccambient4.ogg"); + } + */ + + m_ActivityState = ActivityState::Over; + m_GameOverTimer.Reset(); + } - for (int i = 0; i < dots; i++) - { - Vector dotPos = Vector(actorPos.m_X + sin(i * radsperdot) * radius, actorPos.m_Y + cos(i * radsperdot) * radius); - Vector dotDrawPos = dotPos - targetPos; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateEditing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: This is a special update step for when any player is still editing the + // scene. + + void GameActivity::UpdateEditing() { + // Editing the scene, just update the editor guis and see if players are ready to start or not + if (m_ActivityState != ActivityState::Editing) + return; + + /////////////////////////////////////////// + // Iterate through all human players + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + m_pEditorGUI[player]->Update(); + + // Set the team associations with each screen displayed + g_CameraMan.SetScreenTeam(m_Team[player], ScreenOfPlayer(player)); + + // Check if the player says he's done editing, and if so, make sure he really is good to go + if (m_pEditorGUI[player]->GetEditorGUIMode() == SceneEditorGUI::DONEEDITING) { + // See if a brain has been placed yet by this player - IN A VALID LOCATION + if (!m_pEditorGUI[player]->TestBrainResidence()) { + // Hm not ready yet without resident brain in the right spot, so let user know + m_ReadyToStart[player] = false; + const Entity* pBrain = g_PresetMan.GetEntityPreset("Actor", "Brain Case"); + if (pBrain) + m_pEditorGUI[player]->SetCurrentObject(dynamic_cast(pBrain->Clone())); + m_pEditorGUI[player]->SetEditorGUIMode(SceneEditorGUI::INSTALLINGBRAIN); + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + g_FrameMan.SetScreenText("PLACE YOUR BRAIN IN A VALID SPOT FIRST!", ScreenOfPlayer(player), 250, 3500); + m_MessageTimer[player].Reset(); + } + // Ready to start + else { + m_ReadyToStart[player] = true; + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + g_FrameMan.SetScreenText("READY to start - wait for others to finish...", ScreenOfPlayer(player), 333); + m_pEditorGUI[player]->SetEditorGUIMode(SceneEditorGUI::ADDINGOBJECT); + } + } - if (!targetPos.IsZero()) - { - // Spans vertical scene seam - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) - { - if ((targetPos.m_X < 0) && (dotPos.m_X > (sceneWidth - pTargetBitmap->w))) - { - dotDrawPos.m_X -= sceneWidth; + // Keep showing ready message + if (m_ReadyToStart[player]) + g_FrameMan.SetScreenText("READY to start - wait for others to finish...", ScreenOfPlayer(player), 333); + } + + // Have all players flagged themselves as ready to start the game? + bool allReady = true; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + if (!m_ReadyToStart[player]) + allReady = false; + } + + // YES, we are allegedly all ready to stop editing and start the game! + if (allReady) { + // Make sure any players haven't moved or entombed their brains in the period after flagging themselves "done" + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + // See if a brain has been placed yet by this player - IN A VALID LOCATION + if (!m_pEditorGUI[player]->TestBrainResidence()) { + // Hm not ready yet without resident brain in the right spot, so let user know + m_ReadyToStart[player] = false; + allReady = false; + const Entity* pBrain = g_PresetMan.GetEntityPreset("Actor", "Brain Case"); + if (pBrain) + m_pEditorGUI[player]->SetCurrentObject(dynamic_cast(pBrain->Clone())); + m_pEditorGUI[player]->SetEditorGUIMode(SceneEditorGUI::INSTALLINGBRAIN); + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + g_FrameMan.SetScreenText("PLACE YOUR BRAIN IN A VALID SPOT FIRST!", ScreenOfPlayer(player), 333, 3500); + m_MessageTimer[player].Reset(); + } + } + + // Still good to go?? + if (allReady) { + // All resident brains are still in valid spots - place them into the simulation + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + // Place this player's resident brain into the simulation and set it as the player's assigned brain + g_SceneMan.GetScene()->PlaceResidentBrain(player, *this); + + // Still no brain of this player? Last ditch effort to find one and assign it to this player + if (!m_Brain[player]) + m_Brain[player] = g_MovableMan.GetUnassignedBrain(m_Team[player]); + // Um, something went wrong.. we're not done placing brains after all?? + if (!m_Brain[player]) { + allReady = false; + // Get the brains back into residency so the players who are OK are still so + g_SceneMan.GetScene()->RetrieveResidentBrains(*this); + break; + } + + // Set the brain to be the selected actor at start + SwitchToActor(m_Brain[player], player, m_Team[player]); + m_ActorCursor[player] = m_Brain[player]->GetPos(); + m_LandingZone[player].m_X = m_Brain[player]->GetPos().m_X; + // Set the observation target to the brain, so that if/when it dies, the view flies to it in observation mode + m_ObservationTarget[player] = m_Brain[player]->GetPos(); + // CLear the messages before starting the game + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + // Reset the screen occlusion if any players are still in menus + g_CameraMan.SetScreenOcclusion(Vector(), ScreenOfPlayer(player)); + } + } + + // Still good to go?? then GO + if (allReady) { + // START the game! + m_ActivityState = ActivityState::Running; + // Re-enable the AI's if we are done editing + DisableAIs(false); + InitAIs(); + // Reset the mouse value and pathfinding so it'll know about the newly placed stuff + g_UInputMan.SetMouseValueMagnitude(0); + g_SceneMan.GetScene()->ResetPathFinding(); + // Start the in-game track + g_AudioMan.ClearMusicQueue(); + g_AudioMan.PlayMusic("Base.rte/Music/dBSoundworks/cc2g.ogg", 0); + g_AudioMan.QueueSilence(30); + g_AudioMan.QueueMusicStream("Base.rte/Music/Watts/Last Man.ogg"); + g_AudioMan.QueueSilence(30); + g_AudioMan.QueueMusicStream("Base.rte/Music/dBSoundworks/cc2g.ogg"); + } + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this GameActivity. Supposed to be done every frame + // before drawing. + + void GameActivity::Update() { + Activity::Update(); + + // Avoid game logic when we're editing + if (m_ActivityState == ActivityState::Editing) { + UpdateEditing(); + return; + } + + /////////////////////////////////////////// + // Iterate through all human players + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + // The current player's team + int team = m_Team[player]; + if (team == Teams::NoTeam) + continue; + + // Temporary hack to avoid teh buy menu buy button to be pressed immediately after selecting an LZ for a previous order + bool skipBuyUpdate = false; + + // Set the team associations with each screen displayed + g_CameraMan.SetScreenTeam(team, ScreenOfPlayer(player)); + + ////////////////////////////////////////////////////// + // Assure that Controlled Actor is a safe pointer + + // Only allow this if player's brain is intact + if (m_Brain[player] && !m_Brain[player]->IsDead()) { + // Note that we have now had a brain + m_HadBrain[player] = true; + + // Tracking normally + if (m_ViewState[player] == ViewState::Normal) { + // Get a next actor if there isn't one + if (!m_ControlledActor[player]) + SwitchToNextActor(player, team); + + // Continually set the observation target to the brain during play, so that if/when it dies, the view flies to it in observation mode + if (m_ActivityState != ActivityState::Over && m_ViewState[player] != ViewState::Observe) + m_ObservationTarget[player] = m_Brain[player]->GetPos(); + + // Save the location of the currently controlled actor so we can know where to watch if he died on us + if (g_MovableMan.IsActor(m_ControlledActor[player])) { + m_DeathViewTarget[player] = m_ControlledActor[player]->GetPos(); + m_DeathTimer[player].Reset(); + } + // Add delay after death before switching so the death comedy can be witnessed + // Died, so enter death watch mode + else { + LoseControlOfActor(player); + } + } + // Ok, done watching death comedy, now automatically switch + else if (m_ViewState[player] == ViewState::DeathWatch && m_DeathTimer[player].IsPastSimMS(1500)) { + // Get a next actor if there isn't one + if (!m_ControlledActor[player]) + SwitchToNextActor(player, team); + + // If currently focused actor died, get next one + if (!g_MovableMan.IsActor(m_ControlledActor[player])) + SwitchToNextActor(player, team); + + if (m_ViewState[player] != ViewState::ActorSelect) + m_ViewState[player] = ViewState::Normal; + } + // Any other viewing mode and the actor died... go to deathwatch + else if (m_ControlledActor[player] && !g_MovableMan.IsActor(m_ControlledActor[player])) { + LoseControlOfActor(player); + } + } + // Player brain is now gone! Remove any control he may have had + else if (m_HadBrain[player]) { + if (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) + m_ControlledActor[player]->SetControllerMode(Controller::CIM_AI); + m_ControlledActor[player] = 0; + m_ViewState[player] = ViewState::Observe; + } + // Never had a brain, and no actor is selected, so just select the first one we do have + else if (m_ViewState[player] != ViewState::Observe && !g_MovableMan.IsActor(m_ControlledActor[player])) { + // Only try to switch if there's somehting to switch to + if (!g_MovableMan.GetTeamRoster(team)->empty()) + SwitchToNextActor(player, team); + else + m_ControlledActor[player] = 0; + } + + // Player-commanded actor switching + if (m_ViewState[player] != ViewState::Observe) { + // Switch to brain actor directly if the player wants to + if (m_PlayerController[player].IsState(ACTOR_BRAIN) && m_ViewState[player] != ViewState::ActorSelect) { + SwitchToActor(m_Brain[player], player, team); + m_ViewState[player] = ViewState::Normal; + } else if (m_PlayerController[player].IsState(ACTOR_NEXT) && m_ViewState[player] != ViewState::ActorSelect && !m_pBuyGUI[player]->IsVisible() && !m_LuaLockActor[player]) { + // Switch to next actor if the player wants to. Don't do it while the buy menu is open + if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->SetEnabled(false); + } + + SwitchToNextActor(player, team); + m_ViewState[player] = ViewState::Normal; + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + } + // Switch to prev actor if the player wants to. Don't do it while the buy menu is open + else if (m_PlayerController[player].IsState(ACTOR_PREV) && m_ViewState[player] != ViewState::ActorSelect && !m_pBuyGUI[player]->IsVisible()) { + if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->SetEnabled(false); + } + + SwitchToPrevActor(player, team); + m_ViewState[player] = ViewState::Normal; + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + } else if (m_ViewState[player] != ViewState::ActorSelect && !m_pBuyGUI[player]->IsVisible() && !m_LuaLockActor[player] && (m_PlayerController[player].IsState(ACTOR_NEXT_PREP) || m_PlayerController[player].IsState(ACTOR_PREV_PREP))) { + // Go into manual actor select mode if either actor switch buttons are held for a duration + if (m_ActorSelectTimer[player].IsPastRealMS(250)) { + // Set cursor to start at the head of controlled actor + if (m_ControlledActor[player]) { + // Give switched from actor an AI controller + m_ControlledActor[player]->SetControllerMode(Controller::CIM_AI); + m_ControlledActor[player]->GetController()->SetDisabled(false); + m_ActorCursor[player] = m_ControlledActor[player]->GetCPUPos(); + m_CursorTimer.Reset(); } - else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (actorPos.m_X < pTargetBitmap->w)) - { - dotDrawPos.m_X += sceneWidth; + + m_ViewState[player] = ViewState::ActorSelect; + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + } + } else { + m_ActorSelectTimer[player].Reset(); + } + } + + //////////////////////////////////// + // Update sceneman scroll targets + + if (m_ViewState[player] == ViewState::Observe) { + // If we're observing game over state, freeze the view for a bit so the player's input doesn't ruin the focus + if (!(m_ActivityState == ActivityState::Over && !m_GameOverTimer.IsPastRealMS(1000))) { + // Get cursor input + m_PlayerController[player].RelativeCursorMovement(m_ObservationTarget[player], 1.2f); + } + // Set the view to the observation position + g_SceneMan.ForceBounds(m_ObservationTarget[player]); + g_CameraMan.SetScrollTarget(m_ObservationTarget[player], 0.1, ScreenOfPlayer(player)); + } + + /////////////////////////////////////////////////// + // Manually selecting a new actor to switch to + + else if (m_ViewState[player] == ViewState::ActorSelect) { + // Continuously display message + g_FrameMan.SetScreenText("Select a body to switch control to...", ScreenOfPlayer(player)); + // Get cursor input + m_PlayerController[player].RelativeCursorMovement(m_ActorCursor[player]); + + // Find the actor closest to the cursor, if any within the radius + Vector markedDistance; + Actor* pMarkedActor = g_MovableMan.GetClosestTeamActor(team, player, m_ActorCursor[player], g_SceneMan.GetSceneWidth(), markedDistance, true); + // Actor *pMarkedActor = g_MovableMan.GetClosestTeamActor(team, player, m_ActorCursor[player], g_FrameMan.GetPlayerScreenWidth() / 4); + + // Player canceled selection of actor + if (m_PlayerController[player].IsState(PRESS_SECONDARY)) { + // Reset the mouse so the actor doesn't change aim because mouse has been moved + if (m_PlayerController[player].IsMouseControlled()) { + g_UInputMan.SetMouseValueMagnitude(0); + } + + m_ViewState[player] = ViewState::Normal; + g_GUISound.UserErrorSound()->Play(player); + if (m_ControlledActor[player]) { + if (m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); } + m_ControlledActor[player]->SetControllerMode(Controller::CIM_PLAYER, player); } - // Spans horizontal scene seam - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) - { - if ((targetPos.m_Y < 0) && (dotPos.m_Y > (sceneHeight - pTargetBitmap->h))) - { - dotDrawPos.m_Y -= sceneHeight; + if (pMarkedActor && pMarkedActor->GetPieMenu()) { + pMarkedActor->GetPieMenu()->DoDisableAnimation(); + } + } + // Player is done selecting new actor; switch to it if we have anything marked + else if (m_PlayerController[player].IsState(ACTOR_NEXT) || m_PlayerController[player].IsState(ACTOR_PREV) || m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) { + // Reset the mouse so the actor doesn't change aim because mouse has been moved + if (m_PlayerController[player].IsMouseControlled()) { + g_UInputMan.SetMouseValueMagnitude(0); + } + + if (pMarkedActor) { + SwitchToActor(pMarkedActor, player, team); + } else { + g_GUISound.UserErrorSound()->Play(player); + } + + m_ViewState[player] = ViewState::Normal; + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + // Flash the same actor, jsut to show the control went back to him + if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); + } + } else if (pMarkedActor && pMarkedActor->GetPieMenu()) { + int quarterFrameBuffer = g_FrameMan.GetPlayerFrameBufferWidth(player) / 4; + if (markedDistance.MagnitudeIsGreaterThan(static_cast(quarterFrameBuffer))) { + pMarkedActor->GetPieMenu()->Wobble(); + } else { + pMarkedActor->GetPieMenu()->FreezeAtRadius(30); + } + } + + // Set the view to the cursor pos + g_SceneMan.ForceBounds(m_ActorCursor[player]); + g_CameraMan.SetScrollTarget(m_ActorCursor[player], 0.1, ScreenOfPlayer(player)); + + if (m_pLastMarkedActor[player]) { + if (!g_MovableMan.ValidMO(m_pLastMarkedActor[player])) { + m_pLastMarkedActor[player] = nullptr; + } else if (m_pLastMarkedActor[player] != pMarkedActor && m_pLastMarkedActor[player]->GetPieMenu()) { + m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); + } + } + if (pMarkedActor) { + m_pLastMarkedActor[player] = pMarkedActor; + } + } + + /////////////////////////////////////////////////// + // Selecting points on the scene for the AI to go to + + else if (m_ViewState[player] == ViewState::AIGoToPoint) { + // Continuously display message + g_FrameMan.SetScreenText("Set waypoints for the AI to go to...", ScreenOfPlayer(player)); + // Get cursor input + m_PlayerController[player].RelativeCursorMovement(m_ActorCursor[player]); + + // If we are pointing to an actor to follow, then snap cursor to that actor's position + Actor* pTargetActor = 0; + Vector distance; + if (pTargetActor = g_MovableMan.GetClosestActor(m_ActorCursor[player], 40, distance, m_ControlledActor[player]); pTargetActor && pTargetActor->GetPieMenu()) { + if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { + m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); + } + pTargetActor->GetPieMenu()->FreezeAtRadius(15); + m_pLastMarkedActor[player] = pTargetActor; + } else if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { + m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); + } + + // Set the view to the cursor pos + g_SceneMan.ForceBounds(m_ActorCursor[player]); + g_CameraMan.SetScrollTarget(m_ActorCursor[player], 0.1, ScreenOfPlayer(player)); + + // Draw the actor's waypoints + m_ControlledActor[player]->DrawWaypoints(true); + + // Disable the actor's controller + m_ControlledActor[player]->GetController()->SetDisabled(true); + + // Player is done setting waypoints + if (m_PlayerController[player].IsState(PRESS_SECONDARY) || m_PlayerController[player].IsState(ACTOR_NEXT_PREP) || m_PlayerController[player].IsState(ACTOR_PREV_PREP)) { + // Stop drawing the waypoints + // m_ControlledActor[player]->DrawWaypoints(false); + // Update the player's move path now to the first waypoint set + m_ControlledActor[player]->UpdateMovePath(); + // Give player control back to actor + m_ControlledActor[player]->GetController()->SetDisabled(false); + // Switch back to normal view + m_ViewState[player] = ViewState::Normal; + // Stop displaying the message + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { + m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); + } + } + // Player set a new waypoint + else if (m_ControlledActor[player] && m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) { + // TODO: Sound? + // If we are pointing to an actor to follow, tehn give that kind of waypoint command + if (pTargetActor) + m_ControlledActor[player]->AddAIMOWaypoint(pTargetActor); + // Just pointing into somewhere in the scene, so give that command + else + m_ControlledActor[player]->AddAISceneWaypoint(m_ActorCursor[player]); + // Update the player's move path now to the first waypoint set + m_ControlledActor[player]->UpdateMovePath(); + if (m_pLastMarkedActor[player] && m_pLastMarkedActor[player]->GetPieMenu()) { + m_pLastMarkedActor[player]->GetPieMenu()->SetAnimationModeToNormal(); + } + } + } else if (m_ViewState[player] == ViewState::UnitSelectCircle) { + // Continuously display message + g_FrameMan.SetScreenText("Select units to group...", ScreenOfPlayer(player)); + + m_PlayerController[player].RelativeCursorMovement(m_ActorCursor[player]); + + Vector relativeToActor = m_ActorCursor[player] - m_ControlledActor[player]->GetPos(); + + float sceneWidth = static_cast(g_SceneMan.GetSceneWidth()); + float seamMinimum = 350.0F; + + // Check if we crossed the seam + if (g_SceneMan.GetScene()->WrapsX()) { + float halfSceneWidth = sceneWidth * 0.5F; + if (relativeToActor.MagnitudeIsGreaterThan(std::max(halfSceneWidth, seamMinimum))) { + if (m_ActorCursor->m_X < halfSceneWidth) { + relativeToActor = m_ActorCursor[player] + Vector(sceneWidth, 0) - m_ControlledActor[player]->GetPos(); + } else { + relativeToActor = m_ActorCursor[player] - Vector(sceneWidth, 0) - m_ControlledActor[player]->GetPos(); } - else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (actorPos.m_Y < pTargetBitmap->h)) - { - dotDrawPos.m_Y += sceneHeight; + } + } + + // Limit selection range + relativeToActor = relativeToActor.CapMagnitude(seamMinimum); + m_ActorCursor[player] = m_ControlledActor[player]->GetPos() + relativeToActor; + + bool wrapped; + + // Set the view to the cursor pos + wrapped = g_SceneMan.ForceBounds(m_ActorCursor[player]); + // g_CameraMan.SetScrollTarget(m_ActorCursor[player], 0.1, wrapped, ScreenOfPlayer(player)); + + // Set the view to the actor pos + Vector scrollPos = Vector(m_ControlledActor[player]->GetPos()); + g_SceneMan.ForceBounds(scrollPos); + g_CameraMan.SetScrollTarget(scrollPos, 0.1, ScreenOfPlayer(player)); + + // Disable the actor's controller + m_ControlledActor[player]->GetController()->SetDisabled(true); + + // Player is done setting waypoints + if (m_PlayerController[player].IsState(PRESS_SECONDARY) || m_PlayerController[player].IsState(ACTOR_NEXT_PREP) || m_PlayerController[player].IsState(ACTOR_PREV_PREP)) { + // Give player control back to actor + m_ControlledActor[player]->GetController()->SetDisabled(false); + // Switch back to normal view + m_ViewState[player] = ViewState::Normal; + // Stop displaying the message + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + } + // Player set a new waypoint + else if (m_ControlledActor[player] && m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) { + // m_ControlledActor[player]->AddAISceneWaypoint(m_ActorCursor[player]); + // Give player control back to actor + m_ControlledActor[player]->GetController()->SetDisabled(false); + // Switch back to normal view + m_ViewState[player] = ViewState::Normal; + // Stop displaying the message + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + + // Switch commander to sentry mode + m_ControlledActor[player]->SetAIMode(Actor::AIMODE_SENTRY); + + // Detect nearby actors and attach them to commander + float sqrRadius = g_SceneMan.ShortestDistance(m_ActorCursor[player], m_ControlledActor[player]->GetPos(), true).GetSqrMagnitude(); + + Actor* pActor = 0; + Actor* pFirstActor = 0; + + // Get the first one + pFirstActor = pActor = g_MovableMan.GetNextTeamActor(m_ControlledActor[player]->GetTeam()); + + do { + // Set up commander if actor is not player controlled and not brain + if (pActor && !pActor->GetController()->IsPlayerControlled() && !pActor->IsInGroup("Brains")) { + // If human, set appropriate AI mode + if (dynamic_cast(pActor) || dynamic_cast(pActor)) + if (g_SceneMan.ShortestDistance(m_ControlledActor[player]->GetPos(), pActor->GetPos(), true).GetSqrMagnitude() < sqrRadius) { + pActor->FlashWhite(); + pActor->ClearAIWaypoints(); + pActor->SetAIMode(Actor::AIMODE_SQUAD); + pActor->AddAIMOWaypoint(m_ControlledActor[player]); + pActor->UpdateMovePath(); // Make sure pActor has m_ControlledActor registered as an AIMOWaypoint + } + } + + // Next! + pActor = g_MovableMan.GetNextTeamActor(team, pActor); + } while (pActor && pActor != pFirstActor); + } + } + /////////////////////////////////////////////////// + // Selecting LZ, a place for the craft to land + + else if (m_ViewState[player] == ViewState::LandingZoneSelect) { + g_FrameMan.SetScreenText("Choose your landing zone... Hold UP or DOWN to place multiple orders", ScreenOfPlayer(player)); + + // Save the x pos so we can see which direction the user is moving it + float prevLZX = m_LandingZone[player].m_X; + + // See if there's analog input + if (m_PlayerController[player].GetAnalogMove().m_X > 0.1) + m_LandingZone[player].m_X += m_PlayerController[player].GetAnalogMove().m_X * 8; + // Try the mouse + else if (!m_PlayerController[player].GetMouseMovement().IsZero()) + m_LandingZone[player].m_X += m_PlayerController[player].GetMouseMovement().m_X; + // Digital movement + else { + if (m_PlayerController[player].IsState(MOVE_RIGHT)) + m_LandingZone[player].m_X += 8; + else if (m_PlayerController[player].IsState(MOVE_LEFT)) + m_LandingZone[player].m_X -= 8; + } + + // Limit the LZ selection to the special LZ Area:s both specified in the derived Activity and moving with the brain + if (!m_LandingZoneArea[m_Team[player]].HasNoArea()) { + // Add up the static LZ loaded from the Scene to the one(s) around the player's team's brains + Scene::Area totalLZ(m_LandingZoneArea[m_Team[player]]); + /* This whole concept kinda sucks - defensive AA robots are more fun way to go to prevent bumrushing the brain with craft + for (int p = Players::PlayerOne; p < Players::MaxPlayerCount; ++p) + { + if (!(m_IsActive[p] && m_IsHuman[p] && m_BrainLZWidth[p] > 0)) + continue; + // Same team as this player and has a brain + if (m_Brain[p] && m_Team[p] == m_Team[player]) + { + Box brainBox(Vector(0, 0), m_BrainLZWidth[p], 100); + // Center the brain LZ box aroud the player's brain + brainBox.SetCenter(m_Brain[p]->GetPos()); + // Add it to the total LZ + totalLZ.AddBox(brainBox); + } + } + */ + // Move the actual LZ cursor to within the valid LZ Area. We pass in 0 for direction so it doesn't try to wrap around on wrapping maps. + totalLZ.MovePointInsideX(m_LandingZone[player].m_X, 0); + } + + // Interface for the craft AI post-delivery mode + if (m_PlayerController[player].IsState(PRESS_DOWN)) { + if (m_AIReturnCraft[player]) { + g_GUISound.SelectionChangeSound()->Play(player); + } + + m_AIReturnCraft[player] = false; + } else if (m_PlayerController[player].IsState(PRESS_UP)) { + if (!m_AIReturnCraft[player]) { + g_GUISound.SelectionChangeSound()->Play(player); + } + + m_AIReturnCraft[player] = true; + } + + // Player canceled the order while selecting LZ - can't be done in pregame + if (m_PlayerController[player].IsState(PRESS_SECONDARY) && m_ActivityState != ActivityState::PreGame) { + // Switch back to normal view + m_ViewState[player] = ViewState::Normal; + // Play err sound to indicate cancellation + g_FrameMan.SetScreenText("Order canceled!", ScreenOfPlayer(player), 333); + m_MessageTimer[player].Reset(); + g_GUISound.UserErrorSound()->Play(player); + // Flash the same actor, jsut to show the control went back to him + if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); + } + } else if (m_PlayerController[player].IsState(PRESS_FACEBUTTON) || m_PlayerController[player].IsState(PRESS_PRIMARY)) { + m_LandingZone[player].m_Y = 0; + float lzOffsetY = 0; + // Holding up or down will allow the player to make multiple orders without exiting the delivery phase. TODO: this should probably have a cooldown? + if (!m_PlayerController[player].IsState(MOVE_UP) && !m_PlayerController[player].IsState(MOVE_DOWN)) { + m_LandingZone[player].m_Y = g_SceneMan.FindAltitude(m_LandingZone[player], g_SceneMan.GetSceneHeight(), 10, true); + if (!g_MovableMan.GetNextTeamActor(team)) { + m_ObservationTarget[player] = m_LandingZone[player]; + m_ViewState[player] = ViewState::Observe; + } else { + m_ViewState[player] = ViewState::Normal; + } + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + if (m_ControlledActor[player] && m_ControlledActor[player]->GetPieMenu()) { + m_ControlledActor[player]->GetPieMenu()->DoDisableAnimation(); + } + + CreateDelivery(player); + } else { + // Place the new marker above the cursor so that they don't intersect with each other. + lzOffsetY += m_AIReturnCraft[player] ? -32.0F : 32.0F; + if (g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { + lzOffsetY *= -1.0f; + } + + m_LandingZone[player].m_Y = g_SceneMan.FindAltitude(m_LandingZone[player], g_SceneMan.GetSceneHeight(), 10, true) + lzOffsetY; + + if (m_pBuyGUI[player]->GetTotalOrderCost() > GetTeamFunds(team)) { + g_GUISound.UserErrorSound()->Play(player); + m_FundsChanged[team] = true; + if (!g_MovableMan.GetNextTeamActor(team)) { + m_ObservationTarget[player] = m_LandingZone[player]; + m_ViewState[player] = ViewState::Observe; + } else { + m_ViewState[player] = ViewState::Normal; + } + } else { + CreateDelivery(player); + m_Deliveries[team].rbegin()->multiOrderYOffset = lzOffsetY; + } + } + // Revert the Y offset so that the cursor doesn't flinch. + m_LandingZone[player].m_Y -= lzOffsetY; + } + + g_SceneMan.ForceBounds(m_LandingZone[player]); + + // Interpolate the LZ altitude to the height of the highest terrain point at the player-chosen X + float prevHeight = m_LandingZone[player].m_Y; + + float viewOffset = g_FrameMan.GetPlayerScreenHeight() / 4; + m_LandingZone[player].m_Y = 0.0f; + if (g_SceneMan.GetTerrain() && g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { + m_LandingZone[player].m_Y = g_SceneMan.GetSceneHeight(); + viewOffset *= -1; + } + + m_LandingZone[player].m_Y = prevHeight + ((g_SceneMan.FindAltitude(m_LandingZone[player], g_SceneMan.GetSceneHeight(), 10, true) - prevHeight) * 0.2); + + // Set the view to a little above the LZ position + Vector viewTarget(m_LandingZone[player].m_X, m_LandingZone[player].m_Y - viewOffset); + g_CameraMan.SetScrollTarget(viewTarget, 0.1, ScreenOfPlayer(player)); + } + + //////////////////////////// + // Deathwatching + + else if (m_ViewState[player] == ViewState::DeathWatch) { + // Continuously deathwatch message + g_FrameMan.SetScreenText("Lost control of remote body!", ScreenOfPlayer(player)); + // Don't move anything, just stay put watching the death funnies + g_CameraMan.SetScrollTarget(m_DeathViewTarget[player], 0.1, ScreenOfPlayer(player)); + } + + //////////////////////////////////////////////////// + // Normal scrolling to view the currently controlled Actor + // But only if we're not editing something, because editor will scroll the screen himself + // and double scrolling will cause CC gitch when we'll cross the seam + else if (m_ControlledActor[player] && m_ActivityState != ActivityState::Editing && m_ActivityState != ActivityState::PreGame) { + g_CameraMan.SetScrollTarget(m_ControlledActor[player]->GetViewPoint(), 0.1, ScreenOfPlayer(player)); + } + + if (m_ControlledActor[player] && m_ViewState[player] != ViewState::DeathWatch && m_ViewState[player] != ViewState::ActorSelect && m_ViewState[player] != ViewState::AIGoToPoint && m_ViewState[player] != ViewState::UnitSelectCircle) { + PieMenu* controlledActorPieMenu = m_ControlledActor[player]->GetPieMenu(); + if (controlledActorPieMenu && m_ControlledActor[player]->GetController()->IsState(PIE_MENU_ACTIVE)) { + if (!m_BuyMenuEnabled && controlledActorPieMenu->IsEnabling()) { + controlledActorPieMenu->RemovePieSlicesByType(PieSlice::SliceType::BuyMenu); + } + + if (controlledActorPieMenu->IsEnabled() && controlledActorPieMenu->HasSubPieMenuOpen() && m_InventoryMenuGUI[player]->GetMenuMode() == InventoryMenuGUI::MenuMode::Carousel) { + m_InventoryMenuGUI[player]->SetEnabled(false); + } else if (m_InventoryMenuGUI[player]->GetMenuMode() == InventoryMenuGUI::MenuMode::Carousel || !m_InventoryMenuGUI[player]->IsVisible()) { + m_InventoryMenuGUI[player]->SetMenuMode(InventoryMenuGUI::MenuMode::Carousel); + m_InventoryMenuGUI[player]->EnableIfNotEmpty(); + } + } else if (!m_PlayerController[player].IsState(PIE_MENU_ACTIVE) && m_InventoryMenuGUI[player]->GetMenuMode() == InventoryMenuGUI::MenuMode::Carousel) { + m_InventoryMenuGUI[player]->SetEnabled(false); + } + + if (PieSlice::SliceType command = controlledActorPieMenu->GetPieCommand(); command != PieSlice::SliceType::NoType) { + // AI mode commands that need extra points set in special view modes here + // TODO I don't think these viewstates are actually used?! + if (command == PieSlice::SliceType::Sentry) { + m_ViewState[player] = ViewState::AISentryPoint; + } else if (command == PieSlice::SliceType::Patrol) { + m_ViewState[player] = ViewState::AIPatrolPoints; + } else if (command == PieSlice::SliceType::GoldDig) { + m_ViewState[player] = ViewState::AIGoldDigPoint; + } else if (command == PieSlice::SliceType::GoTo) { + m_ViewState[player] = ViewState::AIGoToPoint; + m_ControlledActor[player]->ClearAIWaypoints(); + m_ActorCursor[player] = m_ControlledActor[player]->GetPos(); + m_ControlledActor[player]->GetController()->SetDisabled(true); + } else if (command == PieSlice::SliceType::FormSquad) { + // Find out if we have any connected units, and disconnect them + bool isCommander = false; + + Actor* pActor = 0; + Actor* pFirstActor = 0; + + pFirstActor = pActor = g_MovableMan.GetNextTeamActor(m_ControlledActor[player]->GetTeam()); + + // Reset commander if we have any subordinates + do { + if (pActor) { + // Set appropriate AI mode + if (dynamic_cast(pActor) || dynamic_cast(pActor)) + if (pActor->GetAIMOWaypointID() == m_ControlledActor[player]->GetID()) { + pActor->FlashWhite(); + pActor->ClearAIWaypoints(); + pActor->SetAIMode((Actor::AIMode)m_ControlledActor[player]->GetAIMode()); // Inherit the leader's AI mode + isCommander = true; + } + } + pActor = g_MovableMan.GetNextTeamActor(team, pActor); + } while (pActor && pActor != pFirstActor); + + // Now turn on selection UI, if we didn't disconnect anyone + if (!isCommander) { + m_ViewState[player] = ViewState::UnitSelectCircle; + // Set cursor to the actor + m_ActorCursor[player] = m_ControlledActor[player]->GetPos() + Vector(50, -50); + // Disable Actor's controller while we set the waypoints + m_ControlledActor[player]->GetController()->SetDisabled(true); + if (controlledActorPieMenu) { + controlledActorPieMenu->SetEnabled(false); + } } + } else if (command == PieSlice::SliceType::BuyMenu) { + m_pBuyGUI[player]->SetEnabled(true); + skipBuyUpdate = true; + } else if (command == PieSlice::SliceType::FullInventory) { + controlledActorPieMenu->SetEnabled(false); + m_InventoryMenuGUI[player]->SetEnabled(false); + m_InventoryMenuGUI[player]->SetMenuMode(InventoryMenuGUI::MenuMode::Full); + m_InventoryMenuGUI[player]->SetEnabled(true); } + m_ControlledActor[player]->HandlePieCommand(command); + } - circlefill(pTargetBitmap, dotDrawPos.m_X, dotDrawPos.m_Y, 1, g_YellowGlowColor); - g_PostProcessMan.RegisterGlowArea(dotPos, 3); + m_InventoryMenuGUI[player]->SetInventoryActor(m_ControlledActor[player]); + m_InventoryMenuGUI[player]->Update(); + } + + /////////////////////////////////////// + // Update Buy Menu GUIs + + // Enable or disable the Buy Menus if the brain is selected, Skip if an LZ selection button press was just performed + if (!skipBuyUpdate) { + // m_pBuyGUI[player]->SetEnabled(m_ControlledActor[player] == m_Brain[player] && m_ViewState[player] != ViewState::LandingZoneSelect && m_ActivityState != ActivityState::Over); + m_pBuyGUI[player]->Update(); + } + + // Trap the mouse if we're in gameplay and not in menus + g_UInputMan.TrapMousePos(!m_pBuyGUI[player]->IsEnabled() && !m_InventoryMenuGUI[player]->IsEnabledAndNotCarousel() && !m_LuaLockActor[player], player); + + // Start LZ picking mode if a purchase was made + if (m_pBuyGUI[player]->PurchaseMade()) { + m_LZCursorWidth[player] = std::min(m_pBuyGUI[player]->GetDeliveryWidth(), g_FrameMan.GetPlayerScreenWidth() - 24); + m_pBuyGUI[player]->SetEnabled(false); + // SwitchToPrevActor(player, team, m_Brain[player]); + // Start selecting the landing zone + m_ViewState[player] = ViewState::LandingZoneSelect; + + // Set this to zero so the cursor interpolates down from the sky + float landingSpot = 0.0f; + if (g_SceneMan.GetTerrain() && g_SceneMan.GetTerrain()->GetOrbitDirection() == Directions::Down) { + landingSpot = g_SceneMan.GetSceneHeight(); } + + m_LandingZone[player].m_Y = landingSpot; } + + // After a while of game over, change messages to the final one for everyone + if (m_ActivityState == ActivityState::Over && m_GameOverTimer.IsPastRealMS(m_GameOverPeriod)) { + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + // g_FrameMan.SetScreenText("Press [Esc] to leave the battlefield", ScreenOfPlayer(player), 750); + if (g_FrameMan.IsInMultiplayerMode()) + g_FrameMan.SetScreenText("All players must press and hold [BACKSPACE] to continue!", ScreenOfPlayer(player), 750); + else + g_FrameMan.SetScreenText("Press [SPACE] or [START] to continue!", ScreenOfPlayer(player), 750); + + // Actually end on space + if (m_GameOverTimer.IsPastSimMS(55000) || g_UInputMan.AnyStartPress()) { + g_ActivityMan.EndActivity(); + g_ActivityMan.SetInActivity(false); + } + } + + /////////////////////////////////// + // Enable/disable controlled actors' AI as appropriate when in menus + + if (m_ControlledActor[player] && m_ControlledActor[player]->GetController()->GetPlayerRaw() == player) { + // Don't disable when pie menu is active; it is done inside the Controller Update + if (m_pBuyGUI[player]->IsVisible() || m_ViewState[player] == ViewState::ActorSelect || m_ViewState[player] == ViewState::LandingZoneSelect || m_ViewState[player] == ViewState::Observe) { + m_ControlledActor[player]->GetController()->SetInputMode(Controller::CIM_AI); + } else if (m_InventoryMenuGUI[player]->IsEnabledAndNotCarousel()) { + m_ControlledActor[player]->GetController()->SetInputMode(Controller::CIM_DISABLED); + } else if (m_LuaLockActor[player]) { + m_ControlledActor[player]->GetController()->SetInputMode(m_LuaLockActorMode[player]); + } else { + m_ControlledActor[player]->GetController()->SetInputMode(Controller::CIM_PLAYER); + } + } + + /////////////////////////////////////// + // Configure banners to show when important things happen, like the game over or death of brain + + if (IsOver()) { + // Override previous messages + if (m_pBannerRed[player]->IsVisible() && m_pBannerRed[player]->GetBannerText() != "FAIL") + m_pBannerRed[player]->HideText(2500, 0); + if (m_pBannerYellow[player]->IsVisible() && m_pBannerYellow[player]->GetBannerText() != "WIN") + m_pBannerYellow[player]->HideText(2500, 0); + + // Player on a winning team + if (GetWinnerTeam() == m_Team[player] && !m_pBannerYellow[player]->IsVisible()) + m_pBannerYellow[player]->ShowText("WIN", GUIBanner::FLYBYRIGHTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); + + // Loser player + if (GetWinnerTeam() != m_Team[player] && !m_pBannerRed[player]->IsVisible()) + m_pBannerRed[player]->ShowText("FAIL", GUIBanner::FLYBYLEFTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); + } + // If a player had a brain that is now dead, but his team is not yet done, show the dead banner on his screen + else if (m_ActivityState != ActivityState::Editing && m_ActivityState != ActivityState::Starting && m_HadBrain[player] && !m_Brain[player] && !m_pBannerRed[player]->IsVisible()) { + // If repeated too many times, just let the banner stop at showing and not cycle + if (m_BannerRepeats[player]++ < 6) + m_pBannerRed[player]->ShowText("DEAD", GUIBanner::FLYBYLEFTWARD, 1000, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); + else + m_pBannerRed[player]->ShowText("DEAD", GUIBanner::FLYBYLEFTWARD, -1, Vector(g_FrameMan.GetPlayerFrameBufferWidth(player), g_FrameMan.GetPlayerFrameBufferHeight(player)), 0.5, 1500, 400); + } + + /////////////////////////////////////// + // Update message banners + + m_pBannerRed[player]->Update(); + m_pBannerYellow[player]->Update(); } - else - { - // Cancel squad selection + /////////////////////////////////////////// + // Iterate through all teams + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + + // Pause deliveries if game hasn't started yet + if (m_ActivityState == ActivityState::PreGame) { + for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) + (*itr).timer.Reset(); + } + + //////////////////////////////// + // Delivery status update + + if (!m_Deliveries[team].empty()) { + int player = m_Deliveries[team].front().orderedByPlayer; + if (m_MessageTimer[player].IsPastSimMS(1000)) { + char message[512]; + std::snprintf(message, sizeof(message), "Next delivery in %i secs", ((int)m_Deliveries[team].front().delay - (int)m_Deliveries[team].front().timer.GetElapsedSimTimeMS()) / 1000); + g_FrameMan.SetScreenText(message, ScreenOfPlayer(player)); + m_MessageTimer[player].Reset(); + } + } + + // Delivery has arrived! Unpack and put into the world + if (!m_Deliveries[team].empty() && m_Deliveries[team].front().timer.IsPastSimMS(m_Deliveries[team].front().delay)) { + // This is transferring ownership of the craft instance from the Delivery struct + ACraft* pDeliveryCraft = m_Deliveries[team].front().pCraft; + int player = m_Deliveries[team].front().orderedByPlayer; + if (pDeliveryCraft) { + g_FrameMan.SetScreenText("Your order has arrived!", ScreenOfPlayer(player), 333); + m_MessageTimer[player].Reset(); + + pDeliveryCraft->ResetAllTimers(); + pDeliveryCraft->Update(); + + // Add the delivery craft to the world, TRANSFERRING OWNERSHIP + g_MovableMan.AddActor(pDeliveryCraft); + /* + // If the player who ordered this seems stuck int he manu waiting for the delivery, give him direct control + if (m_ControlledActor[player] == m_Brain[player] && m_ViewState[player] != ViewState::LandingZoneSelect) + { + SwitchToActor(pDeliveryCraft, player, team); + } + */ + } + m_Deliveries[team].pop_front(); + } } + + /////////////////////////////////////////// + // Special observer mode for the FOURTH screen in a THREE player game + /* Problematic with new player scheme.. what if the fourth player is active?? + if (m_PlayerCount == 3) + { + // Update the controller of the observation view + m_PlayerController[Players::PlayerFour].Update(); + + // Observer user control override + if (m_PlayerController[Players::PlayerFour].RelativeCursorMovement(m_ObservationTarget[Players::PlayerFour], 1.2)) + m_DeathTimer[Players::PlayerFour].Reset(); + + // If no user input in a few seconds, start scrolling along the terrain + if (m_DeathTimer[Players::PlayerFour].IsPastSimMS(5000)) + { + // Make it scroll along + m_ObservationTarget[Players::PlayerFour].m_X += 0.5; + + // Make view follow the terrain + float prevHeight = m_ObservationTarget[Players::PlayerFour].m_Y; + m_ObservationTarget[Players::PlayerFour].m_Y = 0; + m_ObservationTarget[Players::PlayerFour].m_Y = prevHeight + ((g_SceneMan.FindAltitude(m_ObservationTarget[Players::PlayerFour], g_SceneMan.GetSceneHeight(), 20, true) - prevHeight) * 0.02); + } + + // Set the view to the observation position + g_CameraMan.SetScrollTarget(m_ObservationTarget[Players::PlayerFour], 0.1, g_SceneMan.ForceBounds(m_ObservationTarget[Players::PlayerFour]), ScreenOfPlayer(Players::PlayerFour)); + } + */ } - if ((m_ActivityState == ActivityState::Editing || m_ActivityState == ActivityState::PreGame) && m_pEditorGUI[PoS]) - m_pEditorGUI[PoS]->Draw(pTargetBitmap, targetPos); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + + void GameActivity::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + if (which < 0 || which >= c_MaxScreenCount) + return; + + char str[512]; + int yTextPos = 0; + int team = Teams::NoTeam; + int cursor = 0; + int PoS = PlayerOfScreen(which); + if (PoS < Players::PlayerOne || PoS >= Players::MaxPlayerCount) + return; + Box screenBox(targetPos, pTargetBitmap->w, pTargetBitmap->h); + GUIFont* pLargeFont = g_FrameMan.GetLargeFont(); + GUIFont* pSmallFont = g_FrameMan.GetSmallFont(); + AllegroBitmap pBitmapInt(pTargetBitmap); + int frame = ((int)m_CursorTimer.GetElapsedSimTimeMS() % 1000) / 250; + Vector landZone; + + // Iterate through all players, drawing each currently used LZ cursor. + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + if (m_ViewState[player] == ViewState::LandingZoneSelect) { + int halfWidth = std::max(m_LZCursorWidth[player] / 2, 36); + team = m_Team[player]; + if (team == Teams::NoTeam) + continue; + cursor = team; + landZone = m_LandingZone[player] - targetPos; + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); + pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 36, "and then", GUIFont::Centre); + pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); + // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap + if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) { + // Wrap shit around and draw dupe on the other side + int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); + pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 36, "and then", GUIFont::Centre); + pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); + } + } + } - // Draw Banners - m_pBannerRed[PoS]->Draw(pTargetBitmap); - m_pBannerYellow[PoS]->Draw(pTargetBitmap); -} + // Iterate through all teams, drawing all pending delivery cursors + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + char str[64]; + cursor = team; + for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { + int halfWidth = 24; + landZone = itr->landingZone - targetPos; + bool anyPlayerOnTeamIsInLandingZoneSelectViewState = false; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (GetTeamOfPlayer(player) == team && m_ViewState[player] == ViewState::LandingZoneSelect) { + anyPlayerOnTeamIsInLandingZoneSelectViewState = true; + break; + } + } + if (!anyPlayerOnTeamIsInLandingZoneSelectViewState) { + landZone.m_Y -= itr->multiOrderYOffset; + } + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 38, "ETA:", GUIFont::Centre); + if (m_ActivityState == ActivityState::PreGame) + std::snprintf(str, sizeof(str), "???s"); + else + std::snprintf(str, sizeof(str), "%is", ((int)itr->delay - (int)itr->timer.GetElapsedSimTimeMS()) / 1000); + pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 32, str, GUIFont::Centre); + // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap + if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) { + // Wrap shit around and draw dupe on the other side + int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 38, "ETA:", GUIFont::Centre); + pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 32, str, GUIFont::Centre); + } + } + } + // The team of the screen + team = m_Team[PoS]; + if (team == Teams::NoTeam) + return; + + // None of the following player-specific GUI elements apply if this isn't a played human actor + if (!(m_IsActive[PoS] && m_IsHuman[PoS])) + return; + + // Get all possible wrapped boxes of the screen + std::list wrappedBoxes; + g_SceneMan.WrapBox(screenBox, wrappedBoxes); + Vector wrappingOffset, objScenePos, onScreenEdgePos; + float distance, shortestDist; + float sceneWidth = static_cast(g_SceneMan.GetSceneWidth()); + float halfScreenWidth = pTargetBitmap->w / 2; + float halfScreenHeight = pTargetBitmap->h / 2; + // THis is the max distance that is possible between a point inside the scene, but outside the screen box, and the screen box's outer edge closest to the point (taking wrapping into account) + float maxOffScreenSceneWidth = g_SceneMan.SceneWrapsX() ? ((sceneWidth / 2) - halfScreenWidth) : (sceneWidth - pTargetBitmap->w); + // These handle arranging the left and right stacks of arrows, so they don't pile up on top of each other + cursor = team; + float leftStackY = halfScreenHeight - m_aObjCursor[cursor][frame]->h * 2; + float rightStackY = leftStackY; + + // Draw the objective points this player should care about + for (std::list::iterator itr = m_Objectives.begin(); itr != m_Objectives.end(); ++itr) { + // Only draw objectives of the same team as the current player + if (itr->m_Team == team) { + // Iterate through the wrapped screen boxes - will only be one if there's no wrapping + // Try to the find one that contains the objective point + bool withinAny = false; + std::list::iterator nearestBoxItr = wrappedBoxes.begin(); + shortestDist = 1000000.0; + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + // See if we found the point to be within the screen or not + if (wItr->IsWithinBox((*itr).m_ScenePos)) { + nearestBoxItr = wItr; + withinAny = true; + break; + } + // Well, which wrapped screen box is closest to the point? + distance = g_SceneMan.ShortestDistance(wItr->GetCenter(), (*itr).m_ScenePos).GetLargest(); + if (distance < shortestDist) { + shortestDist = distance; + nearestBoxItr = wItr; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this GameActivity's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. - -void GameActivity::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) -{ - GUIFont *pLargeFont = g_FrameMan.GetLargeFont(); - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); - AllegroBitmap pBitmapInt(pTargetBitmap); - int frame = ((int)m_CursorTimer.GetElapsedSimTimeMS() % 1000) / 250; - int cursor = 0; - Vector landZone; - - // Iterate through all players, drawing each currently used LZ cursor. - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (!(m_IsActive[player] && m_IsHuman[player])) - continue; - - if (m_ViewState[player] == ViewState::LandingZoneSelect) - { - int halfWidth = std::max(m_LZCursorWidth[player] / 2, 36); - int team = m_Team[player]; - if (team == Teams::NoTeam) - continue; - landZone = m_LandingZone[player] - targetPos; - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); - pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 36, "and then", GUIFont::Centre); - pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); - // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap - if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) - { - // Wrap shit around and draw dupe on the other side - int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); - pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 36, "and then", GUIFont::Centre); - pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); - } - } - } - - // Iterate through all teams, drawing all pending delivery cursors - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - char str[64]; - for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) - { - int halfWidth = 24; - landZone = itr->landingZone - targetPos; - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 38, "ETA:", GUIFont::Centre); - if (m_ActivityState == ActivityState::PreGame) - std::snprintf(str, sizeof(str), "???s"); - else - std::snprintf(str, sizeof(str), "%is", ((int)itr->delay - (int)itr->timer.GetElapsedSimTimeMS()) / 1000); - pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 32, str, GUIFont::Centre); - // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap - if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) - { - // Wrap shit around and draw dupe on the other side - int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); - // Cursor - draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); - draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); - // Text - pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 38, "ETA:", GUIFont::Centre); - pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 32, str, GUIFont::Centre); - } - } - } -} + // Get the difference that the wrapped screen has from the actual one + wrappingOffset = screenBox.GetCorner() - nearestBoxItr->GetCorner(); + // Apply that offet to the objective point's position + objScenePos = itr->m_ScenePos + wrappingOffset; + + // Objective is within the screen, so draw the set arrow over it + if (withinAny) + itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], objScenePos - targetPos, itr->m_ArrowDir); + // Outside the screen, so draw it at the edge of it + else { + // Figure out which point is closest to the box, taking scene wrapping into account + objScenePos = nearestBoxItr->GetCenter() + g_SceneMan.ShortestDistance(nearestBoxItr->GetCenter(), objScenePos); + // Shortest distance from the edge of the screen box, not the center. + shortestDist -= halfScreenWidth; + + // Make the arrow point toward the edge of the screen + if (objScenePos.m_X >= nearestBoxItr->GetCorner().m_X + nearestBoxItr->GetWidth()) { + // Make the edge position approach the center of the vertical edge of the screen the farther away the objective position is from the screen + onScreenEdgePos = nearestBoxItr->GetWithinBox(objScenePos) - targetPos; + // Double the EaseIn to make it even more exponential, want the arrow to stay close to the edge for a long time + onScreenEdgePos.m_Y = rightStackY + EaseIn(0, onScreenEdgePos.m_Y - rightStackY, EaseIn(0, 1.0, 1.0 - (shortestDist / maxOffScreenSceneWidth))); + itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], onScreenEdgePos, ARROWRIGHT); + // Stack cursor moves down an arrowheight + rightStackY += m_aObjCursor[cursor][frame]->h; + } else if (objScenePos.m_X < nearestBoxItr->GetCorner().m_X) { + // Make the edge position approach the center of the vertical edge of the screen the farther away the objective position is from the screen + onScreenEdgePos = nearestBoxItr->GetWithinBox(objScenePos) - targetPos; + // Double the EaseIn to make it even more exponential, want the arrow to stay close to the edge for a long time + onScreenEdgePos.m_Y = leftStackY + EaseIn(0, onScreenEdgePos.m_Y - leftStackY, EaseIn(0, 1.0, 1.0 - (shortestDist / maxOffScreenSceneWidth))); + itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], onScreenEdgePos, ARROWLEFT); + // Stack cursor moves down an arrowheight + leftStackY += m_aObjCursor[cursor][frame]->h; + } else if (objScenePos.m_Y < nearestBoxItr->GetCorner().m_Y) + itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], nearestBoxItr->GetWithinBox(objScenePos) - targetPos, ARROWUP); + else + itr->Draw(pTargetBitmap, m_aObjCursor[cursor][frame], nearestBoxItr->GetWithinBox(objScenePos) - targetPos, ARROWDOWN); + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActiveCPUTeamCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns active CPU team count. -// Arguments: None. -// Return value: Returns active CPU team count. + // Team Icon up in the top left corner + const Icon* pIcon = GetTeamIcon(m_Team[PoS]); + if (pIcon) + draw_sprite(pTargetBitmap, pIcon->GetBitmaps8()[0], MAX(2, g_CameraMan.GetScreenOcclusion(which).m_X + 2), 2); + // Gold + std::snprintf(str, sizeof(str), "%c Funds: %.10g oz", TeamFundsChanged(which) ? -57 : -58, std::floor(GetTeamFunds(m_Team[PoS]))); + g_FrameMan.GetLargeFont()->DrawAligned(&pBitmapInt, MAX(16, g_CameraMan.GetScreenOcclusion(which).m_X + 16), yTextPos, str, GUIFont::Left); + /* Not applicable anymore to the 4-team games + // Body losses + std::snprintf(str, sizeof(str), "%c Losses: %c%i %c%i", -39, -62, GetTeamDeathCount(Teams::TeamOne), -59, GetTeamDeathCount(Teams::TeamTwo)); + g_FrameMan.GetLargeFont()->DrawAligned(&pBitmapInt, MIN(pTargetBitmap->w - 4, pTargetBitmap->w - 4 + g_CameraMan.GetScreenOcclusion(which).m_X), yTextPos, str, GUIFont::Right); + */ + // Show the player's controller scheme icon in the upper right corner of his screen, but only for a minute + if (m_GameTimer.GetElapsedRealTimeS() < 30) { + // TODO: Only blink if there hasn't been any input on a controller since start of game?? + // Blink them at first, but only if there's more than one human player + if (m_GameTimer.GetElapsedRealTimeS() > 4 || m_GameTimer.AlternateReal(150) || GetHumanCount() < 2) { + pIcon = g_UInputMan.GetSchemeIcon(PoS); + if (pIcon) { + draw_sprite(pTargetBitmap, pIcon->GetBitmaps8()[0], MIN(pTargetBitmap->w - pIcon->GetBitmaps8()[0]->w - 2, pTargetBitmap->w - pIcon->GetBitmaps8()[0]->w - 2 + g_CameraMan.GetScreenOcclusion(which).m_X), yTextPos); + // TODO: make a black Activity intro screen, saying "Player X, press any key/button to show that you are ready!, and display their controller icon, then fade into the scene" + // stretch_sprite(pTargetBitmap, pIcon->GetBitmaps8()[0], 10, 10, pIcon->GetBitmaps8()[0]->w * 4, pIcon->GetBitmaps8()[0]->h * 4); + } + } + } -int GameActivity::GetActiveCPUTeamCount() const -{ - int count = 0; + if (m_ActivityState == ActivityState::Running) { + if (m_InventoryMenuGUI[PoS] && m_InventoryMenuGUI[PoS]->IsVisible()) { + m_InventoryMenuGUI[PoS]->Draw(pTargetBitmap, targetPos); + } + if (m_pBuyGUI[PoS] && m_pBuyGUI[PoS]->IsVisible()) { + m_pBuyGUI[PoS]->Draw(pTargetBitmap); + } + } - for (int team = Teams::TeamOne; team < Activity::MaxTeamCount; team++) - if (TeamActive(team) && TeamIsCPU(team)) - count++; + // Draw actor picking crosshairs if applicable + if (m_ViewState[PoS] == ViewState::ActorSelect && m_IsActive[PoS] && m_IsHuman[PoS]) { + Vector center = m_ActorCursor[PoS] - targetPos; + circle(pTargetBitmap, center.m_X, center.m_Y, m_CursorTimer.AlternateReal(150) ? 6 : 8, g_YellowGlowColor); + // Add pixel glow area around it, in scene coordinates + g_PostProcessMan.RegisterGlowArea(m_ActorCursor[PoS], 10); + /* Crosshairs + putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); + */ + } + // AI point commands cursor + else if (m_ViewState[PoS] == ViewState::AIGoToPoint) { + Vector center = m_ActorCursor[PoS] - targetPos; + circle(pTargetBitmap, center.m_X, center.m_Y, m_CursorTimer.AlternateReal(150) ? 6 : 8, g_YellowGlowColor); + circlefill(pTargetBitmap, center.m_X, center.m_Y, 2, g_YellowGlowColor); + // putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); + // Add pixel glow area around it, in scene coordinates + g_PostProcessMan.RegisterGlowArea(m_ActorCursor[PoS], 10); - return count; -} + // Draw a line from the last set waypoint to the cursor + if (m_ControlledActor[PoS] && g_MovableMan.IsActor(m_ControlledActor[PoS])) + g_FrameMan.DrawLine(pTargetBitmap, m_ControlledActor[PoS]->GetLastAIWaypoint() - targetPos, m_ActorCursor[PoS] - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); + } + // Group selection circle + else if (m_ViewState[PoS] == ViewState::UnitSelectCircle) { + if (m_ControlledActor[PoS] && g_MovableMan.IsActor(m_ControlledActor[PoS])) { + Vector cursorDrawPos = m_ActorCursor[PoS] - targetPos; + Vector actorPos = m_ControlledActor[PoS]->GetPos(); + Vector drawPos = actorPos - targetPos; + + // Fix cursor coordinates + if (!targetPos.IsZero()) { + // Spans vertical scene seam + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.m_X < 0) && (m_ActorCursor[PoS].m_X > (sceneWidth - pTargetBitmap->w))) + cursorDrawPos.m_X -= sceneWidth; + else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_ActorCursor[PoS].m_X < pTargetBitmap->w)) + cursorDrawPos.m_X += sceneWidth; + } + // Spans horizontal scene seam + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.m_Y < 0) && (m_ActorCursor[PoS].m_Y > (sceneHeight - pTargetBitmap->h))) + cursorDrawPos.m_Y -= sceneHeight; + else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_ActorCursor[PoS].m_Y < pTargetBitmap->h)) + cursorDrawPos.m_Y += sceneHeight; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActiveHumanTeamCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns active human team count. -// Arguments: None. -// Return value: Returns active human team count. + // Fix circle center coordinates + if (!targetPos.IsZero()) { + // Spans vertical scene seam + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.m_X < 0) && (actorPos.m_X > (sceneWidth - pTargetBitmap->w))) + drawPos.m_X -= sceneWidth; + else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (actorPos.m_X < pTargetBitmap->w)) + drawPos.m_X += sceneWidth; + } + // Spans horizontal scene seam + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.m_Y < 0) && (actorPos.m_Y > (sceneHeight - pTargetBitmap->h))) + drawPos.m_Y -= sceneHeight; + else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (actorPos.m_Y < pTargetBitmap->h)) + drawPos.m_Y += sceneHeight; + } + } -int GameActivity::GetActiveHumanTeamCount() const -{ - int count = 0; + float radius = g_SceneMan.ShortestDistance(m_ActorCursor[PoS], m_ControlledActor[PoS]->GetPos(), true).GetMagnitude(); - for (int team = Teams::TeamOne; team < Activity::MaxTeamCount; team++) - if (TeamActive(team) && !TeamIsCPU(team)) - count++; + circle(pTargetBitmap, cursorDrawPos.m_X, cursorDrawPos.m_Y, m_CursorTimer.AlternateReal(150) ? 6 : 8, g_YellowGlowColor); + circlefill(pTargetBitmap, cursorDrawPos.m_X, cursorDrawPos.m_Y, 2, g_YellowGlowColor); - return count; -} + Vector unwrappedPos; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OtherTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next other team number from the one passed in, if any. If there -// are more than two teams in this game, then the next one in the series -// will be returned here. + // Check if we crossed the seam + if (g_SceneMan.GetScene()->WrapsX()) { + // Calculate unwrapped cursor position, or it won't glow + unwrappedPos = m_ActorCursor[PoS] - m_ControlledActor[PoS]->GetPos(); + float halfSceneWidth = sceneWidth * 0.5F; + float seamMinimum = 350.0F; -int GameActivity::OtherTeam(int team) -{ - // Only one team in this game, so can't return another one - if (m_TeamCount == 1) - return Teams::NoTeam; + if (unwrappedPos.MagnitudeIsGreaterThan(std::max(halfSceneWidth, seamMinimum))) { + if (m_ActorCursor->m_X < halfSceneWidth) + unwrappedPos = m_ActorCursor[PoS] + Vector(sceneWidth, 0); + else + unwrappedPos = m_ActorCursor[PoS] - Vector(sceneWidth, 0); + g_PostProcessMan.RegisterGlowArea(unwrappedPos, 10); + } + } else + unwrappedPos = m_ActorCursor[PoS]; + + g_PostProcessMan.RegisterGlowArea(m_ActorCursor[PoS], 10); + + // Glowing dotted circle version + int dots = 2 * c_PI * radius / 25; // 5 + (int)(radius / 10); + float radsperdot = 2 * 3.14159265359 / dots; + + for (int i = 0; i < dots; i++) { + Vector dotPos = Vector(actorPos.m_X + sin(i * radsperdot) * radius, actorPos.m_Y + cos(i * radsperdot) * radius); + Vector dotDrawPos = dotPos - targetPos; + + if (!targetPos.IsZero()) { + // Spans vertical scene seam + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.m_X < 0) && (dotPos.m_X > (sceneWidth - pTargetBitmap->w))) { + dotDrawPos.m_X -= sceneWidth; + } else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (actorPos.m_X < pTargetBitmap->w)) { + dotDrawPos.m_X += sceneWidth; + } + } + // Spans horizontal scene seam + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.m_Y < 0) && (dotPos.m_Y > (sceneHeight - pTargetBitmap->h))) { + dotDrawPos.m_Y -= sceneHeight; + } else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (actorPos.m_Y < pTargetBitmap->h)) { + dotDrawPos.m_Y += sceneHeight; + } + } - // Find another team that is active - bool loopedOnce = false; - for (int t = team + 1; ; t++) - { - // Loop - if (t >= MaxTeamCount) - t = Teams::TeamOne; + circlefill(pTargetBitmap, dotDrawPos.m_X, dotDrawPos.m_Y, 1, g_YellowGlowColor); + g_PostProcessMan.RegisterGlowArea(dotPos, 3); + } + } + } else { + // Cancel squad selection + } + } - if (t == team) - break; + if ((m_ActivityState == ActivityState::Editing || m_ActivityState == ActivityState::PreGame) && m_pEditorGUI[PoS]) + m_pEditorGUI[PoS]->Draw(pTargetBitmap, targetPos); - if (m_TeamActive[t]) - return t; - } + // Draw Banners + m_pBannerRed[PoS]->Draw(pTargetBitmap); + m_pBannerYellow[PoS]->Draw(pTargetBitmap); + } - return Teams::NoTeam; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this GameActivity's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + + void GameActivity::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + GUIFont* pLargeFont = g_FrameMan.GetLargeFont(); + GUIFont* pSmallFont = g_FrameMan.GetSmallFont(); + AllegroBitmap pBitmapInt(pTargetBitmap); + int frame = ((int)m_CursorTimer.GetElapsedSimTimeMS() % 1000) / 250; + int cursor = 0; + Vector landZone; + + // Iterate through all players, drawing each currently used LZ cursor. + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (!(m_IsActive[player] && m_IsHuman[player])) + continue; + + if (m_ViewState[player] == ViewState::LandingZoneSelect) { + int halfWidth = std::max(m_LZCursorWidth[player] / 2, 36); + int team = m_Team[player]; + if (team == Teams::NoTeam) + continue; + landZone = m_LandingZone[player] - targetPos; + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); + pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 36, "and then", GUIFont::Centre); + pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); + // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap + if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) { + // Wrap shit around and draw dupe on the other side + int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 42, m_AIReturnCraft[player] ? "Deliver here" : "Travel here", GUIFont::Centre); + pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 36, "and then", GUIFont::Centre); + pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 30, m_AIReturnCraft[player] ? "RETURN" : "STAY", GUIFont::Centre); + } + } + } + // Iterate through all teams, drawing all pending delivery cursors + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + char str[64]; + for (std::deque::iterator itr = m_Deliveries[team].begin(); itr != m_Deliveries[team].end(); ++itr) { + int halfWidth = 24; + landZone = itr->landingZone - targetPos; + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], landZone.m_X + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 38, "ETA:", GUIFont::Centre); + if (m_ActivityState == ActivityState::PreGame) + std::snprintf(str, sizeof(str), "???s"); + else + std::snprintf(str, sizeof(str), "%is", ((int)itr->delay - (int)itr->timer.GetElapsedSimTimeMS()) / 1000); + pLargeFont->DrawAligned(&pBitmapInt, landZone.m_X, landZone.m_Y - 32, str, GUIFont::Centre); + // Draw wrap around the world if necessary, and only if this is being drawn directly to a scenewide target bitmap + if (targetPos.IsZero() && (landZone.m_X < halfWidth || landZone.m_X > g_SceneMan.GetSceneWidth() - halfWidth)) { + // Wrap shit around and draw dupe on the other side + int wrappedX = landZone.m_X + (landZone.m_X < halfWidth ? g_SceneMan.GetSceneWidth() : -g_SceneMan.GetSceneWidth()); + // Cursor + draw_sprite(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX - halfWidth, landZone.m_Y - 48); + draw_sprite_h_flip(pTargetBitmap, m_aLZCursor[cursor][frame], wrappedX + halfWidth - m_aLZCursor[cursor][frame]->w, landZone.m_Y - 48); + // Text + pSmallFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 38, "ETA:", GUIFont::Centre); + pLargeFont->DrawAligned(&pBitmapInt, wrappedX, landZone.m_Y - 32, str, GUIFont::Centre); + } + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OneOrNoneTeamsLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether there is one and only one team left this game with -// a brain in its ranks. - -bool GameActivity::OneOrNoneTeamsLeft() -{ - // See if only one team remains with any brains - int brainTeamCount = 0; - int brainTeam = Teams::NoTeam; - for (int t = Teams::TeamOne; t < Teams::MaxTeamCount; ++t) - { - if (!m_TeamActive[t]) - continue; - if (g_MovableMan.GetFirstBrainActor(t)) - { - brainTeamCount++; - brainTeam = t; - } - } - - // If less than two teams left with any brains, they get indicated - // Also, if NO teams with brain are left, that is indicated with NoTeam - if (brainTeamCount <= 1) - return true; - - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActiveCPUTeamCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns active CPU team count. + // Arguments: None. + // Return value: Returns active CPU team count. + int GameActivity::GetActiveCPUTeamCount() const { + int count = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WhichTeamLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which single team is left, if any. -// Arguments: None. - -int GameActivity::WhichTeamLeft() -{ - int whichTeam = Teams::NoTeam; - - // See if only one team remains with any brains - int brainTeamCount = 0; - int brainTeam = Teams::NoTeam; - for (int t = Teams::TeamOne; t < Teams::MaxTeamCount; ++t) - { - if (!m_TeamActive[t]) - continue; - if (g_MovableMan.GetFirstBrainActor(t)) - { - brainTeamCount++; - brainTeam = t; - } - } - - // If exactly one team with brains, return that - if (brainTeamCount == 1) - return brainTeam; - - return Teams::NoTeam; -} + for (int team = Teams::TeamOne; team < Activity::MaxTeamCount; team++) + if (TeamActive(team) && TeamIsCPU(team)) + count++; + return count; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NoTeamLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether there are NO teams left with any brains at all! + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActiveHumanTeamCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns active human team count. + // Arguments: None. + // Return value: Returns active human team count. -bool GameActivity::NoTeamLeft() -{ - for (int t = Teams::TeamOne; t < Teams::MaxTeamCount; ++t) - { - if (!m_TeamActive[t]) - continue; - if (g_MovableMan.GetFirstBrainActor(t)) - return false; - } - return true; -} + int GameActivity::GetActiveHumanTeamCount() const { + int count = 0; + for (int team = Teams::TeamOne; team < Activity::MaxTeamCount; team++) + if (TeamActive(team) && !TeamIsCPU(team)) + count++; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: InitAIs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through all Actor:s currently in the MovableMan and gives each -// one not controlled by a Controller a CAI and appropriate AIMode setting -// based on team and CPU team. - -void GameActivity::InitAIs() -{ - Actor *pActor = 0; - Actor *pFirstActor = 0; - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team]) - continue; - // Get the first one - pFirstActor = pActor = g_MovableMan.GetNextTeamActor(team); - - do - { - // Set up AI controller if currently not player controlled - if (pActor && !pActor->GetController()->IsPlayerControlled()) - { - pActor->SetControllerMode(Controller::CIM_AI); - - // If human, set appropriate AI mode -// TODO: IMPROVE - if (dynamic_cast(pActor) || dynamic_cast(pActor)) - { - // Hunt if of CPU team, sentry default if of player team - if (team == m_CPUTeam) - pActor->SetAIMode(AHuman::AIMODE_BRAINHUNT); - else - pActor->SetAIMode(AHuman::AIMODE_SENTRY); - } - } - - // Next! - pActor = g_MovableMan.GetNextTeamActor(team, pActor); - } - while (pActor && pActor != pFirstActor); - } -} + return count; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OtherTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next other team number from the one passed in, if any. If there + // are more than two teams in this game, then the next one in the series + // will be returned here. + + int GameActivity::OtherTeam(int team) { + // Only one team in this game, so can't return another one + if (m_TeamCount == 1) + return Teams::NoTeam; + + // Find another team that is active + bool loopedOnce = false; + for (int t = team + 1;; t++) { + // Loop + if (t >= MaxTeamCount) + t = Teams::TeamOne; + + if (t == team) + break; + + if (m_TeamActive[t]) + return t; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DisableAIs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through all Actor:s currently in the MovableMan and gives each -// one not controlled by a Controller a CAI and appropriate AIMode setting -// based on team and CPU team. - -void GameActivity::DisableAIs(bool disable, int whichTeam) -{ - Actor *pActor = 0; - Actor *pFirstActor = 0; - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { - if (!m_TeamActive[team] || (whichTeam != Teams::NoTeam && team != whichTeam)) - continue; - // Get the first one - pFirstActor = pActor = g_MovableMan.GetNextTeamActor(team); - - do - { - // Disable the AI controllers - if (pActor && pActor->GetController()->GetInputMode() == Controller::CIM_AI) - pActor->GetController()->SetDisabled(disable); - - // Next! - pActor = g_MovableMan.GetNextTeamActor(team, pActor); - } - while (pActor && pActor != pFirstActor); - } -} + return Teams::NoTeam; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OneOrNoneTeamsLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether there is one and only one team left this game with + // a brain in its ranks. + + bool GameActivity::OneOrNoneTeamsLeft() { + // See if only one team remains with any brains + int brainTeamCount = 0; + int brainTeam = Teams::NoTeam; + for (int t = Teams::TeamOne; t < Teams::MaxTeamCount; ++t) { + if (!m_TeamActive[t]) + continue; + if (g_MovableMan.GetFirstBrainActor(t)) { + brainTeamCount++; + brainTeam = t; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Simply draws this' arrow relative to a point on a bitmap. - -void GameActivity::ObjectivePoint::Draw(BITMAP *pTargetBitmap, BITMAP *pArrowBitmap, const Vector &arrowPoint, ObjectiveArrowDir arrowDir) -{ - if (!pTargetBitmap || !pArrowBitmap) - return; - - AllegroBitmap allegroBitmap(pTargetBitmap); - int x = arrowPoint.GetFloorIntX(); - int y = arrowPoint.GetFloorIntY(); - int halfWidth = pArrowBitmap->w / 2; - int halfHeight = pArrowBitmap->h / 2; - int textSpace = 4; - - // Constrain the point within a gutter of the whole screen so the arrow is never right up agains teh edge of the screen. -/* - Box constrainBox(halfWidth, pArrowBitmap->h, pTargetBitmap->w - halfWidth, pTargetBitmap->h - pArrowBitmap->h); - x = constrainBox.GetWithinBoxX(x); - y = constrainBox.GetWithinBoxY(y); -*/ - if (x < halfWidth || x > pTargetBitmap->w - halfWidth) - { - if (x < halfWidth) - x = halfWidth; - if (x > pTargetBitmap->w - halfWidth) - x = pTargetBitmap->w - halfWidth - 1.0; - - if (y > pTargetBitmap->h - pArrowBitmap->h) - y = pTargetBitmap->h - pArrowBitmap->h; - else if (y < pArrowBitmap->h) - y = pArrowBitmap->h; - } - else if (y < halfHeight || y > pTargetBitmap->h - halfHeight) - { - if (y < halfHeight) - y = halfHeight; - if (y > pTargetBitmap->h - halfHeight) - y = pTargetBitmap->h - halfHeight - 1.0; - - if (x > pTargetBitmap->w - pArrowBitmap->w) - x = pTargetBitmap->w - pArrowBitmap->w; - else if (x < pArrowBitmap->w) - x = pArrowBitmap->w; - } - - // Draw the arrow and text descritpion of the Object so the point of the arrow ends up on the arrowPoint - if (arrowDir == ARROWDOWN) - { - masked_blit(pArrowBitmap, pTargetBitmap, 0, 0, x - halfWidth, y - pArrowBitmap->h, pArrowBitmap->w, pArrowBitmap->h); - g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x, y - pArrowBitmap->h - textSpace, m_Description, GUIFont::Centre, GUIFont::Bottom); - } - else if (arrowDir == ARROWLEFT) - { - rotate_sprite(pTargetBitmap, pArrowBitmap, x, y - halfHeight, itofix(64)); - g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x + pArrowBitmap->w + textSpace, y, m_Description, GUIFont::Left, GUIFont::Middle); - } - else if (arrowDir == ARROWRIGHT) - { - rotate_sprite(pTargetBitmap, pArrowBitmap, x - pArrowBitmap->w, y - halfHeight, itofix(-64)); - g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x - pArrowBitmap->w - textSpace, y, m_Description, GUIFont::Right, GUIFont::Middle); - } - else if (arrowDir == ARROWUP) - { - rotate_sprite(pTargetBitmap, pArrowBitmap, x - halfWidth, y, itofix(-128)); - g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x, y + pArrowBitmap->h + textSpace, m_Description, GUIFont::Centre, GUIFont::Top); - } -} - -std::string & GameActivity::GetNetworkPlayerName(int player) -{ - if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) - return m_NetworkPlayerNames[player]; - else - return m_NetworkPlayerNames[0]; -} - -void GameActivity::SetNetworkPlayerName(int player, std::string name) -{ - if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) - m_NetworkPlayerNames[player] = name; -} + // If less than two teams left with any brains, they get indicated + // Also, if NO teams with brain are left, that is indicated with NoTeam + if (brainTeamCount <= 1) + return true; + + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WhichTeamLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which single team is left, if any. + // Arguments: None. + + int GameActivity::WhichTeamLeft() { + int whichTeam = Teams::NoTeam; + + // See if only one team remains with any brains + int brainTeamCount = 0; + int brainTeam = Teams::NoTeam; + for (int t = Teams::TeamOne; t < Teams::MaxTeamCount; ++t) { + if (!m_TeamActive[t]) + continue; + if (g_MovableMan.GetFirstBrainActor(t)) { + brainTeamCount++; + brainTeam = t; + } + } + + // If exactly one team with brains, return that + if (brainTeamCount == 1) + return brainTeam; + + return Teams::NoTeam; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NoTeamLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether there are NO teams left with any brains at all! + + bool GameActivity::NoTeamLeft() { + for (int t = Teams::TeamOne; t < Teams::MaxTeamCount; ++t) { + if (!m_TeamActive[t]) + continue; + if (g_MovableMan.GetFirstBrainActor(t)) + return false; + } + return true; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: InitAIs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through all Actor:s currently in the MovableMan and gives each + // one not controlled by a Controller a CAI and appropriate AIMode setting + // based on team and CPU team. + + void GameActivity::InitAIs() { + Actor* pActor = 0; + Actor* pFirstActor = 0; + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team]) + continue; + // Get the first one + pFirstActor = pActor = g_MovableMan.GetNextTeamActor(team); + + do { + // Set up AI controller if currently not player controlled + if (pActor && !pActor->GetController()->IsPlayerControlled()) { + pActor->SetControllerMode(Controller::CIM_AI); + + // If human, set appropriate AI mode + // TODO: IMPROVE + if (dynamic_cast(pActor) || dynamic_cast(pActor)) { + // Hunt if of CPU team, sentry default if of player team + if (team == m_CPUTeam) + pActor->SetAIMode(AHuman::AIMODE_BRAINHUNT); + else + pActor->SetAIMode(AHuman::AIMODE_SENTRY); + } + } + + // Next! + pActor = g_MovableMan.GetNextTeamActor(team, pActor); + } while (pActor && pActor != pFirstActor); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DisableAIs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through all Actor:s currently in the MovableMan and gives each + // one not controlled by a Controller a CAI and appropriate AIMode setting + // based on team and CPU team. + + void GameActivity::DisableAIs(bool disable, int whichTeam) { + Actor* pActor = 0; + Actor* pFirstActor = 0; + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { + if (!m_TeamActive[team] || (whichTeam != Teams::NoTeam && team != whichTeam)) + continue; + // Get the first one + pFirstActor = pActor = g_MovableMan.GetNextTeamActor(team); + + do { + // Disable the AI controllers + if (pActor && pActor->GetController()->GetInputMode() == Controller::CIM_AI) + pActor->GetController()->SetDisabled(disable); + + // Next! + pActor = g_MovableMan.GetNextTeamActor(team, pActor); + } while (pActor && pActor != pFirstActor); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Simply draws this' arrow relative to a point on a bitmap. + + void GameActivity::ObjectivePoint::Draw(BITMAP* pTargetBitmap, BITMAP* pArrowBitmap, const Vector& arrowPoint, ObjectiveArrowDir arrowDir) { + if (!pTargetBitmap || !pArrowBitmap) + return; + + AllegroBitmap allegroBitmap(pTargetBitmap); + int x = arrowPoint.GetFloorIntX(); + int y = arrowPoint.GetFloorIntY(); + int halfWidth = pArrowBitmap->w / 2; + int halfHeight = pArrowBitmap->h / 2; + int textSpace = 4; + + // Constrain the point within a gutter of the whole screen so the arrow is never right up agains teh edge of the screen. + /* + Box constrainBox(halfWidth, pArrowBitmap->h, pTargetBitmap->w - halfWidth, pTargetBitmap->h - pArrowBitmap->h); + x = constrainBox.GetWithinBoxX(x); + y = constrainBox.GetWithinBoxY(y); + */ + if (x < halfWidth || x > pTargetBitmap->w - halfWidth) { + if (x < halfWidth) + x = halfWidth; + if (x > pTargetBitmap->w - halfWidth) + x = pTargetBitmap->w - halfWidth - 1.0; + + if (y > pTargetBitmap->h - pArrowBitmap->h) + y = pTargetBitmap->h - pArrowBitmap->h; + else if (y < pArrowBitmap->h) + y = pArrowBitmap->h; + } else if (y < halfHeight || y > pTargetBitmap->h - halfHeight) { + if (y < halfHeight) + y = halfHeight; + if (y > pTargetBitmap->h - halfHeight) + y = pTargetBitmap->h - halfHeight - 1.0; + + if (x > pTargetBitmap->w - pArrowBitmap->w) + x = pTargetBitmap->w - pArrowBitmap->w; + else if (x < pArrowBitmap->w) + x = pArrowBitmap->w; + } + + // Draw the arrow and text descritpion of the Object so the point of the arrow ends up on the arrowPoint + if (arrowDir == ARROWDOWN) { + masked_blit(pArrowBitmap, pTargetBitmap, 0, 0, x - halfWidth, y - pArrowBitmap->h, pArrowBitmap->w, pArrowBitmap->h); + g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x, y - pArrowBitmap->h - textSpace, m_Description, GUIFont::Centre, GUIFont::Bottom); + } else if (arrowDir == ARROWLEFT) { + rotate_sprite(pTargetBitmap, pArrowBitmap, x, y - halfHeight, itofix(64)); + g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x + pArrowBitmap->w + textSpace, y, m_Description, GUIFont::Left, GUIFont::Middle); + } else if (arrowDir == ARROWRIGHT) { + rotate_sprite(pTargetBitmap, pArrowBitmap, x - pArrowBitmap->w, y - halfHeight, itofix(-64)); + g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x - pArrowBitmap->w - textSpace, y, m_Description, GUIFont::Right, GUIFont::Middle); + } else if (arrowDir == ARROWUP) { + rotate_sprite(pTargetBitmap, pArrowBitmap, x - halfWidth, y, itofix(-128)); + g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, x, y + pArrowBitmap->h + textSpace, m_Description, GUIFont::Centre, GUIFont::Top); + } + } + + std::string& GameActivity::GetNetworkPlayerName(int player) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + return m_NetworkPlayerNames[player]; + else + return m_NetworkPlayerNames[0]; + } + + void GameActivity::SetNetworkPlayerName(int player, std::string name) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + m_NetworkPlayerNames[player] = name; + } } // namespace RTE diff --git a/Source/Activities/GameActivity.h b/Source/Activities/GameActivity.h index a60b9595c..0165b7176 100644 --- a/Source/Activities/GameActivity.h +++ b/Source/Activities/GameActivity.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,1120 +19,1066 @@ #include "Scene.h" #include "Actor.h" -namespace RTE -{ +namespace RTE { #define OBJARROWFRAMECOUNT 4 #define LZCURSORFRAMECOUNT 4 -class Actor; -class ACraft; -class PieMenu; -class InventoryMenuGUI; -class BuyMenuGUI; -class SceneEditorGUI; -class GUIBanner; -class Loadout; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: GameActivity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Base class for all GameActivity:s, including game modes and editors. -// Parent(s): Activity. -// Class history: 8/7/2007 GameActivity created. - -class GameActivity : public Activity { - - friend struct ActivityLuaBindings; - - // Keeps track of everything about a delivery in transit after purchase has been made with the menu - struct Delivery - { - // OWNED by this until the delivery is made! - ACraft *pCraft; - // Which player ordered this delivery - int orderedByPlayer; - // Where to land - Vector landingZone; - // How much this delivery was offset upwards for multi-ordering, stored to help with delivery icons. If 0, this was presumably not a multi-order. - float multiOrderYOffset; - // How long left until entry, in ms - long delay; - // Times how long we've been in transit - Timer timer; - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableOverrideMethods; - ClassInfoGetters; - - enum ObjectiveArrowDir - { - ARROWDOWN = 0, - ARROWLEFT, - ARROWRIGHT, - ARROWUP - }; - - enum BannerColor - { - RED = 0, - YELLOW - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GameActivity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GameActivity object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - GameActivity() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~GameActivity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a GameActivity object before deletion -// from system memory. -// Arguments: None. - - ~GameActivity() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GameActivity object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GameActivity to be identical to another, by deep copy. -// Arguments: A reference to the GameActivity to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const GameActivity &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire GameActivity, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Activity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GameActivity object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCPUTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current CPU-assisted team, if any (NoTeam) - LEGACY function -// Arguments: None. -// Return value: The current setting. NoTeam is no team is assisted. - - int GetCPUTeam() const { return m_CPUTeam; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCPUTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current CPU-assisted team, if any (NoTeam) - LEGACY function -// Arguments: The new setting. NoTeam is no team is assisted. -// Return value: None. - - void SetCPUTeam(int team = Activity::NoTeam); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetObservationTarget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the observation sceneman scroll targets, for when the game is -// over or a player is in observation mode -// Arguments: The new absolute position to observe. -// Which player to set it for. -// Return value: None. - - void SetObservationTarget(const Vector &newTarget, int player = 0) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) m_ObservationTarget[player] = newTarget; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDeathViewTarget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the player death sceneman scroll targets, for when a player- -// controlled actor dies and the view should go to his last position -// Arguments: The new absolute position to set as death view. -// Which player to set it for. -// Return value: None. - - void SetDeathViewTarget(const Vector &newTarget, int player = 0) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) m_DeathViewTarget[player] = newTarget; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLandingZone -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the he last selected landing zone. -// Arguments: The new absolute position to set as the last selected landing zone. -// Which player to set it for. -// Return value: None. - - void SetLandingZone(const Vector &newZone, int player = 0) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) m_LandingZone[player] = newZone; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLandingZone -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the he last selected landing zone. -// Arguments: Which player to get it for. -// Return value: The new absolute position to set as the last selected landing zone. - - Vector GetLandingZone(int player = 0) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) return m_LandingZone[player]; else return Vector(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetActorSelectCursor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the actor selection cursor position. -// Arguments: The new absolute position to put the cursor at. -// Which player to set it for. -// Return value: None. - - void SetActorSelectCursor(const Vector &newPos, int player = 0) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) m_ActorCursor[player] = newPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBuyGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the an in-game GUI Object for a specific player. -// Arguments: Which player to get the GUI for. -// Return value: A pointer to a BuyMenuGUI. Ownership is NOT transferred! - - BuyMenuGUI * GetBuyGUI(unsigned int which = 0) const { return m_pBuyGUI[which]; } - - /// - /// Checks if the in-game GUI Object is visible for a specific player. - /// - /// Which player to check the GUI for. -1 will check all players. - /// Whether or not the BuyMenuGUI is visible for input player(s). - bool IsBuyGUIVisible(int which = 0) const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the an in-game editor GUI Object for a specific player. -// Arguments: Which player to get the GUI for. -// Return value: A pointer to a SceneEditorGUI. Ownership is NOT transferred! - - SceneEditorGUI * GetEditorGUI(unsigned int which = 0) const { return m_pEditorGUI[which]; } - - /// - /// Locks a player controlled actor to a specific controller mode. - /// Locking the actor will disable player input, including switching actors. - /// - /// Which player to lock the actor for. - /// Whether to lock or unlock the actor. (Default: true) - /// Which controller mode to lock the actor to. (Default: `CIM_AI`) - /// Whether the (un)lock was performed. - bool LockControlledActor(Players player, bool lock = true, Controller::InputMode lockToMode = Controller::InputMode::CIM_AI); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SwitchToActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the this to focus player control to a specific Actor for a -// specific team. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: Which Actor to switch focus to. The team of this Actor will be set -// once it is passed in. Ownership IS NOT TRANSFERRED! The Actor should -// be added to MovableMan already. -// Return value: Whether the focus switch was successful or not. - - bool SwitchToActor(Actor *pActor, int player = 0, int team = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SwitchToNextActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the this to focus player control to the next Actor of a -// specific team, other than the current one focused on. -// Arguments: Which team to switch to next actor on. -// An actor pointer to skip in the sequence. -// Return value: None. - - void SwitchToNextActor(int player, int team, Actor *pSkip = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SwitchToPrevActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces this to focus player control to the previous Actor of a -// specific team, other than the current one focused on. -// Arguments: Which team to switch to next actor on. -// An actor pointer to skip in the sequence. -// Return value: None. - - void SwitchToPrevActor(int player, int team, Actor *pSkip = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetWinnerTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team is the winner, when the game is over. -// Arguments: The team number of the winning team. 0 is team #1. Negative number -// means the game isn't over yet. -// Return value: None. - - void SetWinnerTeam(int winnerTeam) { m_WinnerTeam = winnerTeam; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetWinnerTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which team is the winner, when the game is over. -// Arguments: None. -// Return value: The team number of the winning team. 0 is team #1. Negative number -// means the game isn't over yet. - - int GetWinnerTeam() const { return m_WinnerTeam; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBanner -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets access to the huge banner of any player that can display -// messages which can not be missed or ignored. -// Arguments: Which color banner to get - see the GameActivity::BannerColor enum. -// Which player's banner to get. -// Return value: A pointer to the GUIBanner object that we can - - GUIBanner * GetBanner(int whichColor = YELLOW, int player = Players::PlayerOne) { return whichColor == YELLOW ? m_pBannerYellow[player] : m_pBannerRed[player]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLZArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the Area within which a team can land things. -// Arguments: The number of the team we're setting for. -// The Area we're setting to limit their landings within. -// Return value: None. - - void SetLZArea(int team, const Scene::Area &newArea) { m_LandingZoneArea[team].Reset(); m_LandingZoneArea[team].Create(newArea); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLZArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the Area within which a team can land things. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: The number of the team we're setting for. -// Return value: The Area we're using to limit their landings within. OWNERSHIP IS NOT TRANSFERRED! - - const Scene::Area & GetLZArea(int team) const { return m_LandingZoneArea[team]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBrainLZWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the width of the landing zone box that follows around a player's -// brain. -// Arguments: The number of the in-game player we're setting for. -// The width of the box, in pixels. 0 means disabled. -// Return value: None. - - void SetBrainLZWidth(int player, int width) { m_BrainLZWidth[player] = width; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBrainLZWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the width of the landing zone box that follows around a player's -// brain. -// Arguments: The number of the player we're getting for. -// Return value: The width in pixels of the landing zone. - - int GetBrainLZWidth(int player) const { return m_BrainLZWidth[player]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddObjectivePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Created an objective point for one of the teams to show until cleared. -// Arguments: The team number of the team to give objective. 0 is team #1. -// The very short description of what the objective is (three short words max) -// The absolute scene coordiante position of the objective. -// The desired direction of the arrow when the point is on screen. -// Return value: None. - - void AddObjectivePoint(std::string description, Vector objPos, int whichTeam = Teams::TeamOne, ObjectiveArrowDir arrowDir = ARROWDOWN); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: YSortObjectivePoints -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sorts all objective points according to their positions on the Y axis. -// Arguments: None. -// Return value: None. - - void YSortObjectivePoints(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearObjectivePoints -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all objective points previously added, for both teams. -// Arguments: None. -// Return value: None. - - void ClearObjectivePoints() { m_Objectives.clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddOverridePurchase -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds somehting to the purchase list that will override what is set -// in the buy guy next time CreateDelivery is called. -// Arguments: The SceneObject preset to add to the override purchase list. OWNERSHIP IS NOT TRANSFERRED! -// Which player's list to add an override purchase item to. -// Return value: The new total value of what's in the override purchase list. - - int AddOverridePurchase(const SceneObject *pPurchase, int player); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOverridePurchaseList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: First clears and then adds all the stuff in a Loadout to the override -// purchase list. -// Arguments: The Loadout preset to set the override purchase list to reflect. OWNERSHIP IS NOT TRANSFERRED! -// The player we're talking about. -// Return value: The new total value of what's in the override purchase list. - - int SetOverridePurchaseList(const Loadout *pLoadout, int player); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOverridePurchaseList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: First clears and then adds all the stuff in a Loadout to the override -// purchase list. -// Arguments: The name of the Loadout preset to set the override purchase list to -// represent. -// Return value: The new total value of what's in the override purchase list. - - int SetOverridePurchaseList(std::string loadoutName, int player); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearOverridePurchase -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all items from a specific player's override purchase list. -// Arguments: Which player's override purchase list to clear. -// Return value: None. - - void ClearOverridePurchase(int player) { m_PurchaseOverride[player].clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateDelivery -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes the current order out of a player's buy GUI, creates a Delivery -// based off it, and stuffs it into that player's delivery queue. -// Arguments: Which player to create the delivery for. Cargo AI mode and waypoint. -// Return value: Success or not. - - bool CreateDelivery(int player, int mode, Vector &waypoint) { return CreateDelivery(player, mode, waypoint, NULL); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateDelivery -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes the current order out of a player's buy GUI, creates a Delivery -// based off it, and stuffs it into that player's delivery queue. -// Arguments: Which player to create the delivery for. Cargo AI mode and TargetMO. -// Return value: Success or not. - - bool CreateDelivery(int player, int mode, Actor *pTargetMO) { Vector point( -1, -1 ); return CreateDelivery(player, mode, point, pTargetMO); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateDelivery -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes the current order out of a player's buy GUI, creates a Delivery -// based off it, and stuffs it into that player's delivery queue. -// Arguments: Which player to create the delivery for and Cargo AI mode. -// Return value: Success or not. - - bool CreateDelivery(int player, int mode) { Vector point( -1, -1 ); return CreateDelivery(player, mode, point, NULL); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateDelivery -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes the current order out of a player's buy GUI, creates a Delivery -// based off it, and stuffs it into that player's delivery queue. -// Arguments: Which player to create the delivery for. -// Return value: Success or not. - - bool CreateDelivery(int player) { Vector point( -1, -1 ); return CreateDelivery(player, Actor::AIMODE_SENTRY, point, NULL); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeliveryCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows how many deliveries this team has pending. -// Arguments: Which team to check the delivery count for. -// Return value: The number of deliveries this team has coming. - - int GetDeliveryCount(int team) { return m_Deliveries[team].size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetupPlayers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Precalculates the player-to-screen index map, counts the number of -// active players etc. -// Arguments: None. -// Return value: None. - - void SetupPlayers() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateEditing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: This is a special update step for when any player is still editing the -// scene. -// Arguments: None. -// Return value: None. - - void UpdateEditing(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTeamTech -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the name of the tech module selected for this team during scenario setup -// Arguments: Team to return tech module for -// Return value: Tech module name, for example Dummy.rte, or empty string if there is no team - std::string GetTeamTech(int team) const { return (team >= Teams::TeamOne && team < Teams::MaxTeamCount) ? m_TeamTech[team] : ""; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTeamTech -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets tech module name for specified team. Module must set must be loaded. -// Arguments: Team to set module, module name, for example Dummy.rte -// Return value: None - void SetTeamTech(int team, std::string tech); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TeamIsCPU -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether a specific team is assigned a CPU player in the current game. -// Arguments: Which team index to check. -// Return value: Whether the team is assigned a CPU player in the current activity. - bool TeamIsCPU(int team) const { return (team >= Teams::TeamOne && team < Teams::MaxTeamCount) ? m_TeamIsCPU[team] : false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActiveCPUTeamCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns active CPU team count. -// Arguments: None. -// Return value: Returns active CPU team count. - int GetActiveCPUTeamCount() const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActiveHumanTeamCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns active human team count. -// Arguments: None. -// Return value: Returns active human team count. - int GetActiveHumanTeamCount() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetStartingGold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes how much starting gold was selected in scenario setup dialog. 20000 - infinite amount. -// Arguments: Starting gold amount -// Return value: None. - void SetStartingGold(int amount) { m_StartingGold = amount; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetStartingGold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns how much starting gold was selected in scenario setup dialog. 20000 - infinite amount. -// Arguments: None. -// Return value: How much starting gold must be given to human players. - int GetStartingGold() { return m_StartingGold; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFogOfWarEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes whether fog of war must be enabled for this activity or not. -// Never hides or reveals anything, just changes internal flag. -// Arguments: New fog of war state. true = enabled. -// Return value: None. - void SetFogOfWarEnabled(bool enable) { m_FogOfWarEnabled = enable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFogOfWareEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether fog of war must be enabled for this activity or not. -// Call it to determine whether you should call MakeAllUnseen or not at the start of activity. -// Arguments: None. -// Return value: Whether Fog of war flag was checked during scenario setup dialog. - bool GetFogOfWarEnabled() { return m_FogOfWarEnabled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRequireClearPathToOrbit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether player activity requires a cleat path to orbit to place brain -// -// Arguments: None. -// Return value: Whether we need a clear path to orbit to place brains. - bool GetRequireClearPathToOrbit() const { return m_RequireClearPathToOrbit; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetRequireClearPathToOrbit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether player activity requires a cleat path to orbit to place brain -// -// Arguments: Whether we need a clear path to orbit to place brains. -// Return value: None. - void SetRequireClearPathToOrbit(bool newvalue) { m_RequireClearPathToOrbit = newvalue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultFogOfWar() const { return m_DefaultFogOfWar; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultRequireClearPathToOrbit() const { return m_DefaultRequireClearPathToOrbit; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultDeployUnits() const { return m_DefaultDeployUnits; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultGoldCakeDifficulty() const { return m_DefaultGoldCakeDifficulty; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultGoldEasyDifficulty() const { return m_DefaultGoldEasyDifficulty; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultGoldMediumDifficulty() const { return m_DefaultGoldMediumDifficulty; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultGoldHardDifficulty() const { return m_DefaultGoldHardDifficulty; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - int GetDefaultGoldNutsDifficulty() const { return m_DefaultGoldNutsDifficulty; } - - - /// - /// Gets the default gold for max difficulty. - /// - /// The default gold for max difficulty. - int GetDefaultGoldMaxDifficulty() const { return m_DefaultGoldMaxDifficulty; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - bool GetFogOfWarSwitchEnabled() const { return m_FogOfWarSwitchEnabled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - bool GetDeployUnitsSwitchEnabled() const { return m_DeployUnitsSwitchEnabled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - - bool GetGoldSwitchEnabled() const { return m_GoldSwitchEnabled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// Arguments: None. -// Return value: - - bool GetRequireClearPathToOrbitSwitchEnabled() const { return m_RequireClearPathToOrbitSwitchEnabled; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCrabToHumanSpawnRatio -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns CrabToHumanSpawnRatio for specified module -// Arguments: None. -// Return value: Crab-To-Human spawn ratio value set for specified module, 0.25 is default. - - float GetCrabToHumanSpawnRatio(int moduleid); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeliveryDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns current delivery delay -// Arguments: None. -// Return value: Returns current delivery delay - - long GetDeliveryDelay() const { return m_DeliveryDelay; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDeliveryDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets delivery delay -// Arguments: New delivery delay value in ms -// Return value: None - - void SetDeliveryDelay(long newDeliveryDelay) { m_DeliveryDelay = newDeliveryDelay > 1 ? newDeliveryDelay : 1; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBuyMenuEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether buy menu is enabled in this activity. -// Arguments: True if buy menu enabled false otherwise -// Return value: None. - - bool GetBuyMenuEnabled() const { return m_BuyMenuEnabled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBuyMenuEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether buy menu is enabled in this activity -// Arguments: True to enable buy menu, false otherwise -// Return value: None. - - void SetBuyMenuEnabled(bool newValue) { m_BuyMenuEnabled = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNetworkPlayerName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns network player name -// Arguments: Player -// Return value: Network player name - - std::string & GetNetworkPlayerName(int player); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetNetworkPlayerName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets network player name -// Arguments: Player number, player name -// Return value: None - - void SetNetworkPlayerName(int player, std::string name); - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: CreateDelivery - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Takes the current order out of a player's buy GUI, creates a Delivery - // based off it, and stuffs it into that player's delivery queue. - // Arguments: Which player to create the delivery for. Cargo AI mode waypoint or TargetMO. - // Return value: Success or not. - - bool CreateDelivery(int player, int mode, Vector &waypoint, Actor *pTargetMO); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Struct: ObjectivePoint - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: A struct to keep all data about a mission objective. - // Parent(s): None. - // Class history: 11/17/2008 ObjectivePoint - - struct ObjectivePoint - { - ObjectivePoint() { m_Description.clear(); m_ScenePos.Reset(); m_Team = Teams::NoTeam; m_ArrowDir = ARROWDOWN; } - ObjectivePoint(const std::string &desc, const Vector &pos, int team = -1, ObjectiveArrowDir arrowDir = ARROWDOWN) { m_Description = desc; m_ScenePos = pos; m_Team = (Teams)team; m_ArrowDir = arrowDir; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Draw - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Simply draws this' arrow relative to a point on a bitmap. - // Arguments: A pointer to the BITMAP to draw on. - // The arrow bitmap to draw, assuming it points downward. - // The absolute position on the bitmap to draw the point of the arrow at. - // Which orientation to draw the arrow in, relative to the point. - // Return value: None. - - void Draw(BITMAP *pTargetBitmap, BITMAP *pArrowBitmap, const Vector &arrowPoint, ObjectiveArrowDir arrowDir = ARROWDOWN); - - - // The description of this objective point - std::string m_Description; - // Absolute position in the scene where this is pointed - Vector m_ScenePos; - // The team this objective is relevant to - Teams m_Team; - // The positioning of the arrow that points at this objective - ObjectiveArrowDir m_ArrowDir; - }; - - - // Comparison functor for sorting objective points by their y pos using STL's sort - struct ObjPointYPosComparison { - bool operator()(ObjectivePoint &rhs, ObjectivePoint &lhs) { return rhs.m_ScenePos.m_Y < lhs.m_ScenePos.m_Y; } - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OtherTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next other team number from the one passed in, if any. If there -// are more than two teams in this game, then the next one in the series -// will be returned here. -// Arguments: The team not to get. -// Return value: The other team's number. - - int OtherTeam(int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OneOrNoneTeamsLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether there is less than two teams left in this game with -// a brain in its ranks. -// Arguments: None. -// Return value: Whether less than two teams have brains in them left. - - bool OneOrNoneTeamsLeft(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WhichTeamLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which single team is left, if any. -// Arguments: None. -// Return value: Which team stands alone with any brains in its ranks, if any. NoTeam -// is returned if there's either more than one team, OR there are no -// teams at all left with brains in em. - - int WhichTeamLeft(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NoTeamLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether there are NO teams left with any brains at all! -// Arguments: None. -// Return value: Whether any team has a brain in it at all. - - bool NoTeamLeft(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: InitAIs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through all Actor:s currently in the MovableMan and sets each -// one not controlled by a player to be AI controlled and AIMode setting -// based on team and CPU team. -// Arguments: None. -// Return value: None. - - virtual void InitAIs(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DisableAIs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through all Actor:s currently in the MovableMan and disables or -// enables each one with a Controller set to AI input. -// Arguments: Whether to disable or enable them; -// Which team to do this to. If all, then pass Teams::NoTeam -// Return value: None. - - void DisableAIs(bool disable = true, int whichTeam = Teams::NoTeam); - - - - - // Member variables - static Entity::ClassInfo m_sClass; - - // Which team is CPU-managed, if any (-1) - LEGACY, now controlled by Activity::m_IsHuman - int m_CPUTeam; - // Team is active or not this game - bool m_TeamIsCPU[Teams::MaxTeamCount]; - - // The observation sceneman scroll targets, for when the game is over or a player is in observation mode - Vector m_ObservationTarget[Players::MaxPlayerCount]; - // The player death sceneman scroll targets, for when a player-controlled actor dies and the view should go to his last position - Vector m_DeathViewTarget[Players::MaxPlayerCount]; - // Times the delay between regular actor swtich, and going into manual siwtch mode - Timer m_ActorSelectTimer[Players::MaxPlayerCount]; - // The cursor for selecting new Actors - Vector m_ActorCursor[Players::MaxPlayerCount]; - // Highlighted actor while cursor switching; will be switched to if switch button is released now - Actor *m_pLastMarkedActor[Players::MaxPlayerCount]; - // The last selected landing zone - Vector m_LandingZone[Players::MaxPlayerCount]; - // Whether the last craft was set to return or not after delivering - bool m_AIReturnCraft[Players::MaxPlayerCount]; - std::array, Players::MaxPlayerCount> m_StrategicModePieMenu; //!< The strategic mode PieMenus for each Player. - // The inventory menu gui for each player - InventoryMenuGUI *m_InventoryMenuGUI[Players::MaxPlayerCount]; - // The in-game buy GUIs for each player - BuyMenuGUI *m_pBuyGUI[Players::MaxPlayerCount]; - // The in-game scene editor GUI for each player - SceneEditorGUI *m_pEditorGUI[Players::MaxPlayerCount]; - bool m_LuaLockActor[Players::MaxPlayerCount]; //!< Whether or not to lock input for each player while lua has control. - Controller::InputMode m_LuaLockActorMode[Players::MaxPlayerCount]; //!< The input mode to lock to while lua has control. - // The in-game important message banners for each player - GUIBanner *m_pBannerRed[Players::MaxPlayerCount]; - GUIBanner *m_pBannerYellow[Players::MaxPlayerCount]; - // How many times a banner has been repeated.. so we dont' annoy by repeating forever - int m_BannerRepeats[Players::MaxPlayerCount]; - // Whether each player has marked himself as ready to start. Can still edit while this is set, but when all are set, the game starts - bool m_ReadyToStart[Players::MaxPlayerCount]; - // An override purchase list that can be set by a script and will be used instead of what's in the buy menu. Object held in here are NOT OWNED - // Once a delivery is made with anything in here, this list is automatically cleared out, and the next delivery will be what's set in the buy menu. - std::list m_PurchaseOverride[Players::MaxPlayerCount]; - - // The delivery queue which contains all the info about all the made orders currently in transit to delivery - std::deque m_Deliveries[Teams::MaxTeamCount]; - // The box within where landing zones can be put - Scene::Area m_LandingZoneArea[Teams::MaxTeamCount]; - // How wide around the brain the automatic LZ is following - int m_BrainLZWidth[Players::MaxPlayerCount]; - // The objective points for each team - std::list m_Objectives; - - // Tech of player - std::string m_TeamTech[Teams::MaxTeamCount]; - - // Initial gold amount selected by player in scenario setup dialog - int m_StartingGold; - // Whether fog of war was enabled or not in scenario setup dialog - bool m_FogOfWarEnabled; - // Whether we need a clear path to orbit to place brain - bool m_RequireClearPathToOrbit; - - // Default fog of war switch state for this activity, default -1 (unspecified) - int m_DefaultFogOfWar; - // Default clear path to orbit switch value, default -1 (unspecified) - int m_DefaultRequireClearPathToOrbit; - // Default deploy units swutch value, default -1 (unspecified) - int m_DefaultDeployUnits; - // Default gold amount for different difficulties, defalt -1 (unspecified) - int m_DefaultGoldCakeDifficulty; - int m_DefaultGoldEasyDifficulty; - int m_DefaultGoldMediumDifficulty; - int m_DefaultGoldHardDifficulty; - int m_DefaultGoldNutsDifficulty; - int m_DefaultGoldMaxDifficulty; - // Whether those switches are enabled or disabled in scenario setup dialog, true by default - bool m_FogOfWarSwitchEnabled; - bool m_DeployUnitsSwitchEnabled; - bool m_GoldSwitchEnabled; - bool m_RequireClearPathToOrbitSwitchEnabled; - bool m_BuyMenuEnabled; - - // The cursor animations for the LZ indicators - std::vector m_aLZCursor[4]; - std::array m_LZCursorWidth; //!< The width of each players' LZ cursor. - // The cursor animations for the objective indications - std::vector m_aObjCursor[4]; - - // Time it takes for a delivery to be made, in ms - long m_DeliveryDelay; - // Cursor animation timer - Timer m_CursorTimer; - // Total gameplay timer, not including editing phases - Timer m_GameTimer; - // Game end timer - Timer m_GameOverTimer; - // Time between game over and reset - long m_GameOverPeriod; - // The winning team number, when the game is over - int m_WinnerTeam; - - std::string m_NetworkPlayerNames[Players::MaxPlayerCount]; - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; + class Actor; + class ACraft; + class PieMenu; + class InventoryMenuGUI; + class BuyMenuGUI; + class SceneEditorGUI; + class GUIBanner; + class Loadout; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: GameActivity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Base class for all GameActivity:s, including game modes and editors. + // Parent(s): Activity. + // Class history: 8/7/2007 GameActivity created. + + class GameActivity : public Activity { + + friend struct ActivityLuaBindings; + + // Keeps track of everything about a delivery in transit after purchase has been made with the menu + struct Delivery { + // OWNED by this until the delivery is made! + ACraft* pCraft; + // Which player ordered this delivery + int orderedByPlayer; + // Where to land + Vector landingZone; + // How much this delivery was offset upwards for multi-ordering, stored to help with delivery icons. If 0, this was presumably not a multi-order. + float multiOrderYOffset; + // How long left until entry, in ms + long delay; + // Times how long we've been in transit + Timer timer; + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableOverrideMethods; + ClassInfoGetters; + + enum ObjectiveArrowDir { + ARROWDOWN = 0, + ARROWLEFT, + ARROWRIGHT, + ARROWUP + }; + + enum BannerColor { + RED = 0, + YELLOW + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GameActivity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GameActivity object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + GameActivity() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~GameActivity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a GameActivity object before deletion + // from system memory. + // Arguments: None. + + ~GameActivity() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GameActivity object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GameActivity to be identical to another, by deep copy. + // Arguments: A reference to the GameActivity to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const GameActivity& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire GameActivity, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Activity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GameActivity object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCPUTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current CPU-assisted team, if any (NoTeam) - LEGACY function + // Arguments: None. + // Return value: The current setting. NoTeam is no team is assisted. + + int GetCPUTeam() const { return m_CPUTeam; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCPUTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current CPU-assisted team, if any (NoTeam) - LEGACY function + // Arguments: The new setting. NoTeam is no team is assisted. + // Return value: None. + + void SetCPUTeam(int team = Activity::NoTeam); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetObservationTarget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the observation sceneman scroll targets, for when the game is + // over or a player is in observation mode + // Arguments: The new absolute position to observe. + // Which player to set it for. + // Return value: None. + + void SetObservationTarget(const Vector& newTarget, int player = 0) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + m_ObservationTarget[player] = newTarget; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDeathViewTarget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the player death sceneman scroll targets, for when a player- + // controlled actor dies and the view should go to his last position + // Arguments: The new absolute position to set as death view. + // Which player to set it for. + // Return value: None. + + void SetDeathViewTarget(const Vector& newTarget, int player = 0) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + m_DeathViewTarget[player] = newTarget; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLandingZone + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the he last selected landing zone. + // Arguments: The new absolute position to set as the last selected landing zone. + // Which player to set it for. + // Return value: None. + + void SetLandingZone(const Vector& newZone, int player = 0) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + m_LandingZone[player] = newZone; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLandingZone + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the he last selected landing zone. + // Arguments: Which player to get it for. + // Return value: The new absolute position to set as the last selected landing zone. + + Vector GetLandingZone(int player = 0) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + return m_LandingZone[player]; + else + return Vector(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetActorSelectCursor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the actor selection cursor position. + // Arguments: The new absolute position to put the cursor at. + // Which player to set it for. + // Return value: None. + + void SetActorSelectCursor(const Vector& newPos, int player = 0) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + m_ActorCursor[player] = newPos; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBuyGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the an in-game GUI Object for a specific player. + // Arguments: Which player to get the GUI for. + // Return value: A pointer to a BuyMenuGUI. Ownership is NOT transferred! + + BuyMenuGUI* GetBuyGUI(unsigned int which = 0) const { return m_pBuyGUI[which]; } + + /// + /// Checks if the in-game GUI Object is visible for a specific player. + /// + /// Which player to check the GUI for. -1 will check all players. + /// Whether or not the BuyMenuGUI is visible for input player(s). + bool IsBuyGUIVisible(int which = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the an in-game editor GUI Object for a specific player. + // Arguments: Which player to get the GUI for. + // Return value: A pointer to a SceneEditorGUI. Ownership is NOT transferred! + + SceneEditorGUI* GetEditorGUI(unsigned int which = 0) const { return m_pEditorGUI[which]; } + + /// + /// Locks a player controlled actor to a specific controller mode. + /// Locking the actor will disable player input, including switching actors. + /// + /// Which player to lock the actor for. + /// Whether to lock or unlock the actor. (Default: true) + /// Which controller mode to lock the actor to. (Default: `CIM_AI`) + /// Whether the (un)lock was performed. + bool LockControlledActor(Players player, bool lock = true, Controller::InputMode lockToMode = Controller::InputMode::CIM_AI); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SwitchToActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the this to focus player control to a specific Actor for a + // specific team. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: Which Actor to switch focus to. The team of this Actor will be set + // once it is passed in. Ownership IS NOT TRANSFERRED! The Actor should + // be added to MovableMan already. + // Return value: Whether the focus switch was successful or not. + + bool SwitchToActor(Actor* pActor, int player = 0, int team = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SwitchToNextActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the this to focus player control to the next Actor of a + // specific team, other than the current one focused on. + // Arguments: Which team to switch to next actor on. + // An actor pointer to skip in the sequence. + // Return value: None. + + void SwitchToNextActor(int player, int team, Actor* pSkip = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SwitchToPrevActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces this to focus player control to the previous Actor of a + // specific team, other than the current one focused on. + // Arguments: Which team to switch to next actor on. + // An actor pointer to skip in the sequence. + // Return value: None. + + void SwitchToPrevActor(int player, int team, Actor* pSkip = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetWinnerTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team is the winner, when the game is over. + // Arguments: The team number of the winning team. 0 is team #1. Negative number + // means the game isn't over yet. + // Return value: None. + + void SetWinnerTeam(int winnerTeam) { m_WinnerTeam = winnerTeam; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetWinnerTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which team is the winner, when the game is over. + // Arguments: None. + // Return value: The team number of the winning team. 0 is team #1. Negative number + // means the game isn't over yet. + + int GetWinnerTeam() const { return m_WinnerTeam; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBanner + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets access to the huge banner of any player that can display + // messages which can not be missed or ignored. + // Arguments: Which color banner to get - see the GameActivity::BannerColor enum. + // Which player's banner to get. + // Return value: A pointer to the GUIBanner object that we can + + GUIBanner* GetBanner(int whichColor = YELLOW, int player = Players::PlayerOne) { return whichColor == YELLOW ? m_pBannerYellow[player] : m_pBannerRed[player]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLZArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the Area within which a team can land things. + // Arguments: The number of the team we're setting for. + // The Area we're setting to limit their landings within. + // Return value: None. + + void SetLZArea(int team, const Scene::Area& newArea) { + m_LandingZoneArea[team].Reset(); + m_LandingZoneArea[team].Create(newArea); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLZArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the Area within which a team can land things. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: The number of the team we're setting for. + // Return value: The Area we're using to limit their landings within. OWNERSHIP IS NOT TRANSFERRED! + + const Scene::Area& GetLZArea(int team) const { return m_LandingZoneArea[team]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBrainLZWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the width of the landing zone box that follows around a player's + // brain. + // Arguments: The number of the in-game player we're setting for. + // The width of the box, in pixels. 0 means disabled. + // Return value: None. + + void SetBrainLZWidth(int player, int width) { m_BrainLZWidth[player] = width; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBrainLZWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the width of the landing zone box that follows around a player's + // brain. + // Arguments: The number of the player we're getting for. + // Return value: The width in pixels of the landing zone. + + int GetBrainLZWidth(int player) const { return m_BrainLZWidth[player]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddObjectivePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Created an objective point for one of the teams to show until cleared. + // Arguments: The team number of the team to give objective. 0 is team #1. + // The very short description of what the objective is (three short words max) + // The absolute scene coordiante position of the objective. + // The desired direction of the arrow when the point is on screen. + // Return value: None. + + void AddObjectivePoint(std::string description, Vector objPos, int whichTeam = Teams::TeamOne, ObjectiveArrowDir arrowDir = ARROWDOWN); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: YSortObjectivePoints + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sorts all objective points according to their positions on the Y axis. + // Arguments: None. + // Return value: None. + + void YSortObjectivePoints(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearObjectivePoints + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all objective points previously added, for both teams. + // Arguments: None. + // Return value: None. + + void ClearObjectivePoints() { m_Objectives.clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddOverridePurchase + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds somehting to the purchase list that will override what is set + // in the buy guy next time CreateDelivery is called. + // Arguments: The SceneObject preset to add to the override purchase list. OWNERSHIP IS NOT TRANSFERRED! + // Which player's list to add an override purchase item to. + // Return value: The new total value of what's in the override purchase list. + + int AddOverridePurchase(const SceneObject* pPurchase, int player); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOverridePurchaseList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: First clears and then adds all the stuff in a Loadout to the override + // purchase list. + // Arguments: The Loadout preset to set the override purchase list to reflect. OWNERSHIP IS NOT TRANSFERRED! + // The player we're talking about. + // Return value: The new total value of what's in the override purchase list. + + int SetOverridePurchaseList(const Loadout* pLoadout, int player); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOverridePurchaseList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: First clears and then adds all the stuff in a Loadout to the override + // purchase list. + // Arguments: The name of the Loadout preset to set the override purchase list to + // represent. + // Return value: The new total value of what's in the override purchase list. + + int SetOverridePurchaseList(std::string loadoutName, int player); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearOverridePurchase + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all items from a specific player's override purchase list. + // Arguments: Which player's override purchase list to clear. + // Return value: None. + + void ClearOverridePurchase(int player) { m_PurchaseOverride[player].clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateDelivery + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes the current order out of a player's buy GUI, creates a Delivery + // based off it, and stuffs it into that player's delivery queue. + // Arguments: Which player to create the delivery for. Cargo AI mode and waypoint. + // Return value: Success or not. + + bool CreateDelivery(int player, int mode, Vector& waypoint) { return CreateDelivery(player, mode, waypoint, NULL); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateDelivery + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes the current order out of a player's buy GUI, creates a Delivery + // based off it, and stuffs it into that player's delivery queue. + // Arguments: Which player to create the delivery for. Cargo AI mode and TargetMO. + // Return value: Success or not. + + bool CreateDelivery(int player, int mode, Actor* pTargetMO) { + Vector point(-1, -1); + return CreateDelivery(player, mode, point, pTargetMO); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateDelivery + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes the current order out of a player's buy GUI, creates a Delivery + // based off it, and stuffs it into that player's delivery queue. + // Arguments: Which player to create the delivery for and Cargo AI mode. + // Return value: Success or not. + + bool CreateDelivery(int player, int mode) { + Vector point(-1, -1); + return CreateDelivery(player, mode, point, NULL); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateDelivery + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes the current order out of a player's buy GUI, creates a Delivery + // based off it, and stuffs it into that player's delivery queue. + // Arguments: Which player to create the delivery for. + // Return value: Success or not. + + bool CreateDelivery(int player) { + Vector point(-1, -1); + return CreateDelivery(player, Actor::AIMODE_SENTRY, point, NULL); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeliveryCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows how many deliveries this team has pending. + // Arguments: Which team to check the delivery count for. + // Return value: The number of deliveries this team has coming. + + int GetDeliveryCount(int team) { return m_Deliveries[team].size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetupPlayers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Precalculates the player-to-screen index map, counts the number of + // active players etc. + // Arguments: None. + // Return value: None. + + void SetupPlayers() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateEditing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: This is a special update step for when any player is still editing the + // scene. + // Arguments: None. + // Return value: None. + + void UpdateEditing(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTeamTech + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the name of the tech module selected for this team during scenario setup + // Arguments: Team to return tech module for + // Return value: Tech module name, for example Dummy.rte, or empty string if there is no team + std::string GetTeamTech(int team) const { return (team >= Teams::TeamOne && team < Teams::MaxTeamCount) ? m_TeamTech[team] : ""; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTeamTech + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets tech module name for specified team. Module must set must be loaded. + // Arguments: Team to set module, module name, for example Dummy.rte + // Return value: None + void SetTeamTech(int team, std::string tech); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TeamIsCPU + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether a specific team is assigned a CPU player in the current game. + // Arguments: Which team index to check. + // Return value: Whether the team is assigned a CPU player in the current activity. + bool TeamIsCPU(int team) const { return (team >= Teams::TeamOne && team < Teams::MaxTeamCount) ? m_TeamIsCPU[team] : false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActiveCPUTeamCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns active CPU team count. + // Arguments: None. + // Return value: Returns active CPU team count. + int GetActiveCPUTeamCount() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActiveHumanTeamCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns active human team count. + // Arguments: None. + // Return value: Returns active human team count. + int GetActiveHumanTeamCount() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetStartingGold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes how much starting gold was selected in scenario setup dialog. 20000 - infinite amount. + // Arguments: Starting gold amount + // Return value: None. + void SetStartingGold(int amount) { m_StartingGold = amount; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetStartingGold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns how much starting gold was selected in scenario setup dialog. 20000 - infinite amount. + // Arguments: None. + // Return value: How much starting gold must be given to human players. + int GetStartingGold() { return m_StartingGold; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFogOfWarEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes whether fog of war must be enabled for this activity or not. + // Never hides or reveals anything, just changes internal flag. + // Arguments: New fog of war state. true = enabled. + // Return value: None. + void SetFogOfWarEnabled(bool enable) { m_FogOfWarEnabled = enable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFogOfWareEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether fog of war must be enabled for this activity or not. + // Call it to determine whether you should call MakeAllUnseen or not at the start of activity. + // Arguments: None. + // Return value: Whether Fog of war flag was checked during scenario setup dialog. + bool GetFogOfWarEnabled() { return m_FogOfWarEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRequireClearPathToOrbit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether player activity requires a cleat path to orbit to place brain + // + // Arguments: None. + // Return value: Whether we need a clear path to orbit to place brains. + bool GetRequireClearPathToOrbit() const { return m_RequireClearPathToOrbit; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRequireClearPathToOrbit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether player activity requires a cleat path to orbit to place brain + // + // Arguments: Whether we need a clear path to orbit to place brains. + // Return value: None. + void SetRequireClearPathToOrbit(bool newvalue) { m_RequireClearPathToOrbit = newvalue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultFogOfWar() const { return m_DefaultFogOfWar; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultRequireClearPathToOrbit() const { return m_DefaultRequireClearPathToOrbit; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultDeployUnits() const { return m_DefaultDeployUnits; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultGoldCakeDifficulty() const { return m_DefaultGoldCakeDifficulty; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultGoldEasyDifficulty() const { return m_DefaultGoldEasyDifficulty; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultGoldMediumDifficulty() const { return m_DefaultGoldMediumDifficulty; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultGoldHardDifficulty() const { return m_DefaultGoldHardDifficulty; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + int GetDefaultGoldNutsDifficulty() const { return m_DefaultGoldNutsDifficulty; } + + /// + /// Gets the default gold for max difficulty. + /// + /// The default gold for max difficulty. + int GetDefaultGoldMaxDifficulty() const { return m_DefaultGoldMaxDifficulty; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + bool GetFogOfWarSwitchEnabled() const { return m_FogOfWarSwitchEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + bool GetDeployUnitsSwitchEnabled() const { return m_DeployUnitsSwitchEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + + bool GetGoldSwitchEnabled() const { return m_GoldSwitchEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // Arguments: None. + // Return value: + + bool GetRequireClearPathToOrbitSwitchEnabled() const { return m_RequireClearPathToOrbitSwitchEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCrabToHumanSpawnRatio + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns CrabToHumanSpawnRatio for specified module + // Arguments: None. + // Return value: Crab-To-Human spawn ratio value set for specified module, 0.25 is default. + + float GetCrabToHumanSpawnRatio(int moduleid); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeliveryDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns current delivery delay + // Arguments: None. + // Return value: Returns current delivery delay + + long GetDeliveryDelay() const { return m_DeliveryDelay; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDeliveryDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets delivery delay + // Arguments: New delivery delay value in ms + // Return value: None + + void SetDeliveryDelay(long newDeliveryDelay) { m_DeliveryDelay = newDeliveryDelay > 1 ? newDeliveryDelay : 1; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBuyMenuEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether buy menu is enabled in this activity. + // Arguments: True if buy menu enabled false otherwise + // Return value: None. + + bool GetBuyMenuEnabled() const { return m_BuyMenuEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBuyMenuEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether buy menu is enabled in this activity + // Arguments: True to enable buy menu, false otherwise + // Return value: None. + + void SetBuyMenuEnabled(bool newValue) { m_BuyMenuEnabled = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNetworkPlayerName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns network player name + // Arguments: Player + // Return value: Network player name + + std::string& GetNetworkPlayerName(int player); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetNetworkPlayerName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets network player name + // Arguments: Player number, player name + // Return value: None + + void SetNetworkPlayerName(int player, std::string name); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateDelivery + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes the current order out of a player's buy GUI, creates a Delivery + // based off it, and stuffs it into that player's delivery queue. + // Arguments: Which player to create the delivery for. Cargo AI mode waypoint or TargetMO. + // Return value: Success or not. + + bool CreateDelivery(int player, int mode, Vector& waypoint, Actor* pTargetMO); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Struct: ObjectivePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A struct to keep all data about a mission objective. + // Parent(s): None. + // Class history: 11/17/2008 ObjectivePoint + + struct ObjectivePoint { + ObjectivePoint() { + m_Description.clear(); + m_ScenePos.Reset(); + m_Team = Teams::NoTeam; + m_ArrowDir = ARROWDOWN; + } + ObjectivePoint(const std::string& desc, const Vector& pos, int team = -1, ObjectiveArrowDir arrowDir = ARROWDOWN) { + m_Description = desc; + m_ScenePos = pos; + m_Team = (Teams)team; + m_ArrowDir = arrowDir; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Simply draws this' arrow relative to a point on a bitmap. + // Arguments: A pointer to the BITMAP to draw on. + // The arrow bitmap to draw, assuming it points downward. + // The absolute position on the bitmap to draw the point of the arrow at. + // Which orientation to draw the arrow in, relative to the point. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, BITMAP* pArrowBitmap, const Vector& arrowPoint, ObjectiveArrowDir arrowDir = ARROWDOWN); + + // The description of this objective point + std::string m_Description; + // Absolute position in the scene where this is pointed + Vector m_ScenePos; + // The team this objective is relevant to + Teams m_Team; + // The positioning of the arrow that points at this objective + ObjectiveArrowDir m_ArrowDir; + }; + + // Comparison functor for sorting objective points by their y pos using STL's sort + struct ObjPointYPosComparison { + bool operator()(ObjectivePoint& rhs, ObjectivePoint& lhs) { return rhs.m_ScenePos.m_Y < lhs.m_ScenePos.m_Y; } + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OtherTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next other team number from the one passed in, if any. If there + // are more than two teams in this game, then the next one in the series + // will be returned here. + // Arguments: The team not to get. + // Return value: The other team's number. + + int OtherTeam(int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OneOrNoneTeamsLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether there is less than two teams left in this game with + // a brain in its ranks. + // Arguments: None. + // Return value: Whether less than two teams have brains in them left. + + bool OneOrNoneTeamsLeft(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WhichTeamLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which single team is left, if any. + // Arguments: None. + // Return value: Which team stands alone with any brains in its ranks, if any. NoTeam + // is returned if there's either more than one team, OR there are no + // teams at all left with brains in em. + + int WhichTeamLeft(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NoTeamLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether there are NO teams left with any brains at all! + // Arguments: None. + // Return value: Whether any team has a brain in it at all. + + bool NoTeamLeft(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: InitAIs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through all Actor:s currently in the MovableMan and sets each + // one not controlled by a player to be AI controlled and AIMode setting + // based on team and CPU team. + // Arguments: None. + // Return value: None. + + virtual void InitAIs(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DisableAIs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through all Actor:s currently in the MovableMan and disables or + // enables each one with a Controller set to AI input. + // Arguments: Whether to disable or enable them; + // Which team to do this to. If all, then pass Teams::NoTeam + // Return value: None. + + void DisableAIs(bool disable = true, int whichTeam = Teams::NoTeam); + + // Member variables + static Entity::ClassInfo m_sClass; + + // Which team is CPU-managed, if any (-1) - LEGACY, now controlled by Activity::m_IsHuman + int m_CPUTeam; + // Team is active or not this game + bool m_TeamIsCPU[Teams::MaxTeamCount]; + + // The observation sceneman scroll targets, for when the game is over or a player is in observation mode + Vector m_ObservationTarget[Players::MaxPlayerCount]; + // The player death sceneman scroll targets, for when a player-controlled actor dies and the view should go to his last position + Vector m_DeathViewTarget[Players::MaxPlayerCount]; + // Times the delay between regular actor swtich, and going into manual siwtch mode + Timer m_ActorSelectTimer[Players::MaxPlayerCount]; + // The cursor for selecting new Actors + Vector m_ActorCursor[Players::MaxPlayerCount]; + // Highlighted actor while cursor switching; will be switched to if switch button is released now + Actor* m_pLastMarkedActor[Players::MaxPlayerCount]; + // The last selected landing zone + Vector m_LandingZone[Players::MaxPlayerCount]; + // Whether the last craft was set to return or not after delivering + bool m_AIReturnCraft[Players::MaxPlayerCount]; + std::array, Players::MaxPlayerCount> m_StrategicModePieMenu; //!< The strategic mode PieMenus for each Player. + // The inventory menu gui for each player + InventoryMenuGUI* m_InventoryMenuGUI[Players::MaxPlayerCount]; + // The in-game buy GUIs for each player + BuyMenuGUI* m_pBuyGUI[Players::MaxPlayerCount]; + // The in-game scene editor GUI for each player + SceneEditorGUI* m_pEditorGUI[Players::MaxPlayerCount]; + bool m_LuaLockActor[Players::MaxPlayerCount]; //!< Whether or not to lock input for each player while lua has control. + Controller::InputMode m_LuaLockActorMode[Players::MaxPlayerCount]; //!< The input mode to lock to while lua has control. + // The in-game important message banners for each player + GUIBanner* m_pBannerRed[Players::MaxPlayerCount]; + GUIBanner* m_pBannerYellow[Players::MaxPlayerCount]; + // How many times a banner has been repeated.. so we dont' annoy by repeating forever + int m_BannerRepeats[Players::MaxPlayerCount]; + // Whether each player has marked himself as ready to start. Can still edit while this is set, but when all are set, the game starts + bool m_ReadyToStart[Players::MaxPlayerCount]; + // An override purchase list that can be set by a script and will be used instead of what's in the buy menu. Object held in here are NOT OWNED + // Once a delivery is made with anything in here, this list is automatically cleared out, and the next delivery will be what's set in the buy menu. + std::list m_PurchaseOverride[Players::MaxPlayerCount]; + + // The delivery queue which contains all the info about all the made orders currently in transit to delivery + std::deque m_Deliveries[Teams::MaxTeamCount]; + // The box within where landing zones can be put + Scene::Area m_LandingZoneArea[Teams::MaxTeamCount]; + // How wide around the brain the automatic LZ is following + int m_BrainLZWidth[Players::MaxPlayerCount]; + // The objective points for each team + std::list m_Objectives; + + // Tech of player + std::string m_TeamTech[Teams::MaxTeamCount]; + + // Initial gold amount selected by player in scenario setup dialog + int m_StartingGold; + // Whether fog of war was enabled or not in scenario setup dialog + bool m_FogOfWarEnabled; + // Whether we need a clear path to orbit to place brain + bool m_RequireClearPathToOrbit; + + // Default fog of war switch state for this activity, default -1 (unspecified) + int m_DefaultFogOfWar; + // Default clear path to orbit switch value, default -1 (unspecified) + int m_DefaultRequireClearPathToOrbit; + // Default deploy units swutch value, default -1 (unspecified) + int m_DefaultDeployUnits; + // Default gold amount for different difficulties, defalt -1 (unspecified) + int m_DefaultGoldCakeDifficulty; + int m_DefaultGoldEasyDifficulty; + int m_DefaultGoldMediumDifficulty; + int m_DefaultGoldHardDifficulty; + int m_DefaultGoldNutsDifficulty; + int m_DefaultGoldMaxDifficulty; + // Whether those switches are enabled or disabled in scenario setup dialog, true by default + bool m_FogOfWarSwitchEnabled; + bool m_DeployUnitsSwitchEnabled; + bool m_GoldSwitchEnabled; + bool m_RequireClearPathToOrbitSwitchEnabled; + bool m_BuyMenuEnabled; + + // The cursor animations for the LZ indicators + std::vector m_aLZCursor[4]; + std::array m_LZCursorWidth; //!< The width of each players' LZ cursor. + // The cursor animations for the objective indications + std::vector m_aObjCursor[4]; + + // Time it takes for a delivery to be made, in ms + long m_DeliveryDelay; + // Cursor animation timer + Timer m_CursorTimer; + // Total gameplay timer, not including editing phases + Timer m_GameTimer; + // Game end timer + Timer m_GameOverTimer; + // Time between game over and reset + long m_GameOverPeriod; + // The winning team number, when the game is over + int m_WinnerTeam; + + std::string m_NetworkPlayerNames[Players::MaxPlayerCount]; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE diff --git a/Source/Activities/GibEditor.cpp b/Source/Activities/GibEditor.cpp index fbfa030a0..69e56ecab 100644 --- a/Source/Activities/GibEditor.cpp +++ b/Source/Activities/GibEditor.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -42,894 +41,806 @@ namespace RTE { -ConcreteClassInfo(GibEditor, EditorActivity, 0); + ConcreteClassInfo(GibEditor, EditorActivity, 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this GibEditor, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this GibEditor, effectively -// resetting the members of this abstraction level only. + void GibEditor::Clear() { + m_pEditedObject = 0; + m_pTestingObject = 0; + m_TestCounter = 0; + m_pObjectToLoad = 0; + m_pEditorGUI = 0; + } -void GibEditor::Clear() -{ - m_pEditedObject = 0; - m_pTestingObject = 0; - m_TestCounter = 0; - m_pObjectToLoad = 0; - m_pEditorGUI = 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GibEditor object ready for use. + int GibEditor::Create() { + if (EditorActivity::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GibEditor object ready for use. + return 0; + } -int GibEditor::Create() -{ - if (EditorActivity::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GibEditor to be identical to another, by deep copy. + int GibEditor::Create(const GibEditor& reference) { + if (EditorActivity::Create(reference) < 0) + return -1; - return 0; -} + if (m_Description.empty()) + m_Description = "Edit how Movable Objects break apart into smaller pieces."; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GibEditor to be identical to another, by deep copy. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int GibEditor::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); + /* + MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + */ + EndPropertyList; + } -int GibEditor::Create(const GibEditor &reference) -{ - if (EditorActivity::Create(reference) < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this GibEditor with a Writer for + // later recreation with Create(Reader &reader); - if (m_Description.empty()) - m_Description = "Edit how Movable Objects break apart into smaller pieces."; + int GibEditor::Save(Writer& writer) const { + EditorActivity::Save(writer); + return 0; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GibEditor object. + void GibEditor::Destroy(bool notInherited) { + delete m_pEditedObject; + delete m_pTestingObject; + delete m_pEditorGUI; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int GibEditor::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); -/* - MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); -*/ - EndPropertyList; -} + if (!notInherited) + EditorActivity::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this GibEditor with a Writer for -// later recreation with Create(Reader &reader); + int GibEditor::Start() { + int error = EditorActivity::Start(); -int GibEditor::Save(Writer &writer) const { - EditorActivity::Save(writer); - return 0; -} + ////////////////////////////////////////////// + // Allocate and (re)create the Editor GUI + if (m_pEditorGUI) + m_pEditorGUI->Destroy(); + else + m_pEditorGUI = new GibEditorGUI; + m_pEditorGUI->Create(&(m_PlayerController[0])); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GibEditor object. + ////////////////////////////////////////////////////////////// + // Hooking up directly to the controls defined in the GUI ini -void GibEditor::Destroy(bool notInherited) -{ - delete m_pEditedObject; - delete m_pTestingObject; - delete m_pEditorGUI; + m_pGUIController->Load("Base.rte/GUIs/GibEditorGUI.ini"); - if (!notInherited) - EditorActivity::Destroy(); - Clear(); -} + // Resize the invisible root container so it matches the screen rez + GUICollectionBox* pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); + if (pRootBox) + pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of + if (!m_pNewDialogBox) { + m_pNewDialogBox = dynamic_cast(m_pGUIController->GetControl("NewDialogBox")); + // m_pNewDialogBox->SetDrawType(GUICollectionBox::Color); + m_pNewDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pNewDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pNewDialogBox->GetHeight() / 2)); + m_pNewDialogBox->SetVisible(false); + } + // m_pNewModuleCombo = dynamic_cast(m_pGUIController->GetControl("NewModuleCB")); + m_pNewButton = dynamic_cast(m_pGUIController->GetControl("NewSceneButton")); + m_pNewCancel = dynamic_cast(m_pGUIController->GetControl("NewCancelButton")); + + // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of + if (!m_pLoadDialogBox) { + m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); + // m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); + m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); + m_pLoadDialogBox->SetVisible(false); + } + m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadButton")); + m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); + + if (!m_pSaveDialogBox) { + m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); + + // Set the background image of the parent collection box + // ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); + // m_pSaveDialogBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); + // m_pSaveDialogBox->SetDrawBackground(true); + // m_pSaveDialogBox->SetDrawType(GUICollectionBox::Image); + // m_pSaveDialogBox->SetDrawType(GUICollectionBox::Color); + m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); + m_pSaveDialogBox->SetVisible(false); + } + m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveNameTB")); + m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); + m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveButton")); + m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); + + if (!m_pChangesDialogBox) { + m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); + m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); + m_pChangesDialogBox->SetVisible(false); + } + m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); + m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); + m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); + + if (!m_pOverwriteDialogBox) { + m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); + m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); + m_pOverwriteDialogBox->SetVisible(false); + } + m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); + m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); + m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int GibEditor::Start() -{ - int error = EditorActivity::Start(); - - ////////////////////////////////////////////// - // Allocate and (re)create the Editor GUI - - if (m_pEditorGUI) - m_pEditorGUI->Destroy(); - else - m_pEditorGUI = new GibEditorGUI; - m_pEditorGUI->Create(&(m_PlayerController[0])); - - ////////////////////////////////////////////////////////////// - // Hooking up directly to the controls defined in the GUI ini - - m_pGUIController->Load("Base.rte/GUIs/GibEditorGUI.ini"); - - // Resize the invisible root container so it matches the screen rez - GUICollectionBox *pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); - if (pRootBox) - pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); - - // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of - if (!m_pNewDialogBox) - { - m_pNewDialogBox = dynamic_cast(m_pGUIController->GetControl("NewDialogBox")); -// m_pNewDialogBox->SetDrawType(GUICollectionBox::Color); - m_pNewDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pNewDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pNewDialogBox->GetHeight() / 2)); - m_pNewDialogBox->SetVisible(false); - } -// m_pNewModuleCombo = dynamic_cast(m_pGUIController->GetControl("NewModuleCB")); - m_pNewButton = dynamic_cast(m_pGUIController->GetControl("NewSceneButton")); - m_pNewCancel = dynamic_cast(m_pGUIController->GetControl("NewCancelButton")); - - // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of - if (!m_pLoadDialogBox) - { - m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); -// m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); - m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); - m_pLoadDialogBox->SetVisible(false); - } - m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadButton")); - m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); - - if (!m_pSaveDialogBox) - { - m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); - - // Set the background image of the parent collection box -// ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); -// m_pSaveDialogBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); -// m_pSaveDialogBox->SetDrawBackground(true); -// m_pSaveDialogBox->SetDrawType(GUICollectionBox::Image); -// m_pSaveDialogBox->SetDrawType(GUICollectionBox::Color); - m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); - m_pSaveDialogBox->SetVisible(false); - } - m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveNameTB")); - m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); - m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveButton")); - m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); - - if (!m_pChangesDialogBox) - { - m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); - m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); - m_pChangesDialogBox->SetVisible(false); - } - m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); - m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); - m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); - - if (!m_pOverwriteDialogBox) - { - m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); - m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); - m_pOverwriteDialogBox->SetVisible(false); - } - m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); - m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); - m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); - - m_EditorMode = EditorActivity::EDITINGOBJECT; - // Show the picker dialog to select an object to load - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::PICKOBJECTTOLOAD); - m_ModeChange = true; - - return error; -} + m_EditorMode = EditorActivity::EDITINGOBJECT; + // Show the picker dialog to select an object to load + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::PICKOBJECTTOLOAD); + m_ModeChange = true; + return error; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. -void GibEditor::SetPaused(bool pause) -{ - // Override the pause - m_Paused = false; -} + void GibEditor::SetPaused(bool pause) { + // Override the pause + m_Paused = false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. + void GibEditor::End() { + EditorActivity::End(); -void GibEditor::End() -{ - EditorActivity::End(); + m_ActivityState = ActivityState::Over; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this GibEditor. Supposed to be done every frame + // before drawing. + + void GibEditor::Update() { + // And object hasn't been loaded yet, so get the loading picker going + if (!m_pEditedObject && !m_pObjectToLoad) { + m_NeedSave = false; + m_HasEverBeenSaved = false; + m_PreviousMode = EditorActivity::LOADDIALOG; + m_EditorMode = EditorActivity::EDITINGOBJECT; + // Show the picker dialog to select an object to load + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::PICKOBJECTTOLOAD); + m_ModeChange = true; + } + // Mode switching etc + EditorActivity::Update(); - m_ActivityState = ActivityState::Over; -} + if (!g_SceneMan.GetScene()) + return; + ////////////////////////////////////// + // Special testing mode -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this GibEditor. Supposed to be done every frame -// before drawing. - -void GibEditor::Update() -{ - // And object hasn't been loaded yet, so get the loading picker going - if (!m_pEditedObject && !m_pObjectToLoad) - { - m_NeedSave = false; - m_HasEverBeenSaved = false; - m_PreviousMode = EditorActivity::LOADDIALOG; - m_EditorMode = EditorActivity::EDITINGOBJECT; - // Show the picker dialog to select an object to load - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::PICKOBJECTTOLOAD); - m_ModeChange = true; - } - - // Mode switching etc - EditorActivity::Update(); - - if (!g_SceneMan.GetScene()) - return; - - ////////////////////////////////////// - // Special testing mode - - if (m_EditorMode == EditorActivity::TESTINGOBJECT) - { - if (m_ModeChange) - { - m_pGUIController->EnableMouse(false); - m_ModeChange = false; - } - - // We haven't detonated yet - if (m_pTestingObject) - { - g_FrameMan.SetScreenText("Click to test gib the object!", 0, 333); - - // Detonate on command! - if (m_PlayerController[0].IsState(PRESS_PRIMARY) || m_PlayerController[0].IsState(PRESS_SECONDARY) || m_PlayerController[0].IsState(PRESS_FACEBUTTON)) - { - // This adds all the gibs to the movableman - m_pTestingObject->GibThis(); - // Now safe to get rid of the test subject - m_pTestingObject->DestroyScriptState(); - delete m_pTestingObject; - m_pTestingObject = nullptr; - } - } - // Test has blown up, now waiting for user to finish watching the pieces fly - else - { - g_FrameMan.SetScreenText("Click again to go back to editing..."); - - if (m_PlayerController[0].IsState(PRESS_PRIMARY) || m_PlayerController[0].IsState(PRESS_SECONDARY) || m_PlayerController[0].IsState(PRESS_FACEBUTTON)) - { - // Clear out the terrain after a few tests - if (m_TestCounter >= 3) - { - ClearTestArea(); - m_TestCounter = 0; - } - // Clear all crap still flying around - g_MovableMan.PurgeAllMOs(); - g_MovableMan.Update(); - // Go back to editing the edited object - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - // Pause the sim again - m_Paused = true; - } - } - } - // All dialog boxes are gone and we're editing the object - else if (m_pEditedObject && m_EditorMode == EditorActivity::EDITINGOBJECT) - { - if (m_ModeChange) - { - // Open the picker depending on whetehr there's somehting in the cursor hand or not - m_pEditorGUI->SetEditorGUIMode(m_pEditorGUI->GetCurrentGib() ? GibEditorGUI::ADDINGGIB : GibEditorGUI::PICKINGGIB); - // Hide the cursor for this layer of interface - m_pGUIController->EnableMouse(false); - m_ModeChange = false; - } - g_UInputMan.DisableKeys(false); - } - // We are doing something in the dialog boxes, so don't do anything in the editor interface - else if (m_pEditedObject) - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); - - ///////////////////////////////////////////////////// - // Update the editor interface - - m_pEditorGUI->Update(); - - // Any edits made, dirtying the object? - m_NeedSave = m_NeedSave || m_pEditorGUI->EditMade(); - - // Get any mode change commands that the user gave the Editor GUI - if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::NEWDIALOG; - m_ModeChange = true; - } - // Loading is done differently, only when user has already picked an object ot load from the picker should the dialog box appear - else if (m_pEditorGUI->GetObjectToLoad() && m_EditorMode != LOADDIALOG) - { - m_pObjectToLoad = m_pEditorGUI->GetObjectToLoad(); - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::LOADDIALOG; - m_ModeChange = true; - } - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - // Test the object by allowing the player to gib temporary test copy instances of the edited object - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone) - { - // Make the copy of the current edited object - m_pTestingObject->DestroyScriptState(); - delete m_pTestingObject; - m_pTestingObject = dynamic_cast(m_pEditedObject->Clone()); - - // Put the proxy gibs into the test object - StuffEditedGibs(m_pTestingObject); - // Increment the number of tests, after certain amount the terrain is cleared of debris - m_TestCounter++; - - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); - m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_EditorMode = EditorActivity::TESTINGOBJECT; - m_ModeChange = true; - // Start running the sim - m_Paused = false; - } - - //////////////////////////////////////////////////////// - // Handle events for mouse input on the controls - - GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { - // If we're not supposed to have mouse control, then ignore these messages -// Uh this is not right, editor always has mouse control so far -// if (!m_PlayerController[0].IsMouseControlled()) -// break; - - if (anEvent.GetType() == GUIEvent::Command) - { -/* - ////////////////////////////////////////////////////////// - // NEW button pressed; create a new object - - if (anEvent.GetControl() == m_pNewButton) - { - // Get the selected Module - GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - m_ModuleSpaceID = g_PresetMan.GetModuleID(pItem->m_Name); - - // Allocate Scene - Scene *pNewScene = new Scene(); - // Get the selected Terrain and create the Scene using it - pItem = m_pNewTerrainCombo->GetItem(m_pNewTerrainCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SLTerrain *pNewTerrain = dynamic_cast(g_PresetMan.GetEntityPreset("SLTerrain", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewTerrain, "No SLTerrain of that name defined!"); - pNewScene->Create(pNewTerrain); - } - - // Add specified object layers - pItem = m_pNewBG1Combo->GetItem(m_pNewBG1Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SceneLayer of the name set as BG1 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - pItem = m_pNewBG2Combo->GetItem(m_pNewBG2Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SceneLayer of the name set as BG2 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - pItem = m_pNewBG3Combo->GetItem(m_pNewBG3Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SceneLayer of the name set as BG3 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - - // Actually load the object's data and set it up as the current object - g_SceneMan.LoadScene(pNewScene); - - // Reset the rest of the editor GUI - m_pEditorGUI->Destroy(); - m_pEditorGUI->Create(&(m_PlayerController[0]), m_ModuleSpaceID); - } - - m_NeedSave = false; - m_HasEverBeenSaved = false; - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } -*/ - ////////////////////////////////////////////////////////// - // LOAD button pressed; load the selected Object - - if (anEvent.GetControl() == m_pLoadButton && m_pObjectToLoad) - { - m_pEditedObject = dynamic_cast(m_pObjectToLoad->Clone()); - if (m_pEditedObject) - { - // Get the module space ID - m_ModuleSpaceID = m_pEditedObject->GetModuleID(); - RTEAssert(m_ModuleSpaceID >= 0, "Loaded Object's DataModule ID is negative? Should always be a specific one.."); - - // Restart the editor GUI - m_pEditorGUI->Destroy(); - m_pEditorGUI->Create(&(m_PlayerController[0]), m_ModuleSpaceID); - - // Set the position of the loaded edited object to the middle of the scene - m_pEditedObject->SetPos(Vector(g_SceneMan.GetSceneWidth() / 2, g_SceneMan.GetSceneHeight() / 2)); - m_pEditedObject->Update(); - - // Make proxy copies of the loaded objects' gib reference instances and place them in the list to be edited - std::list *pLoadedGibList = m_pEditedObject->GetGibList(); - std::list *pEditedGibList = m_pEditorGUI->GetPlacedGibs(); - MovableObject *pGibCopy = 0; - - for (auto gItr = pLoadedGibList->begin(); gItr != pLoadedGibList->end(); ++gItr) - { - pGibCopy = dynamic_cast((*gItr).GetParticlePreset()->Clone()); - if (pGibCopy) - { - pGibCopy->SetPos(m_pEditedObject->GetPos() + (*gItr).GetOffset()); - pEditedGibList->push_back(pGibCopy); - } - pGibCopy = 0; - } - - // Clear out the testing area - ClearTestArea(); - m_TestCounter = 0; - - m_pObjectToLoad = 0; - } - m_NeedSave = false; - m_HasEverBeenSaved = true; - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // SAVE button pressed; save the selected Object - - if (anEvent.GetControl() == m_pSaveButton) - { - if (!m_pSaveNameBox->GetText().empty()) - { - // Save the object to the name specified in the text box - if (SaveObject(m_pSaveNameBox->GetText())) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the object - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - // Should really leave dialog box open? error handling, bitte - else - { - ; - } - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes YES pressed - - if (anEvent.GetControl() == m_pChangesYesButton && m_pEditedObject) - { - if (m_HasEverBeenSaved) - { - if (SaveObject(m_pEditedObject->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the object - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - } - // Open the save object dialog to ask user where to save it then - else - { - m_PreviousMode = m_PreviousMode; - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes NO pressed - - if (anEvent.GetControl() == m_pChangesNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - m_NeedSave = false; - } - - /////////////////////////////////////////////////////////////// - // Overwrite Object YES pressed - - if (anEvent.GetControl() == m_pOverwriteYesButton && m_pEditedObject) - { - // Force overwrite - if (SaveObject(m_pEditedObject->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after overwrite dialog is done, may have been on the way to test the object - m_EditorMode = m_PreviousMode != EditorActivity::SAVEDIALOG ? m_PreviousMode : EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } -// TODO: Show overwrite error? - } - - /////////////////////////////////////////////////////////////// - // Overwrite Object NO pressed - - if (anEvent.GetControl() == m_pOverwriteNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - - /////////////////////////////////////////////////////////////// - // CANCEL button pressed; exit any active dialog box - - // If load is cancel when just opening the scene - if (anEvent.GetControl() == m_pLoadCancel && !m_pEditedObject) - { - m_PreviousMode = EditorActivity::LOADDIALOG; - m_EditorMode = EditorActivity::EDITINGOBJECT; - // Show the picker dialog to select an object to load - m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::PICKOBJECTTOLOAD); - m_ModeChange = true; - } - if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) - { - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - } - - // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { - /////////////////////////////////////// - // Clicks on the New Object Module combo - - if (anEvent.GetControl() == m_pNewModuleCombo) - { - // Closed it, IE selected somehting - if(anEvent.GetMsg() == GUIComboBox::Closed) - UpdateNewDialog(); - } - } - } -} + if (m_EditorMode == EditorActivity::TESTINGOBJECT) { + if (m_ModeChange) { + m_pGUIController->EnableMouse(false); + m_ModeChange = false; + } + // We haven't detonated yet + if (m_pTestingObject) { + g_FrameMan.SetScreenText("Click to test gib the object!", 0, 333); + + // Detonate on command! + if (m_PlayerController[0].IsState(PRESS_PRIMARY) || m_PlayerController[0].IsState(PRESS_SECONDARY) || m_PlayerController[0].IsState(PRESS_FACEBUTTON)) { + // This adds all the gibs to the movableman + m_pTestingObject->GibThis(); + // Now safe to get rid of the test subject + m_pTestingObject->DestroyScriptState(); + delete m_pTestingObject; + m_pTestingObject = nullptr; + } + } + // Test has blown up, now waiting for user to finish watching the pieces fly + else { + g_FrameMan.SetScreenText("Click again to go back to editing..."); + + if (m_PlayerController[0].IsState(PRESS_PRIMARY) || m_PlayerController[0].IsState(PRESS_SECONDARY) || m_PlayerController[0].IsState(PRESS_FACEBUTTON)) { + // Clear out the terrain after a few tests + if (m_TestCounter >= 3) { + ClearTestArea(); + m_TestCounter = 0; + } + // Clear all crap still flying around + g_MovableMan.PurgeAllMOs(); + g_MovableMan.Update(); + // Go back to editing the edited object + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + // Pause the sim again + m_Paused = true; + } + } + } + // All dialog boxes are gone and we're editing the object + else if (m_pEditedObject && m_EditorMode == EditorActivity::EDITINGOBJECT) { + if (m_ModeChange) { + // Open the picker depending on whetehr there's somehting in the cursor hand or not + m_pEditorGUI->SetEditorGUIMode(m_pEditorGUI->GetCurrentGib() ? GibEditorGUI::ADDINGGIB : GibEditorGUI::PICKINGGIB); + // Hide the cursor for this layer of interface + m_pGUIController->EnableMouse(false); + m_ModeChange = false; + } + g_UInputMan.DisableKeys(false); + } + // We are doing something in the dialog boxes, so don't do anything in the editor interface + else if (m_pEditedObject) + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. - -void GibEditor::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - // Testing mode - if (m_EditorMode == EditorActivity::TESTINGOBJECT) - { - if (m_pTestingObject) - m_pTestingObject->Draw(pTargetBitmap, targetPos, g_DrawColor, true); - } - // Regular drawing mode - else - { - // Draw ghost outline of edited object to place gibs upon - if (m_pEditedObject) - { - g_FrameMan.SetTransTableFromPreset(TransparencyPreset::MoreTrans); - // Draw only the MOSRotating since that's all we are adding gibs for; any attachables have to be edited separately - m_pEditedObject->MOSRotating::Draw(pTargetBitmap, targetPos, g_DrawTrans, true); - } - - m_pEditorGUI->Draw(pTargetBitmap, targetPos); - EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); - } -} + ///////////////////////////////////////////////////// + // Update the editor interface + m_pEditorGUI->Update(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this GibEditor's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + // Any edits made, dirtying the object? + m_NeedSave = m_NeedSave || m_pEditorGUI->EditMade(); -void GibEditor::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) -{ - EditorActivity::Draw(pTargetBitmap, targetPos); -} + // Get any mode change commands that the user gave the Editor GUI + if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) { + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::NEWDIALOG; + m_ModeChange = true; + } + // Loading is done differently, only when user has already picked an object ot load from the picker should the dialog box appear + else if (m_pEditorGUI->GetObjectToLoad() && m_EditorMode != LOADDIALOG) { + m_pObjectToLoad = m_pEditorGUI->GetObjectToLoad(); + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::LOADDIALOG; + m_ModeChange = true; + } else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) { + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + // Test the object by allowing the player to gib temporary test copy instances of the edited object + else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone) { + // Make the copy of the current edited object + m_pTestingObject->DestroyScriptState(); + delete m_pTestingObject; + m_pTestingObject = dynamic_cast(m_pEditedObject->Clone()); + + // Put the proxy gibs into the test object + StuffEditedGibs(m_pTestingObject); + // Increment the number of tests, after certain amount the terrain is cleared of debris + m_TestCounter++; + + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::INACTIVE); + m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_EditorMode = EditorActivity::TESTINGOBJECT; + m_ModeChange = true; + // Start running the sim + m_Paused = false; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////// + // Handle events for mouse input on the controls + + GUIEvent anEvent; + while (m_pGUIController->GetEvent(&anEvent)) { + // If we're not supposed to have mouse control, then ignore these messages + // Uh this is not right, editor always has mouse control so far + // if (!m_PlayerController[0].IsMouseControlled()) + // break; + + if (anEvent.GetType() == GUIEvent::Command) { + /* + ////////////////////////////////////////////////////////// + // NEW button pressed; create a new object + + if (anEvent.GetControl() == m_pNewButton) + { + // Get the selected Module + GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + m_ModuleSpaceID = g_PresetMan.GetModuleID(pItem->m_Name); + + // Allocate Scene + Scene *pNewScene = new Scene(); + // Get the selected Terrain and create the Scene using it + pItem = m_pNewTerrainCombo->GetItem(m_pNewTerrainCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SLTerrain *pNewTerrain = dynamic_cast(g_PresetMan.GetEntityPreset("SLTerrain", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewTerrain, "No SLTerrain of that name defined!"); + pNewScene->Create(pNewTerrain); + } + + // Add specified object layers + pItem = m_pNewBG1Combo->GetItem(m_pNewBG1Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SceneLayer of the name set as BG1 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + pItem = m_pNewBG2Combo->GetItem(m_pNewBG2Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SceneLayer of the name set as BG2 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + pItem = m_pNewBG3Combo->GetItem(m_pNewBG3Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + { + SceneLayer *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SceneLayer", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SceneLayer of the name set as BG3 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + + // Actually load the object's data and set it up as the current object + g_SceneMan.LoadScene(pNewScene); + + // Reset the rest of the editor GUI + m_pEditorGUI->Destroy(); + m_pEditorGUI->Create(&(m_PlayerController[0]), m_ModuleSpaceID); + } + + m_NeedSave = false; + m_HasEverBeenSaved = false; + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + */ + ////////////////////////////////////////////////////////// + // LOAD button pressed; load the selected Object + + if (anEvent.GetControl() == m_pLoadButton && m_pObjectToLoad) { + m_pEditedObject = dynamic_cast(m_pObjectToLoad->Clone()); + if (m_pEditedObject) { + // Get the module space ID + m_ModuleSpaceID = m_pEditedObject->GetModuleID(); + RTEAssert(m_ModuleSpaceID >= 0, "Loaded Object's DataModule ID is negative? Should always be a specific one.."); + + // Restart the editor GUI + m_pEditorGUI->Destroy(); + m_pEditorGUI->Create(&(m_PlayerController[0]), m_ModuleSpaceID); + + // Set the position of the loaded edited object to the middle of the scene + m_pEditedObject->SetPos(Vector(g_SceneMan.GetSceneWidth() / 2, g_SceneMan.GetSceneHeight() / 2)); + m_pEditedObject->Update(); + + // Make proxy copies of the loaded objects' gib reference instances and place them in the list to be edited + std::list* pLoadedGibList = m_pEditedObject->GetGibList(); + std::list* pEditedGibList = m_pEditorGUI->GetPlacedGibs(); + MovableObject* pGibCopy = 0; + + for (auto gItr = pLoadedGibList->begin(); gItr != pLoadedGibList->end(); ++gItr) { + pGibCopy = dynamic_cast((*gItr).GetParticlePreset()->Clone()); + if (pGibCopy) { + pGibCopy->SetPos(m_pEditedObject->GetPos() + (*gItr).GetOffset()); + pEditedGibList->push_back(pGibCopy); + } + pGibCopy = 0; + } + + // Clear out the testing area + ClearTestArea(); + m_TestCounter = 0; + + m_pObjectToLoad = 0; + } + m_NeedSave = false; + m_HasEverBeenSaved = true; + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } -bool GibEditor::SaveObject(const std::string &saveAsName, bool forceOverwrite) { - if (!m_pEditedObject) { - return false; - } - m_pEditedObject->SetPresetName(saveAsName); + ////////////////////////////////////////////////////////// + // SAVE button pressed; save the selected Object + + if (anEvent.GetControl() == m_pSaveButton) { + if (!m_pSaveNameBox->GetText().empty()) { + // Save the object to the name specified in the text box + if (SaveObject(m_pSaveNameBox->GetText())) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the object + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + // Should really leave dialog box open? error handling, bitte + else { + ; + } + } + } - // Replace the gibs of the object with the proxies that have been edited in the GUI. - StuffEditedGibs(m_pEditedObject); + /////////////////////////////////////////////////////////////// + // Save Changes YES pressed + + if (anEvent.GetControl() == m_pChangesYesButton && m_pEditedObject) { + if (m_HasEverBeenSaved) { + if (SaveObject(m_pEditedObject->GetPresetName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the object + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + } + // Open the save object dialog to ask user where to save it then + else { + m_PreviousMode = m_PreviousMode; + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + } - std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); - std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); - std::string newDataDir = dataModuleFullPath + "/NewData"; - std::string objectSavePath = newDataDir + "/" + saveAsName + ".ini"; + /////////////////////////////////////////////////////////////// + // Save Changes NO pressed - if (!System::PathExistsCaseSensitive(newDataDir) && !System::MakeDirectory(newDataDir)) { - RTEError::ShowMessageBox("Failed to create NewData directory in:\n\n" + dataModuleFullPath + "\n\nTHE EDITED OBJECT PRESET WAS NOT SAVED!!!"); - return false; - } + if (anEvent.GetControl() == m_pChangesNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + m_NeedSave = false; + } - // Force overwrite the stored preset so we aren't prompted to every time for every preset. This doesn't screw with the original ini because there's no system for that in place - // and doesn't actually get loaded on the next game start either, so any changes will be discarded at the end of the current runtime. - if (g_PresetMan.AddEntityPreset(m_pEditedObject, m_ModuleSpaceID, true, objectSavePath)) { - // Show the overwrite dialog only when actually overwriting a saved ini in NewData or forcing an overwrite. - if (!System::PathExistsCaseSensitive(objectSavePath) || forceOverwrite) { - if (Writer objectWriter(objectSavePath, false); !objectWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + objectSavePath + "\n\nTHE EDITED OBJECT PRESET WAS NOT SAVED!!!"); - } else { - std::string addObjectType; - switch (m_pEditedObject->GetMOType()) { - case MovableObject::MOType::TypeActor: - addObjectType = "AddActor"; - break; - case MovableObject::MOType::TypeHeldDevice: - case MovableObject::MOType::TypeThrownDevice: - addObjectType = "AddDevice"; - break; - default: - addObjectType = "AddEffect"; + /////////////////////////////////////////////////////////////// + // Overwrite Object YES pressed + + if (anEvent.GetControl() == m_pOverwriteYesButton && m_pEditedObject) { + // Force overwrite + if (SaveObject(m_pEditedObject->GetPresetName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after overwrite dialog is done, may have been on the way to test the object + m_EditorMode = m_PreviousMode != EditorActivity::SAVEDIALOG ? m_PreviousMode : EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + // TODO: Show overwrite error? } - objectWriter.NewProperty(addObjectType); - m_pEditedObject->Entity::Save(objectWriter); - for (const Gib &gib : *m_pEditedObject->GetGibList()) { - objectWriter.NewPropertyWithValue("AddGib", gib); + + /////////////////////////////////////////////////////////////// + // Overwrite Object NO pressed + + if (anEvent.GetControl() == m_pOverwriteNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; } - objectWriter.ObjectEnd(); - objectWriter.EndWrite(); - m_HasEverBeenSaved = true; + /////////////////////////////////////////////////////////////// + // CANCEL button pressed; exit any active dialog box - // TODO: Maybe make system for saving into/over the existing definition read originally from the ini's, wherever it was. + // If load is cancel when just opening the scene + if (anEvent.GetControl() == m_pLoadCancel && !m_pEditedObject) { + m_PreviousMode = EditorActivity::LOADDIALOG; + m_EditorMode = EditorActivity::EDITINGOBJECT; + // Show the picker dialog to select an object to load + m_pEditorGUI->SetEditorGUIMode(GibEditorGUI::PICKOBJECTTOLOAD); + m_ModeChange = true; + } + if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) { + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + } - return true; + // Notifications + else if (anEvent.GetType() == GUIEvent::Notification) { + /////////////////////////////////////// + // Clicks on the New Object Module combo + + if (anEvent.GetControl() == m_pNewModuleCombo) { + // Closed it, IE selected somehting + if (anEvent.GetMsg() == GUIComboBox::Closed) + UpdateNewDialog(); + } } - } else { - // Got to ask if we can overwrite the existing object. - m_PreviousMode = EditorMode::SAVEDIALOG; - m_EditorMode = EditorMode::OVERWRITEDIALOG; - m_ModeChange = true; } } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StuffEditedGibs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Replaces all the gibs owned by the passed in MOSR with the ones being -// edited that represent the new gibbing setup. - -void GibEditor::StuffEditedGibs(MOSRotating *pEditedObject) -{ - if (!pEditedObject) - return; - - // Replace the gibs of the object with the proxies that have been edited in the gui - std::list *pObjectGibList = pEditedObject->GetGibList(); - pObjectGibList->clear(); - - // Take each proxy object and stuff it into a Gib instance which then gets stuffed into the object to be saved - std::list *pProxyGibList = m_pEditorGUI->GetPlacedGibs(); - for (std::list::iterator gItr = pProxyGibList->begin(); gItr != pProxyGibList->end(); ++gItr) - { - Gib newGib; - // Only set the refernce instance directly from the isntanceman. OWNERSHIP IS NOT TRANSFERRED! - newGib.m_GibParticle = dynamic_cast(g_PresetMan.GetEntityPreset((*gItr)->GetClassName(), (*gItr)->GetPresetName(), m_ModuleSpaceID)); - if (newGib.m_GibParticle) - { - newGib.m_Count = 1; - newGib.m_Offset = (*gItr)->GetPos() - pEditedObject->GetPos(); -// TODO: do proper velocity calculations here! -// ... actually leave these as 0 and let them be calculated in GibThis -// newGib.m_MinVelocity = (100.0f + 50.0f * NormalRand()) / (*gItr)->GetMass(); -// newGib.m_MaxVelocity = newGib.m_MinVelocity + ((100.0f * RandomNum()) / (*gItr)->GetMass()); - pObjectGibList->push_back(newGib); - } - } -} + void GibEditor::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + // Testing mode + if (m_EditorMode == EditorActivity::TESTINGOBJECT) { + if (m_pTestingObject) + m_pTestingObject->Draw(pTargetBitmap, targetPos, g_DrawColor, true); + } + // Regular drawing mode + else { + // Draw ghost outline of edited object to place gibs upon + if (m_pEditedObject) { + g_FrameMan.SetTransTableFromPreset(TransparencyPreset::MoreTrans); + // Draw only the MOSRotating since that's all we are adding gibs for; any attachables have to be edited separately + m_pEditedObject->MOSRotating::Draw(pTargetBitmap, targetPos, g_DrawTrans, true); + } + m_pEditorGUI->Draw(pTargetBitmap, targetPos); + EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. - -void GibEditor::UpdateNewDialog() -{ -/* - // Only refill modules if empty - if (m_pNewModuleCombo->GetCount() <= 0) - { - for (int module = 0; module < g_PresetMan.GetTotalModuleCount(); ++module) - m_pNewModuleCombo->AddItem(g_PresetMan.GetDataModule(module)->GetFileName()); - - // Select the first one - m_pNewModuleCombo->SetSelectedIndex(0); - } - - // Get the ID of the module currently selected so we can limit the following boxes to only show stuff in that module - int selectedModuleID = -1; - GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - selectedModuleID = g_PresetMan.GetModuleID(pItem->m_Name); - - // Refill Terrains - m_pNewTerrainCombo->ClearList(); - // Get the list of all read in terrains - list terrainList; - g_PresetMan.GetAllOfTypeInModuleSpace(terrainList, "SLTerrain", selectedModuleID); - // Go through the list and add their names to the combo box - for (list::iterator itr = terrainList.begin(); itr != terrainList.end(); ++itr) - m_pNewTerrainCombo->AddItem((*itr)->GetPresetName()); - // Select the first one - m_pNewTerrainCombo->SetSelectedIndex(0); - - // Refill backdrops - m_pNewBG1Combo->SetText(""); - m_pNewBG2Combo->SetText(""); - m_pNewBG3Combo->SetText(""); - m_pNewBG1Combo->ClearList(); - m_pNewBG2Combo->ClearList(); - m_pNewBG3Combo->ClearList(); - // Get the list of all read in terrains - list bgList; - g_PresetMan.GetAllOfTypeInModuleSpace(bgList, "SceneLayer", selectedModuleID); - // Go through the list and add their names to the combo box - for (list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) - { - m_pNewBG1Combo->AddItem((*itr)->GetPresetName()); - m_pNewBG2Combo->AddItem((*itr)->GetPresetName()); - m_pNewBG3Combo->AddItem((*itr)->GetPresetName()); - } - // Select the first one - m_pNewBG1Combo->SetSelectedIndex(0); - m_pNewBG2Combo->SetSelectedIndex(0); - m_pNewBG3Combo->SetSelectedIndex(0); -*/ -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this GibEditor's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + void GibEditor::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + EditorActivity::Draw(pTargetBitmap, targetPos); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GibEditor::UpdateLoadDialog() -{ - if (m_pObjectToLoad) - dynamic_cast(m_pGUIController->GetControl("LoadNameLabel"))->SetText("Load object named " + m_pObjectToLoad->GetPresetName() + "?"); -} + bool GibEditor::SaveObject(const std::string& saveAsName, bool forceOverwrite) { + if (!m_pEditedObject) { + return false; + } + m_pEditedObject->SetPresetName(saveAsName); + // Replace the gibs of the object with the proxies that have been edited in the GUI. + StuffEditedGibs(m_pEditedObject); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. + std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); + std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); + std::string newDataDir = dataModuleFullPath + "/NewData"; + std::string objectSavePath = newDataDir + "/" + saveAsName + ".ini"; -void GibEditor::UpdateSaveDialog() -{ - if (!m_pEditedObject) - return; + if (!System::PathExistsCaseSensitive(newDataDir) && !System::MakeDirectory(newDataDir)) { + RTEError::ShowMessageBox("Failed to create NewData directory in:\n\n" + dataModuleFullPath + "\n\nTHE EDITED OBJECT PRESET WAS NOT SAVED!!!"); + return false; + } - m_pSaveNameBox->SetText((m_pEditedObject->GetPresetName() == "None" || !m_HasEverBeenSaved) ? "New Object" : m_pEditedObject->GetPresetName()); -// TODO: Really? - m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/NewData/"); -} + // Force overwrite the stored preset so we aren't prompted to every time for every preset. This doesn't screw with the original ini because there's no system for that in place + // and doesn't actually get loaded on the next game start either, so any changes will be discarded at the end of the current runtime. + if (g_PresetMan.AddEntityPreset(m_pEditedObject, m_ModuleSpaceID, true, objectSavePath)) { + // Show the overwrite dialog only when actually overwriting a saved ini in NewData or forcing an overwrite. + if (!System::PathExistsCaseSensitive(objectSavePath) || forceOverwrite) { + if (Writer objectWriter(objectSavePath, false); !objectWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + objectSavePath + "\n\nTHE EDITED OBJECT PRESET WAS NOT SAVED!!!"); + } else { + std::string addObjectType; + switch (m_pEditedObject->GetMOType()) { + case MovableObject::MOType::TypeActor: + addObjectType = "AddActor"; + break; + case MovableObject::MOType::TypeHeldDevice: + case MovableObject::MOType::TypeThrownDevice: + addObjectType = "AddDevice"; + break; + default: + addObjectType = "AddEffect"; + } + objectWriter.NewProperty(addObjectType); + m_pEditedObject->Entity::Save(objectWriter); + for (const Gib& gib: *m_pEditedObject->GetGibList()) { + objectWriter.NewPropertyWithValue("AddGib", gib); + } + objectWriter.ObjectEnd(); + objectWriter.EndWrite(); + + m_HasEverBeenSaved = true; + + // TODO: Maybe make system for saving into/over the existing definition read originally from the ini's, wherever it was. + + return true; + } + } else { + // Got to ask if we can overwrite the existing object. + m_PreviousMode = EditorMode::SAVEDIALOG; + m_EditorMode = EditorMode::OVERWRITEDIALOG; + m_ModeChange = true; + } + } + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StuffEditedGibs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Replaces all the gibs owned by the passed in MOSR with the ones being + // edited that represent the new gibbing setup. + + void GibEditor::StuffEditedGibs(MOSRotating* pEditedObject) { + if (!pEditedObject) + return; + + // Replace the gibs of the object with the proxies that have been edited in the gui + std::list* pObjectGibList = pEditedObject->GetGibList(); + pObjectGibList->clear(); + + // Take each proxy object and stuff it into a Gib instance which then gets stuffed into the object to be saved + std::list* pProxyGibList = m_pEditorGUI->GetPlacedGibs(); + for (std::list::iterator gItr = pProxyGibList->begin(); gItr != pProxyGibList->end(); ++gItr) { + Gib newGib; + // Only set the refernce instance directly from the isntanceman. OWNERSHIP IS NOT TRANSFERRED! + newGib.m_GibParticle = dynamic_cast(g_PresetMan.GetEntityPreset((*gItr)->GetClassName(), (*gItr)->GetPresetName(), m_ModuleSpaceID)); + if (newGib.m_GibParticle) { + newGib.m_Count = 1; + newGib.m_Offset = (*gItr)->GetPos() - pEditedObject->GetPos(); + // TODO: do proper velocity calculations here! + // ... actually leave these as 0 and let them be calculated in GibThis + // newGib.m_MinVelocity = (100.0f + 50.0f * NormalRand()) / (*gItr)->GetMass(); + // newGib.m_MaxVelocity = newGib.m_MinVelocity + ((100.0f * RandomNum()) / (*gItr)->GetMass()); + pObjectGibList->push_back(newGib); + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. - -void GibEditor::UpdateChangesDialog() -{ - if (!m_pEditedObject) - return; - - if (m_HasEverBeenSaved) - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); - m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/NewData/" + m_pEditedObject->GetPresetName() + ".ini"); - } - else - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Object first?"); - m_pChangesNameLabel->SetText(""); - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + + void GibEditor::UpdateNewDialog() { + /* + // Only refill modules if empty + if (m_pNewModuleCombo->GetCount() <= 0) + { + for (int module = 0; module < g_PresetMan.GetTotalModuleCount(); ++module) + m_pNewModuleCombo->AddItem(g_PresetMan.GetDataModule(module)->GetFileName()); + + // Select the first one + m_pNewModuleCombo->SetSelectedIndex(0); + } + + // Get the ID of the module currently selected so we can limit the following boxes to only show stuff in that module + int selectedModuleID = -1; + GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + selectedModuleID = g_PresetMan.GetModuleID(pItem->m_Name); + + // Refill Terrains + m_pNewTerrainCombo->ClearList(); + // Get the list of all read in terrains + list terrainList; + g_PresetMan.GetAllOfTypeInModuleSpace(terrainList, "SLTerrain", selectedModuleID); + // Go through the list and add their names to the combo box + for (list::iterator itr = terrainList.begin(); itr != terrainList.end(); ++itr) + m_pNewTerrainCombo->AddItem((*itr)->GetPresetName()); + // Select the first one + m_pNewTerrainCombo->SetSelectedIndex(0); + + // Refill backdrops + m_pNewBG1Combo->SetText(""); + m_pNewBG2Combo->SetText(""); + m_pNewBG3Combo->SetText(""); + m_pNewBG1Combo->ClearList(); + m_pNewBG2Combo->ClearList(); + m_pNewBG3Combo->ClearList(); + // Get the list of all read in terrains + list bgList; + g_PresetMan.GetAllOfTypeInModuleSpace(bgList, "SceneLayer", selectedModuleID); + // Go through the list and add their names to the combo box + for (list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) + { + m_pNewBG1Combo->AddItem((*itr)->GetPresetName()); + m_pNewBG2Combo->AddItem((*itr)->GetPresetName()); + m_pNewBG3Combo->AddItem((*itr)->GetPresetName()); + } + // Select the first one + m_pNewBG1Combo->SetSelectedIndex(0); + m_pNewBG2Combo->SetSelectedIndex(0); + m_pNewBG3Combo->SetSelectedIndex(0); + */ + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. + void GibEditor::UpdateLoadDialog() { + if (m_pObjectToLoad) + dynamic_cast(m_pGUIController->GetControl("LoadNameLabel"))->SetText("Load object named " + m_pObjectToLoad->GetPresetName() + "?"); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. + + void GibEditor::UpdateSaveDialog() { + if (!m_pEditedObject) + return; + + m_pSaveNameBox->SetText((m_pEditedObject->GetPresetName() == "None" || !m_HasEverBeenSaved) ? "New Object" : m_pEditedObject->GetPresetName()); + // TODO: Really? + m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/NewData/"); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. -void GibEditor::UpdateOverwriteDialog() -{ - if (m_pEditedObject) - m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/NewData/" + m_pEditedObject->GetPresetName() + ".ini"); -} + void GibEditor::UpdateChangesDialog() { + if (!m_pEditedObject) + return; + + if (m_HasEverBeenSaved) { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); + m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/NewData/" + m_pEditedObject->GetPresetName() + ".ini"); + } else { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Object first?"); + m_pChangesNameLabel->SetText(""); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. + + void GibEditor::UpdateOverwriteDialog() { + if (m_pEditedObject) + m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/NewData/" + m_pEditedObject->GetPresetName() + ".ini"); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GibEditor::ClearTestArea() const { clear_bitmap(g_SceneMan.GetTerrain()->GetFGColorBitmap()); clear_bitmap(g_SceneMan.GetTerrain()->GetBGColorBitmap()); clear_bitmap(g_SceneMan.GetTerrain()->GetMaterialBitmap()); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/GibEditor.h b/Source/Activities/GibEditor.h index 088c56a43..757f3bb0f 100644 --- a/Source/Activities/GibEditor.h +++ b/Source/Activities/GibEditor.h @@ -10,314 +10,285 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "RTETools.h" #include "EditorActivity.h" -namespace RTE -{ - -class MOSRotating; -class GibEditorGUI; -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUIComboBox; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: GibEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activity for editing gib placement within MOSRotating:s. -// Parent(s): EditorActivity. -// Class history: 9/17/2007 GibEditor Created. - -class GibEditor : public EditorActivity { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(GibEditor); -SerializableOverrideMethods; -ClassInfoGetters; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GibEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GibEditor object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - GibEditor() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~GibEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a GibEditor object before deletion -// from system memory. -// Arguments: None. - - ~GibEditor() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GibEditor object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a GibEditor to be identical to another, by deep copy. -// Arguments: A reference to the GibEditor to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const GibEditor &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire GibEditor, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); EditorActivity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GibEditor object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Saves the current object to an appropriate ini file, and asks user if they want to overwrite first if object of this name exists. - /// - /// The name of the new object to be saved. - /// Whether to force any existing Object of that name to be overwritten if it already exists. - /// Whether actually managed to save. Will return false both if an object of this name already exists (and not overwriting), or if other error. - bool SaveObject(const std::string &saveAsName, bool forceOverwrite = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StuffEditedGibs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Replaces all the gibs owned by the passed in MOSR with the ones being -// edited that represent the new gibbing setup. -// Arguments: The MOSRotating to replace the gibs of. Ownership is NOT trnasferred! -// Return value: None. - - void StuffEditedGibs(MOSRotating *pEditedObject); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateNewDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateLoadDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateSaveDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateChangesDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateOverwriteDialog() override; - - - // Member variables - static Entity::ClassInfo m_sClass; - - // The loaded MOSR of which we are editing the gibs. Owned by this. - MOSRotating *m_pEditedObject; - // The temporary copy of the edited object which will be gibbed in the test mode. Owned by this. - MOSRotating *m_pTestingObject; - // How many times tests ahve been run; then the terrain is cleared - int m_TestCounter; - // The MOSR which the user has picked to load. Not owned - const MOSRotating *m_pObjectToLoad; - // The editor GUI - GibEditorGUI *m_pEditorGUI; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - /// - /// Clears all the layers of the testing area terrain so nothing that somehow settled lingers between edited object changes and testing phases. - /// - void ClearTestArea() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class MOSRotating; + class GibEditorGUI; + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUIComboBox; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: GibEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activity for editing gib placement within MOSRotating:s. + // Parent(s): EditorActivity. + // Class history: 9/17/2007 GibEditor Created. + + class GibEditor : public EditorActivity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(GibEditor); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GibEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GibEditor object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + GibEditor() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~GibEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a GibEditor object before deletion + // from system memory. + // Arguments: None. + + ~GibEditor() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GibEditor object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a GibEditor to be identical to another, by deep copy. + // Arguments: A reference to the GibEditor to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const GibEditor& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire GibEditor, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + EditorActivity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GibEditor object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Saves the current object to an appropriate ini file, and asks user if they want to overwrite first if object of this name exists. + /// + /// The name of the new object to be saved. + /// Whether to force any existing Object of that name to be overwritten if it already exists. + /// Whether actually managed to save. Will return false both if an object of this name already exists (and not overwriting), or if other error. + bool SaveObject(const std::string& saveAsName, bool forceOverwrite = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StuffEditedGibs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Replaces all the gibs owned by the passed in MOSR with the ones being + // edited that represent the new gibbing setup. + // Arguments: The MOSRotating to replace the gibs of. Ownership is NOT trnasferred! + // Return value: None. + + void StuffEditedGibs(MOSRotating* pEditedObject); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateNewDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateLoadDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateSaveDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateChangesDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateOverwriteDialog() override; + + // Member variables + static Entity::ClassInfo m_sClass; + + // The loaded MOSR of which we are editing the gibs. Owned by this. + MOSRotating* m_pEditedObject; + // The temporary copy of the edited object which will be gibbed in the test mode. Owned by this. + MOSRotating* m_pTestingObject; + // How many times tests ahve been run; then the terrain is cleared + int m_TestCounter; + // The MOSR which the user has picked to load. Not owned + const MOSRotating* m_pObjectToLoad; + // The editor GUI + GibEditorGUI* m_pEditorGUI; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + /// + /// Clears all the layers of the testing area terrain so nothing that somehow settled lingers between edited object changes and testing phases. + /// + void ClearTestArea() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Activities/MultiplayerGame.cpp b/Source/Activities/MultiplayerGame.cpp index 4f96d9978..f534f7602 100644 --- a/Source/Activities/MultiplayerGame.cpp +++ b/Source/Activities/MultiplayerGame.cpp @@ -5,7 +5,6 @@ // Project: Retro Terrain Engine // Author(s): - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -51,8 +50,7 @@ namespace RTE { // Description: Clears all the member variables of this MultiplayerGame, effectively // resetting the members of this abstraction level only. - void MultiplayerGame::Clear() - { + void MultiplayerGame::Clear() { m_pGUIController = 0; m_pGUIInput = 0; m_pGUIScreen = 0; @@ -81,21 +79,18 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the MultiplayerGame object ready for use. - int MultiplayerGame::Create() - { + int MultiplayerGame::Create() { if (Activity::Create() < 0) return -1; return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Creates a MultiplayerGame to be identical to another, by deep copy. - int MultiplayerGame::Create(const MultiplayerGame &reference) - { + int MultiplayerGame::Create(const MultiplayerGame& reference) { if (Activity::Create(reference) < 0) return -1; @@ -105,7 +100,6 @@ namespace RTE { return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: ReadProperty ////////////////////////////////////////////////////////////////////////////////////////// @@ -114,32 +108,27 @@ namespace RTE { // is called. If the property isn't recognized by any of the base classes, // false is returned, and the reader's position is untouched. - int MultiplayerGame::ReadProperty(const std::string_view &propName, Reader &reader) - { + int MultiplayerGame::ReadProperty(const std::string_view& propName, Reader& reader) { return Activity::ReadProperty(propName, reader); } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Save ////////////////////////////////////////////////////////////////////////////////////////// // Description: Saves the complete state of this MultiplayerGame with a Writer for // later recreation with Create(Reader &reader); - int MultiplayerGame::Save(Writer &writer) const - { + int MultiplayerGame::Save(Writer& writer) const { Activity::Save(writer); return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the MultiplayerGame object. - void MultiplayerGame::Destroy(bool notInherited) - { + void MultiplayerGame::Destroy(bool notInherited) { g_FrameMan.SetDrawNetworkBackBuffer(false); g_NetworkClient.Disconnect(); @@ -158,8 +147,7 @@ namespace RTE { // Description: Officially starts this. Creates all the data etc necessary to start // the activity. - int MultiplayerGame::Start() - { + int MultiplayerGame::Start() { int error = Activity::Start(); g_AudioMan.ClearMusicQueue(); @@ -179,22 +167,21 @@ namespace RTE { m_pGUIController->EnableMouse(true); // Resize the invisible root container so it matches the screen rez - GUICollectionBox *pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); + GUICollectionBox* pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); if (pRootBox) pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); - m_BackToMainButton = dynamic_cast(m_pGUIController->GetControl("ButtonBackToMain")); + m_BackToMainButton = dynamic_cast(m_pGUIController->GetControl("ButtonBackToMain")); - GUICollectionBox *pDialogBox = dynamic_cast(m_pGUIController->GetControl("ConnectDialogBox")); - if (pDialogBox) - { + GUICollectionBox* pDialogBox = dynamic_cast(m_pGUIController->GetControl("ConnectDialogBox")); + if (pDialogBox) { pDialogBox->SetPositionAbs(g_WindowMan.GetResX() / 2 - pDialogBox->GetWidth() / 2, g_WindowMan.GetResY() / 2 - pDialogBox->GetHeight() / 2); m_BackToMainButton->SetPositionAbs((g_WindowMan.GetResX() - m_BackToMainButton->GetWidth()) / 2, pDialogBox->GetYPos() + pDialogBox->GetHeight() + 10); } - m_pServerNameTextBox = dynamic_cast(m_pGUIController->GetControl("ServerNameTB")); - m_pPlayerNameTextBox = dynamic_cast(m_pGUIController->GetControl("PlayerNameTB")); - m_pConnectButton = dynamic_cast(m_pGUIController->GetControl("ConnectButton")); + m_pServerNameTextBox = dynamic_cast(m_pGUIController->GetControl("ServerNameTB")); + m_pPlayerNameTextBox = dynamic_cast(m_pGUIController->GetControl("PlayerNameTB")); + m_pConnectButton = dynamic_cast(m_pGUIController->GetControl("ConnectButton")); /* m_pNATServiceServerNameTextBox = dynamic_cast(m_pGUIController->GetControl("NATServiceNameTB")); @@ -208,8 +195,8 @@ namespace RTE { m_pConnectNATButton->SetVisible(false); */ - //NOTE Instruction labels aren't dynamic so they don't really need to be gotten. Status label should be empty unless there's a status to report. - m_pStatusLabel = dynamic_cast(m_pGUIController->GetControl("StatusLabel")); + // NOTE Instruction labels aren't dynamic so they don't really need to be gotten. Status label should be empty unless there's a status to report. + m_pStatusLabel = dynamic_cast(m_pGUIController->GetControl("StatusLabel")); m_pStatusLabel->SetText(""); m_pServerNameTextBox->SetText(g_SettingsMan.GetNetworkServerAddress()); @@ -229,30 +216,23 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Pauses and unpauses the game. - void MultiplayerGame::SetPaused(bool pause) - { + void MultiplayerGame::SetPaused(bool pause) { // Override the pause - //m_Paused = false; + // m_Paused = false; Activity::SetPaused(pause); - if (pause) - { - if (g_AudioMan.IsMusicPlaying()) - { + if (pause) { + if (g_AudioMan.IsMusicPlaying()) { m_LastMusic = g_AudioMan.GetMusicPath(); m_LastMusicPos = g_AudioMan.GetMusicPosition(); } - } - else - { - if (m_LastMusic != "") - { + } else { + if (m_LastMusic != "") { g_AudioMan.PlayMusic(m_LastMusic.c_str()); g_AudioMan.SetMusicPosition(m_LastMusicPos); } - if (m_Mode == GAMEPLAY) - { + if (m_Mode == GAMEPLAY) { g_UInputMan.TrapMousePos(true, 0); } } @@ -263,8 +243,7 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Forces the current game's end. - void MultiplayerGame::End() - { + void MultiplayerGame::End() { Activity::End(); m_ActivityState = ActivityState::Over; @@ -277,14 +256,12 @@ namespace RTE { // Description: Updates the state of this MultiplayerGame. Supposed to be done every frame // before drawing. - void MultiplayerGame::Update() - { + void MultiplayerGame::Update() { Activity::Update(); ///////////////////////////////////////////////////// // Update the editor interface - if (m_Mode == SETUP) - { + if (m_Mode == SETUP) { m_pGUIController->Update(); //////////////////////////////////////////////////////// @@ -293,34 +270,28 @@ namespace RTE { bool toExit = false; GUIEvent anEvent; - while (m_pGUIController->GetEvent(&anEvent)) - { - if (anEvent.GetType() == GUIEvent::Command) - { + while (m_pGUIController->GetEvent(&anEvent)) { + if (anEvent.GetType() == GUIEvent::Command) { if (anEvent.GetControl() == m_BackToMainButton) { g_ActivityMan.PauseActivity(); return; } - if (anEvent.GetControl() == m_pConnectButton) - { + if (anEvent.GetControl() == m_pConnectButton) { std::string serverName; int port; std::string::size_type portPos = std::string::npos; portPos = m_pServerNameTextBox->GetText().find(":"); - if (portPos != std::string::npos) - { + if (portPos != std::string::npos) { serverName = m_pServerNameTextBox->GetText().substr(0, portPos); std::string portStr = m_pServerNameTextBox->GetText().substr(portPos + 1, m_pServerNameTextBox->GetText().length() - 2); port = atoi(portStr.c_str()); if (port == 0) port = 8000; - } - else - { + } else { serverName = m_pServerNameTextBox->GetText(); port = 8000; } @@ -332,14 +303,12 @@ namespace RTE { g_NetworkClient.Connect(serverName, port, playerName); bool saveSettings = false; - if (g_SettingsMan.GetPlayerNetworkName() != m_pPlayerNameTextBox->GetText()) - { + if (g_SettingsMan.GetPlayerNetworkName() != m_pPlayerNameTextBox->GetText()) { g_SettingsMan.SetPlayerNetworkName(m_pPlayerNameTextBox->GetText()); saveSettings = true; } - if (g_SettingsMan.GetNetworkServerAddress() != m_pServerNameTextBox->GetText()) - { + if (g_SettingsMan.GetNetworkServerAddress() != m_pServerNameTextBox->GetText()) { g_SettingsMan.SetNetworkServerAddress(m_pServerNameTextBox->GetText()); saveSettings = true; } @@ -353,26 +322,21 @@ namespace RTE { g_GUISound.ButtonPressSound()->Play(); } - - if (anEvent.GetControl() == m_pConnectNATButton) - { + if (anEvent.GetControl() == m_pConnectNATButton) { std::string serverName; int port; std::string::size_type portPos = std::string::npos; portPos = m_pNATServiceServerNameTextBox->GetText().find(":"); - if (portPos != std::string::npos) - { + if (portPos != std::string::npos) { serverName = m_pNATServiceServerNameTextBox->GetText().substr(0, portPos); std::string portStr = m_pNATServiceServerNameTextBox->GetText().substr(portPos + 1, m_pNATServiceServerNameTextBox->GetText().length() - 2); port = atoi(portStr.c_str()); if (port == 0) port = 61111; - } - else - { + } else { serverName = m_pNATServiceServerNameTextBox->GetText(); port = 61111; } @@ -384,26 +348,22 @@ namespace RTE { g_NetworkClient.PerformNATPunchThrough(serverName, port, playerName, m_pNATServerNameTextBox->GetText(), m_pNATServerPasswordTextBox->GetText()); bool saveSettings = false; - if (g_SettingsMan.GetPlayerNetworkName() != m_pPlayerNameTextBox->GetText()) - { + if (g_SettingsMan.GetPlayerNetworkName() != m_pPlayerNameTextBox->GetText()) { g_SettingsMan.SetPlayerNetworkName(m_pPlayerNameTextBox->GetText()); saveSettings = true; } - if (g_SettingsMan.GetNATServiceAddress() != m_pNATServiceServerNameTextBox->GetText()) - { + if (g_SettingsMan.GetNATServiceAddress() != m_pNATServiceServerNameTextBox->GetText()) { g_SettingsMan.SetNATServiceAddress(m_pNATServiceServerNameTextBox->GetText()); saveSettings = true; } - if (g_SettingsMan.GetNATServerName() != m_pNATServerNameTextBox->GetText()) - { + if (g_SettingsMan.GetNATServerName() != m_pNATServerNameTextBox->GetText()) { g_SettingsMan.SetNATServerName(m_pNATServerNameTextBox->GetText()); saveSettings = true; } - if (g_SettingsMan.GetNATServerPassword() != m_pNATServerPasswordTextBox->GetText()) - { + if (g_SettingsMan.GetNATServerPassword() != m_pNATServerPasswordTextBox->GetText()) { g_SettingsMan.SetNATServerPassword(m_pNATServerPasswordTextBox->GetText()); saveSettings = true; } @@ -418,19 +378,16 @@ namespace RTE { } } // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { + else if (anEvent.GetType() == GUIEvent::Notification) { } } } - if (m_Mode == CONNECTION) - { + if (m_Mode == CONNECTION) { if (g_NetworkClient.IsConnectedAndRegistered()) m_Mode = GAMEPLAY; - if (m_ConnectionWaitTimer.IsPastRealMS(8000)) - { + if (m_ConnectionWaitTimer.IsPastRealMS(8000)) { g_NetworkClient.Disconnect(); m_Mode = SETUP; m_pStatusLabel->SetText("Connection failed. Check console for error messages."); @@ -438,16 +395,14 @@ namespace RTE { } } - if (m_Mode == GAMEPLAY) - { + if (m_Mode == GAMEPLAY) { g_UInputMan.TrapMousePos(true, 0); g_FrameMan.SetDrawNetworkBackBuffer(true); m_pGUIController->EnableMouse(false); - if (!g_NetworkClient.IsConnectedAndRegistered()) - { - //g_ActivityMan.EndActivity(); - //g_ActivityMan.SetRestartActivity(); + if (!g_NetworkClient.IsConnectedAndRegistered()) { + // g_ActivityMan.EndActivity(); + // g_ActivityMan.SetRestartActivity(); m_Mode = SETUP; m_pGUIController->EnableMouse(true); g_UInputMan.TrapMousePos(false, 0); @@ -456,9 +411,9 @@ namespace RTE { } /*if (g_UInputMan.ElementHeld(0, UInputMan::INPUT_FIRE)) - g_FrameMan.SetScreenText("FIRE", 0, 0, -1, false); + g_FrameMan.SetScreenText("FIRE", 0, 0, -1, false); else - g_FrameMan.SetScreenText("-", 0, 0, -1, false);*/ + g_FrameMan.SetScreenText("-", 0, 0, -1, false);*/ g_NetworkClient.Update(); } @@ -468,10 +423,8 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the currently active GUI of a screen to a BITMAP of choice. - void MultiplayerGame::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) - { - if (m_pGUIController) - { + void MultiplayerGame::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + if (m_pGUIController) { AllegroScreen drawScreen(pTargetBitmap); m_pGUIController->Draw(&drawScreen); if (m_Mode == SETUP) @@ -485,8 +438,7 @@ namespace RTE { // Description: Draws this MultiplayerGame's current graphical representation to a // BITMAP of choice. This includes all game-related graphics. - void MultiplayerGame::Draw(BITMAP* pTargetBitmap, const Vector &targetPos) - { + void MultiplayerGame::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { Activity::Draw(pTargetBitmap, targetPos); } diff --git a/Source/Activities/MultiplayerGame.h b/Source/Activities/MultiplayerGame.h index 0fc755755..66efb1048 100644 --- a/Source/Activities/MultiplayerGame.h +++ b/Source/Activities/MultiplayerGame.h @@ -4,10 +4,9 @@ ////////////////////////////////////////////////////////////////////////////////////////// // File: MultiplayerGame.h ////////////////////////////////////////////////////////////////////////////////////////// -// Description: +// Description: // Project: Retro Terrain Engine -// Author(s): - +// Author(s): ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -15,8 +14,7 @@ #include "RTETools.h" #include "ActivityMan.h" -namespace RTE -{ +namespace RTE { class MultiplayerGameGUI; class GUIScreen; @@ -30,7 +28,6 @@ namespace RTE class GUILabel; class GUIComboBox; - ////////////////////////////////////////////////////////////////////////////////////////// // Class: MultiplayerGame ////////////////////////////////////////////////////////////////////////////////////////// @@ -45,21 +42,17 @@ namespace RTE // Public member variable, method and friend function declarations public: - // Concrete allocation and cloning definitions EntityAllocation(MultiplayerGame); SerializableOverrideMethods; ClassInfoGetters; - - enum MultiplayerGameMode - { + enum MultiplayerGameMode { SETUP, CONNECTION, GAMEPLAY }; - ////////////////////////////////////////////////////////////////////////////////////////// // Constructor: MultiplayerGame ////////////////////////////////////////////////////////////////////////////////////////// @@ -69,7 +62,6 @@ namespace RTE MultiplayerGame() { Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Destructor: ~MultiplayerGame ////////////////////////////////////////////////////////////////////////////////////////// @@ -79,7 +71,6 @@ namespace RTE ~MultiplayerGame() override { Destroy(true); } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// @@ -90,7 +81,6 @@ namespace RTE int Create() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// @@ -99,8 +89,7 @@ namespace RTE // Return value: An error return value signaling sucess or any particular failure. // Anything below 0 is an error signal. - int Create(const MultiplayerGame &reference); - + int Create(const MultiplayerGame& reference); ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Reset @@ -110,8 +99,10 @@ namespace RTE // Arguments: None. // Return value: None. - void Reset() override { Clear(); Activity::Reset(); } - + void Reset() override { + Clear(); + Activity::Reset(); + } ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Destroy @@ -123,7 +114,6 @@ namespace RTE void Destroy(bool notInherited = false) override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Start ////////////////////////////////////////////////////////////////////////////////////////// @@ -134,7 +124,6 @@ namespace RTE int Start() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Pause ////////////////////////////////////////////////////////////////////////////////////////// @@ -144,7 +133,6 @@ namespace RTE void SetPaused(bool pause = true) override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: End ////////////////////////////////////////////////////////////////////////////////////////// @@ -154,7 +142,6 @@ namespace RTE void End() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Update ////////////////////////////////////////////////////////////////////////////////////////// @@ -165,7 +152,6 @@ namespace RTE void Update() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: DrawGUI ////////////////////////////////////////////////////////////////////////////////////////// @@ -175,8 +161,7 @@ namespace RTE // Which screen's GUI to draw onto the bitmap. // Return value: None. - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Draw @@ -187,8 +172,7 @@ namespace RTE // The absolute position of the target bitmap's upper left corner in the scene. // Return value: None. - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; ////////////////////////////////////////////////////////////////////////////////////////// // Protected member variable and method declarations @@ -198,37 +182,33 @@ namespace RTE static Entity::ClassInfo m_sClass; // The editor GUI - //MultiplayerGameGUI *m_pEditorGUI; - - GUIButton *m_BackToMainButton; //!< Button to return to main menu. + // MultiplayerGameGUI *m_pEditorGUI; - // - GUITextBox *m_pServerNameTextBox; + GUIButton* m_BackToMainButton; //!< Button to return to main menu. - GUITextBox *m_pPlayerNameTextBox; + // + GUITextBox* m_pServerNameTextBox; - GUIButton *m_pConnectButton; + GUITextBox* m_pPlayerNameTextBox; + GUIButton* m_pConnectButton; + GUITextBox* m_pNATServiceServerNameTextBox; - GUITextBox *m_pNATServiceServerNameTextBox; + GUITextBox* m_pNATServerNameTextBox; - GUITextBox *m_pNATServerNameTextBox; + GUITextBox* m_pNATServerPasswordTextBox; - GUITextBox *m_pNATServerPasswordTextBox; + GUIButton* m_pConnectNATButton; - GUIButton *m_pConnectNATButton; - - - - GUILabel *m_pStatusLabel; + GUILabel* m_pStatusLabel; // GUI Screen for use by the GUI dialog boxes. Owned - GUIScreen *m_pGUIScreen; + GUIScreen* m_pGUIScreen; // Input controller for he dialog box gui. Owned - GUIInput *m_pGUIInput; + GUIInput* m_pGUIInput; // The control manager which holds all the gui elements for the dialog boxes. Owned - GUIControlManager *m_pGUIController; + GUIControlManager* m_pGUIController; // Current state of the activity MultiplayerGameMode m_Mode; @@ -241,12 +221,10 @@ namespace RTE // Position of music being played, used to recover playback state after pause double m_LastMusicPos; - ////////////////////////////////////////////////////////////////////////////////////////// // Private member variable and method declarations private: - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Clear ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Source/Activities/MultiplayerServerLobby.cpp b/Source/Activities/MultiplayerServerLobby.cpp index 43ad9b4b3..43debc89c 100644 --- a/Source/Activities/MultiplayerServerLobby.cpp +++ b/Source/Activities/MultiplayerServerLobby.cpp @@ -1,10 +1,9 @@ ////////////////////////////////////////////////////////////////////////////////////////// // File: MultiplayerServerLobby.cpp ////////////////////////////////////////////////////////////////////////////////////////// -// Description: +// Description: // Project: Retro Terrain Engine -// Author(s): - +// Author(s): ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -51,9 +50,8 @@ namespace RTE { // Description: Clears all the member variables of this MultiplayerServerLobby, effectively // resetting the members of this abstraction level only. - void MultiplayerServerLobby::Clear() - { - //m_pEditorGUI = 0; + void MultiplayerServerLobby::Clear() { + // m_pEditorGUI = 0; m_pGUIController = 0; m_pGUIInput = 0; m_pGUIScreen = 0; @@ -67,23 +65,19 @@ namespace RTE { m_pDifficultyLabel = 0; m_pDifficultySlider = 0; - for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) - { - for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) - { + for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) { + for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) { // m_aaControls = team == TEAM_DISABLED; m_aapPlayerBoxes[player][team] = 0; } } - for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) - { + for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) { m_apTeamBoxes[team] = 0; m_apTeamNameLabels[team] = 0; } - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { m_apTeamTechSelect[team] = 0; m_apTeamAISkillSlider[team] = 0; m_apTeamAISkillLabel[team] = 0; @@ -109,28 +103,24 @@ namespace RTE { m_pUIDrawBitmap = 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the MultiplayerServerLobby object ready for use. - int MultiplayerServerLobby::Create() - { + int MultiplayerServerLobby::Create() { if (Activity::Create() < 0) return -1; return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Creates a MultiplayerServerLobby to be identical to another, by deep copy. - int MultiplayerServerLobby::Create(const MultiplayerServerLobby &reference) - { + int MultiplayerServerLobby::Create(const MultiplayerServerLobby& reference) { if (Activity::Create(reference) < 0) return -1; @@ -140,7 +130,6 @@ namespace RTE { return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: ReadProperty ////////////////////////////////////////////////////////////////////////////////////////// @@ -149,32 +138,27 @@ namespace RTE { // is called. If the property isn't recognized by any of the base classes, // false is returned, and the reader's position is untouched. - int MultiplayerServerLobby::ReadProperty(const std::string_view &propName, Reader &reader) - { + int MultiplayerServerLobby::ReadProperty(const std::string_view& propName, Reader& reader) { return Activity::ReadProperty(propName, reader); } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Save ////////////////////////////////////////////////////////////////////////////////////////// // Description: Saves the complete state of this MultiplayerServerLobby with a Writer for // later recreation with Create(Reader &reader); - int MultiplayerServerLobby::Save(Writer &writer) const - { + int MultiplayerServerLobby::Save(Writer& writer) const { Activity::Save(writer); return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the MultiplayerServerLobby object. - void MultiplayerServerLobby::Destroy(bool notInherited) - { + void MultiplayerServerLobby::Destroy(bool notInherited) { delete m_pGUIController; delete m_pGUIInput; delete m_pGUIScreen; @@ -197,8 +181,7 @@ namespace RTE { // Description: Officially starts this. Creates all the data etc necessary to start // the activity. - int MultiplayerServerLobby::Start() - { + int MultiplayerServerLobby::Start() { int error = GameActivity::Start(); g_AudioMan.ClearMusicQueue(); @@ -210,9 +193,9 @@ namespace RTE { // Allocate and (re)create the Editor GUI /*if (m_pEditorGUI) - m_pEditorGUI->Destroy(); + m_pEditorGUI->Destroy(); else - m_pEditorGUI = new MultiplayerServerLobbyGUI; + m_pEditorGUI = new MultiplayerServerLobbyGUI; m_pEditorGUI->Create(&(m_PlayerController[0]));*/ ////////////////////////////////////////////////////////////// @@ -231,56 +214,51 @@ namespace RTE { m_pGUIController->EnableMouse(true); // Resize the invisible root container so it matches the screen rez - m_pRootBox = dynamic_cast(m_pGUIController->GetControl("root")); - m_pPlayerSetupBox = dynamic_cast(m_pGUIController->GetControl("PlayerSetupBox")); - + m_pRootBox = dynamic_cast(m_pGUIController->GetControl("root")); + m_pPlayerSetupBox = dynamic_cast(m_pGUIController->GetControl("PlayerSetupBox")); // Activity Selection Box - m_pActivitySelect = dynamic_cast(m_pGUIController->GetControl("ActivitySelectCombo")); - m_pSceneSelect = dynamic_cast(m_pGUIController->GetControl("SceneSelectCombo")); - m_pDifficultyLabel = dynamic_cast(m_pGUIController->GetControl("DifficultyLabel")); - m_pDifficultySlider = dynamic_cast(m_pGUIController->GetControl("DifficultySlider")); - //m_pActivitySelect->SetDropHeight(64); - // m_pActivitySelect->GetListPanel()->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); - //m_pActivityLabel->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); + m_pActivitySelect = dynamic_cast(m_pGUIController->GetControl("ActivitySelectCombo")); + m_pSceneSelect = dynamic_cast(m_pGUIController->GetControl("SceneSelectCombo")); + m_pDifficultyLabel = dynamic_cast(m_pGUIController->GetControl("DifficultyLabel")); + m_pDifficultySlider = dynamic_cast(m_pGUIController->GetControl("DifficultySlider")); + // m_pActivitySelect->SetDropHeight(64); + // m_pActivitySelect->GetListPanel()->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); + // m_pActivityLabel->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); // Player team assignment box char str[128]; - for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) - { - for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) - { + for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) { + for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) { // +1 because the controls are indexed starting at 1, not 0 std::snprintf(str, sizeof(str), "P%dT%dBox", player + 1, team + 1); - m_aapPlayerBoxes[player][team] = dynamic_cast(m_pGUIController->GetControl(str)); + m_aapPlayerBoxes[player][team] = dynamic_cast(m_pGUIController->GetControl(str)); } } - m_apTeamBoxes[TEAM_DISABLED] = dynamic_cast(m_pGUIController->GetControl("TDIcon")); - m_apTeamBoxes[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1Icon")); - m_apTeamBoxes[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2Icon")); - m_apTeamBoxes[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3Icon")); - m_apTeamBoxes[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4Icon")); - m_apTeamNameLabels[TEAM_DISABLED] = dynamic_cast(m_pGUIController->GetControl("TDLabel")); - m_apTeamNameLabels[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1Label")); - m_apTeamNameLabels[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2Label")); - m_apTeamNameLabels[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3Label")); - m_apTeamNameLabels[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4Label")); - m_apTeamTechSelect[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1TechCombo")); - m_apTeamTechSelect[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2TechCombo")); - m_apTeamTechSelect[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3TechCombo")); - m_apTeamTechSelect[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4TechCombo")); - m_apTeamAISkillSlider[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1AISkillSlider")); - m_apTeamAISkillSlider[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2AISkillSlider")); - m_apTeamAISkillSlider[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3AISkillSlider")); - m_apTeamAISkillSlider[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4AISkillSlider")); - m_apTeamAISkillLabel[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1AISkillLabel")); - m_apTeamAISkillLabel[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2AISkillLabel")); - m_apTeamAISkillLabel[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3AISkillLabel")); - m_apTeamAISkillLabel[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4AISkillLabel")); - - - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) - { + m_apTeamBoxes[TEAM_DISABLED] = dynamic_cast(m_pGUIController->GetControl("TDIcon")); + m_apTeamBoxes[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1Icon")); + m_apTeamBoxes[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2Icon")); + m_apTeamBoxes[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3Icon")); + m_apTeamBoxes[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4Icon")); + m_apTeamNameLabels[TEAM_DISABLED] = dynamic_cast(m_pGUIController->GetControl("TDLabel")); + m_apTeamNameLabels[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1Label")); + m_apTeamNameLabels[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2Label")); + m_apTeamNameLabels[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3Label")); + m_apTeamNameLabels[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4Label")); + m_apTeamTechSelect[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1TechCombo")); + m_apTeamTechSelect[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2TechCombo")); + m_apTeamTechSelect[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3TechCombo")); + m_apTeamTechSelect[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4TechCombo")); + m_apTeamAISkillSlider[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1AISkillSlider")); + m_apTeamAISkillSlider[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2AISkillSlider")); + m_apTeamAISkillSlider[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3AISkillSlider")); + m_apTeamAISkillSlider[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4AISkillSlider")); + m_apTeamAISkillLabel[Teams::TeamOne] = dynamic_cast(m_pGUIController->GetControl("T1AISkillLabel")); + m_apTeamAISkillLabel[Teams::TeamTwo] = dynamic_cast(m_pGUIController->GetControl("T2AISkillLabel")); + m_apTeamAISkillLabel[Teams::TeamThree] = dynamic_cast(m_pGUIController->GetControl("T3AISkillLabel")); + m_apTeamAISkillLabel[Teams::TeamFour] = dynamic_cast(m_pGUIController->GetControl("T4AISkillLabel")); + + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { // Hide tech combobxes by default m_apTeamTechSelect[team]->SetEnabled(false); m_apTeamTechSelect[team]->SetVisible(false); @@ -297,12 +275,12 @@ namespace RTE { m_apTeamAISkillLabel[team]->SetVisible(false); m_apTeamAISkillLabel[team]->SetText(Activity::GetAISkillString(m_apTeamAISkillSlider[team]->GetValue())); } - m_pStartErrorLabel = dynamic_cast(m_pGUIController->GetControl("StartErrorLabel")); - m_pCPULockLabel = dynamic_cast(m_pGUIController->GetControl("CPULockLabel")); + m_pStartErrorLabel = dynamic_cast(m_pGUIController->GetControl("StartErrorLabel")); + m_pCPULockLabel = dynamic_cast(m_pGUIController->GetControl("CPULockLabel")); // Populate the tech comboboxes with the available tech modules for (int moduleID = 0; moduleID < g_PresetMan.GetTotalModuleCount(); ++moduleID) { - if (const DataModule *dataModule = g_PresetMan.GetDataModule(moduleID)) { + if (const DataModule* dataModule = g_PresetMan.GetDataModule(moduleID)) { if (dataModule->IsFaction()) { for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { m_apTeamTechSelect[team]->GetListPanel()->AddItem(dataModule->GetFriendlyName(), "", nullptr, nullptr, moduleID); @@ -312,35 +290,34 @@ namespace RTE { } } - m_pGoldLabel = dynamic_cast(m_pGUIController->GetControl("GoldLabel")); - m_pGoldSlider = dynamic_cast(m_pGUIController->GetControl("GoldSlider")); - m_pFogOfWarCheckbox = dynamic_cast(m_pGUIController->GetControl("FogOfWarCheckbox")); - m_pRequireClearPathToOrbitCheckbox = dynamic_cast(m_pGUIController->GetControl("RequireClearPathToOrbitCheckbox")); - m_pDeployUnitsCheckbox = dynamic_cast(m_pGUIController->GetControl("DeployUnitsCheckbox")); + m_pGoldLabel = dynamic_cast(m_pGUIController->GetControl("GoldLabel")); + m_pGoldSlider = dynamic_cast(m_pGUIController->GetControl("GoldSlider")); + m_pFogOfWarCheckbox = dynamic_cast(m_pGUIController->GetControl("FogOfWarCheckbox")); + m_pRequireClearPathToOrbitCheckbox = dynamic_cast(m_pGUIController->GetControl("RequireClearPathToOrbitCheckbox")); + m_pDeployUnitsCheckbox = dynamic_cast(m_pGUIController->GetControl("DeployUnitsCheckbox")); - m_pStartScenarioButton = dynamic_cast(m_pGUIController->GetControl("StartButton")); + m_pStartScenarioButton = dynamic_cast(m_pGUIController->GetControl("StartButton")); // TODO: Use old dimensions because don't feel like redesigning this whole GUI. Deal with this eventually. m_pScenePreviewBitmap = create_bitmap_ex(8, 140, 55); - //m_pScenePreviewBitmap = create_bitmap_ex(8, c_ScenePreviewWidth, c_ScenePreviewHeight); + // m_pScenePreviewBitmap = create_bitmap_ex(8, c_ScenePreviewWidth, c_ScenePreviewHeight); ContentFile defaultPreview("Base.rte/GUIs/DefaultPreview000.png"); m_pDefaultPreviewBitmap = defaultPreview.GetAsBitmap(COLORCONV_NONE, false); clear_to_color(m_pScenePreviewBitmap, g_MaskColor); - m_apPlayerIcons[0] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 1")); - m_apPlayerIcons[1] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 2")); - m_apPlayerIcons[2] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 3")); - m_apPlayerIcons[3] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 4")); + m_apPlayerIcons[0] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 1")); + m_apPlayerIcons[1] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 2")); + m_apPlayerIcons[2] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 3")); + m_apPlayerIcons[3] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad 4")); - m_apPlayerNameLabel[0] = dynamic_cast(m_pGUIController->GetControl("Player1NameLabel")); - m_apPlayerNameLabel[1] = dynamic_cast(m_pGUIController->GetControl("Player2NameLabel")); - m_apPlayerNameLabel[2] = dynamic_cast(m_pGUIController->GetControl("Player3NameLabel")); - m_apPlayerNameLabel[3] = dynamic_cast(m_pGUIController->GetControl("Player4NameLabel")); + m_apPlayerNameLabel[0] = dynamic_cast(m_pGUIController->GetControl("Player1NameLabel")); + m_apPlayerNameLabel[1] = dynamic_cast(m_pGUIController->GetControl("Player2NameLabel")); + m_apPlayerNameLabel[2] = dynamic_cast(m_pGUIController->GetControl("Player3NameLabel")); + m_apPlayerNameLabel[3] = dynamic_cast(m_pGUIController->GetControl("Player4NameLabel")); - if (!m_pCursor) - { + if (!m_pCursor) { ContentFile cursorFile("Base.rte/GUIs/Skins/Cursor.png"); m_pCursor = cursorFile.GetAsBitmap(); } @@ -352,62 +329,53 @@ namespace RTE { UpdateActivityBox(); // This allow to reduce looby bandwidth by 50% while still somewhat descent looking - //g_NetworkServer.SetInterlacingMode(true); + // g_NetworkServer.SetInterlacingMode(true); return error; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateActivityBox ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the contents of the Activity selection box. - void MultiplayerServerLobby::UpdateActivityBox() - { + void MultiplayerServerLobby::UpdateActivityBox() { // Get the currently selected Activity - const Activity *pSelected = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; + const Activity* pSelected = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; - if (pSelected) - { + if (pSelected) { m_pSceneSelect->ClearList(); // Pull out the list of Scenes that are compatible with this Activity - std::map >::iterator asItr; - if (m_Activities.end() != (asItr = m_Activities.find(const_cast(pSelected)))) - { + std::map>::iterator asItr; + if (m_Activities.end() != (asItr = m_Activities.find(const_cast(pSelected)))) { m_pScenes = &((*asItr).second); // Fill scenes combo with compatible scenes - for (std::list::iterator pItr = m_pScenes->begin(); pItr != m_pScenes->end(); ++pItr) - { - Scene *pScene = (*pItr); + for (std::list::iterator pItr = m_pScenes->begin(); pItr != m_pScenes->end(); ++pItr) { + Scene* pScene = (*pItr); m_pSceneSelect->AddItem(pScene->GetPresetName(), "", 0, pScene); } if (m_pSceneSelect->GetCount() > 0) m_pSceneSelect->SetSelectedIndex(0); - m_pSelectedScene = m_pSceneSelect->GetSelectedItem() ? dynamic_cast(m_pSceneSelect->GetSelectedItem()->m_pEntity) : 0; - } - else - { + m_pSelectedScene = m_pSceneSelect->GetSelectedItem() ? dynamic_cast(m_pSceneSelect->GetSelectedItem()->m_pEntity) : 0; + } else { m_pSelectedScene = 0; m_pScenes = 0; } // Resize the box to fit the desc - //m_pActivityBox->Resize(m_pActivityBox->GetWidth(), newHeight + 110); - //UpdateScenesBox(); + // m_pActivityBox->Resize(m_pActivityBox->GetWidth(), newHeight + 110); + // UpdateScenesBox(); - const GameActivity * pSelectedGA = dynamic_cast(pSelected); - if (pSelectedGA) - { + const GameActivity* pSelectedGA = dynamic_cast(pSelected); + if (pSelectedGA) { UpdateGoldSlider(pSelectedGA); UpdateDifficultySlider(); - //Set default fog of war flag and enable or disable it if necessary - if (pSelectedGA->GetDefaultFogOfWar() > -1) - { + // Set default fog of war flag and enable or disable it if necessary + if (pSelectedGA->GetDefaultFogOfWar() > -1) { if (pSelectedGA->GetDefaultFogOfWar() == 0) m_pFogOfWarCheckbox->SetCheck(0); else @@ -415,9 +383,8 @@ namespace RTE { } m_pFogOfWarCheckbox->SetEnabled(pSelectedGA->GetFogOfWarSwitchEnabled()); - //Set default clear path to orbit flag and enable or disable it if necessary - if (pSelectedGA->GetDefaultRequireClearPathToOrbit() > -1) - { + // Set default clear path to orbit flag and enable or disable it if necessary + if (pSelectedGA->GetDefaultRequireClearPathToOrbit() > -1) { if (pSelectedGA->GetDefaultRequireClearPathToOrbit() == 0) m_pRequireClearPathToOrbitCheckbox->SetCheck(0); else @@ -425,9 +392,8 @@ namespace RTE { } m_pRequireClearPathToOrbitCheckbox->SetEnabled(pSelectedGA->GetRequireClearPathToOrbitSwitchEnabled()); - //Set default deploy units flag and enable or disable it if necessary - if (pSelectedGA->GetDefaultDeployUnits() > -1) - { + // Set default deploy units flag and enable or disable it if necessary + if (pSelectedGA->GetDefaultDeployUnits() > -1) { if (pSelectedGA->GetDefaultDeployUnits() == 0) m_pDeployUnitsCheckbox->SetCheck(0); else @@ -439,47 +405,34 @@ namespace RTE { } } - void MultiplayerServerLobby::UpdateGoldSlider(const GameActivity * pSelectedGA) - { + void MultiplayerServerLobby::UpdateGoldSlider(const GameActivity* pSelectedGA) { if (!pSelectedGA) return; // Set gold slider value if activity sepcifies default gold amounts for difficulties - if (m_pDifficultySlider->GetValue() < DifficultySetting::CakeDifficulty) - { + if (m_pDifficultySlider->GetValue() < DifficultySetting::CakeDifficulty) { if (pSelectedGA->GetDefaultGoldCakeDifficulty() > -1) m_pGoldSlider->SetValue(pSelectedGA->GetDefaultGoldCakeDifficulty()); - } - else if (m_pDifficultySlider->GetValue() < DifficultySetting::EasyDifficulty) - { + } else if (m_pDifficultySlider->GetValue() < DifficultySetting::EasyDifficulty) { if (pSelectedGA->GetDefaultGoldEasyDifficulty() > -1) m_pGoldSlider->SetValue(pSelectedGA->GetDefaultGoldEasyDifficulty()); - } - else if (m_pDifficultySlider->GetValue() < DifficultySetting::MediumDifficulty) - { + } else if (m_pDifficultySlider->GetValue() < DifficultySetting::MediumDifficulty) { if (pSelectedGA->GetDefaultGoldMediumDifficulty() > -1) m_pGoldSlider->SetValue(pSelectedGA->GetDefaultGoldMediumDifficulty()); - } - else if (m_pDifficultySlider->GetValue() < DifficultySetting::HardDifficulty) - { + } else if (m_pDifficultySlider->GetValue() < DifficultySetting::HardDifficulty) { if (pSelectedGA->GetDefaultGoldHardDifficulty() > -1) m_pGoldSlider->SetValue(pSelectedGA->GetDefaultGoldHardDifficulty()); - } - else if (m_pDifficultySlider->GetValue() < DifficultySetting::NutsDifficulty) - { + } else if (m_pDifficultySlider->GetValue() < DifficultySetting::NutsDifficulty) { if (pSelectedGA->GetDefaultGoldNutsDifficulty() > -1) m_pGoldSlider->SetValue(pSelectedGA->GetDefaultGoldNutsDifficulty()); - } - else - { + } else { if (pSelectedGA->GetDefaultGoldNutsDifficulty() > -1) m_pGoldSlider->SetValue(pSelectedGA->GetDefaultGoldNutsDifficulty()); } m_pGoldSlider->SetEnabled(pSelectedGA->GetGoldSwitchEnabled()); } - void MultiplayerServerLobby::UpdateDifficultySlider() - { + void MultiplayerServerLobby::UpdateDifficultySlider() { // Set the description if (m_pDifficultySlider->GetValue() < DifficultySetting::CakeDifficulty) m_pDifficultyLabel->SetText("Difficulty: Cake"); @@ -495,43 +448,36 @@ namespace RTE { m_pDifficultyLabel->SetText("Difficulty: Nuts!"); } - - void MultiplayerServerLobby::UpdateSkillSlider() - { - + void MultiplayerServerLobby::UpdateSkillSlider() { } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePlayersBox ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the contents of the player config box. - void MultiplayerServerLobby::UpdatePlayersBox(bool newActivity) - { + void MultiplayerServerLobby::UpdatePlayersBox(bool newActivity) { // Get the currently selected Activity - const Activity *pActivity = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; - const Icon *pIcon = 0; + const Activity* pActivity = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; + const Icon* pIcon = 0; bool teamHasPlayers = false; bool teamHasHumans = false; int teamsWithPlayers = 0; int teamsWithHumans = 0; - if (pActivity && m_pSelectedScene) - { + if (pActivity && m_pSelectedScene) { // Get mouse position and figure out if any cell is being hovered over int mouseX, mouseY; m_pGUIInput->GetMousePosition(&mouseX, &mouseY); Vector mousePos(mouseX, mouseY); bool menuButtonHeld = g_UInputMan.MenuButtonHeld(UInputMan::MENU_EITHER); bool menuButtonReleased = g_UInputMan.MenuButtonReleased(UInputMan::MENU_EITHER); - GUICollectionBox *pHoveredCell = dynamic_cast(m_pGUIController->GetControlUnderPoint(mouseX, mouseY, m_pPlayerSetupBox, 1)); + GUICollectionBox* pHoveredCell = dynamic_cast(m_pGUIController->GetControlUnderPoint(mouseX, mouseY, m_pPlayerSetupBox, 1)); // Is this a game activity? - const GameActivity *pGameActivity = dynamic_cast(pActivity); + const GameActivity* pGameActivity = dynamic_cast(pActivity); - if (newActivity && pGameActivity) - { + if (newActivity && pGameActivity) { // The pre-set team that should absolutely be CPU played m_LockedCPUTeam = pGameActivity->GetCPUTeam(); // Align the locked CPU team text label with the appropriate row @@ -540,39 +486,30 @@ namespace RTE { } // Set up the matrix of player control boxes - for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) - { - for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) - { - if (newActivity) - { + for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) { + for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) { + if (newActivity) { // Everyone starts on the Disabled row, except perhaps the CPU which may be on its locked team - if (team == TEAM_DISABLED) - { + if (team == TEAM_DISABLED) { m_aapPlayerBoxes[player][team]->SetDrawType(GUICollectionBox::Image); - pIcon = player == PLAYER_CPU ? dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")) : m_apPlayerIcons[player];// g_UInputMan.GetSchemeIcon(player); + pIcon = player == PLAYER_CPU ? dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")) : m_apPlayerIcons[player]; // g_UInputMan.GetSchemeIcon(player); if (pIcon) m_aapPlayerBoxes[player][team]->SetDrawImage(new AllegroBitmap(pIcon->GetBitmaps8()[0])); } // De-highlight all other cells initially - else - { + else { m_aapPlayerBoxes[player][team]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[player][team]->SetDrawColor(c_PlayerSlotColorDefault); } // The CPU gets placed on its locked team - if (m_LockedCPUTeam != Teams::NoTeam && player == PLAYER_CPU) - { - if (team == m_LockedCPUTeam) - { + if (m_LockedCPUTeam != Teams::NoTeam && player == PLAYER_CPU) { + if (team == m_LockedCPUTeam) { m_aapPlayerBoxes[player][team]->SetDrawType(GUICollectionBox::Image); - pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); + pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); if (pIcon) m_aapPlayerBoxes[player][team]->SetDrawImage(new AllegroBitmap(pIcon->GetBitmaps8()[0])); - } - else - { + } else { m_aapPlayerBoxes[player][team]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[player][team]->SetDrawColor(c_PlayerSlotColorDefault); } @@ -581,45 +518,37 @@ namespace RTE { // Make the hovered cell light up and able to be selected if (m_aapPlayerBoxes[player][team] == pHoveredCell - // if an active team row, but including the 'not playing' row - && (pActivity->TeamActive(team) || team == TEAM_DISABLED) - // That isn't on a team row locked to the CPU - && m_LockedCPUTeam != team - // And not the CPU player if he is locked to a CPU team - && (m_LockedCPUTeam == Teams::NoTeam || player != PLAYER_CPU)) - // And a cell not already selected - //&& m_aapPlayerBoxes[player][team]->GetDrawType() != GUICollectionBox::Image) - // And players aren't maxed out for this Activity, or we are removing a player from team assignment - // && (player == PLAYER_CPU || team == TEAM_DISABLED || (pGameActivity && PlayerCount() < pGameActivity->GetMaxPlayerSupport()))) + // if an active team row, but including the 'not playing' row + && (pActivity->TeamActive(team) || team == TEAM_DISABLED) + // That isn't on a team row locked to the CPU + && m_LockedCPUTeam != team + // And not the CPU player if he is locked to a CPU team + && (m_LockedCPUTeam == Teams::NoTeam || player != PLAYER_CPU)) + // And a cell not already selected + //&& m_aapPlayerBoxes[player][team]->GetDrawType() != GUICollectionBox::Image) + // And players aren't maxed out for this Activity, or we are removing a player from team assignment + // && (player == PLAYER_CPU || team == TEAM_DISABLED || (pGameActivity && PlayerCount() < pGameActivity->GetMaxPlayerSupport()))) { // Is this being pushed and selected? - if (menuButtonReleased) - { + if (menuButtonReleased) { // Need to clear all other rows of this column - // TODO: -- unless the CPU column? - for (int t2 = Teams::TeamOne; t2 < TEAMROWCOUNT; ++t2) - { + // TODO: -- unless the CPU column? + for (int t2 = Teams::TeamOne; t2 < TEAMROWCOUNT; ++t2) { // This clicked cell should get the icon of this column - if (t2 == team) - { - if (player != PLAYER_CPU) - { + if (t2 == team) { + if (player != PLAYER_CPU) { m_aapPlayerBoxes[player][t2]->SetDrawType(GUICollectionBox::Image); - pIcon = player == PLAYER_CPU ? dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")) : m_apPlayerIcons[player]; //g_UInputMan.GetSchemeIcon(player); + pIcon = player == PLAYER_CPU ? dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")) : m_apPlayerIcons[player]; // g_UInputMan.GetSchemeIcon(player); if (pIcon) m_aapPlayerBoxes[player][t2]->SetDrawImage(new AllegroBitmap(pIcon->GetBitmaps8()[0])); - } - else { - //Select or unselect CPU cells - if (m_aapPlayerBoxes[player][t2]->GetDrawType() == GUICollectionBox::Image) - { + } else { + // Select or unselect CPU cells + if (m_aapPlayerBoxes[player][t2]->GetDrawType() == GUICollectionBox::Image) { m_aapPlayerBoxes[player][t2]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[player][t2]->SetDrawColor(c_PlayerSlotColorDefault); - } - else { - pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); - if (pIcon) - { + } else { + pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); + if (pIcon) { m_aapPlayerBoxes[player][t2]->SetDrawType(GUICollectionBox::Image); m_aapPlayerBoxes[player][t2]->SetDrawImage(new AllegroBitmap(pIcon->GetBitmaps8()[0])); } @@ -627,23 +556,18 @@ namespace RTE { } } // Now unselected columns - else - { - if (player != PLAYER_CPU) - { + else { + if (player != PLAYER_CPU) { m_aapPlayerBoxes[player][t2]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[player][t2]->SetDrawColor(c_PlayerSlotColorDefault); } } } // If CPU changed to an actual team assignment, clear all human players off his new team - if (player == PLAYER_CPU && team != TEAM_DISABLED) - { - for (int p2 = Players::PlayerOne; p2 < Players::MaxPlayerCount; ++p2) - { + if (player == PLAYER_CPU && team != TEAM_DISABLED) { + for (int p2 = Players::PlayerOne; p2 < Players::MaxPlayerCount; ++p2) { // Deselect the player's team assignment if he's on the same team as the CPU - if (m_aapPlayerBoxes[p2][team]->GetDrawType() == GUICollectionBox::Image) - { + if (m_aapPlayerBoxes[p2][team]->GetDrawType() == GUICollectionBox::Image) { m_aapPlayerBoxes[p2][team]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[p2][team]->SetDrawColor(c_PlayerSlotColorDefault); // Move him to disabled @@ -655,62 +579,52 @@ namespace RTE { } } // If Player clicked CPU disabled button, clear CPU row - if (player == PLAYER_CPU && team == TEAM_DISABLED) - { - for (int t2 = Teams::TeamOne; t2 <= Teams::TeamFour; ++t2) - { - if (m_aapPlayerBoxes[PLAYER_CPU][t2]->GetDrawType() == GUICollectionBox::Image) - { + if (player == PLAYER_CPU && team == TEAM_DISABLED) { + for (int t2 = Teams::TeamOne; t2 <= Teams::TeamFour; ++t2) { + if (m_aapPlayerBoxes[PLAYER_CPU][t2]->GetDrawType() == GUICollectionBox::Image) { m_aapPlayerBoxes[PLAYER_CPU][t2]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[PLAYER_CPU][t2]->SetDrawColor(c_PlayerSlotColorDefault); } } } // If a human player changed to a CPU team, remove the CPU guy - else if (player != PLAYER_CPU && team != TEAM_DISABLED) - { + else if (player != PLAYER_CPU && team != TEAM_DISABLED) { // Deselect the CPU's team assignment if he's on the same team as the newly assigned human player - if (m_aapPlayerBoxes[PLAYER_CPU][team]->GetDrawType() == GUICollectionBox::Image) - { + if (m_aapPlayerBoxes[PLAYER_CPU][team]->GetDrawType() == GUICollectionBox::Image) { m_aapPlayerBoxes[PLAYER_CPU][team]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[PLAYER_CPU][team]->SetDrawColor(c_PlayerSlotColorDefault); // Move him to disabled - //m_aapPlayerBoxes[PLAYER_CPU][TEAM_DISABLED]->SetDrawType(GUICollectionBox::Image); - //pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); - //if (pIcon) + // m_aapPlayerBoxes[PLAYER_CPU][TEAM_DISABLED]->SetDrawType(GUICollectionBox::Image); + // pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); + // if (pIcon) // m_aapPlayerBoxes[PLAYER_CPU][TEAM_DISABLED]->SetDrawImage(new AllegroBitmap(pIcon->GetBitmaps8()[0])); } } - //g_GUISound.FocusChangeSound()->Play(); + // g_GUISound.FocusChangeSound()->Play(); - //Check if we need to clear or set CPU disabled team icon + // Check if we need to clear or set CPU disabled team icon bool noCPUs = true; - for (int t2 = Teams::TeamOne; t2 <= Teams::TeamFour; ++t2) - { + for (int t2 = Teams::TeamOne; t2 <= Teams::TeamFour; ++t2) { if (m_aapPlayerBoxes[PLAYER_CPU][t2]->GetDrawType() == GUICollectionBox::Image) noCPUs = false; } - //Select or unselect CPU disabled icon - if (noCPUs) - { - pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); - if (pIcon) - { + // Select or unselect CPU disabled icon + if (noCPUs) { + pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); + if (pIcon) { m_aapPlayerBoxes[PLAYER_CPU][TEAM_DISABLED]->SetDrawType(GUICollectionBox::Image); m_aapPlayerBoxes[PLAYER_CPU][TEAM_DISABLED]->SetDrawImage(new AllegroBitmap(pIcon->GetBitmaps8()[0])); } - } - else { + } else { m_aapPlayerBoxes[PLAYER_CPU][TEAM_DISABLED]->SetDrawType(GUICollectionBox::Color); m_aapPlayerBoxes[PLAYER_CPU][TEAM_DISABLED]->SetDrawColor(c_PlayerSlotColorDefault); } } // Just highlight the cell - else if (m_aapPlayerBoxes[player][team]->GetDrawColor() != c_PlayerSlotColorHovered) - { + else if (m_aapPlayerBoxes[player][team]->GetDrawColor() != c_PlayerSlotColorHovered) { m_aapPlayerBoxes[player][team]->SetDrawColor(c_PlayerSlotColorHovered); - //g_GUISound.SelectionChangeSound()->Play(); + // g_GUISound.SelectionChangeSound()->Play(); } } // Un-highlight all other cells @@ -720,45 +634,40 @@ namespace RTE { } // Team info columns - for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) - { + for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) { // Update the team names and such - if (newActivity) - { + if (newActivity) { m_apTeamBoxes[team]->SetDrawType(GUICollectionBox::Image); /* pointless; the CPU player icon suffices, and doesn't block the real team banner - // CPU Team - if (pGameActivity && pGameActivity->GetCPUTeam() == team) - { - pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "CPU Team")); - m_apTeamNameLabels[team]->SetText(pActivity->GetTeamName(team) + ":"); - } - // The not playing row - else */if (team == TEAM_DISABLED) - { - pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Disabled Team")); - m_apTeamNameLabels[team]->SetText("Not Playing:"); - } + // CPU Team + if (pGameActivity && pGameActivity->GetCPUTeam() == team) + { + pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "CPU Team")); + m_apTeamNameLabels[team]->SetText(pActivity->GetTeamName(team) + ":"); + } + // The not playing row + else */ + if (team == TEAM_DISABLED) { + pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Disabled Team")); + m_apTeamNameLabels[team]->SetText("Not Playing:"); + } // Active player team - else if (pActivity->TeamActive(team)) - { - // Set the team flag icons on the floating player bars - pIcon = pActivity->GetTeamIcon(team); - // Revert to default if needed - if (!pIcon) - { - char str[128]; - std::snprintf(str, sizeof(str), "Team %d Default", team + 1); - pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", str)); - } - m_apTeamNameLabels[team]->SetText(pActivity->GetTeamName(team) + ":"); - } + else if (pActivity->TeamActive(team)) { + // Set the team flag icons on the floating player bars + pIcon = pActivity->GetTeamIcon(team); + // Revert to default if needed + if (!pIcon) { + char str[128]; + std::snprintf(str, sizeof(str), "Team %d Default", team + 1); + pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", str)); + } + m_apTeamNameLabels[team]->SetText(pActivity->GetTeamName(team) + ":"); + } // Disabled/unplayable teams - else - { - pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Locked Team")); - m_apTeamNameLabels[team]->SetText("Unavailable"); - } + else { + pIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Locked Team")); + m_apTeamNameLabels[team]->SetText("Unavailable"); + } // Finally set whatever Icon we came up with if (pIcon) @@ -766,14 +675,11 @@ namespace RTE { } // Check if the team has any players assigned at all - if (pActivity->TeamActive(team)) - { + if (pActivity->TeamActive(team)) { teamHasPlayers = false; - for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) - { + for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) { // CPU is sometimes disabled, but still counts as a team - if (team != TEAM_DISABLED && m_aapPlayerBoxes[player][team]->GetDrawType() == GUICollectionBox::Image) - { + if (team != TEAM_DISABLED && m_aapPlayerBoxes[player][team]->GetDrawType() == GUICollectionBox::Image) { teamHasPlayers = true; if (player != PLAYER_CPU) teamHasHumans = true; @@ -790,11 +696,8 @@ namespace RTE { m_apTeamAISkillSlider[team]->SetEnabled(true); m_apTeamAISkillSlider[team]->SetVisible(true); m_apTeamAISkillLabel[team]->SetVisible(true); - } - else - { - if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) - { + } else { + if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { m_apTeamTechSelect[team]->SetEnabled(false); m_apTeamTechSelect[team]->SetVisible(false); @@ -806,8 +709,7 @@ namespace RTE { } // If we are over capacity with players, disable the start button and show why - if (pActivity->GetMaxPlayerSupport() < PlayerCount()) - { + if (pActivity->GetMaxPlayerSupport() < PlayerCount()) { m_pStartScenarioButton->SetVisible(false); m_pStartErrorLabel->SetVisible(true); char str[256]; @@ -815,8 +717,7 @@ namespace RTE { m_pStartErrorLabel->SetText(str); } // If we are under the required number of teams with players assigned, disable the start button and show why - else if (pActivity->GetMinTeamsRequired() > teamsWithPlayers) - { + else if (pActivity->GetMinTeamsRequired() > teamsWithPlayers) { m_pStartScenarioButton->SetVisible(false); m_pStartErrorLabel->SetVisible(true); char str[256]; @@ -824,22 +725,20 @@ namespace RTE { m_pStartErrorLabel->SetText(str); } // Assign at least one human player - else if (teamsWithHumans == 0) - { + else if (teamsWithHumans == 0) { m_pStartScenarioButton->SetVisible(false); m_pStartErrorLabel->SetVisible(true); m_pStartErrorLabel->SetText("Assign human players\nto at least one team!"); } // Everything checks out; let the player start if they want to - else - { + else { m_pStartScenarioButton->SetVisible(true); m_pStartErrorLabel->SetVisible(false); } // How much starting gold does the slider yield char str[256]; - //int startGold = (float)m_pGoldSlider->GetMinimum() + ((m_pGoldSlider->GetMaximum() - m_pGoldSlider->GetMinimum()) * (float)m_pGoldSlider->GetValue() / 100.0); + // int startGold = (float)m_pGoldSlider->GetMinimum() + ((m_pGoldSlider->GetMaximum() - m_pGoldSlider->GetMinimum()) * (float)m_pGoldSlider->GetValue() / 100.0); int startGold = m_pGoldSlider->GetValue(); startGold = startGold - startGold % 500; if (m_pGoldSlider->GetValue() == m_pGoldSlider->GetMaximum()) @@ -848,17 +747,14 @@ namespace RTE { std::snprintf(str, sizeof(str), "Starting Gold: %c %d oz", -58, startGold); m_pGoldLabel->SetText(str); - // Set skill labels - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) - { + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { m_apTeamAISkillLabel[team]->SetText(Activity::GetAISkillString(m_apTeamAISkillSlider[team]->GetValue())); } } // Reset all buttons and positions of things if a new activity has been selected - if (newActivity) - { + if (newActivity) { m_pStartScenarioButton->SetVisible(false); m_pStartErrorLabel->SetVisible(true); m_pCPULockLabel->SetVisible(m_LockedCPUTeam != Teams::NoTeam); @@ -870,14 +766,11 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Counts how many players are currently assigned to play this Activity. - int MultiplayerServerLobby::PlayerCount() - { + int MultiplayerServerLobby::PlayerCount() { int count = 0; // Go through all the on-team non-CPU cells and see how many players are already assigned. - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { if (m_aapPlayerBoxes[player][team]->GetDrawType() == GUICollectionBox::Image) ++count; } @@ -885,7 +778,6 @@ namespace RTE { return count; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: StartGame ////////////////////////////////////////////////////////////////////////////////////////// @@ -893,21 +785,19 @@ namespace RTE { // Arguments: None. // Return value: None. - bool MultiplayerServerLobby::StartGame() - { + bool MultiplayerServerLobby::StartGame() { // Get the currently selected Activity - const Activity *pActivityPreset = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; + const Activity* pActivityPreset = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; if (!pActivityPreset || !m_pSelectedScene) return false; // Create the actual instance of hte Activity we want to start - Activity *pActivity = dynamic_cast(pActivityPreset->Clone()); - GameActivity *pGameActivity = dynamic_cast(pActivity); + Activity* pActivity = dynamic_cast(pActivityPreset->Clone()); + GameActivity* pGameActivity = dynamic_cast(pActivity); // Set up the basic settings - if (pGameActivity) - { + if (pGameActivity) { pGameActivity->SetDifficulty(m_pDifficultySlider->GetValue()); pGameActivity->SetFogOfWarEnabled(m_pFogOfWarCheckbox->GetCheck()); @@ -919,8 +809,7 @@ namespace RTE { // If gold slider is at it max value then the amount is 'infinite' and we must set some rediculously high value if (m_pGoldSlider->GetValue() == m_pGoldSlider->GetMaximum()) pGameActivity->SetStartingGold(1000000); - else - { + else { int startGold = m_pGoldSlider->GetValue(); startGold = startGold - startGold % 500; pGameActivity->SetStartingGold(startGold); @@ -931,32 +820,26 @@ namespace RTE { // Set up the player and team assignments pActivity->ClearPlayers(false); - for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) - { - for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) - { - if (team != TEAM_DISABLED && m_aapPlayerBoxes[player][team]->GetDrawType() == GUICollectionBox::Image) - { + for (int player = Players::PlayerOne; player < PLAYERCOLUMNCOUNT; ++player) { + for (int team = Teams::TeamOne; team < TEAMROWCOUNT; ++team) { + if (team != TEAM_DISABLED && m_aapPlayerBoxes[player][team]->GetDrawType() == GUICollectionBox::Image) { // Add the human players, not including CPU players if (player != PLAYER_CPU) pActivity->AddPlayer(player, true, team, 0); // CPU team, so mark it as such.. there are no actual CPU players - else if (pGameActivity) - { + else if (pGameActivity) { pGameActivity->SetCPUTeam(team); } } } } - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { // Set up techs - GUIListPanel::Item *pTechItem = m_apTeamTechSelect[team]->GetSelectedItem(); - if (pTechItem) - { + GUIListPanel::Item* pTechItem = m_apTeamTechSelect[team]->GetSelectedItem(); + if (pTechItem) { // If the "random" selection, choose one from the list of loaded techs - if (m_apTeamTechSelect[team]->GetSelectedIndex() == 1)//pTechItem->m_ExtraIndex < 0) + if (m_apTeamTechSelect[team]->GetSelectedIndex() == 1) // pTechItem->m_ExtraIndex < 0) { int selection = RandomNum(1, m_apTeamTechSelect[team]->GetListPanel()->GetItemList()->size() - 1); m_apTeamTechSelect[team]->SetSelectedIndex(selection); @@ -981,7 +864,7 @@ namespace RTE { pGameActivity->SetTeamAISkill(team, AISkillSetting::DefaultSkill); } - //Force close all previously opened files + // Force close all previously opened files g_LuaMan.FileCloseAll(); // Put the new and newly set up Activity as the one to start @@ -998,30 +881,27 @@ namespace RTE { g_MetaMan.EndGame(); // Signal the start of this Activity we just set up - return /*m_ActivityRestarted = */true; + return /*m_ActivityRestarted = */ true; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetAllScenesAndActivities ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gathers all the available Scene:s and Activity presets there are. - void MultiplayerServerLobby::GetAllScenesAndActivities() - { + void MultiplayerServerLobby::GetAllScenesAndActivities() { // Redo the list of Activities m_Activities.clear(); // Get the list of all read in Scene presets - std::list presetList; + std::list presetList; g_PresetMan.GetAllOfType(presetList, "Scene"); - std::list filteredScenes; - Scene *pScene = 0; + std::list filteredScenes; + Scene* pScene = 0; // Go through the list and cast all the pointers to scenes so we have a handy list - for (std::list::iterator pItr = presetList.begin(); pItr != presetList.end(); ++pItr) - { - pScene = dynamic_cast(*pItr); + for (std::list::iterator pItr = presetList.begin(); pItr != presetList.end(); ++pItr) { + pScene = dynamic_cast(*pItr); // Only add non-editor and non-special scenes, or ones that don't have locations defined, or have Test in their names, or are metascenes if (pScene && !pScene->GetLocation().IsZero() && !pScene->IsMetagameInternal() && !pScene->IsSavedGameInternal() && (pScene->GetMetasceneParent() == "" || g_SettingsMan.ShowMetascenes())) filteredScenes.push_back(pScene); @@ -1030,7 +910,7 @@ namespace RTE { // Get the list of all read-in Activity presets presetList.clear(); g_PresetMan.GetAllOfType(presetList, "Activity"); - Activity *pActivity = 0; + Activity* pActivity = 0; int selectedActivityIndex = m_pActivitySelect->GetSelectedIndex(); @@ -1040,18 +920,15 @@ namespace RTE { m_pActivitySelect->ClearList(); int index = 0; int skirmishIndex = -1; - for (std::list::iterator pItr = presetList.begin(); pItr != presetList.end(); ++pItr) - { + for (std::list::iterator pItr = presetList.begin(); pItr != presetList.end(); ++pItr) { bool isMetaActivity = false; - pActivity = dynamic_cast(*pItr); + pActivity = dynamic_cast(*pItr); // Only add non-editor and non-special activities - if (pActivity/* && pActivity->GetClassName() != "GATutorial" */&& pActivity->GetClassName().find("Editor") == std::string::npos) - { + if (pActivity /* && pActivity->GetClassName() != "GATutorial" */ && pActivity->GetClassName().find("Editor") == std::string::npos) { // Prepare a new entry in the list of Activity:ies that we have - std::pair > newPair(pActivity, std::list()); - for (std::list::iterator sItr = filteredScenes.begin(); sItr != filteredScenes.end(); ++sItr) - { + std::pair> newPair(pActivity, std::list()); + for (std::list::iterator sItr = filteredScenes.begin(); sItr != filteredScenes.end(); ++sItr) { // Check if the Scene has the required Area:s and such needed for this Activity if (pActivity->SceneIsCompatible(*sItr)) newPair.second.push_back(*sItr); @@ -1076,22 +953,20 @@ namespace RTE { // Select the Tutorial Activity and Scene by default to start if (skirmishIndex >= 0) m_pActivitySelect->SetSelectedIndex(skirmishIndex); - else + else m_pActivitySelect->SetSelectedIndex(0); UpdateActivityBox(); - //UpdateScenesBox(); + // UpdateScenesBox(); m_pSelectedScene = m_pScenes ? m_pScenes->front() : 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Pause ////////////////////////////////////////////////////////////////////////////////////////// // Description: Pauses and unpauses the game. - void MultiplayerServerLobby::SetPaused(bool pause) - { + void MultiplayerServerLobby::SetPaused(bool pause) { // Override the pause m_Paused = false; } @@ -1101,8 +976,7 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Forces the current game's end. - void MultiplayerServerLobby::End() - { + void MultiplayerServerLobby::End() { Activity::End(); m_ActivityState = ActivityState::Over; @@ -1115,19 +989,14 @@ namespace RTE { // Description: Updates the state of this MultiplayerServerLobby. Supposed to be done every frame // before drawing. - void MultiplayerServerLobby::Update() - { + void MultiplayerServerLobby::Update() { Activity::Update(); - for (int i = 0; i < c_MaxClients; i++) - { - if (g_NetworkServer.IsPlayerConnected(i)) - { + for (int i = 0; i < c_MaxClients; i++) { + if (g_NetworkServer.IsPlayerConnected(i)) { if (m_apPlayerNameLabel[i]->GetText() != g_NetworkServer.GetPlayerName(i) && g_NetworkServer.GetPlayerName(i) != "") m_apPlayerNameLabel[i]->SetText(g_NetworkServer.GetPlayerName(i)); - } - else - { + } else { if (m_apPlayerNameLabel[i]->GetText() != "- NO PLAYER -") m_apPlayerNameLabel[i]->SetText("- NO PLAYER -"); } @@ -1162,8 +1031,7 @@ namespace RTE { // Arguments: None. // Return value: None. - void MultiplayerServerLobby::UpdateInput() - { + void MultiplayerServerLobby::UpdateInput() { // Move the dialog to the center of the player 0 screen so it could operate in absoute mouse coordintaes of the player 0 screen // During draw we move the dialog to 0,0 before drawing to draw it properly into the intermediate buffer co we can draw it centered on other player's screens. BITMAP* drawBitmap = m_pUIDrawBitmap; @@ -1175,7 +1043,6 @@ namespace RTE { // Move to the center of the player 0 screen m_pRootBox->SetPositionAbs(offsetX, offsetY); - m_pGUIController->Update(); // Move to next state as current have been processed in GUIController:Update @@ -1194,51 +1061,42 @@ namespace RTE { // Handle events GUIEvent anEvent; - while (m_pGUIController->GetEvent(&anEvent)) - { + while (m_pGUIController->GetEvent(&anEvent)) { // Commands - if (anEvent.GetType() == GUIEvent::Command) - { + if (anEvent.GetType() == GUIEvent::Command) { // Start game button pressed - if (anEvent.GetControl() == m_pStartScenarioButton) - { + if (anEvent.GetControl() == m_pStartScenarioButton) { // Try to start the game - if (StartGame()) - { + if (StartGame()) { // Hide all previously shown screens, show - //HideAllScreens(); + // HideAllScreens(); // m_MenuScreen = SCENESELECT; // m_ScreenChange = true; - //g_GUISound.ButtonPressSound()->Play(); - } - else + // g_GUISound.ButtonPressSound()->Play(); + } else g_GUISound.UserErrorSound()->Play(); } } // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { + else if (anEvent.GetType() == GUIEvent::Notification) { // Difficulty slider changed - if (anEvent.GetControl() == m_pDifficultySlider) - { + if (anEvent.GetControl() == m_pDifficultySlider) { // Update the difficulty label etc - //UpdateActivityBox(); + // UpdateActivityBox(); UpdateDifficultySlider(); - const Activity *pSelected = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; - const GameActivity * pSelectedGA = dynamic_cast(pSelected); + const Activity* pSelected = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; + const GameActivity* pSelectedGA = dynamic_cast(pSelected); if (pSelectedGA) UpdateGoldSlider(pSelectedGA); } // Activity selection box affected - if (anEvent.GetControl() == m_pActivitySelect) - { + if (anEvent.GetControl() == m_pActivitySelect) { // The activity selection changed - if (anEvent.GetMsg() == GUIComboBox::Closed) - { + if (anEvent.GetMsg() == GUIComboBox::Closed) { // Update the difficulty label etc UpdateActivityBox(); @@ -1250,19 +1108,17 @@ namespace RTE { m_pSelectedScene = 0; // Update the scene info box - //UpdateScenesBox(); - //g_GUISound.ItemChangeSound()->Play(); + // UpdateScenesBox(); + // g_GUISound.ItemChangeSound()->Play(); } } // Scene selection affected - if (anEvent.GetControl() == m_pSceneSelect) - { + if (anEvent.GetControl() == m_pSceneSelect) { // Scene selection changed - if (anEvent.GetMsg() == GUIComboBox::Closed) - { + if (anEvent.GetMsg() == GUIComboBox::Closed) { if (m_pSceneSelect->GetSelectedItem()) - m_pSelectedScene = m_pSceneSelect->GetSelectedItem() ? dynamic_cast(m_pSceneSelect->GetSelectedItem()->m_pEntity) : 0; + m_pSelectedScene = m_pSceneSelect->GetSelectedItem() ? dynamic_cast(m_pSceneSelect->GetSelectedItem()->m_pEntity) : 0; } } } @@ -1271,19 +1127,17 @@ namespace RTE { } } - - ////////////////////////////////////////////////////////////////////////////////////////// // Method: DrawGUI ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the currently active GUI of a screen to a BITMAP of choice. - void MultiplayerServerLobby::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) - { - if (!m_pGUIController) return; + void MultiplayerServerLobby::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + if (!m_pGUIController) + return; - BITMAP * drawBitmap = m_pUIDrawBitmap; - BITMAP * finalDestBitmap = 0; + BITMAP* drawBitmap = m_pUIDrawBitmap; + BITMAP* finalDestBitmap = 0; clear_to_color(drawBitmap, g_MaskColor); @@ -1295,8 +1149,7 @@ namespace RTE { m_pRootBox->SetPositionAbs(0, 0); // We need to manually draw UI's to intermediate buffer first, then to the player's backbuffer to make it centered on each player's screen. - for (int i = 0; i < 4; i++) - { + for (int i = 0; i < 4; i++) { if (i < c_MaxClients) finalDestBitmap = g_FrameMan.GetNetworkBackBufferIntermediateGUI8Current(i); else @@ -1304,70 +1157,61 @@ namespace RTE { AllegroScreen drawScreen(drawBitmap); m_pGUIController->Draw(&drawScreen); - //m_pGUIController->DrawMouse(); + // m_pGUIController->DrawMouse(); - //Draw player icons + // Draw player icons for (int j = 0; j < c_MaxClients; j++) draw_sprite(drawBitmap, m_apPlayerIcons[j]->GetBitmaps8()[0], m_apPlayerNameLabel[j]->GetXPos() - 32, m_apPlayerNameLabel[j]->GetYPos() - 5); // Draw scene preview after GUI - if (m_pSelectedScene) - { - BITMAP * preview = m_pSelectedScene->GetPreviewBitmap(); - if (preview) - { + if (m_pSelectedScene) { + BITMAP* preview = m_pSelectedScene->GetPreviewBitmap(); + if (preview) { int xOffset = 0; int yOffset = 0; // TODO: Scale down the previews to old dimensions so they fit. Deal with this when redesigning GUI one day. - stretch_blit(preview, m_pScenePreviewBitmap, xOffset, yOffset, c_ScenePreviewWidth, c_ScenePreviewHeight, 0, 0, 140, 55 ); - //blit(preview, m_pScenePreviewBitmap, xOffset, yOffset, 0, 0, m_pScenePreviewBitmap->w, m_pScenePreviewBitmap->h); - } - else - { + stretch_blit(preview, m_pScenePreviewBitmap, xOffset, yOffset, c_ScenePreviewWidth, c_ScenePreviewHeight, 0, 0, 140, 55); + // blit(preview, m_pScenePreviewBitmap, xOffset, yOffset, 0, 0, m_pScenePreviewBitmap->w, m_pScenePreviewBitmap->h); + } else { int xOffset = 0; int yOffset = 0; // TODO: Scale down the previews to old dimensions so they fit. Deal with this when redesigning GUI one day. stretch_blit(m_pDefaultPreviewBitmap, m_pScenePreviewBitmap, xOffset, yOffset, c_ScenePreviewWidth, c_ScenePreviewHeight, 0, 0, 140, 55); - //blit(m_pDefaultPreviewBitmap, m_pScenePreviewBitmap, xOffset, yOffset, 0, 0, m_pScenePreviewBitmap->w, m_pScenePreviewBitmap->h); + // blit(m_pDefaultPreviewBitmap, m_pScenePreviewBitmap, xOffset, yOffset, 0, 0, m_pScenePreviewBitmap->w, m_pScenePreviewBitmap->h); } - draw_sprite(drawBitmap, m_pScenePreviewBitmap, 419, 57); + draw_sprite(drawBitmap, m_pScenePreviewBitmap, 419, 57); } // Draw the Player-Team matrix lines and disabled overlay effects - const Activity *pActivity = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; + const Activity* pActivity = m_pActivitySelect->GetSelectedItem() ? dynamic_cast(m_pActivitySelect->GetSelectedItem()->m_pEntity) : 0; int lineY = 80; - for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) - { + for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { // Disabled shaded boxes - if (pActivity && (!pActivity->TeamActive(team) || m_LockedCPUTeam == team)) - { + if (pActivity && (!pActivity->TeamActive(team) || m_LockedCPUTeam == team)) { // TODO: understand why the blending isnt working as desired - // Transparency effect on the overlay boxes - //drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); - // Screen blend the dots and lines, with some flicekring in its intensity - //int blendAmount = 230; - //set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + // Transparency effect on the overlay boxes + // drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); + // Screen blend the dots and lines, with some flicekring in its intensity + // int blendAmount = 230; + // set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); rectfill(drawBitmap, m_pPlayerSetupBox->GetXPos() + 110, m_pPlayerSetupBox->GetYPos() + lineY + 56, m_pPlayerSetupBox->GetXPos() + m_pPlayerSetupBox->GetWidth() - 12, m_pPlayerSetupBox->GetYPos() + lineY + 25 + 56, c_PlayerSlotColorDisabled); } // Back to solid drawing - //drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); + // drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); // Cell border separator lines line(drawBitmap, m_pPlayerSetupBox->GetXPos() + 110, m_pPlayerSetupBox->GetYPos() + lineY + 56, m_pPlayerSetupBox->GetXPos() + m_pPlayerSetupBox->GetWidth() - 12, m_pPlayerSetupBox->GetYPos() + lineY + 56, c_PlayerSlotColorHovered); lineY += 25; } // Manually draw UI elements on top of colored rectangle - for (int team = Teams::MaxTeamCount - 1; team >= Teams::TeamOne; team--) - { - if (m_apTeamTechSelect[team]->GetVisible()) - { + for (int team = Teams::MaxTeamCount - 1; team >= Teams::TeamOne; team--) { + if (m_apTeamTechSelect[team]->GetVisible()) { m_apTeamTechSelect[team]->Draw(&drawScreen); if (m_apTeamTechSelect[team]->IsDropped()) m_apTeamTechSelect[team]->GetListPanel()->Draw(&drawScreen); } - if (m_apTeamAISkillSlider[team]->GetVisible()) - { + if (m_apTeamAISkillSlider[team]->GetVisible()) { m_apTeamAISkillSlider[team]->Draw(&drawScreen); m_apTeamAISkillLabel[team]->Draw(&drawScreen); } @@ -1381,16 +1225,15 @@ namespace RTE { masked_blit(drawBitmap, finalDestBitmap, 0, 0, offsetX, offsetY, drawBitmap->w, drawBitmap->h); - if (i == 0) - { + if (i == 0) { // Don't apply offsets for player 0 as he always sees mouse in abs coords draw_sprite(finalDestBitmap, m_pCursor, mouseX, mouseY); draw_sprite(finalDestBitmap, m_apPlayerIcons[0]->GetBitmaps8()[0], mouseX + 7, mouseY + 7); } /*else { - draw_sprite(finalDestBitmap, m_pCursor, mouseX - offsetX, mouseY - offsetY); - draw_sprite(finalDestBitmap, m_apPlayerIcons[0]->GetBitmaps8()[0], mouseX + 7 + (baseOffsetX - offsetX), mouseY + 7 + (baseOffsetY - offsetY)); + draw_sprite(finalDestBitmap, m_pCursor, mouseX - offsetX, mouseY - offsetY); + draw_sprite(finalDestBitmap, m_apPlayerIcons[0]->GetBitmaps8()[0], mouseX + 7 + (baseOffsetX - offsetX), mouseY + 7 + (baseOffsetY - offsetY)); }*/ } } @@ -1401,9 +1244,8 @@ namespace RTE { // Description: Draws this MultiplayerServerLobby's current graphical representation to a // BITMAP of choice. This includes all game-related graphics. - void MultiplayerServerLobby::Draw(BITMAP* pTargetBitmap, const Vector &targetPos) - { + void MultiplayerServerLobby::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { Activity::Draw(pTargetBitmap, targetPos); } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/MultiplayerServerLobby.h b/Source/Activities/MultiplayerServerLobby.h index 9575db046..03fa83e5e 100644 --- a/Source/Activities/MultiplayerServerLobby.h +++ b/Source/Activities/MultiplayerServerLobby.h @@ -4,10 +4,9 @@ ////////////////////////////////////////////////////////////////////////////////////////// // File: MultiplayerServerLobby.h ////////////////////////////////////////////////////////////////////////////////////////// -// Description: +// Description: // Project: Retro Terrain Engine -// Author(s): - +// Author(s): ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -16,8 +15,7 @@ #include "ActivityMan.h" #include "GameActivity.h" -namespace RTE -{ +namespace RTE { class GUIScreen; class GUIInput; class GUIControlManager; @@ -34,7 +32,6 @@ namespace RTE class Scene; class Activity; - ////////////////////////////////////////////////////////////////////////////////////////// // Class: MultiplayerServerLobby ////////////////////////////////////////////////////////////////////////////////////////// @@ -49,7 +46,6 @@ namespace RTE // Public member variable, method and friend function declarations public: - // Concrete allocation and cloning definitions EntityAllocation(MultiplayerServerLobby); SerializableOverrideMethods; @@ -64,7 +60,6 @@ namespace RTE MultiplayerServerLobby() { Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Destructor: ~MultiplayerServerLobby ////////////////////////////////////////////////////////////////////////////////////////// @@ -74,7 +69,6 @@ namespace RTE ~MultiplayerServerLobby() override { Destroy(true); } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// @@ -85,7 +79,6 @@ namespace RTE int Create() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// @@ -94,8 +87,7 @@ namespace RTE // Return value: An error return value signaling sucess or any particular failure. // Anything below 0 is an error signal. - int Create(const MultiplayerServerLobby &reference); - + int Create(const MultiplayerServerLobby& reference); ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Reset @@ -105,8 +97,10 @@ namespace RTE // Arguments: None. // Return value: None. - void Reset() override { Clear(); Activity::Reset(); } - + void Reset() override { + Clear(); + Activity::Reset(); + } ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Destroy @@ -118,7 +112,6 @@ namespace RTE void Destroy(bool notInherited = false) override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Start ////////////////////////////////////////////////////////////////////////////////////////// @@ -129,7 +122,6 @@ namespace RTE int Start() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Pause ////////////////////////////////////////////////////////////////////////////////////////// @@ -139,7 +131,6 @@ namespace RTE void SetPaused(bool pause = true) override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: End ////////////////////////////////////////////////////////////////////////////////////////// @@ -149,7 +140,6 @@ namespace RTE void End() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Update ////////////////////////////////////////////////////////////////////////////////////////// @@ -160,7 +150,6 @@ namespace RTE void Update() override; - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: DrawGUI ////////////////////////////////////////////////////////////////////////////////////////// @@ -170,8 +159,7 @@ namespace RTE // Which screen's GUI to draw onto the bitmap. // Return value: None. - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Draw @@ -182,17 +170,17 @@ namespace RTE // The absolute position of the target bitmap's upper left corner in the scene. // Return value: None. - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; void UpdateInput(); void UpdateActivityBox(); - //void UpdateScenesBox(); + // void UpdateScenesBox(); void UpdatePlayersBox(bool newActivity); - void UpdateGoldSlider(const GameActivity * pSelectedGA); + void UpdateGoldSlider(const GameActivity* pSelectedGA); void UpdateDifficultySlider(); @@ -204,95 +192,89 @@ namespace RTE int PlayerCount(); - ////////////////////////////////////////////////////////////////////////////////////////// // Protected member variable and method declarations protected: - // These add on the player and team max counts - enum PlayerColumns - { + enum PlayerColumns { PLAYER_CPU = Players::MaxPlayerCount, PLAYERCOLUMNCOUNT }; - enum TeamRows - { + enum TeamRows { TEAM_DISABLED = Teams::MaxTeamCount, TEAMROWCOUNT }; - // Member variables static Entity::ClassInfo m_sClass; // The editor GUI - //MultiplayerServerLobbyGUI *m_pEditorGUI; + // MultiplayerServerLobbyGUI *m_pEditorGUI; // GUI Screen for use by the GUI dialog boxes. Owned - GUIScreen *m_pGUIScreen; + GUIScreen* m_pGUIScreen; // Input controller for he dialog box gui. Owned - GUIInput *m_pGUIInput; + GUIInput* m_pGUIInput; // The control manager which holds all the gui elements for the dialog boxes. Owned - GUIControlManager *m_pGUIController; + GUIControlManager* m_pGUIController; - GUICollectionBox *m_pRootBox; - GUICollectionBox *m_pPlayerSetupBox; + GUICollectionBox* m_pRootBox; + GUICollectionBox* m_pPlayerSetupBox; // Activity selection screen controls - GUIComboBox *m_pActivitySelect; - GUIComboBox *m_pSceneSelect; - GUILabel *m_pDifficultyLabel; - GUISlider *m_pDifficultySlider; - - GUICollectionBox *m_aapPlayerBoxes[PLAYERCOLUMNCOUNT][TEAMROWCOUNT]; - GUICollectionBox *m_apTeamBoxes[TEAMROWCOUNT]; - GUILabel *m_apTeamNameLabels[TEAMROWCOUNT]; - GUILabel *m_pStartErrorLabel; - GUILabel *m_pCPULockLabel; + GUIComboBox* m_pActivitySelect; + GUIComboBox* m_pSceneSelect; + GUILabel* m_pDifficultyLabel; + GUISlider* m_pDifficultySlider; + + GUICollectionBox* m_aapPlayerBoxes[PLAYERCOLUMNCOUNT][TEAMROWCOUNT]; + GUICollectionBox* m_apTeamBoxes[TEAMROWCOUNT]; + GUILabel* m_apTeamNameLabels[TEAMROWCOUNT]; + GUILabel* m_pStartErrorLabel; + GUILabel* m_pCPULockLabel; // Which team the CPU is locked to, if any int m_LockedCPUTeam; - //Tech selection combos - GUIComboBox *m_apTeamTechSelect[Teams::MaxTeamCount]; + // Tech selection combos + GUIComboBox* m_apTeamTechSelect[Teams::MaxTeamCount]; // AI skill selection - GUISlider *m_apTeamAISkillSlider[Teams::MaxTeamCount]; - GUILabel *m_apTeamAISkillLabel[Teams::MaxTeamCount]; + GUISlider* m_apTeamAISkillSlider[Teams::MaxTeamCount]; + GUILabel* m_apTeamAISkillLabel[Teams::MaxTeamCount]; - GUILabel *m_pGoldLabel; - GUISlider *m_pGoldSlider; - GUICheckbox *m_pFogOfWarCheckbox; - GUICheckbox *m_pRequireClearPathToOrbitCheckbox; - GUICheckbox *m_pDeployUnitsCheckbox; + GUILabel* m_pGoldLabel; + GUISlider* m_pGoldSlider; + GUICheckbox* m_pFogOfWarCheckbox; + GUICheckbox* m_pRequireClearPathToOrbitCheckbox; + GUICheckbox* m_pDeployUnitsCheckbox; - const Icon *m_apPlayerIcons[c_MaxClients]; + const Icon* m_apPlayerIcons[c_MaxClients]; - GUILabel * m_apPlayerNameLabel[c_MaxClients]; + GUILabel* m_apPlayerNameLabel[c_MaxClients]; BITMAP* m_pUIDrawBitmap; - BITMAP * m_pCursor; + BITMAP* m_pCursor; - BITMAP *m_pScenePreviewBitmap; - BITMAP *m_pDefaultPreviewBitmap; + BITMAP* m_pScenePreviewBitmap; + BITMAP* m_pDefaultPreviewBitmap; - GUIButton *m_pStartScenarioButton; + GUIButton* m_pStartScenarioButton; // The scene preset currently selected, NOT OWNED - const Scene *m_pSelectedScene; + const Scene* m_pSelectedScene; // The current set of Scenes being displayed - not owned, nor are the scenes - std::list *m_pScenes; + std::list* m_pScenes; // The map of Activity:ies, and the Scene:s compatible with each, neither of which are owned here - std::map > m_Activities; + std::map> m_Activities; ////////////////////////////////////////////////////////////////////////////////////////// // Private member variable and method declarations private: - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Clear ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Source/Activities/SceneEditor.cpp b/Source/Activities/SceneEditor.cpp index 1bf015572..70737d645 100644 --- a/Source/Activities/SceneEditor.cpp +++ b/Source/Activities/SceneEditor.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -42,838 +41,750 @@ namespace RTE { -ConcreteClassInfo(SceneEditor, EditorActivity, 0); + ConcreteClassInfo(SceneEditor, EditorActivity, 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this SceneEditor, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this SceneEditor, effectively -// resetting the members of this abstraction level only. + void SceneEditor::Clear() { + m_pEditorGUI = 0; + m_pNewTerrainCombo = 0; + m_pNewBG1Combo = 0; + m_pNewBG2Combo = 0; + m_pNewBG3Combo = 0; + } -void SceneEditor::Clear() -{ - m_pEditorGUI = 0; - m_pNewTerrainCombo = 0; - m_pNewBG1Combo = 0; - m_pNewBG2Combo = 0; - m_pNewBG3Combo = 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SceneEditor object ready for use. + int SceneEditor::Create() { + if (EditorActivity::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SceneEditor object ready for use. + return 0; + } -int SceneEditor::Create() -{ - if (EditorActivity::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a SceneEditor to be identical to another, by deep copy. + int SceneEditor::Create(const SceneEditor& reference) { + if (EditorActivity::Create(reference) < 0) + return -1; - return 0; -} + if (m_Description.empty()) + m_Description = "Edit this Scene, including placement of all terrain objects and movable objects, AI blueprints, etc."; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a SceneEditor to be identical to another, by deep copy. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int SceneEditor::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); + /* + MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); + */ + EndPropertyList; + } -int SceneEditor::Create(const SceneEditor &reference) -{ - if (EditorActivity::Create(reference) < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this SceneEditor with a Writer for + // later recreation with Create(Reader &reader); - if (m_Description.empty()) - m_Description = "Edit this Scene, including placement of all terrain objects and movable objects, AI blueprints, etc."; + int SceneEditor::Save(Writer& writer) const { + EditorActivity::Save(writer); + return 0; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneEditor object. + void SceneEditor::Destroy(bool notInherited) { + delete m_pEditorGUI; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int SceneEditor::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return EditorActivity::ReadProperty(propName, reader)); -/* - MatchProperty("CPUTeam", { reader >> m_CPUTeam; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("DeliveryDelay", { reader >> m_DeliveryDelay; }); -*/ - EndPropertyList; -} + if (!notInherited) + EditorActivity::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts this. Creates all the data etc necessary to start + // the activity. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this SceneEditor with a Writer for -// later recreation with Create(Reader &reader); + int SceneEditor::Start() { + int error = EditorActivity::Start(); -int SceneEditor::Save(Writer &writer) const { - EditorActivity::Save(writer); - return 0; -} + ////////////////////////////////////////////// + // Allocate and (re)create the Editor GUI + if (m_pEditorGUI) + m_pEditorGUI->Destroy(); + else + m_pEditorGUI = new SceneEditorGUI; + m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneEditor object. + ////////////////////////////////////////////////////////////// + // Hooking up directly to the controls defined in the GUI ini -void SceneEditor::Destroy(bool notInherited) -{ - delete m_pEditorGUI; + m_pGUIController->Load("Base.rte/GUIs/SceneEditorGUI.ini"); - if (!notInherited) - EditorActivity::Destroy(); - Clear(); -} + // Resize the invisible root container so it matches the screen rez + GUICollectionBox* pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); + if (pRootBox) + pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of + if (!m_pNewDialogBox) { + m_pNewDialogBox = dynamic_cast(m_pGUIController->GetControl("NewDialogBox")); + // m_pNewDialogBox->SetDrawType(GUICollectionBox::Color); + m_pNewDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pNewDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pNewDialogBox->GetHeight() / 2)); + m_pNewDialogBox->SetVisible(false); + } + m_pNewModuleCombo = dynamic_cast(m_pGUIController->GetControl("NewModuleCB")); + if (g_SettingsMan.AllowSavingToBase()) + m_pNewModuleCombo->SetEnabled(true); + else + m_pNewModuleCombo->SetEnabled(false); + m_pNewTerrainCombo = dynamic_cast(m_pGUIController->GetControl("NewTerrainCB")); + m_pNewBG1Combo = dynamic_cast(m_pGUIController->GetControl("NewBG1CB")); + m_pNewBG2Combo = dynamic_cast(m_pGUIController->GetControl("NewBG2CB")); + m_pNewBG3Combo = dynamic_cast(m_pGUIController->GetControl("NewBG3CB")); + m_pNewButton = dynamic_cast(m_pGUIController->GetControl("NewSceneButton")); + m_pNewCancel = dynamic_cast(m_pGUIController->GetControl("NewCancelButton")); + + // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of + if (!m_pLoadDialogBox) { + m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); + // m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); + m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); + m_pLoadDialogBox->SetVisible(false); + } + m_pLoadNameCombo = dynamic_cast(m_pGUIController->GetControl("LoadSceneCB")); + m_pLoadNameCombo->SetDropHeight(std::min(m_pLoadNameCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); + m_pLoadDialogBox->SetSize(m_pLoadDialogBox->GetWidth(), m_pLoadDialogBox->GetHeight() + m_pLoadNameCombo->GetDropHeight()); // Make sure the dropdown can fit, no matter how tall it is. + m_pLoadToNewButton = dynamic_cast(m_pGUIController->GetControl("LoadToNewButton")); + m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadSceneButton")); + m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); + + if (!m_pSaveDialogBox) { + m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); + + // Set the background image of the parent collection box + // ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); + // m_pSaveDialogBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); + // m_pSaveDialogBox->SetDrawBackground(true); + // m_pSaveDialogBox->SetDrawType(GUICollectionBox::Image); + // m_pSaveDialogBox->SetDrawType(GUICollectionBox::Color); + m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); + m_pSaveDialogBox->SetVisible(false); + } + m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveSceneNameTB")); + m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); + m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveSceneButton")); + m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); + + if (!m_pChangesDialogBox) { + m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); + m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); + m_pChangesDialogBox->SetVisible(false); + } + m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); + m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); + m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); + + if (!m_pOverwriteDialogBox) { + m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); + m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); + m_pOverwriteDialogBox->SetVisible(false); + } + m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); + m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); + m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts this. Creates all the data etc necessary to start -// the activity. - -int SceneEditor::Start() -{ - int error = EditorActivity::Start(); - - ////////////////////////////////////////////// - // Allocate and (re)create the Editor GUI - - if (m_pEditorGUI) - m_pEditorGUI->Destroy(); - else - m_pEditorGUI = new SceneEditorGUI; - m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT); - - ////////////////////////////////////////////////////////////// - // Hooking up directly to the controls defined in the GUI ini - - m_pGUIController->Load("Base.rte/GUIs/SceneEditorGUI.ini"); - - // Resize the invisible root container so it matches the screen rez - GUICollectionBox *pRootBox = dynamic_cast(m_pGUIController->GetControl("base")); - if (pRootBox) - pRootBox->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); - - // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of - if (!m_pNewDialogBox) - { - m_pNewDialogBox = dynamic_cast(m_pGUIController->GetControl("NewDialogBox")); -// m_pNewDialogBox->SetDrawType(GUICollectionBox::Color); - m_pNewDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pNewDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pNewDialogBox->GetHeight() / 2)); - m_pNewDialogBox->SetVisible(false); - } - m_pNewModuleCombo = dynamic_cast(m_pGUIController->GetControl("NewModuleCB")); - if (g_SettingsMan.AllowSavingToBase()) - m_pNewModuleCombo->SetEnabled(true); - else - m_pNewModuleCombo->SetEnabled(false); - m_pNewTerrainCombo = dynamic_cast(m_pGUIController->GetControl("NewTerrainCB")); - m_pNewBG1Combo = dynamic_cast(m_pGUIController->GetControl("NewBG1CB")); - m_pNewBG2Combo = dynamic_cast(m_pGUIController->GetControl("NewBG2CB")); - m_pNewBG3Combo = dynamic_cast(m_pGUIController->GetControl("NewBG3CB")); - m_pNewButton = dynamic_cast(m_pGUIController->GetControl("NewSceneButton")); - m_pNewCancel = dynamic_cast(m_pGUIController->GetControl("NewCancelButton")); - - // Make sure we have convenient points to the containing GUI dialog boxes that we will manipulate the positions of - if (!m_pLoadDialogBox) - { - m_pLoadDialogBox = dynamic_cast(m_pGUIController->GetControl("LoadDialogBox")); -// m_pLoadDialogBox->SetDrawType(GUICollectionBox::Color); - m_pLoadDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pLoadDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pLoadDialogBox->GetHeight() / 2)); - m_pLoadDialogBox->SetVisible(false); - } - m_pLoadNameCombo = dynamic_cast(m_pGUIController->GetControl("LoadSceneCB")); - m_pLoadNameCombo->SetDropHeight(std::min(m_pLoadNameCombo->GetDropHeight(), g_WindowMan.GetResY() / 2)); - m_pLoadDialogBox->SetSize(m_pLoadDialogBox->GetWidth(), m_pLoadDialogBox->GetHeight() + m_pLoadNameCombo->GetDropHeight()); // Make sure the dropdown can fit, no matter how tall it is. - m_pLoadToNewButton = dynamic_cast(m_pGUIController->GetControl("LoadToNewButton")); - m_pLoadButton = dynamic_cast(m_pGUIController->GetControl("LoadSceneButton")); - m_pLoadCancel = dynamic_cast(m_pGUIController->GetControl("LoadCancelButton")); - - if (!m_pSaveDialogBox) - { - m_pSaveDialogBox = dynamic_cast(m_pGUIController->GetControl("SaveDialogBox")); - - // Set the background image of the parent collection box -// ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); -// m_pSaveDialogBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); -// m_pSaveDialogBox->SetDrawBackground(true); -// m_pSaveDialogBox->SetDrawType(GUICollectionBox::Image); -// m_pSaveDialogBox->SetDrawType(GUICollectionBox::Color); - m_pSaveDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pSaveDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pSaveDialogBox->GetHeight() / 2)); - m_pSaveDialogBox->SetVisible(false); - } - m_pSaveNameBox = dynamic_cast(m_pGUIController->GetControl("SaveSceneNameTB")); - m_pSaveModuleLabel = dynamic_cast(m_pGUIController->GetControl("SaveModuleLabel")); - m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveSceneButton")); - m_pSaveCancel = dynamic_cast(m_pGUIController->GetControl("SaveCancelButton")); - - if (!m_pChangesDialogBox) - { - m_pChangesDialogBox = dynamic_cast(m_pGUIController->GetControl("ChangesDialogBox")); - m_pChangesDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pChangesDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pChangesDialogBox->GetHeight() / 2)); - m_pChangesDialogBox->SetVisible(false); - } - m_pChangesNameLabel = dynamic_cast(m_pGUIController->GetControl("ChangesNameLabel")); - m_pChangesYesButton = dynamic_cast(m_pGUIController->GetControl("ChangesYesButton")); - m_pChangesNoButton = dynamic_cast(m_pGUIController->GetControl("ChangesNoButton")); - - if (!m_pOverwriteDialogBox) - { - m_pOverwriteDialogBox = dynamic_cast(m_pGUIController->GetControl("OverwriteDialogBox")); - m_pOverwriteDialogBox->SetPositionAbs((g_FrameMan.GetPlayerScreenWidth() / 2) - (m_pOverwriteDialogBox->GetWidth() / 2), (g_FrameMan.GetPlayerScreenHeight() / 2) - (m_pOverwriteDialogBox->GetHeight() / 2)); - m_pOverwriteDialogBox->SetVisible(false); - } - m_pOverwriteNameLabel = dynamic_cast(m_pGUIController->GetControl("OverwriteNameLabel")); - m_pOverwriteYesButton = dynamic_cast(m_pGUIController->GetControl("OverwriteYesButton")); - m_pOverwriteNoButton = dynamic_cast(m_pGUIController->GetControl("OverwriteNoButton")); - - return error; -} + return error; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. + void SceneEditor::SetPaused(bool pause) { + // Override the pause + m_Paused = false; + } -void SceneEditor::SetPaused(bool pause) -{ - // Override the pause - m_Paused = false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + void SceneEditor::End() { + EditorActivity::End(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. + m_ActivityState = ActivityState::Over; + } -void SceneEditor::End() -{ - EditorActivity::End(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this SceneEditor. Supposed to be done every frame + // before drawing. + + void SceneEditor::Update() { + EditorActivity::Update(); + + if (!g_SceneMan.GetScene()) + return; + + // Update the loaded objects of the loaded scene so they look right + g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::PLACEONLOAD); + + // All dialog boxes are gone and we're editing the scene + if (m_EditorMode == EditorActivity::EDITINGOBJECT) { + if (m_ModeChange) { + // Open the picker depending on whetehr there's somehting in the cursor hand or not + m_pEditorGUI->SetEditorGUIMode(m_pEditorGUI->GetCurrentObject() ? SceneEditorGUI::ADDINGOBJECT : SceneEditorGUI::PICKINGOBJECT); + // Hide the cursor for this layer of interface + m_pGUIController->EnableMouse(false); + m_ModeChange = false; + } + g_UInputMan.DisableKeys(false); + } + // We are doing something int he dialog boxes, so don't do anything in the editor interface + else + m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); + + ///////////////////////////////////////////////////// + // Update the editor interface + + m_pEditorGUI->Update(); + + // Any edits made, dirtying the scene? + m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; + + // Get any mode change commands that the user gave the Editor GUI + if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) { + m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::NEWDIALOG; + m_ModeChange = true; + } else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorLoad && m_EditorMode != LOADDIALOG) { + m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::LOADDIALOG; + m_ModeChange = true; + } else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) { + m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + // Test the scene by starting a Skirmish Defense with it, after saving + else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone || m_EditorMode == TESTINGOBJECT) { + m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); + + if (m_NeedSave) { + m_PreviousMode = EditorActivity::TESTINGOBJECT; + m_EditorMode = EditorActivity::CHANGESDIALOG; + m_ModeChange = true; + /* + if (m_HasEverBeenSaved) + SaveScene(g_SceneMan.GetScene()->GetPresetName()); + else + { + m_PreviousMode = TESTINGOBJECT; + m_EditorMode = SAVEDIALOG; + m_ModeChange = true; + } + */ + } else { + g_SceneMan.SetSceneToLoad(g_SceneMan.GetScene()->GetPresetName(), Scene::PLACEONLOAD); + + const Activity* pActivityPreset = dynamic_cast(g_PresetMan.GetEntityPreset("GAScripted", "Skirmish Defense")); + Activity* pActivity = dynamic_cast(pActivityPreset->Clone()); + GameActivity* pTestGame = dynamic_cast(pActivity); + RTEAssert(pTestGame, "Couldn't find the \"Skirmish Defense\" GAScripted Activity! Has it been defined?"); + pTestGame->SetTeamOfPlayer(0, 0); + pTestGame->SetCPUTeam(1); + pTestGame->SetStartingGold(10000); + pTestGame->SetFogOfWarEnabled(false); + pTestGame->SetDifficulty(DifficultySetting::MediumDifficulty); + g_ActivityMan.SetStartActivity(pTestGame); + g_ActivityMan.SetRestartActivity(); + } + } + //////////////////////////////////////////////////////// + // Handle events for mouse input on the controls + + GUIEvent anEvent; + while (m_pGUIController->GetEvent(&anEvent)) { + // If we're not supposed to have mouse control, then ignore these messages + // Uh this is not right, editor always has mouse control so far + // if (!m_PlayerController[0].IsMouseControlled()) + // break; + + if (anEvent.GetType() == GUIEvent::Command) { + ////////////////////////////////////////////////////////// + // NEW button pressed; create a new scene + + if (anEvent.GetControl() == m_pNewButton) { + // Get the selected Module + GUIListPanel::Item* pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + m_ModuleSpaceID = g_PresetMan.GetModuleID(pItem->m_Name); + + // Allocate Scene + Scene* pNewScene = new Scene(); + // Get the selected Terrain and create the Scene using it + pItem = m_pNewTerrainCombo->GetItem(m_pNewTerrainCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + SLTerrain* pNewTerrain = dynamic_cast(g_PresetMan.GetEntityPreset("SLTerrain", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewTerrain, "No SLTerrain of that name defined!"); + pNewScene->Create(pNewTerrain); + } + // Add specified scene layers + pItem = m_pNewBG1Combo->GetItem(m_pNewBG1Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + SLBackground* pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SLBackground", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SLBackground of the name set as BG1 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + pItem = m_pNewBG2Combo->GetItem(m_pNewBG2Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + SLBackground* pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SLBackground", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SLBackground of the name set as BG2 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } + pItem = m_pNewBG3Combo->GetItem(m_pNewBG3Combo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + SLBackground* pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SLBackground", pItem->m_Name, m_ModuleSpaceID)->Clone()); + RTEAssert(pNewLayer, "No SLBackground of the name set as BG3 is defined!"); + pNewScene->GetBackLayers().push_back(pNewLayer); + } - m_ActivityState = ActivityState::Over; -} + // Make random planet coord's for this scene + float angle = RandomNum(0.0F, c_TwoPI); + Vector pos = Vector((int)(150 * cos(angle)), (int)(150 * sin(angle))); + pNewScene->SetLocation(pos); + // Actually load the scene's data and set it up as the current scene + g_SceneMan.LoadScene(pNewScene, Scene::PLACEONLOAD); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this SceneEditor. Supposed to be done every frame -// before drawing. - -void SceneEditor::Update() -{ - EditorActivity::Update(); - - if (!g_SceneMan.GetScene()) - return; - - // Update the loaded objects of the loaded scene so they look right - g_SceneMan.GetScene()->UpdatePlacedObjects(Scene::PLACEONLOAD); - - // All dialog boxes are gone and we're editing the scene - if (m_EditorMode == EditorActivity::EDITINGOBJECT) - { - if (m_ModeChange) - { - // Open the picker depending on whetehr there's somehting in the cursor hand or not - m_pEditorGUI->SetEditorGUIMode(m_pEditorGUI->GetCurrentObject() ? SceneEditorGUI::ADDINGOBJECT : SceneEditorGUI::PICKINGOBJECT); - // Hide the cursor for this layer of interface - m_pGUIController->EnableMouse(false); - m_ModeChange = false; - } - g_UInputMan.DisableKeys(false); - } - // We are doing something int he dialog boxes, so don't do anything in the editor interface - else - m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); - - - ///////////////////////////////////////////////////// - // Update the editor interface - - m_pEditorGUI->Update(); - - // Any edits made, dirtying the scene? - m_NeedSave = m_pEditorGUI->EditMade() || m_NeedSave; - - // Get any mode change commands that the user gave the Editor GUI - if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorNew && m_EditorMode != NEWDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::NEWDIALOG; - m_ModeChange = true; - } - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorLoad && m_EditorMode != LOADDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::LOADDIALOG; - m_ModeChange = true; - } - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorSave && m_EditorMode != SAVEDIALOG) - { - m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - // Test the scene by starting a Skirmish Defense with it, after saving - else if (m_pEditorGUI->GetActivatedPieSlice() == PieSlice::SliceType::EditorDone || m_EditorMode == TESTINGOBJECT) - { - m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); - - if (m_NeedSave) - { - m_PreviousMode = EditorActivity::TESTINGOBJECT; - m_EditorMode = EditorActivity::CHANGESDIALOG; - m_ModeChange = true; -/* - if (m_HasEverBeenSaved) - SaveScene(g_SceneMan.GetScene()->GetPresetName()); - else - { - m_PreviousMode = TESTINGOBJECT; - m_EditorMode = SAVEDIALOG; - m_ModeChange = true; - } -*/ - } - else - { - g_SceneMan.SetSceneToLoad(g_SceneMan.GetScene()->GetPresetName(), Scene::PLACEONLOAD); - - const Activity *pActivityPreset = dynamic_cast(g_PresetMan.GetEntityPreset("GAScripted", "Skirmish Defense")); - Activity * pActivity = dynamic_cast(pActivityPreset->Clone()); - GameActivity *pTestGame = dynamic_cast(pActivity); - RTEAssert(pTestGame, "Couldn't find the \"Skirmish Defense\" GAScripted Activity! Has it been defined?"); - pTestGame->SetTeamOfPlayer(0, 0); - pTestGame->SetCPUTeam(1); - pTestGame->SetStartingGold(10000); - pTestGame->SetFogOfWarEnabled(false); - pTestGame->SetDifficulty(DifficultySetting::MediumDifficulty); - g_ActivityMan.SetStartActivity(pTestGame); - g_ActivityMan.SetRestartActivity(); - } - } - - //////////////////////////////////////////////////////// - // Handle events for mouse input on the controls - - GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { - // If we're not supposed to have mouse control, then ignore these messages -// Uh this is not right, editor always has mouse control so far -// if (!m_PlayerController[0].IsMouseControlled()) -// break; - - if (anEvent.GetType() == GUIEvent::Command) - { - ////////////////////////////////////////////////////////// - // NEW button pressed; create a new scene - - if (anEvent.GetControl() == m_pNewButton) - { - // Get the selected Module - GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - m_ModuleSpaceID = g_PresetMan.GetModuleID(pItem->m_Name); - - // Allocate Scene - Scene *pNewScene = new Scene(); - // Get the selected Terrain and create the Scene using it - pItem = m_pNewTerrainCombo->GetItem(m_pNewTerrainCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SLTerrain *pNewTerrain = dynamic_cast(g_PresetMan.GetEntityPreset("SLTerrain", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewTerrain, "No SLTerrain of that name defined!"); - pNewScene->Create(pNewTerrain); - } - - // Add specified scene layers - pItem = m_pNewBG1Combo->GetItem(m_pNewBG1Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SLBackground *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SLBackground", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SLBackground of the name set as BG1 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - pItem = m_pNewBG2Combo->GetItem(m_pNewBG2Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SLBackground *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SLBackground", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SLBackground of the name set as BG2 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - pItem = m_pNewBG3Combo->GetItem(m_pNewBG3Combo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - SLBackground *pNewLayer = dynamic_cast(g_PresetMan.GetEntityPreset("SLBackground", pItem->m_Name, m_ModuleSpaceID)->Clone()); - RTEAssert(pNewLayer, "No SLBackground of the name set as BG3 is defined!"); - pNewScene->GetBackLayers().push_back(pNewLayer); - } - - // Make random planet coord's for this scene - float angle = RandomNum(0.0F, c_TwoPI); - Vector pos = Vector((int)(150 * cos(angle)), (int)(150 * sin(angle))); - pNewScene->SetLocation(pos); - - // Actually load the scene's data and set it up as the current scene - g_SceneMan.LoadScene(pNewScene, Scene::PLACEONLOAD); - - // Reset the rest of the editor GUI - m_pEditorGUI->Destroy(); - if (m_ModuleSpaceID == g_PresetMan.GetModuleID(c_UserScenesModuleName)) - m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, -1); - else - m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, m_ModuleSpaceID); - } - - m_NeedSave = false; - m_HasEverBeenSaved = false; - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // LOAD TO NEW button pressed; go from the load to the new dialog - - if (anEvent.GetControl() == m_pLoadToNewButton) - { - m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); - m_EditorMode = EditorActivity::NEWDIALOG; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // LOAD button pressed; load the selected Scene - - if (anEvent.GetControl() == m_pLoadButton) - { - GUIListPanel::Item *pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - { - // Attempt to load the scene, without applying its placed objects - g_SceneMan.SetSceneToLoad(pItem->m_Name, false); - g_SceneMan.LoadScene(); - // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space - if (g_SceneMan.GetScene()) - { - m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); - RTEAssert(m_ModuleSpaceID >= 0, "Loaded Scene's DataModule ID is negative? Should always be a specific one.."); - m_pEditorGUI->Destroy(); + // Reset the rest of the editor GUI + m_pEditorGUI->Destroy(); if (m_ModuleSpaceID == g_PresetMan.GetModuleID(c_UserScenesModuleName)) m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, -1); else m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, m_ModuleSpaceID); -// TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead - } - } - m_NeedSave = false; - m_HasEverBeenSaved = true; - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } - - ////////////////////////////////////////////////////////// - // SAVE button pressed; save the selected Scene - - if (anEvent.GetControl() == m_pSaveButton) - { - if (!m_pSaveNameBox->GetText().empty()) - { - // Save the scene to the name specified in the text box - if (SaveScene(m_pSaveNameBox->GetText())) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - // Should really leave dialog box open? - else - { - ; - } - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes YES pressed - - if (anEvent.GetControl() == m_pChangesYesButton) - { - if (m_HasEverBeenSaved) - { - if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after save dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - } - // Open the save scene dialog to ask user where to save it then - else - { - m_PreviousMode = m_PreviousMode; - m_EditorMode = EditorActivity::SAVEDIALOG; - m_ModeChange = true; - } - } - - /////////////////////////////////////////////////////////////// - // Save Changes NO pressed - - if (anEvent.GetControl() == m_pChangesNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - m_NeedSave = false; - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene YES pressed - - if (anEvent.GetControl() == m_pOverwriteYesButton) - { - // Force overwrite - if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) - { - // Close the dialog box on success - m_NeedSave = false; - m_HasEverBeenSaved = true; - // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene - m_EditorMode = m_PreviousMode != EditorActivity::SAVEDIALOG ? m_PreviousMode : EditorActivity::EDITINGOBJECT; - m_ModeChange = true; - } -// TODO: Show overwrite error? - } - - /////////////////////////////////////////////////////////////// - // Overwrite Scene NO pressed - - if (anEvent.GetControl() == m_pOverwriteNoButton) - { - // Just go back to previous mode - m_EditorMode = m_PreviousMode; - m_ModeChange = true; - } - - /////////////////////////////////////////////////////////////// - // CANCEL button pressed; exit any active dialog box - - if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) - { - // Don't allow canceling out of diags if we're still in the special "Editor Scene", don't allow users to edit it! - // Just exit the whole editor into the main menu - if (g_SceneMan.GetScene()->GetPresetName() == "Editor Scene") - { - g_ActivityMan.PauseActivity(); - } - // Just do normal cancel of the dialog and go back to editing - else - m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; - - m_ModeChange = true; - } - } - - // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { - /////////////////////////////////////// - // Clicks on the New Scene Module combo - - if (anEvent.GetControl() == m_pNewModuleCombo) - { - // Closed it, IE selected somehting - if(anEvent.GetMsg() == GUIComboBox::Closed) - UpdateNewDialog(); - } - } - } -} + } + m_NeedSave = false; + m_HasEverBeenSaved = false; + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. + ////////////////////////////////////////////////////////// + // LOAD TO NEW button pressed; go from the load to the new dialog -void SceneEditor::DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos, int which) -{ - m_pEditorGUI->Draw(pTargetBitmap, targetPos); + if (anEvent.GetControl() == m_pLoadToNewButton) { + m_pEditorGUI->SetEditorGUIMode(SceneEditorGUI::INACTIVE); + m_EditorMode = EditorActivity::NEWDIALOG; + m_ModeChange = true; + } - EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); -} + ////////////////////////////////////////////////////////// + // LOAD button pressed; load the selected Scene + + if (anEvent.GetControl() == m_pLoadButton) { + GUIListPanel::Item* pItem = m_pLoadNameCombo->GetItem(m_pLoadNameCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) { + // Attempt to load the scene, without applying its placed objects + g_SceneMan.SetSceneToLoad(pItem->m_Name, false); + g_SceneMan.LoadScene(); + // Get the Module ID that the scene exists in, so we can limit the picker to only show objects from that DataModule space + if (g_SceneMan.GetScene()) { + m_ModuleSpaceID = g_SceneMan.GetScene()->GetModuleID(); + RTEAssert(m_ModuleSpaceID >= 0, "Loaded Scene's DataModule ID is negative? Should always be a specific one.."); + m_pEditorGUI->Destroy(); + if (m_ModuleSpaceID == g_PresetMan.GetModuleID(c_UserScenesModuleName)) + m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, -1); + else + m_pEditorGUI->Create(&(m_PlayerController[0]), SceneEditorGUI::ONLOADEDIT, m_ModuleSpaceID); + // TODO: Should read in all the already placed objects in the loaded scene and have them appear int he editor instead + } + } + m_NeedSave = false; + m_HasEverBeenSaved = true; + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + ////////////////////////////////////////////////////////// + // SAVE button pressed; save the selected Scene + + if (anEvent.GetControl() == m_pSaveButton) { + if (!m_pSaveNameBox->GetText().empty()) { + // Save the scene to the name specified in the text box + if (SaveScene(m_pSaveNameBox->GetText())) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + // Should really leave dialog box open? + else { + ; + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this SceneEditor's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. + /////////////////////////////////////////////////////////////// + // Save Changes YES pressed + + if (anEvent.GetControl() == m_pChangesYesButton) { + if (m_HasEverBeenSaved) { + if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after save dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } + } + // Open the save scene dialog to ask user where to save it then + else { + m_PreviousMode = m_PreviousMode; + m_EditorMode = EditorActivity::SAVEDIALOG; + m_ModeChange = true; + } + } -void SceneEditor::Draw(BITMAP* pTargetBitmap, const Vector &targetPos) -{ - EditorActivity::Draw(pTargetBitmap, targetPos); -} + /////////////////////////////////////////////////////////////// + // Save Changes NO pressed -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (anEvent.GetControl() == m_pChangesNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + m_NeedSave = false; + } -bool SceneEditor::SaveScene(const std::string &saveAsName, bool forceOverwrite) { - Scene *editedScene = g_SceneMan.GetScene(); - editedScene->SetPresetName(saveAsName); + /////////////////////////////////////////////////////////////// + // Overwrite Scene YES pressed + + if (anEvent.GetControl() == m_pOverwriteYesButton) { + // Force overwrite + if (SaveScene(g_SceneMan.GetScene()->GetPresetName(), true)) { + // Close the dialog box on success + m_NeedSave = false; + m_HasEverBeenSaved = true; + // Go back to previous mode after overwrite dialog is done, may have been on the way to test the scene + m_EditorMode = m_PreviousMode != EditorActivity::SAVEDIALOG ? m_PreviousMode : EditorActivity::EDITINGOBJECT; + m_ModeChange = true; + } + // TODO: Show overwrite error? + } - std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); - bool savingToUserScenesModule = (dataModuleName == c_UserScenesModuleName); + /////////////////////////////////////////////////////////////// + // Overwrite Scene NO pressed - std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); - std::string sceneSavePath; - std::string previewSavePath; + if (anEvent.GetControl() == m_pOverwriteNoButton) { + // Just go back to previous mode + m_EditorMode = m_PreviousMode; + m_ModeChange = true; + } - if (savingToUserScenesModule) { - sceneSavePath = dataModuleFullPath + "/" + saveAsName + ".ini"; - previewSavePath = dataModuleFullPath + "/" + saveAsName + ".preview.png"; - } else { - sceneSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".ini"; - previewSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".preview.png"; - } + /////////////////////////////////////////////////////////////// + // CANCEL button pressed; exit any active dialog box - if (g_PresetMan.AddEntityPreset(editedScene, m_ModuleSpaceID, forceOverwrite, sceneSavePath)) { - if (Writer sceneWriter(sceneSavePath, false); !sceneWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + sceneSavePath + "\n\nTHE EDITED SCENE PRESET WAS NOT SAVED!!!"); - } else { - // TODO: Check if the ini file already exists, and then ask if overwrite. - sceneWriter.NewPropertyWithValue("AddScene", editedScene); - sceneWriter.EndWrite(); - - editedScene->SavePreview(previewSavePath); - m_HasEverBeenSaved = true; - - if (!savingToUserScenesModule) { - // First find/create a Scenes.ini file to include the new .ini into. - std::string scenesFilePath(dataModuleFullPath + "/Scenes.ini"); - bool scenesFileExists = System::PathExistsCaseSensitive(scenesFilePath); - - if (Writer scenesFileWriter(scenesFilePath, true); !scenesFileWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + scenesFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); - } else { - scenesFileWriter.NewPropertyWithValue("IncludeFile", sceneSavePath); - scenesFileWriter.EndWrite(); - - // Append to the end of the modules' Index.ini to include the newly created Scenes.ini next startup. - // If it's somehow already included without actually existing, it doesn't matter, the definitions will just bounce the second time. - if (!scenesFileExists) { - std::string indexFilePath = dataModuleFullPath + "/Index.ini"; - - if (Writer indexWriter(indexFilePath, true); !indexWriter.WriterOK()) { - RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + indexFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); - } else { - // Add extra tab since the DataModule has everything indented. - indexWriter.NewProperty("\tIncludeFile"); - indexWriter << scenesFilePath; - indexWriter.EndWrite(); - } + if (anEvent.GetControl() == m_pNewCancel || anEvent.GetControl() == m_pLoadCancel || anEvent.GetControl() == m_pSaveCancel) { + // Don't allow canceling out of diags if we're still in the special "Editor Scene", don't allow users to edit it! + // Just exit the whole editor into the main menu + if (g_SceneMan.GetScene()->GetPresetName() == "Editor Scene") { + g_ActivityMan.PauseActivity(); } + // Just do normal cancel of the dialog and go back to editing + else + m_EditorMode = m_PreviousMode = EditorActivity::EDITINGOBJECT; + + m_ModeChange = true; + } + } + + // Notifications + else if (anEvent.GetType() == GUIEvent::Notification) { + /////////////////////////////////////// + // Clicks on the New Scene Module combo + + if (anEvent.GetControl() == m_pNewModuleCombo) { + // Closed it, IE selected somehting + if (anEvent.GetMsg() == GUIComboBox::Closed) + UpdateNewDialog(); } } - return true; } - } else { - // Got to ask if we can overwrite the existing preset. - m_PreviousMode = EditorMode::SAVEDIALOG; - m_EditorMode = EditorMode::OVERWRITEDIALOG; - m_ModeChange = true; } - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. -void SceneEditor::UpdateNewDialog() -{ - int scenesIndex = 0; + void SceneEditor::DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos, int which) { + m_pEditorGUI->Draw(pTargetBitmap, targetPos); - // Only refill modules if empty - if (m_pNewModuleCombo->GetCount() <= 0) - { - for (int module = 0; module < g_PresetMan.GetTotalModuleCount(); ++module) - { - m_pNewModuleCombo->AddItem(g_PresetMan.GetDataModule(module)->GetFileName()); + EditorActivity::DrawGUI(pTargetBitmap, targetPos, which); + } - if (g_PresetMan.GetDataModule(module)->GetFileName() == c_UserScenesModuleName) - scenesIndex = m_pNewModuleCombo->GetCount() - 1; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this SceneEditor's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. - // Select the user scenes module - m_pNewModuleCombo->SetSelectedIndex(scenesIndex); - } - - // Get the ID of the module currently selected so we can limit the following boxes to only show stuff in that module - int selectedModuleID = -1; - GUIListPanel::Item *pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); - if (pItem && !pItem->m_Name.empty()) - selectedModuleID = g_PresetMan.GetModuleID(pItem->m_Name); - - // Refill Terrains - m_pNewTerrainCombo->ClearList(); - // Get the list of all read in terrains - std::list terrainList; - g_PresetMan.GetAllOfTypeInModuleSpace(terrainList, "SLTerrain", selectedModuleID); - // Go through the list and add their names to the combo box - for (std::list::iterator itr = terrainList.begin(); itr != terrainList.end(); ++itr) - { - if ((*itr)->GetPresetName() != "Editor Terrain" && - (*itr)->GetPresetName() != "Physics Test Terrain") - m_pNewTerrainCombo->AddItem((*itr)->GetPresetName()); + void SceneEditor::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + EditorActivity::Draw(pTargetBitmap, targetPos); } - // Select the first one - m_pNewTerrainCombo->SetSelectedIndex(0); - - // Refill backdrops - m_pNewBG1Combo->SetText(""); - m_pNewBG2Combo->SetText(""); - m_pNewBG3Combo->SetText(""); - m_pNewBG1Combo->ClearList(); - m_pNewBG2Combo->ClearList(); - m_pNewBG3Combo->ClearList(); - - // Get the list of all read in NEAR background layers - std::list bgList; - g_PresetMan.GetAllOfGroupInModuleSpace(bgList, "Near Backdrops", "SLBackground", selectedModuleID); - // Go through the list and add their names to the combo box - for (std::list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) - m_pNewBG1Combo->AddItem((*itr)->GetPresetName()); - - // Get the list of all read in MID background layers - bgList.clear(); - g_PresetMan.GetAllOfGroupInModuleSpace(bgList, "Mid Backdrops", "SLBackground", selectedModuleID); - // Go through the list and add their names to the combo box - for (std::list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) - m_pNewBG2Combo->AddItem((*itr)->GetPresetName()); - - // Get the list of all read in FAR background layers - bgList.clear(); - g_PresetMan.GetAllOfGroupInModuleSpace(bgList, "Far Backdrops", "SLBackground", selectedModuleID); - // Go through the list and add their names to the combo box - for (std::list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) - m_pNewBG3Combo->AddItem((*itr)->GetPresetName()); - - // Select the first one for each - m_pNewBG1Combo->SetSelectedIndex(0); - m_pNewBG2Combo->SetSelectedIndex(0); - m_pNewBG3Combo->SetSelectedIndex(0); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. + bool SceneEditor::SaveScene(const std::string& saveAsName, bool forceOverwrite) { + Scene* editedScene = g_SceneMan.GetScene(); + editedScene->SetPresetName(saveAsName); -void SceneEditor::UpdateLoadDialog() -{ - // Clear out the control - m_pLoadNameCombo->ClearList(); + std::string dataModuleName = g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName(); + bool savingToUserScenesModule = (dataModuleName == c_UserScenesModuleName); - // Get the list of all read in scenes - std::list sceneList; - g_PresetMan.GetAllOfType(sceneList, "Scene"); + std::string dataModuleFullPath = g_PresetMan.GetFullModulePath(dataModuleName); + std::string sceneSavePath; + std::string previewSavePath; - // Go through the list and add their names to the combo box - for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) - { - Scene * pScene = dynamic_cast(*itr); - if (pScene) - // Don't add the special "Editor Scene" or metascenes, users shouldn't be messing with them - if (pScene->GetPresetName() != "Editor Scene" && !pScene->IsMetagameInternal() && !pScene->IsSavedGameInternal() && (pScene->GetMetasceneParent() == "" || g_SettingsMan.ShowMetascenes())) - m_pLoadNameCombo->AddItem(pScene->GetPresetName()); - } + if (savingToUserScenesModule) { + sceneSavePath = dataModuleFullPath + "/" + saveAsName + ".ini"; + previewSavePath = dataModuleFullPath + "/" + saveAsName + ".preview.png"; + } else { + sceneSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".ini"; + previewSavePath = dataModuleFullPath + "/Scenes/" + saveAsName + ".preview.png"; + } - // Select the first one - m_pLoadNameCombo->SetSelectedIndex(0); -} + if (g_PresetMan.AddEntityPreset(editedScene, m_ModuleSpaceID, forceOverwrite, sceneSavePath)) { + if (Writer sceneWriter(sceneSavePath, false); !sceneWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + sceneSavePath + "\n\nTHE EDITED SCENE PRESET WAS NOT SAVED!!!"); + } else { + // TODO: Check if the ini file already exists, and then ask if overwrite. + sceneWriter.NewPropertyWithValue("AddScene", editedScene); + sceneWriter.EndWrite(); + + editedScene->SavePreview(previewSavePath); + m_HasEverBeenSaved = true; + + if (!savingToUserScenesModule) { + // First find/create a Scenes.ini file to include the new .ini into. + std::string scenesFilePath(dataModuleFullPath + "/Scenes.ini"); + bool scenesFileExists = System::PathExistsCaseSensitive(scenesFilePath); + + if (Writer scenesFileWriter(scenesFilePath, true); !scenesFileWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + scenesFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); + } else { + scenesFileWriter.NewPropertyWithValue("IncludeFile", sceneSavePath); + scenesFileWriter.EndWrite(); + + // Append to the end of the modules' Index.ini to include the newly created Scenes.ini next startup. + // If it's somehow already included without actually existing, it doesn't matter, the definitions will just bounce the second time. + if (!scenesFileExists) { + std::string indexFilePath = dataModuleFullPath + "/Index.ini"; + + if (Writer indexWriter(indexFilePath, true); !indexWriter.WriterOK()) { + RTEError::ShowMessageBox("Failed to create Writer to path:\n\n" + indexFilePath + "\n\nThe edited Scene preset was saved but will not be loaded on next game start!\nPlease include the Scene preset manually!"); + } else { + // Add extra tab since the DataModule has everything indented. + indexWriter.NewProperty("\tIncludeFile"); + indexWriter << scenesFilePath; + indexWriter.EndWrite(); + } + } + } + } + return true; + } + } else { + // Got to ask if we can overwrite the existing preset. + m_PreviousMode = EditorMode::SAVEDIALOG; + m_EditorMode = EditorMode::OVERWRITEDIALOG; + m_ModeChange = true; + } + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. + void SceneEditor::UpdateNewDialog() { + int scenesIndex = 0; -void SceneEditor::UpdateSaveDialog() -{ - m_pSaveNameBox->SetText((g_SceneMan.GetScene()->GetPresetName() == "None" || !m_HasEverBeenSaved) ? "New Scene" : g_SceneMan.GetScene()->GetPresetName()); + // Only refill modules if empty + if (m_pNewModuleCombo->GetCount() <= 0) { + for (int module = 0; module < g_PresetMan.GetTotalModuleCount(); ++module) { + m_pNewModuleCombo->AddItem(g_PresetMan.GetDataModule(module)->GetFileName()); - if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) - m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/"); - else - m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes"); -} + if (g_PresetMan.GetDataModule(module)->GetFileName() == c_UserScenesModuleName) + scenesIndex = m_pNewModuleCombo->GetCount() - 1; + } + // Select the user scenes module + m_pNewModuleCombo->SetSelectedIndex(scenesIndex); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. + // Get the ID of the module currently selected so we can limit the following boxes to only show stuff in that module + int selectedModuleID = -1; + GUIListPanel::Item* pItem = m_pNewModuleCombo->GetItem(m_pNewModuleCombo->GetSelectedIndex()); + if (pItem && !pItem->m_Name.empty()) + selectedModuleID = g_PresetMan.GetModuleID(pItem->m_Name); + + // Refill Terrains + m_pNewTerrainCombo->ClearList(); + // Get the list of all read in terrains + std::list terrainList; + g_PresetMan.GetAllOfTypeInModuleSpace(terrainList, "SLTerrain", selectedModuleID); + // Go through the list and add their names to the combo box + for (std::list::iterator itr = terrainList.begin(); itr != terrainList.end(); ++itr) { + if ((*itr)->GetPresetName() != "Editor Terrain" && + (*itr)->GetPresetName() != "Physics Test Terrain") + m_pNewTerrainCombo->AddItem((*itr)->GetPresetName()); + } + // Select the first one + m_pNewTerrainCombo->SetSelectedIndex(0); + + // Refill backdrops + m_pNewBG1Combo->SetText(""); + m_pNewBG2Combo->SetText(""); + m_pNewBG3Combo->SetText(""); + m_pNewBG1Combo->ClearList(); + m_pNewBG2Combo->ClearList(); + m_pNewBG3Combo->ClearList(); + + // Get the list of all read in NEAR background layers + std::list bgList; + g_PresetMan.GetAllOfGroupInModuleSpace(bgList, "Near Backdrops", "SLBackground", selectedModuleID); + // Go through the list and add their names to the combo box + for (std::list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) + m_pNewBG1Combo->AddItem((*itr)->GetPresetName()); + + // Get the list of all read in MID background layers + bgList.clear(); + g_PresetMan.GetAllOfGroupInModuleSpace(bgList, "Mid Backdrops", "SLBackground", selectedModuleID); + // Go through the list and add their names to the combo box + for (std::list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) + m_pNewBG2Combo->AddItem((*itr)->GetPresetName()); + + // Get the list of all read in FAR background layers + bgList.clear(); + g_PresetMan.GetAllOfGroupInModuleSpace(bgList, "Far Backdrops", "SLBackground", selectedModuleID); + // Go through the list and add their names to the combo box + for (std::list::iterator itr = bgList.begin(); itr != bgList.end(); ++itr) + m_pNewBG3Combo->AddItem((*itr)->GetPresetName()); + + // Select the first one for each + m_pNewBG1Combo->SetSelectedIndex(0); + m_pNewBG2Combo->SetSelectedIndex(0); + m_pNewBG3Combo->SetSelectedIndex(0); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. + + void SceneEditor::UpdateLoadDialog() { + // Clear out the control + m_pLoadNameCombo->ClearList(); + + // Get the list of all read in scenes + std::list sceneList; + g_PresetMan.GetAllOfType(sceneList, "Scene"); + + // Go through the list and add their names to the combo box + for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) { + Scene* pScene = dynamic_cast(*itr); + if (pScene) + // Don't add the special "Editor Scene" or metascenes, users shouldn't be messing with them + if (pScene->GetPresetName() != "Editor Scene" && !pScene->IsMetagameInternal() && !pScene->IsSavedGameInternal() && (pScene->GetMetasceneParent() == "" || g_SettingsMan.ShowMetascenes())) + m_pLoadNameCombo->AddItem(pScene->GetPresetName()); + } + + // Select the first one + m_pLoadNameCombo->SetSelectedIndex(0); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. + + void SceneEditor::UpdateSaveDialog() { + m_pSaveNameBox->SetText((g_SceneMan.GetScene()->GetPresetName() == "None" || !m_HasEverBeenSaved) ? "New Scene" : g_SceneMan.GetScene()->GetPresetName()); -void SceneEditor::UpdateChangesDialog() -{ - if (m_HasEverBeenSaved) - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) - m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); + m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/"); else - m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); - } - else - { - dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Scene first?"); - m_pChangesNameLabel->SetText(""); - } -} + m_pSaveModuleLabel->SetText("Will save in " + g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes"); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + + void SceneEditor::UpdateChangesDialog() { + if (m_HasEverBeenSaved) { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Do you want to save your changes to:"); + if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) + m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); + else + m_pChangesNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); + } else { + dynamic_cast(m_pGUIController->GetControl("ChangesExpLabel"))->SetText("Save your new Scene first?"); + m_pChangesNameLabel->SetText(""); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. -void SceneEditor::UpdateOverwriteDialog() -{ - if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) - m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); - else - m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); -} + void SceneEditor::UpdateOverwriteDialog() { + if (g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() == c_UserScenesModuleName) + m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/" + g_SceneMan.GetScene()->GetPresetName()); + else + m_pOverwriteNameLabel->SetText(g_PresetMan.GetDataModule(m_ModuleSpaceID)->GetFileName() + "/Scenes/" + g_SceneMan.GetScene()->GetPresetName()); + } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Activities/SceneEditor.h b/Source/Activities/SceneEditor.h index 4930f0fa2..784628a8c 100644 --- a/Source/Activities/SceneEditor.h +++ b/Source/Activities/SceneEditor.h @@ -10,298 +10,271 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "RTETools.h" #include "EditorActivity.h" -namespace RTE -{ - -class SceneEditorGUI; -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUIComboBox; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: SceneEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activity for editing scenes. -// Parent(s): EditorActivity. -// Class history: 8/30/2007 SceneEditor created, inheriting directly from Activity. -// 9/17/2007 Spliced out and made to derive from EditorActivty - -class SceneEditor : public EditorActivity { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(SceneEditor); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: SceneEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a SceneEditor object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - SceneEditor() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~SceneEditor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a SceneEditor object before deletion -// from system memory. -// Arguments: None. - - ~SceneEditor() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SceneEditor object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a SceneEditor to be identical to another, by deep copy. -// Arguments: A reference to the SceneEditor to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const SceneEditor &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire SceneEditor, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); EditorActivity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneEditor object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Start -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Officially starts the game accroding to parameters previously set. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Start() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Pause -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pauses and unpauses the game. -// Arguments: Whether to pause the game or not. -// Return value: None. - - void SetPaused(bool pause = true) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: End -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces the current game's end. -// Arguments: None. -// Return value: None. - - void End() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this ActivityMan. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the currently active GUI of a screen to a BITMAP of choice. -// Arguments: A pointer to a screen-sized BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which screen's GUI to draw onto the bitmap. -// Return value: None. - - void DrawGUI(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ActivityMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. -// Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Saves the current Scene to an appropriate ini file, and asks user if they want to overwrite first if scene of this name exists. - /// - /// The name of the new Scene to be saved. - /// Whether to force any existing Scene of that name to be overwritten if it already exists. - /// Whether actually managed to save. Will return false both if a scene of this name already exists, or if other error. - bool SaveScene(const std::string &saveAsName, bool forceOverwrite = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateNewDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateNewDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateLoadDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Load dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateLoadDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateSaveDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateSaveDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateChangesDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Save Changes dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateChangesDialog() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: UpdateOverwriteDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Overwrite dialog box, populates its lists etc. -// Arguments: None. -// Return value: None. - - void UpdateOverwriteDialog() override; - - - // Member variables - static Entity::ClassInfo m_sClass; - - // The editor GUI - SceneEditorGUI *m_pEditorGUI; - - // The combobox which lists all the Terrain:s that can be loaded for a new scene - GUIComboBox *m_pNewTerrainCombo; - // The combobox which lists all the background SceneLayer:s that can be loaded for a new scene, near - GUIComboBox *m_pNewBG1Combo; - // The combobox which lists all the background SceneLayer:s that can be loaded for a new scene, mid - GUIComboBox *m_pNewBG2Combo; - // The combobox which lists all the background SceneLayer:s that can be loaded for a new scene, far/sky - GUIComboBox *m_pNewBG3Combo; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Activity, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class SceneEditorGUI; + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUIComboBox; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: SceneEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activity for editing scenes. + // Parent(s): EditorActivity. + // Class history: 8/30/2007 SceneEditor created, inheriting directly from Activity. + // 9/17/2007 Spliced out and made to derive from EditorActivty + + class SceneEditor : public EditorActivity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(SceneEditor); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: SceneEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a SceneEditor object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + SceneEditor() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~SceneEditor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a SceneEditor object before deletion + // from system memory. + // Arguments: None. + + ~SceneEditor() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SceneEditor object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a SceneEditor to be identical to another, by deep copy. + // Arguments: A reference to the SceneEditor to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const SceneEditor& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire SceneEditor, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + EditorActivity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneEditor object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorMode(EditorActivity::EditorMode newMode) { m_EditorMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorActivity::EditorMode GetEditorMode() const { return m_EditorMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Start + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Officially starts the game accroding to parameters previously set. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Start() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Pause + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pauses and unpauses the game. + // Arguments: Whether to pause the game or not. + // Return value: None. + + void SetPaused(bool pause = true) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: End + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces the current game's end. + // Arguments: None. + // Return value: None. + + void End() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this ActivityMan. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the currently active GUI of a screen to a BITMAP of choice. + // Arguments: A pointer to a screen-sized BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which screen's GUI to draw onto the bitmap. + // Return value: None. + + void DrawGUI(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ActivityMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + // Arguments: A pointer to a BITMAP to draw on. OWNERSHIP IS NOT TRANSFERRED! + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Saves the current Scene to an appropriate ini file, and asks user if they want to overwrite first if scene of this name exists. + /// + /// The name of the new Scene to be saved. + /// Whether to force any existing Scene of that name to be overwritten if it already exists. + /// Whether actually managed to save. Will return false both if a scene of this name already exists, or if other error. + bool SaveScene(const std::string& saveAsName, bool forceOverwrite = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateNewDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateNewDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateLoadDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Load dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateLoadDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateSaveDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateSaveDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateChangesDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Save Changes dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateChangesDialog() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: UpdateOverwriteDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Overwrite dialog box, populates its lists etc. + // Arguments: None. + // Return value: None. + + void UpdateOverwriteDialog() override; + + // Member variables + static Entity::ClassInfo m_sClass; + + // The editor GUI + SceneEditorGUI* m_pEditorGUI; + + // The combobox which lists all the Terrain:s that can be loaded for a new scene + GUIComboBox* m_pNewTerrainCombo; + // The combobox which lists all the background SceneLayer:s that can be loaded for a new scene, near + GUIComboBox* m_pNewBG1Combo; + // The combobox which lists all the background SceneLayer:s that can be loaded for a new scene, mid + GUIComboBox* m_pNewBG2Combo; + // The combobox which lists all the background SceneLayer:s that can be loaded for a new scene, far/sky + GUIComboBox* m_pNewBG3Combo; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Activity, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/ACDropShip.cpp b/Source/Entities/ACDropShip.cpp index b3db4b68e..e0a1a20d7 100644 --- a/Source/Entities/ACDropShip.cpp +++ b/Source/Entities/ACDropShip.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -22,600 +21,618 @@ namespace RTE { -ConcreteClassInfo(ACDropShip, ACraft, 10); + ConcreteClassInfo(ACDropShip, ACraft, 10); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACDropShip, effectively + // resetting the members of this abstraction level only. + + void ACDropShip::Clear() { + m_pBodyAG = 0; + m_pRThruster = 0; + m_pLThruster = 0; + m_pURThruster = 0; + m_pULThruster = 0; + m_pRHatch = 0; + m_pLHatch = 0; + m_HatchSwingRange.SetDegAngle(90); + m_HatchOpeness = 0; + m_LateralControl = 0; + m_LateralControlSpeed = 6.0f; + m_AutoStabilize = 1; + m_MaxEngineAngle = 20.0f; + m_HoverHeightModifier = 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACDropShip object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACDropShip, effectively -// resetting the members of this abstraction level only. - -void ACDropShip::Clear() -{ - m_pBodyAG = 0; - m_pRThruster = 0; - m_pLThruster = 0; - m_pURThruster = 0; - m_pULThruster = 0; - m_pRHatch = 0; - m_pLHatch = 0; - m_HatchSwingRange.SetDegAngle(90); - m_HatchOpeness = 0; - m_LateralControl = 0; - m_LateralControlSpeed = 6.0f; - m_AutoStabilize = 1; - m_MaxEngineAngle = 20.0f; - m_HoverHeightModifier = 0; -} + int ACDropShip::Create() { + if (ACraft::Create() < 0) + return -1; + // Save the AtomGroup read in by MOSRotating, as we are going to make it + // into a composite group, and want to have the base body stored for reference. + m_pBodyAG = dynamic_cast(m_pAtomGroup->Clone()); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACDropShip object ready for use. + return 0; + } -int ACDropShip::Create() -{ - if (ACraft::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACDropShip to be identical to another, by deep copy. - // Save the AtomGroup read in by MOSRotating, as we are going to make it - // into a composite group, and want to have the base body stored for reference. - m_pBodyAG = dynamic_cast(m_pAtomGroup->Clone()); + int ACDropShip::Create(const ACDropShip& reference) { + if (reference.m_pRThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRThruster->GetUniqueID()); + } + if (reference.m_pLThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLThruster->GetUniqueID()); + } + if (reference.m_pURThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pURThruster->GetUniqueID()); + } + if (reference.m_pULThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pULThruster->GetUniqueID()); + } + if (reference.m_pRHatch) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRHatch->GetUniqueID()); + } + if (reference.m_pLHatch) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLHatch->GetUniqueID()); + } - return 0; -} + ACraft::Create(reference); + if (reference.m_pRThruster) { + SetRightThruster(dynamic_cast(reference.m_pRThruster->Clone())); + } + if (reference.m_pLThruster) { + SetLeftThruster(dynamic_cast(reference.m_pLThruster->Clone())); + } + if (reference.m_pURThruster) { + SetURightThruster(dynamic_cast(reference.m_pURThruster->Clone())); + } + if (reference.m_pULThruster) { + SetULeftThruster(dynamic_cast(reference.m_pULThruster->Clone())); + } + if (reference.m_pRHatch) { + SetRightHatch(dynamic_cast(reference.m_pRHatch->Clone())); + } + if (reference.m_pLHatch) { + SetLeftHatch(dynamic_cast(reference.m_pLHatch->Clone())); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ACDropShip to be identical to another, by deep copy. + m_pBodyAG = dynamic_cast(reference.m_pBodyAG->Clone()); + m_pBodyAG->SetOwner(this); + m_HatchSwingRange = reference.m_HatchSwingRange; + m_HatchOpeness = reference.m_HatchOpeness; -int ACDropShip::Create(const ACDropShip &reference) { - if (reference.m_pRThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRThruster->GetUniqueID()); } - if (reference.m_pLThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLThruster->GetUniqueID()); } - if (reference.m_pURThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pURThruster->GetUniqueID()); } - if (reference.m_pULThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pULThruster->GetUniqueID()); } - if (reference.m_pRHatch) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRHatch->GetUniqueID()); } - if (reference.m_pLHatch) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLHatch->GetUniqueID()); } + m_LateralControl = reference.m_LateralControl; + m_LateralControlSpeed = reference.m_LateralControlSpeed; + m_AutoStabilize = reference.m_AutoStabilize; - ACraft::Create(reference); + m_MaxEngineAngle = reference.m_MaxEngineAngle; - if (reference.m_pRThruster) { SetRightThruster(dynamic_cast(reference.m_pRThruster->Clone())); } - if (reference.m_pLThruster) { SetLeftThruster(dynamic_cast(reference.m_pLThruster->Clone())); } - if (reference.m_pURThruster) { SetURightThruster(dynamic_cast(reference.m_pURThruster->Clone())); } - if (reference.m_pULThruster) { SetULeftThruster(dynamic_cast(reference.m_pULThruster->Clone())); } - if (reference.m_pRHatch) { SetRightHatch(dynamic_cast(reference.m_pRHatch->Clone())); } - if (reference.m_pLHatch) { SetLeftHatch(dynamic_cast(reference.m_pLHatch->Clone())); } + m_HoverHeightModifier = reference.m_HoverHeightModifier; - m_pBodyAG = dynamic_cast(reference.m_pBodyAG->Clone()); - m_pBodyAG->SetOwner(this); - m_HatchSwingRange = reference.m_HatchSwingRange; - m_HatchOpeness = reference.m_HatchOpeness; + return 0; + } - m_LateralControl = reference.m_LateralControl; - m_LateralControlSpeed = reference.m_LateralControlSpeed; - m_AutoStabilize = reference.m_AutoStabilize; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int ACDropShip::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return ACraft::ReadProperty(propName, reader)); + + MatchForwards("RThruster") MatchForwards("RightThruster") MatchProperty("RightEngine", { SetRightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("LThruster") MatchForwards("LeftThruster") MatchProperty("LeftEngine", { SetLeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("URThruster") MatchProperty("UpRightThruster", { SetURightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("ULThruster") MatchProperty("UpLeftThruster", { SetULeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("RHatchDoor") MatchProperty("RightHatchDoor", { SetRightHatch(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("LHatchDoor") MatchProperty("LeftHatchDoor", { SetLeftHatch(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("HatchDoorSwingRange", { reader >> m_HatchSwingRange; }); + MatchProperty("AutoStabilize", { reader >> m_AutoStabilize; }); + MatchProperty("MaxEngineAngle", { reader >> m_MaxEngineAngle; }); + MatchProperty("LateralControlSpeed", { reader >> m_LateralControlSpeed; }); + MatchProperty("HoverHeightModifier", { reader >> m_HoverHeightModifier; }); + + EndPropertyList; + } - m_MaxEngineAngle = reference.m_MaxEngineAngle; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this ACDropShip with a Writer for + // later recreation with Create(Reader &reader); + + int ACDropShip::Save(Writer& writer) const { + ACraft::Save(writer); + + writer.NewProperty("RThruster"); + writer << m_pRThruster; + writer.NewProperty("LThruster"); + writer << m_pLThruster; + writer.NewProperty("URThruster"); + writer << m_pURThruster; + writer.NewProperty("ULThruster"); + writer << m_pULThruster; + writer.NewProperty("RHatchDoor"); + writer << m_pRHatch; + writer.NewProperty("LHatchDoor"); + writer << m_pLHatch; + writer.NewProperty("HatchDoorSwingRange"); + writer << m_HatchSwingRange; + writer.NewProperty("AutoStabilize"); + writer << m_AutoStabilize; + writer.NewProperty("MaxEngineAngle"); + writer << m_MaxEngineAngle; + writer.NewProperty("LateralControlSpeed"); + writer << m_LateralControlSpeed; + writer.NewPropertyWithValue("HoverHeightModifier", m_HoverHeightModifier); + + return 0; + } - m_HoverHeightModifier = reference.m_HoverHeightModifier; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ACDropShip object. - return 0; -} + void ACDropShip::Destroy(bool notInherited) { + delete m_pBodyAG; + if (!notInherited) + ACraft::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int ACDropShip::ReadProperty(const std::string_view &propName, Reader &reader) { - StartPropertyList(return ACraft::ReadProperty(propName, reader)); - - MatchForwards("RThruster") MatchForwards("RightThruster") MatchProperty("RightEngine", { SetRightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("LThruster") MatchForwards("LeftThruster") MatchProperty("LeftEngine", { SetLeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("URThruster") MatchProperty("UpRightThruster", { SetURightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("ULThruster") MatchProperty("UpLeftThruster", { SetULeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("RHatchDoor") MatchProperty("RightHatchDoor", { SetRightHatch(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("LHatchDoor") MatchProperty("LeftHatchDoor", { SetLeftHatch(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("HatchDoorSwingRange", { reader >> m_HatchSwingRange; }); - MatchProperty("AutoStabilize", { reader >> m_AutoStabilize; }); - MatchProperty("MaxEngineAngle", { reader >> m_MaxEngineAngle; }); - MatchProperty("LateralControlSpeed", { reader >> m_LateralControlSpeed; }); - MatchProperty("HoverHeightModifier", { reader >> m_HoverHeightModifier; }); - - EndPropertyList; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the altitide of this' pos (or appropriate low point) over the + // terrain, in pixels. + float ACDropShip::GetAltitude(int max, int accuracy) { + // Check altitude both thrusters, and report the one closest to the ground. + Vector rPos, lPos; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this ACDropShip with a Writer for -// later recreation with Create(Reader &reader); - -int ACDropShip::Save(Writer &writer) const -{ - ACraft::Save(writer); - - writer.NewProperty("RThruster"); - writer << m_pRThruster; - writer.NewProperty("LThruster"); - writer << m_pLThruster; - writer.NewProperty("URThruster"); - writer << m_pURThruster; - writer.NewProperty("ULThruster"); - writer << m_pULThruster; - writer.NewProperty("RHatchDoor"); - writer << m_pRHatch; - writer.NewProperty("LHatchDoor"); - writer << m_pLHatch; - writer.NewProperty("HatchDoorSwingRange"); - writer << m_HatchSwingRange; - writer.NewProperty("AutoStabilize"); - writer << m_AutoStabilize; - writer.NewProperty("MaxEngineAngle"); - writer << m_MaxEngineAngle; - writer.NewProperty("LateralControlSpeed"); - writer << m_LateralControlSpeed; - writer.NewPropertyWithValue("HoverHeightModifier", m_HoverHeightModifier); - - return 0; -} + if (m_pRThruster && m_pRThruster->IsAttached()) + rPos = m_Pos + RotateOffset(m_pRThruster->GetParentOffset()); // + Vector(m_pRThruster->GetRadius(), 0)); + else + rPos = m_Pos; + if (m_pLThruster && m_pLThruster->IsAttached()) + lPos = m_Pos + RotateOffset(m_pLThruster->GetParentOffset()); // + Vector(-m_pLThruster->GetRadius(), 0)); + else + lPos = m_Pos; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ACDropShip object. + // Wrap the engine positions + g_SceneMan.WrapPosition(lPos); + g_SceneMan.WrapPosition(rPos); -void ACDropShip::Destroy(bool notInherited) -{ - delete m_pBodyAG; + // Check center too + float cAlt = g_SceneMan.FindAltitude(m_Pos, max, accuracy, true); + float rAlt = g_SceneMan.FindAltitude(rPos, max, accuracy, true); + float lAlt = g_SceneMan.FindAltitude(lPos, max, accuracy, true); - if (!notInherited) - ACraft::Destroy(); - Clear(); -} + // Return the lowest of the three + return MIN(cAlt, MIN(rAlt, lAlt)); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DetectObstacle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks for obstacles in the travel direction. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the altitide of this' pos (or appropriate low point) over the -// terrain, in pixels. + MOID ACDropShip::DetectObstacle(float distance) { + // Check altitude both thrusters, and report the one closest to the ground. + Vector rPos, lPos; -float ACDropShip::GetAltitude(int max, int accuracy) -{ - // Check altitude both thrusters, and report the one closest to the ground. - Vector rPos, lPos; + if (m_pRThruster && m_pRThruster->IsAttached()) + rPos = m_Pos + RotateOffset(m_pRThruster->GetParentOffset() + Vector(m_pRThruster->GetRadius(), 0)); + else + rPos = m_Pos; - if (m_pRThruster && m_pRThruster->IsAttached()) - rPos = m_Pos + RotateOffset(m_pRThruster->GetParentOffset());// + Vector(m_pRThruster->GetRadius(), 0)); - else - rPos = m_Pos; + if (m_pLThruster && m_pLThruster->IsAttached()) + lPos = m_Pos + RotateOffset(m_pLThruster->GetParentOffset() + Vector(-m_pLThruster->GetRadius(), 0)); + else + lPos = m_Pos; + + // Wrap the engine positions + g_SceneMan.WrapPosition(lPos); + g_SceneMan.WrapPosition(rPos); + + // Make the ray to check along point in an appropriate direction + Vector checkRay; + if (m_AltitudeMoveState == DESCEND) + checkRay.m_Y = distance; + else if (m_AltitudeMoveState == ASCEND) + checkRay.m_Y = -distance; + // Just rotate it to align iwth the velocity + else { + checkRay.m_X = distance; + checkRay.AbsRotateTo(m_Vel); + } - if (m_pLThruster && m_pLThruster->IsAttached()) - lPos = m_Pos + RotateOffset(m_pLThruster->GetParentOffset());// + Vector(-m_pLThruster->GetRadius(), 0)); - else - lPos = m_Pos; + MOID detected = g_NoMOID; - // Wrap the engine positions - g_SceneMan.WrapPosition(lPos); - g_SceneMan.WrapPosition(rPos); + // Check center too? + if ((detected = g_SceneMan.CastMORay(m_Pos, checkRay, m_RootMOID, Activity::NoTeam, 0, true, 30)) != g_NoMOID) + return detected; + if ((detected = g_SceneMan.CastMORay(rPos, checkRay, m_RootMOID, Activity::NoTeam, 0, true, 30)) != g_NoMOID) + return detected; + if ((detected = g_SceneMan.CastMORay(lPos, checkRay, m_RootMOID, Activity::NoTeam, 0, true, 30)) != g_NoMOID) + return detected; - // Check center too - float cAlt = g_SceneMan.FindAltitude(m_Pos, max, accuracy, true); - float rAlt = g_SceneMan.FindAltitude(rPos, max, accuracy, true); - float lAlt = g_SceneMan.FindAltitude(lPos, max, accuracy, true); + return false; + } - // Return the lowest of the three - return MIN(cAlt, MIN(rAlt, lAlt)); -} + ////////////////////////////////////////////////////////////////////////////////////////// + void ACDropShip::PreControllerUpdate() { + ZoneScoped; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DetectObstacle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks for obstacles in the travel direction. - -MOID ACDropShip::DetectObstacle(float distance) -{ - // Check altitude both thrusters, and report the one closest to the ground. - Vector rPos, lPos; - - if (m_pRThruster && m_pRThruster->IsAttached()) - rPos = m_Pos + RotateOffset(m_pRThruster->GetParentOffset() + Vector(m_pRThruster->GetRadius(), 0)); - else - rPos = m_Pos; - - if (m_pLThruster && m_pLThruster->IsAttached()) - lPos = m_Pos + RotateOffset(m_pLThruster->GetParentOffset() + Vector(-m_pLThruster->GetRadius(), 0)); - else - lPos = m_Pos; - - // Wrap the engine positions - g_SceneMan.WrapPosition(lPos); - g_SceneMan.WrapPosition(rPos); - - // Make the ray to check along point in an appropriate direction - Vector checkRay; - if (m_AltitudeMoveState == DESCEND) - checkRay.m_Y = distance; - else if (m_AltitudeMoveState == ASCEND) - checkRay.m_Y = -distance; - // Just rotate it to align iwth the velocity - else - { - checkRay.m_X = distance; - checkRay.AbsRotateTo(m_Vel); - } - - MOID detected = g_NoMOID; - - // Check center too? - if ((detected = g_SceneMan.CastMORay(m_Pos, checkRay, m_RootMOID, Activity::NoTeam, 0, true, 30)) != g_NoMOID) - return detected; - if ((detected = g_SceneMan.CastMORay(rPos, checkRay, m_RootMOID, Activity::NoTeam, 0, true, 30)) != g_NoMOID) - return detected; - if ((detected = g_SceneMan.CastMORay(lPos, checkRay, m_RootMOID, Activity::NoTeam, 0, true, 30)) != g_NoMOID) - return detected; - - return false; -} + ACraft::PreControllerUpdate(); -////////////////////////////////////////////////////////////////////////////////////////// + // TODO: Improve and make optional thrusters more robust! + if (m_Status != DEAD && m_Status != DYING) { + float targetYVel = 0.0F; + float throttleRange = 7.5f; -void ACDropShip::PreControllerUpdate() -{ - ZoneScoped; + if (m_Controller.IsState(PRESS_UP)) { + // This is to make sure se get loose from being sideways stuck + m_ForceDeepCheck = true; + } + // TODO: make framerate independent! + // Altitude control, check analog first + if (fabs(m_Controller.GetAnalogMove().m_Y) > 0.1) { + targetYVel = -m_Controller.GetAnalogMove().m_Y * throttleRange; + } + // Fall back to digital altitude control + else if (m_Controller.IsState(MOVE_UP) || m_Controller.IsState(AIM_UP)) + targetYVel = throttleRange; + else if (m_Controller.IsState(MOVE_DOWN) || m_Controller.IsState(AIM_DOWN)) + targetYVel = -throttleRange; - ACraft::PreControllerUpdate(); + ////////////////////////////////////////////////////// + // Main thruster throttling to stay hovering - // TODO: Improve and make optional thrusters more robust! - if (m_Status != DEAD && m_Status != DYING) - { - float targetYVel = 0.0F; - float throttleRange = 7.5f; + // ugly hacks. the entire trimming to hover system is shit and should be replaced - if (m_Controller.IsState(PRESS_UP)) - { - // This is to make sure se get loose from being sideways stuck - m_ForceDeepCheck = true; - } - // TODO: make framerate independent! - // Altitude control, check analog first - if (fabs(m_Controller.GetAnalogMove().m_Y) > 0.1) - { - targetYVel = -m_Controller.GetAnalogMove().m_Y * throttleRange; - } - // Fall back to digital altitude control - else if (m_Controller.IsState(MOVE_UP) || m_Controller.IsState(AIM_UP)) - targetYVel = throttleRange; - else if (m_Controller.IsState(MOVE_DOWN) || m_Controller.IsState(AIM_DOWN)) - targetYVel = -throttleRange; + // This is to trim the hover so it's perfectly still altitude-wise + float trimming = -2.6f; - ////////////////////////////////////////////////////// - // Main thruster throttling to stay hovering + float throttle = (targetYVel + m_Vel.m_Y + trimming) / throttleRange; - // ugly hacks. the entire trimming to hover system is shit and should be replaced + // Adjust trim based on weight. Dropships hover nicely at zero weight, but tend to drop when they have a large inventory + float massAdjustment = GetMass() / GetBaseMass(); - // This is to trim the hover so it's perfectly still altitude-wise - float trimming = -2.6f; + // Right main thruster + if (m_pRThruster && m_pRThruster->IsAttached()) { + float baseThrottleForThruster = m_pRThruster->GetThrottleForThrottleFactor(1.0f); + float rightThrottle = m_pRThruster->GetScaledThrottle(throttle + baseThrottleForThruster, massAdjustment); + + // Throttle override control for correcting heavy tilt, only applies if both engines are present + if (m_pLThruster && m_pLThruster->IsAttached()) { + if (m_Rotation.GetRadAngle() > c_SixteenthPI) { + rightThrottle = -0.8f; + } else if (m_Rotation.GetRadAngle() < -c_SixteenthPI) { + rightThrottle = 0.8f; + } + } + + if (rightThrottle > m_pRThruster->GetThrottle()) { + rightThrottle = rightThrottle * 0.3f + m_pRThruster->GetThrottle() * 0.7f; // Increase throttle slowly + } + + m_pRThruster->EnableEmission(m_Status == STABLE); + m_pRThruster->SetThrottle(rightThrottle); + m_pRThruster->SetFlashScale((m_pRThruster->GetThrottle() + 1.5f) / 2.0f); + // Engines are noisy! Make AI aware of them + m_pRThruster->AlarmOnEmit(m_Team); + } + // Left main thruster + if (m_pLThruster && m_pLThruster->IsAttached()) { + float baseThrottleForThruster = m_pLThruster->GetThrottleForThrottleFactor(1.0f); + float leftThrottle = m_pLThruster->GetScaledThrottle(throttle + baseThrottleForThruster, massAdjustment); + + // Throttle override control for correcting heavy tilt, only applies if both engines are present + if (m_pRThruster && m_pRThruster->IsAttached()) { + if (m_Rotation.GetRadAngle() > c_SixteenthPI) { + leftThrottle = 0.8f; + } else if (m_Rotation.GetRadAngle() < -c_SixteenthPI) { + leftThrottle = -0.8f; + } + } + + if (leftThrottle > m_pLThruster->GetThrottle()) { + leftThrottle = leftThrottle * 0.3f + m_pLThruster->GetThrottle() * 0.7f; // Increase throttle slowly + } + + m_pLThruster->EnableEmission(m_Status == STABLE); + m_pLThruster->SetThrottle(leftThrottle); + m_pLThruster->SetFlashScale((m_pLThruster->GetThrottle() + 1.5f) / 2.0F); + // Engines are noisy! Make AI aware of them + m_pLThruster->AlarmOnEmit(m_Team); + } - float throttle = (targetYVel + m_Vel.m_Y + trimming) / throttleRange; + /////////////////////////////////////////////// + // Lateral control - // Adjust trim based on weight. Dropships hover nicely at zero weight, but tend to drop when they have a large inventory - float massAdjustment = GetMass() / GetBaseMass(); + // Check analog first + if (fabs(m_Controller.GetAnalogMove().m_X) > 0.1) { + if (m_LateralControl < -m_Controller.GetAnalogMove().m_X) + m_LateralControl += m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); // 0.1 per update at 60fps + else if (m_LateralControl > -m_Controller.GetAnalogMove().m_X) + m_LateralControl -= m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); + } + // Fall back to digital lateral control + else { + if (m_Controller.IsState(MOVE_RIGHT)) + m_LateralControl -= m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); + else if (m_Controller.IsState(MOVE_LEFT)) + m_LateralControl += m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); + else if (m_LateralControl != 0.0) + m_LateralControl *= 54.0f * g_TimerMan.GetDeltaTimeSecs(); // 90% per update at 60fps + } - // Right main thruster - if (m_pRThruster && m_pRThruster->IsAttached()) - { - float baseThrottleForThruster = m_pRThruster->GetThrottleForThrottleFactor(1.0f); - float rightThrottle = m_pRThruster->GetScaledThrottle(throttle + baseThrottleForThruster, massAdjustment); + // Clamp the lateral control + if (m_LateralControl > 1.0) + m_LateralControl = 1.0; + else if (m_LateralControl < -1.0) + m_LateralControl = -1.0; + + if (m_Controller.IsState(PRESS_FACEBUTTON)) { + if (m_HatchState == CLOSED) + DropAllInventory(); + else if (m_HatchState == OPEN) + CloseHatch(); + } + } + // No Controller present, or dead + else { + if (m_pRThruster && m_pRThruster->IsAttached()) + m_pRThruster->EnableEmission(false); + if (m_pLThruster && m_pLThruster->IsAttached()) + m_pLThruster->EnableEmission(false); + /* + if (m_pURThruster && m_pURThruster->IsAttached()) + m_pURThruster->EnableEmission(false); + if (m_pULThruster && m_pULThruster->IsAttached()) + m_pULThruster->EnableEmission(false); + */ + } - // Throttle override control for correcting heavy tilt, only applies if both engines are present - if (m_pLThruster && m_pLThruster->IsAttached()) { - if (m_Rotation.GetRadAngle() > c_SixteenthPI) { - rightThrottle = -0.8f; - } else if (m_Rotation.GetRadAngle() < -c_SixteenthPI) { - rightThrottle = 0.8f; - } + //////////////////////////////////////// + // Hatch Operation + + if (m_HatchState == OPENING) { + if (m_HatchDelay > 0 && !m_HatchTimer.IsPastSimMS(m_HatchDelay)) + m_HatchOpeness = (float)m_HatchTimer.GetElapsedSimTimeMS() / (float)m_HatchDelay; + else { + m_HatchOpeness = 1.0; + m_HatchState = OPEN; + DropAllInventory(); + } + } else if (m_HatchState == CLOSING) { + if (m_HatchDelay > 0 && !m_HatchTimer.IsPastSimMS(m_HatchDelay)) + m_HatchOpeness = 1.0 - ((float)m_HatchTimer.GetElapsedSimTimeMS() / (float)m_HatchDelay); + else { + m_HatchOpeness = 0; + m_HatchState = CLOSED; } + } - if (rightThrottle > m_pRThruster->GetThrottle()) { - rightThrottle = rightThrottle * 0.3f + m_pRThruster->GetThrottle() * 0.7f; // Increase throttle slowly - } + ///////////////////////////////// + // Manage Attachable:s + Matrix engineRot = 0; + if (m_Rotation.GetDegAngle() > m_MaxEngineAngle) { + engineRot.SetDegAngle(m_Rotation.GetDegAngle() - m_MaxEngineAngle); + } else if (m_Rotation.GetDegAngle() < -m_MaxEngineAngle) { + engineRot.SetDegAngle(m_Rotation.GetDegAngle() + m_MaxEngineAngle); + } else { + // Lateral control application + engineRot.SetDegAngle(m_MaxEngineAngle * m_LateralControl); + } - m_pRThruster->EnableEmission(m_Status == STABLE); - m_pRThruster->SetThrottle(rightThrottle); - m_pRThruster->SetFlashScale((m_pRThruster->GetThrottle() + 1.5f) / 2.0f); - // Engines are noisy! Make AI aware of them - m_pRThruster->AlarmOnEmit(m_Team); + if (m_pRThruster && m_pRThruster->IsAttached()) { + m_pRThruster->SetRotAngle(engineRot.GetRadAngle()); + m_pRThruster->SetAngularVel(0.0F); } - // Left main thruster - if (m_pLThruster && m_pLThruster->IsAttached()) - { - float baseThrottleForThruster = m_pLThruster->GetThrottleForThrottleFactor(1.0f); - float leftThrottle = m_pLThruster->GetScaledThrottle(throttle + baseThrottleForThruster, massAdjustment); - // Throttle override control for correcting heavy tilt, only applies if both engines are present - if (m_pRThruster && m_pRThruster->IsAttached()) { - if (m_Rotation.GetRadAngle() > c_SixteenthPI) { - leftThrottle = 0.8f; - } else if (m_Rotation.GetRadAngle() < -c_SixteenthPI) { - leftThrottle = -0.8f; - } + if (m_pLThruster && m_pLThruster->IsAttached()) { + m_pLThruster->SetRotAngle(engineRot.GetRadAngle()); + m_pLThruster->SetAngularVel(0.0F); + } + + // Auto balancing with the up thrusters + if (m_pURThruster && m_pURThruster->IsAttached() && m_pULThruster && m_pULThruster->IsAttached()) { + if (m_AutoStabilize) { + // Use a PD-controller for balance + float change = 0.9F * m_AngularVel + 0.8F * m_Rotation.GetRadAngle(); + if (change > 0.2F) { + if (!m_pURThruster->IsEmitting()) { + m_pURThruster->TriggerBurst(); + } + m_pURThruster->EnableEmission(true); + } else { + m_pURThruster->EnableEmission(false); + } + + if (change < -0.2F) { + if (!m_pULThruster->IsEmitting()) { + m_pULThruster->TriggerBurst(); + } + m_pULThruster->EnableEmission(true); + } else { + m_pULThruster->EnableEmission(false); + } } + } - if (leftThrottle > m_pLThruster->GetThrottle()) { - leftThrottle = leftThrottle * 0.3f + m_pLThruster->GetThrottle() * 0.7f; // Increase throttle slowly - } + // Hatch door pieces + if (m_pRHatch && m_pRHatch->IsAttached()) { + m_pRHatch->SetRotAngle(m_Rotation.GetRadAngle() + m_HatchSwingRange.GetRadAngle() * m_HatchOpeness); + } - m_pLThruster->EnableEmission(m_Status == STABLE); - m_pLThruster->SetThrottle(leftThrottle); - m_pLThruster->SetFlashScale((m_pLThruster->GetThrottle() + 1.5f) / 2.0F); - // Engines are noisy! Make AI aware of them - m_pLThruster->AlarmOnEmit(m_Team); + if (m_pLHatch && m_pLHatch->IsAttached()) { + m_pLHatch->SetRotAngle(m_Rotation.GetRadAngle() - m_HatchSwingRange.GetRadAngle() * m_HatchOpeness); } + } - /////////////////////////////////////////////// - // Lateral control + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Check analog first - if (fabs(m_Controller.GetAnalogMove().m_X) > 0.1) - { - if (m_LateralControl < -m_Controller.GetAnalogMove().m_X) - m_LateralControl += m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); // 0.1 per update at 60fps - else if (m_LateralControl > -m_Controller.GetAnalogMove().m_X) - m_LateralControl -= m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); + void ACDropShip::SetRightThruster(AEmitter* newThruster) { + if (m_pRThruster && m_pRThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pRThruster); } - // Fall back to digital lateral control - else - { - if (m_Controller.IsState(MOVE_RIGHT)) - m_LateralControl -= m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); - else if (m_Controller.IsState(MOVE_LEFT)) - m_LateralControl += m_LateralControlSpeed * g_TimerMan.GetDeltaTimeSecs(); - else if (m_LateralControl != 0.0) - m_LateralControl *= 54.0f * g_TimerMan.GetDeltaTimeSecs(); // 90% per update at 60fps - } - - // Clamp the lateral control - if (m_LateralControl > 1.0) - m_LateralControl = 1.0; - else if (m_LateralControl < -1.0) - m_LateralControl = -1.0; - - if (m_Controller.IsState(PRESS_FACEBUTTON)) - { - if (m_HatchState == CLOSED) - DropAllInventory(); - else if (m_HatchState == OPEN) - CloseHatch(); + if (newThruster == nullptr) { + m_pRThruster = nullptr; + } else { + m_pRThruster = newThruster; + AddAttachable(newThruster); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightThruster"); + dynamic_cast(parent)->SetRightThruster(castedAttachable); + }}); + + if (m_pRThruster->HasNoSetDamageMultiplier()) { + m_pRThruster->SetDamageMultiplier(1.0F); + } + m_pRThruster->SetInheritsRotAngle(false); } } - // No Controller present, or dead - else - { - if (m_pRThruster && m_pRThruster->IsAttached()) - m_pRThruster->EnableEmission(false); - if (m_pLThruster && m_pLThruster->IsAttached()) - m_pLThruster->EnableEmission(false); - /* - if (m_pURThruster && m_pURThruster->IsAttached()) - m_pURThruster->EnableEmission(false); - if (m_pULThruster && m_pULThruster->IsAttached()) - m_pULThruster->EnableEmission(false); - */ + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACDropShip::SetLeftThruster(AEmitter* newThruster) { + if (m_pLThruster && m_pLThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pLThruster); + } + if (newThruster == nullptr) { + m_pLThruster = nullptr; + } else { + m_pLThruster = newThruster; + AddAttachable(newThruster); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftThruster"); + dynamic_cast(parent)->SetLeftThruster(castedAttachable); + }}); + + if (m_pLThruster->HasNoSetDamageMultiplier()) { + m_pLThruster->SetDamageMultiplier(1.0F); + } + m_pLThruster->SetInheritsRotAngle(false); + } } - //////////////////////////////////////// - // Hatch Operation + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (m_HatchState == OPENING) - { - if (m_HatchDelay > 0 && !m_HatchTimer.IsPastSimMS(m_HatchDelay)) - m_HatchOpeness = (float)m_HatchTimer.GetElapsedSimTimeMS() / (float)m_HatchDelay; - else - { - m_HatchOpeness = 1.0; - m_HatchState = OPEN; - DropAllInventory(); + void ACDropShip::SetURightThruster(AEmitter* newThruster) { + if (m_pURThruster && m_pURThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pURThruster); + } + if (newThruster == nullptr) { + m_pURThruster = nullptr; + } else { + m_pURThruster = newThruster; + AddAttachable(newThruster); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetURightThruster"); + dynamic_cast(parent)->SetURightThruster(castedAttachable); + }}); + + if (m_pURThruster->HasNoSetDamageMultiplier()) { + m_pURThruster->SetDamageMultiplier(1.0F); + } } } - else if (m_HatchState == CLOSING) - { - if (m_HatchDelay > 0 && !m_HatchTimer.IsPastSimMS(m_HatchDelay)) - m_HatchOpeness = 1.0 - ((float)m_HatchTimer.GetElapsedSimTimeMS() / (float)m_HatchDelay); - else - { - m_HatchOpeness = 0; - m_HatchState = CLOSED; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACDropShip::SetULeftThruster(AEmitter* newThruster) { + if (m_pULThruster && m_pULThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pULThruster); + } + if (newThruster == nullptr) { + m_pULThruster = nullptr; + } else { + m_pULThruster = newThruster; + AddAttachable(newThruster); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetULeftThruster"); + dynamic_cast(parent)->SetULeftThruster(castedAttachable); + }}); + + if (m_pULThruster->HasNoSetDamageMultiplier()) { + m_pULThruster->SetDamageMultiplier(1.0F); + } } } - ///////////////////////////////// - // Manage Attachable:s - Matrix engineRot = 0; - if (m_Rotation.GetDegAngle() > m_MaxEngineAngle) { - engineRot.SetDegAngle(m_Rotation.GetDegAngle() - m_MaxEngineAngle); - } else if (m_Rotation.GetDegAngle() < -m_MaxEngineAngle) { - engineRot.SetDegAngle(m_Rotation.GetDegAngle() + m_MaxEngineAngle); - } else { - // Lateral control application - engineRot.SetDegAngle(m_MaxEngineAngle * m_LateralControl); - } - - if (m_pRThruster && m_pRThruster->IsAttached()) { - m_pRThruster->SetRotAngle(engineRot.GetRadAngle()); - m_pRThruster->SetAngularVel(0.0F); - } - - if (m_pLThruster && m_pLThruster->IsAttached()) { - m_pLThruster->SetRotAngle(engineRot.GetRadAngle()); - m_pLThruster->SetAngularVel(0.0F); - } - - // Auto balancing with the up thrusters - if (m_pURThruster && m_pURThruster->IsAttached() && m_pULThruster && m_pULThruster->IsAttached()) { - if (m_AutoStabilize) { - // Use a PD-controller for balance - float change = 0.9F * m_AngularVel + 0.8F * m_Rotation.GetRadAngle(); - if (change > 0.2F) { - if (!m_pURThruster->IsEmitting()) { - m_pURThruster->TriggerBurst(); - } - m_pURThruster->EnableEmission(true); - } else { - m_pURThruster->EnableEmission(false); - } - - if (change < -0.2F) { - if (!m_pULThruster->IsEmitting()) { - m_pULThruster->TriggerBurst(); - } - m_pULThruster->EnableEmission(true); - } else { - m_pULThruster->EnableEmission(false); - } - } - } - - // Hatch door pieces - if (m_pRHatch && m_pRHatch->IsAttached()) { - m_pRHatch->SetRotAngle(m_Rotation.GetRadAngle() + m_HatchSwingRange.GetRadAngle() * m_HatchOpeness); - } - - if (m_pLHatch && m_pLHatch->IsAttached()) { - m_pLHatch->SetRotAngle(m_Rotation.GetRadAngle() - m_HatchSwingRange.GetRadAngle() * m_HatchOpeness); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACDropShip::SetRightThruster(AEmitter *newThruster) { - if (m_pRThruster && m_pRThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pRThruster); } - if (newThruster == nullptr) { - m_pRThruster = nullptr; - } else { - m_pRThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightThruster"); - dynamic_cast(parent)->SetRightThruster(castedAttachable); - }}); - - if (m_pRThruster->HasNoSetDamageMultiplier()) { m_pRThruster->SetDamageMultiplier(1.0F); } - m_pRThruster->SetInheritsRotAngle(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACDropShip::SetLeftThruster(AEmitter *newThruster) { - if (m_pLThruster && m_pLThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pLThruster); } - if (newThruster == nullptr) { - m_pLThruster = nullptr; - } else { - m_pLThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftThruster"); - dynamic_cast(parent)->SetLeftThruster(castedAttachable); - }}); - - if (m_pLThruster->HasNoSetDamageMultiplier()) { m_pLThruster->SetDamageMultiplier(1.0F); } - m_pLThruster->SetInheritsRotAngle(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACDropShip::SetURightThruster(AEmitter *newThruster) { - if (m_pURThruster && m_pURThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pURThruster); } - if (newThruster == nullptr) { - m_pURThruster = nullptr; - } else { - m_pURThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetURightThruster"); - dynamic_cast(parent)->SetURightThruster(castedAttachable); - }}); - - if (m_pURThruster->HasNoSetDamageMultiplier()) { m_pURThruster->SetDamageMultiplier(1.0F); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACDropShip::SetULeftThruster(AEmitter *newThruster) { - if (m_pULThruster && m_pULThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pULThruster); } - if (newThruster == nullptr) { - m_pULThruster = nullptr; - } else { - m_pULThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetULeftThruster"); - dynamic_cast(parent)->SetULeftThruster(castedAttachable); - }}); - - if (m_pULThruster->HasNoSetDamageMultiplier()) { m_pULThruster->SetDamageMultiplier(1.0F); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACDropShip::SetRightHatch(Attachable *newHatch) { - if (m_pRHatch && m_pRHatch->IsAttached()) { RemoveAndDeleteAttachable(m_pRHatch); } - if (newHatch == nullptr) { - m_pRHatch = nullptr; - } else { - m_pRHatch = newHatch; - AddAttachable(newHatch); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newHatch->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - dynamic_cast(parent)->SetRightHatch(attachable); - }}); - - if (m_pRHatch->HasNoSetDamageMultiplier()) { m_pRHatch->SetDamageMultiplier(1.0F); } - m_pRHatch->SetInheritsRotAngle(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACDropShip::SetLeftHatch(Attachable *newHatch) { - if (m_pLHatch && m_pLHatch->IsAttached()) { RemoveAndDeleteAttachable(m_pLHatch); } - if (newHatch == nullptr) { - m_pLHatch = nullptr; - } else { - m_pLHatch = newHatch; - AddAttachable(newHatch); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newHatch->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - dynamic_cast(parent)->SetLeftHatch(attachable); - }}); - - if (m_pLHatch->HasNoSetDamageMultiplier()) { m_pLHatch->SetDamageMultiplier(1.0F); } - m_pLHatch->SetInheritsRotAngle(false); - } -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACDropShip::SetRightHatch(Attachable* newHatch) { + if (m_pRHatch && m_pRHatch->IsAttached()) { + RemoveAndDeleteAttachable(m_pRHatch); + } + if (newHatch == nullptr) { + m_pRHatch = nullptr; + } else { + m_pRHatch = newHatch; + AddAttachable(newHatch); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newHatch->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + dynamic_cast(parent)->SetRightHatch(attachable); + }}); + + if (m_pRHatch->HasNoSetDamageMultiplier()) { + m_pRHatch->SetDamageMultiplier(1.0F); + } + m_pRHatch->SetInheritsRotAngle(false); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACDropShip::SetLeftHatch(Attachable* newHatch) { + if (m_pLHatch && m_pLHatch->IsAttached()) { + RemoveAndDeleteAttachable(m_pLHatch); + } + if (newHatch == nullptr) { + m_pLHatch = nullptr; + } else { + m_pLHatch = newHatch; + AddAttachable(newHatch); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newHatch->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + dynamic_cast(parent)->SetLeftHatch(attachable); + }}); + + if (m_pLHatch->HasNoSetDamageMultiplier()) { + m_pLHatch->SetDamageMultiplier(1.0F); + } + m_pLHatch->SetInheritsRotAngle(false); + } + } } // namespace RTE diff --git a/Source/Entities/ACDropShip.h b/Source/Entities/ACDropShip.h index aeb171fba..332402449 100644 --- a/Source/Entities/ACDropShip.h +++ b/Source/Entities/ACDropShip.h @@ -10,354 +10,330 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "ACraft.h" -namespace RTE -{ - -class Attachable; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: ACDropShip -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A hovering craft, with two engines on each attached on each end which -// tilt independently of the body to achieve steering. -// Parent(s): ACraft. -// Class history: 12/13/2006 ACDropShip created. - -class ACDropShip : public ACraft { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(ACDropShip); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: ACDropShip -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a ACDropShip object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - ACDropShip() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~ACDropShip -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a ACDropShip object before deletion -// from system memory. -// Arguments: None. - - ~ACDropShip() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACDropShip object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ACDropShip to be identical to another, by deep copy. -// Arguments: A reference to the ACDropShip to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const ACDropShip &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire ACDropShip, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); ACraft::Reset(); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the altitide of this' pos (or appropriate low point) over the -// terrain, in pixels. -// Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. -// The accuracy within which measurement is acceptable. Higher number -// here means less calculation. -// Return value: The rough altitude over the terrain, in pixels. - - float GetAltitude(int max = 0, int accuracy = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DetectObstacle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks for obstacles in the travel direction. -// Arguments: How far ahead of travel direction to check for obstacles. -// Return value: Which MOID was detected as obstacle. g_NoMOID means nothing was detected. - - MOID DetectObstacle(float distance); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AutoStabilizing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this has the means and will try to right itself, or if -// that's up to the Controller to do. -// Arguments: None. -// Return value: Wheter this will try to auto stabilize. - - bool AutoStabilizing() override { return true; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreControllerUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void PreControllerUpdate() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMaxPassengers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The recomended, not absolute, maximum number of actors that fit in the -// invetory. Used by the activity AI. -// Arguments: None. -// Return value: An integer with the recomended number of actors that fit in the craft. -// Default is four. - - int GetMaxPassengers() const override { return m_MaxPassengers > -1 ? m_MaxPassengers : 4; } - - - /// - /// Gets the right side thruster of this ACDropship. - /// - /// A pointer to the right side thruster of this ACDropship. Ownership is NOT transferred. - AEmitter * GetRightThruster() const { return m_pRThruster; } - - /// - /// Sets the right side thruster for this ACDropship. - /// - /// The new thruster to use. - void SetRightThruster(AEmitter *newThruster); - - /// - /// Gets the left side thruster of this ACDropship. - /// - /// A pointer to the left side thruster of this ACDropship. Ownership is NOT transferred. - AEmitter * GetLeftThruster() const { return m_pLThruster; } - - /// - /// Sets the left side thruster for this ACDropship. - /// - /// The new thruster to use. - void SetLeftThruster(AEmitter *newThruster); - - /// - /// Gets the right side secondary thruster of this ACDropship. - /// - /// A pointer to the right side secondary thruster of this ACDropship. Ownership is NOT transferred. - AEmitter * GetURightThruster() const { return m_pURThruster; } - - /// - /// Sets the right side secondary thruster for this ACDropship. - /// - /// The new thruster to use. - void SetURightThruster(AEmitter *newThruster); - - /// - /// Gets the left side secondary thruster of this ACDropship. - /// - /// A pointer to the left side secondary thruster of this ACDropship. Ownership is NOT transferred. - AEmitter * GetULeftThruster() const { return m_pULThruster; } - - /// - /// Sets the left side secondary thruster for this ACDropship. - /// - /// The new thruster to use. - void SetULeftThruster(AEmitter *newThruster); - - /// - /// Gets the left side hatch of this ACDropship. - /// - /// A pointer to the left side hatch of this ACDropship. Ownership is NOT transferred. - Attachable * GetLeftHatch() const { return m_pLHatch; } - - /// - /// Sets the left side hatch for this ACDropship. - /// - /// The new hatch to use. - void SetLeftHatch(Attachable *newHatch); - - /// - /// Gets the right side hatch of this ACDropship. - /// - /// A pointer to the right side hatch of this ACDropship. Ownership is NOT transferred. - Attachable * GetRightHatch() const { return m_pRHatch; } - - /// - /// Sets the right side hatch for this ACDropship. - /// - /// The new hatch to use. - void SetRightHatch(Attachable *newHatch); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMaxEngineAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get max engine rotation angle in degrees. -// Arguments: None. -// Return value: Max engine angle in degrees. - - float GetMaxEngineAngle() const { return m_MaxEngineAngle; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetMaxEngineAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets max engine rotation angle in degrees. -// Arguments: Max engine angle in degrees. -// Return value: None. - - void SetMaxEngineAngle(float newAngle) { m_MaxEngineAngle = newAngle; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLateralControlSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the abstract rate of LateralControl change. Default is 6 -// Arguments: None. -// Return value: Current lateral control speed value. - - float GetLateralControlSpeed() const { return m_LateralControlSpeed; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetLateralControlSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the abstract rate of LateralControl change. Default is 6 -// Arguments: New lateral control speed value. -// Return value: None. - - void SetLateralControlSpeed(float newSpeed) { m_LateralControl = newSpeed; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLateralControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets lateral control value -1.0 to 1.0 control of sideways movement. 0 means try to stand still in X. -// Arguments: None. -// Return value: Current lateral control value. - - float GetLateralControl() const { return m_LateralControl; } - - /// - /// Gets the modifier for height at which this ACDropship should hover above terrain. - /// - /// The modifier for height at which this ACDropship should hover above terrain. - float GetHoverHeightModifier() const { return m_HoverHeightModifier; } - - /// - /// Sets the modifier for height at which this ACDropship should hover above terrain. - /// - /// The new modifier for height at which this ACDropship should hover above terrain. - void SetHoverHeightModifier(float newHoverHeightModifier) { m_HoverHeightModifier = newHoverHeightModifier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - - // Member variables - static Entity::ClassInfo m_sClass; - // Body AtomGroups. - AtomGroup *m_pBodyAG; - // Thruster emitters. - //TODO when this class is cleaned up, these and their getters and setters should probably be renamed (I'd argue the lua bindings should be broken to match but that's debatable). L and R should be Left and Right and they should probably be Primary and Secondary. - AEmitter *m_pRThruster; - AEmitter *m_pLThruster; - AEmitter *m_pURThruster; - AEmitter *m_pULThruster; - - // Hatch doors - Attachable *m_pRHatch; - Attachable *m_pLHatch; - // How much the hatch doors rotate to open - Matrix m_HatchSwingRange; - // From 0 to 1.0, the state of hatch door openness - float m_HatchOpeness; - - // -1.0 to 1.0 control of sideways movement. 0 means try to stand still in X. - float m_LateralControl; - // Abstract speed at which Lateralcontroll is changed - float m_LateralControlSpeed; - - // Automatically stabilize the craft with the upper thrusters? Defaults to yes. - int m_AutoStabilize; - - // Maximum engine rotation in degrees - float m_MaxEngineAngle; - - float m_HoverHeightModifier; //!< The modifier for the height at which this ACDropShip should hover above terrain when releasing its cargo. Used in cpp and Lua AI. - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACDropShip, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - ACDropShip(const ACDropShip &reference) = delete; - ACDropShip & operator=(const ACDropShip &rhs) = delete; - -}; +namespace RTE { + + class Attachable; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: ACDropShip + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A hovering craft, with two engines on each attached on each end which + // tilt independently of the body to achieve steering. + // Parent(s): ACraft. + // Class history: 12/13/2006 ACDropShip created. + + class ACDropShip : public ACraft { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(ACDropShip); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: ACDropShip + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a ACDropShip object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + ACDropShip() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~ACDropShip + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a ACDropShip object before deletion + // from system memory. + // Arguments: None. + + ~ACDropShip() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACDropShip object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACDropShip to be identical to another, by deep copy. + // Arguments: A reference to the ACDropShip to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const ACDropShip& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire ACDropShip, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + ACraft::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the altitide of this' pos (or appropriate low point) over the + // terrain, in pixels. + // Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. + // The accuracy within which measurement is acceptable. Higher number + // here means less calculation. + // Return value: The rough altitude over the terrain, in pixels. + + float GetAltitude(int max = 0, int accuracy = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DetectObstacle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks for obstacles in the travel direction. + // Arguments: How far ahead of travel direction to check for obstacles. + // Return value: Which MOID was detected as obstacle. g_NoMOID means nothing was detected. + + MOID DetectObstacle(float distance); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AutoStabilizing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this has the means and will try to right itself, or if + // that's up to the Controller to do. + // Arguments: None. + // Return value: Wheter this will try to auto stabilize. + + bool AutoStabilizing() override { return true; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreControllerUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void PreControllerUpdate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMaxPassengers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The recomended, not absolute, maximum number of actors that fit in the + // invetory. Used by the activity AI. + // Arguments: None. + // Return value: An integer with the recomended number of actors that fit in the craft. + // Default is four. + + int GetMaxPassengers() const override { return m_MaxPassengers > -1 ? m_MaxPassengers : 4; } + + /// + /// Gets the right side thruster of this ACDropship. + /// + /// A pointer to the right side thruster of this ACDropship. Ownership is NOT transferred. + AEmitter* GetRightThruster() const { return m_pRThruster; } + + /// + /// Sets the right side thruster for this ACDropship. + /// + /// The new thruster to use. + void SetRightThruster(AEmitter* newThruster); + + /// + /// Gets the left side thruster of this ACDropship. + /// + /// A pointer to the left side thruster of this ACDropship. Ownership is NOT transferred. + AEmitter* GetLeftThruster() const { return m_pLThruster; } + + /// + /// Sets the left side thruster for this ACDropship. + /// + /// The new thruster to use. + void SetLeftThruster(AEmitter* newThruster); + + /// + /// Gets the right side secondary thruster of this ACDropship. + /// + /// A pointer to the right side secondary thruster of this ACDropship. Ownership is NOT transferred. + AEmitter* GetURightThruster() const { return m_pURThruster; } + + /// + /// Sets the right side secondary thruster for this ACDropship. + /// + /// The new thruster to use. + void SetURightThruster(AEmitter* newThruster); + + /// + /// Gets the left side secondary thruster of this ACDropship. + /// + /// A pointer to the left side secondary thruster of this ACDropship. Ownership is NOT transferred. + AEmitter* GetULeftThruster() const { return m_pULThruster; } + + /// + /// Sets the left side secondary thruster for this ACDropship. + /// + /// The new thruster to use. + void SetULeftThruster(AEmitter* newThruster); + + /// + /// Gets the left side hatch of this ACDropship. + /// + /// A pointer to the left side hatch of this ACDropship. Ownership is NOT transferred. + Attachable* GetLeftHatch() const { return m_pLHatch; } + + /// + /// Sets the left side hatch for this ACDropship. + /// + /// The new hatch to use. + void SetLeftHatch(Attachable* newHatch); + + /// + /// Gets the right side hatch of this ACDropship. + /// + /// A pointer to the right side hatch of this ACDropship. Ownership is NOT transferred. + Attachable* GetRightHatch() const { return m_pRHatch; } + + /// + /// Sets the right side hatch for this ACDropship. + /// + /// The new hatch to use. + void SetRightHatch(Attachable* newHatch); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMaxEngineAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get max engine rotation angle in degrees. + // Arguments: None. + // Return value: Max engine angle in degrees. + + float GetMaxEngineAngle() const { return m_MaxEngineAngle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetMaxEngineAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets max engine rotation angle in degrees. + // Arguments: Max engine angle in degrees. + // Return value: None. + + void SetMaxEngineAngle(float newAngle) { m_MaxEngineAngle = newAngle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLateralControlSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the abstract rate of LateralControl change. Default is 6 + // Arguments: None. + // Return value: Current lateral control speed value. + + float GetLateralControlSpeed() const { return m_LateralControlSpeed; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetLateralControlSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the abstract rate of LateralControl change. Default is 6 + // Arguments: New lateral control speed value. + // Return value: None. + + void SetLateralControlSpeed(float newSpeed) { m_LateralControl = newSpeed; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLateralControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets lateral control value -1.0 to 1.0 control of sideways movement. 0 means try to stand still in X. + // Arguments: None. + // Return value: Current lateral control value. + + float GetLateralControl() const { return m_LateralControl; } + + /// + /// Gets the modifier for height at which this ACDropship should hover above terrain. + /// + /// The modifier for height at which this ACDropship should hover above terrain. + float GetHoverHeightModifier() const { return m_HoverHeightModifier; } + + /// + /// Sets the modifier for height at which this ACDropship should hover above terrain. + /// + /// The new modifier for height at which this ACDropship should hover above terrain. + void SetHoverHeightModifier(float newHoverHeightModifier) { m_HoverHeightModifier = newHoverHeightModifier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + // Body AtomGroups. + AtomGroup* m_pBodyAG; + // Thruster emitters. + // TODO when this class is cleaned up, these and their getters and setters should probably be renamed (I'd argue the lua bindings should be broken to match but that's debatable). L and R should be Left and Right and they should probably be Primary and Secondary. + AEmitter* m_pRThruster; + AEmitter* m_pLThruster; + AEmitter* m_pURThruster; + AEmitter* m_pULThruster; + + // Hatch doors + Attachable* m_pRHatch; + Attachable* m_pLHatch; + // How much the hatch doors rotate to open + Matrix m_HatchSwingRange; + // From 0 to 1.0, the state of hatch door openness + float m_HatchOpeness; + + // -1.0 to 1.0 control of sideways movement. 0 means try to stand still in X. + float m_LateralControl; + // Abstract speed at which Lateralcontroll is changed + float m_LateralControlSpeed; + + // Automatically stabilize the craft with the upper thrusters? Defaults to yes. + int m_AutoStabilize; + + // Maximum engine rotation in degrees + float m_MaxEngineAngle; + + float m_HoverHeightModifier; //!< The modifier for the height at which this ACDropShip should hover above terrain when releasing its cargo. Used in cpp and Lua AI. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACDropShip, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + ACDropShip(const ACDropShip& reference) = delete; + ACDropShip& operator=(const ACDropShip& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/ACRocket.cpp b/Source/Entities/ACRocket.cpp index a1eb56a49..7219d80b4 100644 --- a/Source/Entities/ACRocket.cpp +++ b/Source/Entities/ACRocket.cpp @@ -7,11 +7,9 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files - #include "ACRocket.h" #include "AtomGroup.h" #include "Attachable.h" @@ -27,546 +25,616 @@ namespace RTE { -ConcreteClassInfo(ACRocket, ACraft, 10); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACRocket, effectively -// resetting the members of this abstraction level only. - -void ACRocket::Clear() -{ -// m_pCapsule = 0; - m_pRLeg = 0; - m_pLLeg = 0; - m_pBodyAG = 0; - m_pRFootGroup = 0; - m_pLFootGroup = 0; - m_pMThruster = 0; - m_pRThruster = 0; - m_pLThruster = 0; - m_pURThruster = 0; - m_pULThruster = 0; - m_GearState = RAISED; - for (int i = 0; i < GearStateCount; ++i) { - m_Paths[RIGHT][i].Reset(); - m_Paths[LEFT][i].Reset(); - m_Paths[RIGHT][i].Terminate(); - m_Paths[LEFT][i].Terminate(); - } - m_MaxGimbalAngle = 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACRocket object ready for use. - -int ACRocket::Create() -{ - // Read all the properties - if (ACraft::Create() < 0) - return -1; - - // Save the AtomGroup read in by MOSRotating, as we are going to make it - // into a composite group, and want to have the base body stored for reference. - m_pBodyAG = dynamic_cast(m_pAtomGroup->Clone()); + ConcreteClassInfo(ACRocket, ACraft, 10); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACRocket, effectively + // resetting the members of this abstraction level only. + + void ACRocket::Clear() { + // m_pCapsule = 0; + m_pRLeg = 0; + m_pLLeg = 0; + m_pBodyAG = 0; + m_pRFootGroup = 0; + m_pLFootGroup = 0; + m_pMThruster = 0; + m_pRThruster = 0; + m_pLThruster = 0; + m_pURThruster = 0; + m_pULThruster = 0; + m_GearState = RAISED; + for (int i = 0; i < GearStateCount; ++i) { + m_Paths[RIGHT][i].Reset(); + m_Paths[LEFT][i].Reset(); + m_Paths[RIGHT][i].Terminate(); + m_Paths[LEFT][i].Terminate(); + } + m_MaxGimbalAngle = 0; + } - // Mirror the limb paths - for (int i = 0; i < GearStateCount; ++i) - { - m_Paths[LEFT][i].Create(m_Paths[RIGHT][i]); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACRocket object ready for use. - // Override the body animation mode - m_SpriteAnimMode = PINGPONGOPENCLOSE; + int ACRocket::Create() { + // Read all the properties + if (ACraft::Create() < 0) + return -1; - return 0; -} + // Save the AtomGroup read in by MOSRotating, as we are going to make it + // into a composite group, and want to have the base body stored for reference. + m_pBodyAG = dynamic_cast(m_pAtomGroup->Clone()); + // Mirror the limb paths + for (int i = 0; i < GearStateCount; ++i) { + m_Paths[LEFT][i].Create(m_Paths[RIGHT][i]); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ACRocket to be identical to another, by deep copy. - -int ACRocket::Create(const ACRocket &reference) { - if (reference.m_pRLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRLeg->GetUniqueID()); } - if (reference.m_pLLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLLeg->GetUniqueID()); } - if (reference.m_pMThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pMThruster->GetUniqueID()); } - if (reference.m_pRThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRThruster->GetUniqueID()); } - if (reference.m_pLThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLThruster->GetUniqueID()); } - if (reference.m_pURThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pURThruster->GetUniqueID()); } - if (reference.m_pULThruster) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pULThruster->GetUniqueID()); } - - ACraft::Create(reference); - - if (reference.m_pRLeg) { SetRightLeg(dynamic_cast(reference.m_pRLeg->Clone())); } - if (reference.m_pLLeg) { SetLeftLeg(dynamic_cast(reference.m_pLLeg->Clone())); } - if (reference.m_pMThruster) { SetMainThruster(dynamic_cast(reference.m_pMThruster->Clone())); } - if (reference.m_pRThruster) { SetRightThruster(dynamic_cast(reference.m_pRThruster->Clone())); } - if (reference.m_pLThruster) { SetLeftThruster(dynamic_cast(reference.m_pLThruster->Clone())); } - if (reference.m_pURThruster) { SetURightThruster(dynamic_cast(reference.m_pURThruster->Clone())); } - if (reference.m_pULThruster) { SetULeftThruster(dynamic_cast(reference.m_pULThruster->Clone())); } - - m_pBodyAG = dynamic_cast(reference.m_pBodyAG->Clone()); - m_pBodyAG->SetOwner(this); - - if (reference.m_pLFootGroup) { - m_pLFootGroup = dynamic_cast(reference.m_pLFootGroup->Clone()); - } else if (m_pLLeg) { - m_pLFootGroup = m_pLLeg->GetFootGroupFromFootAtomGroup(); - } - if (m_pLFootGroup) { - m_pLFootGroup->SetOwner(this); - } + // Override the body animation mode + m_SpriteAnimMode = PINGPONGOPENCLOSE; - if (reference.m_pRFootGroup) { - m_pRFootGroup = dynamic_cast(reference.m_pRFootGroup->Clone()); - } else if (m_pRLeg) { - m_pRFootGroup = m_pRLeg->GetFootGroupFromFootAtomGroup(); - } - if (m_pRFootGroup) { - m_pRFootGroup->SetOwner(this); + return 0; } - m_GearState = reference.m_GearState; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACRocket to be identical to another, by deep copy. - for (int i = 0; i < GearStateCount; ++i) { - m_Paths[RIGHT][i].Create(reference.m_Paths[RIGHT][i]); - m_Paths[LEFT][i].Create(reference.m_Paths[LEFT][i]); - } + int ACRocket::Create(const ACRocket& reference) { + if (reference.m_pRLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRLeg->GetUniqueID()); + } + if (reference.m_pLLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLLeg->GetUniqueID()); + } + if (reference.m_pMThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pMThruster->GetUniqueID()); + } + if (reference.m_pRThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRThruster->GetUniqueID()); + } + if (reference.m_pLThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLThruster->GetUniqueID()); + } + if (reference.m_pURThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pURThruster->GetUniqueID()); + } + if (reference.m_pULThruster) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pULThruster->GetUniqueID()); + } - m_MaxGimbalAngle = reference.m_MaxGimbalAngle; + ACraft::Create(reference); - return 0; -} + if (reference.m_pRLeg) { + SetRightLeg(dynamic_cast(reference.m_pRLeg->Clone())); + } + if (reference.m_pLLeg) { + SetLeftLeg(dynamic_cast(reference.m_pLLeg->Clone())); + } + if (reference.m_pMThruster) { + SetMainThruster(dynamic_cast(reference.m_pMThruster->Clone())); + } + if (reference.m_pRThruster) { + SetRightThruster(dynamic_cast(reference.m_pRThruster->Clone())); + } + if (reference.m_pLThruster) { + SetLeftThruster(dynamic_cast(reference.m_pLThruster->Clone())); + } + if (reference.m_pURThruster) { + SetURightThruster(dynamic_cast(reference.m_pURThruster->Clone())); + } + if (reference.m_pULThruster) { + SetULeftThruster(dynamic_cast(reference.m_pULThruster->Clone())); + } + m_pBodyAG = dynamic_cast(reference.m_pBodyAG->Clone()); + m_pBodyAG->SetOwner(this); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int ACRocket::ReadProperty(const std::string_view &propName, Reader &reader) { - StartPropertyList(return ACraft::ReadProperty(propName, reader)); - - MatchForwards("RLeg") MatchProperty("RightLeg", { SetRightLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("LLeg") MatchProperty("LeftLeg", { SetLeftLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("RFootGroup") MatchProperty("RightFootGroup", { - delete m_pRFootGroup; - m_pRFootGroup = new AtomGroup(); - reader >> m_pRFootGroup; - m_pRFootGroup->SetOwner(this); - }); - MatchForwards("LFootGroup") MatchProperty("LeftFootGroup", { - delete m_pLFootGroup; - m_pLFootGroup = new AtomGroup(); - reader >> m_pLFootGroup; - m_pLFootGroup->SetOwner(this); - }); - MatchForwards("MThruster") MatchProperty("MainThruster", { SetMainThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("RThruster") MatchProperty("RightThruster", { SetRightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("LThruster") MatchProperty("LeftThruster", { SetLeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("URThruster") MatchProperty("UpRightThruster", { SetURightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("ULThruster") MatchProperty("UpLeftThruster", { SetULeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("RaisedGearLimbPath", { reader >> m_Paths[RIGHT][RAISED]; }); - MatchProperty("LoweredGearLimbPath", { reader >> m_Paths[RIGHT][LOWERED]; }); - MatchProperty("LoweringGearLimbPath", { reader >> m_Paths[RIGHT][LOWERING]; }); - MatchProperty("RaisingGearLimbPath", { reader >> m_Paths[RIGHT][RAISING]; }); - MatchProperty("MaxGimbalAngle", { - reader >> m_MaxGimbalAngle; - m_MaxGimbalAngle *= (c_PI / 180.0F); - }); - - EndPropertyList; -} + if (reference.m_pLFootGroup) { + m_pLFootGroup = dynamic_cast(reference.m_pLFootGroup->Clone()); + } else if (m_pLLeg) { + m_pLFootGroup = m_pLLeg->GetFootGroupFromFootAtomGroup(); + } + if (m_pLFootGroup) { + m_pLFootGroup->SetOwner(this); + } + if (reference.m_pRFootGroup) { + m_pRFootGroup = dynamic_cast(reference.m_pRFootGroup->Clone()); + } else if (m_pRLeg) { + m_pRFootGroup = m_pRLeg->GetFootGroupFromFootAtomGroup(); + } + if (m_pRFootGroup) { + m_pRFootGroup->SetOwner(this); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this ACRocket with a Writer for -// later recreation with Create(Reader &reader); - -int ACRocket::Save(Writer &writer) const -{ - ACraft::Save(writer); - - writer.NewProperty("RLeg"); - writer << m_pRLeg; - writer.NewProperty("LLeg"); - writer << m_pLLeg; - writer.NewProperty("RFootGroup"); - writer << m_pRFootGroup; - writer.NewProperty("LFootGroup"); - writer << m_pLFootGroup; - writer.NewProperty("MThruster"); - writer << m_pMThruster; - writer.NewProperty("RThruster"); - writer << m_pRThruster; - writer.NewProperty("LThruster"); - writer << m_pLThruster; - writer.NewProperty("URThruster"); - writer << m_pURThruster; - writer.NewProperty("ULThruster"); - writer << m_pULThruster; - writer.NewProperty("RaisedGearLimbPath"); - writer << m_Paths[RIGHT][RAISED]; - writer.NewProperty("LoweredGearLimbPath"); - writer << m_Paths[RIGHT][LOWERED]; - writer.NewProperty("LoweringGearLimbPath"); - writer << m_Paths[RIGHT][LOWERING]; - writer.NewProperty("RaisingGearLimbPath"); - writer << m_Paths[RIGHT][RAISING]; - writer.NewProperty("MaxGimbalAngle"); - writer << m_MaxGimbalAngle / (c_PI / 180.0F); - - return 0; -} + m_GearState = reference.m_GearState; + for (int i = 0; i < GearStateCount; ++i) { + m_Paths[RIGHT][i].Create(reference.m_Paths[RIGHT][i]); + m_Paths[LEFT][i].Create(reference.m_Paths[LEFT][i]); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ACRocket object. + m_MaxGimbalAngle = reference.m_MaxGimbalAngle; -void ACRocket::Destroy(bool notInherited) -{ - delete m_pBodyAG; - delete m_pRFootGroup; - delete m_pLFootGroup; + return 0; + } -// for (deque::iterator itr = m_WalkPaths.begin(); -// itr != m_WalkPaths.end(); ++itr) -// delete *itr; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int ACRocket::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return ACraft::ReadProperty(propName, reader)); + + MatchForwards("RLeg") MatchProperty("RightLeg", { SetRightLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("LLeg") MatchProperty("LeftLeg", { SetLeftLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("RFootGroup") MatchProperty("RightFootGroup", { + delete m_pRFootGroup; + m_pRFootGroup = new AtomGroup(); + reader >> m_pRFootGroup; + m_pRFootGroup->SetOwner(this); + }); + MatchForwards("LFootGroup") MatchProperty("LeftFootGroup", { + delete m_pLFootGroup; + m_pLFootGroup = new AtomGroup(); + reader >> m_pLFootGroup; + m_pLFootGroup->SetOwner(this); + }); + MatchForwards("MThruster") MatchProperty("MainThruster", { SetMainThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("RThruster") MatchProperty("RightThruster", { SetRightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("LThruster") MatchProperty("LeftThruster", { SetLeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("URThruster") MatchProperty("UpRightThruster", { SetURightThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("ULThruster") MatchProperty("UpLeftThruster", { SetULeftThruster(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("RaisedGearLimbPath", { reader >> m_Paths[RIGHT][RAISED]; }); + MatchProperty("LoweredGearLimbPath", { reader >> m_Paths[RIGHT][LOWERED]; }); + MatchProperty("LoweringGearLimbPath", { reader >> m_Paths[RIGHT][LOWERING]; }); + MatchProperty("RaisingGearLimbPath", { reader >> m_Paths[RIGHT][RAISING]; }); + MatchProperty("MaxGimbalAngle", { + reader >> m_MaxGimbalAngle; + m_MaxGimbalAngle *= (c_PI / 180.0F); + }); + + EndPropertyList; + } - if (!notInherited) - ACraft::Destroy(); - Clear(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this ACRocket with a Writer for + // later recreation with Create(Reader &reader); + + int ACRocket::Save(Writer& writer) const { + ACraft::Save(writer); + + writer.NewProperty("RLeg"); + writer << m_pRLeg; + writer.NewProperty("LLeg"); + writer << m_pLLeg; + writer.NewProperty("RFootGroup"); + writer << m_pRFootGroup; + writer.NewProperty("LFootGroup"); + writer << m_pLFootGroup; + writer.NewProperty("MThruster"); + writer << m_pMThruster; + writer.NewProperty("RThruster"); + writer << m_pRThruster; + writer.NewProperty("LThruster"); + writer << m_pLThruster; + writer.NewProperty("URThruster"); + writer << m_pURThruster; + writer.NewProperty("ULThruster"); + writer << m_pULThruster; + writer.NewProperty("RaisedGearLimbPath"); + writer << m_Paths[RIGHT][RAISED]; + writer.NewProperty("LoweredGearLimbPath"); + writer << m_Paths[RIGHT][LOWERED]; + writer.NewProperty("LoweringGearLimbPath"); + writer << m_Paths[RIGHT][LOWERING]; + writer.NewProperty("RaisingGearLimbPath"); + writer << m_Paths[RIGHT][RAISING]; + writer.NewProperty("MaxGimbalAngle"); + writer << m_MaxGimbalAngle / (c_PI / 180.0F); + + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ACRocket object. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the altitide of this' pos (or appropriate low point) over the -// terrain, in pixels. + void ACRocket::Destroy(bool notInherited) { + delete m_pBodyAG; + delete m_pRFootGroup; + delete m_pLFootGroup; -float ACRocket::GetAltitude(int max, int accuracy) -{ - // Use the main thruster's position as the position ot measure from - Vector pos; - if (m_pMThruster && m_pMThruster->IsAttached()) - pos = m_Pos + RotateOffset(m_pMThruster->GetParentOffset()); - else - pos = m_Pos; + // for (deque::iterator itr = m_WalkPaths.begin(); + // itr != m_WalkPaths.end(); ++itr) + // delete *itr; - return g_SceneMan.FindAltitude(pos, max, accuracy, true); -} + if (!notInherited) + ACraft::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the altitide of this' pos (or appropriate low point) over the + // terrain, in pixels. + + float ACRocket::GetAltitude(int max, int accuracy) { + // Use the main thruster's position as the position ot measure from + Vector pos; + if (m_pMThruster && m_pMThruster->IsAttached()) + pos = m_Pos + RotateOffset(m_pMThruster->GetParentOffset()); + else + pos = m_Pos; + + return g_SceneMan.FindAltitude(pos, max, accuracy, true); + } -void ACRocket::PreControllerUpdate() -{ - ACraft::PreControllerUpdate(); + ////////////////////////////////////////////////////////////////////////////////////////// - float deltaTime = g_TimerMan.GetDeltaTimeSecs(); + void ACRocket::PreControllerUpdate() { + ACraft::PreControllerUpdate(); - // Look/aim update, make the scanner point aftward if the rocket is falling - m_AimAngle = m_Vel.m_Y < 0 ? c_HalfPI : -c_HalfPI; + float deltaTime = g_TimerMan.GetDeltaTimeSecs(); - ///////////////////////////////// - // Controller update and handling + // Look/aim update, make the scanner point aftward if the rocket is falling + m_AimAngle = m_Vel.m_Y < 0 ? c_HalfPI : -c_HalfPI; - if ((m_Status == STABLE || m_Status == UNSTABLE) && !m_Controller.IsDisabled()) { - if (m_pMThruster) { - if (m_MaxGimbalAngle != 0) { m_pMThruster->SetInheritedRotAngleOffset(std::sin(m_Rotation.GetRadAngle()) * m_MaxGimbalAngle - c_HalfPI); } + ///////////////////////////////// + // Controller update and handling - if (m_Controller.IsState(MOVE_UP) || m_Controller.IsState(AIM_UP)) { - if (!m_pMThruster->IsEmitting()) { - m_pMThruster->TriggerBurst(); - m_ForceDeepCheck = true; + if ((m_Status == STABLE || m_Status == UNSTABLE) && !m_Controller.IsDisabled()) { + if (m_pMThruster) { + if (m_MaxGimbalAngle != 0) { + m_pMThruster->SetInheritedRotAngleOffset(std::sin(m_Rotation.GetRadAngle()) * m_MaxGimbalAngle - c_HalfPI); } - m_pMThruster->EnableEmission(true); - m_pMThruster->AlarmOnEmit(m_Team); - if (m_HatchState == OPEN) { + if (m_Controller.IsState(MOVE_UP) || m_Controller.IsState(AIM_UP)) { + if (!m_pMThruster->IsEmitting()) { + m_pMThruster->TriggerBurst(); + m_ForceDeepCheck = true; + } + m_pMThruster->EnableEmission(true); + m_pMThruster->AlarmOnEmit(m_Team); + + if (m_HatchState == OPEN) { + CloseHatch(); + m_HatchTimer.Reset(); + } + } else { + m_pMThruster->EnableEmission(false); + } + } + if (m_pULThruster || m_pURThruster) { + if (m_Controller.IsState(MOVE_DOWN) || m_Controller.IsState(AIM_DOWN)) { + if (m_pURThruster) { + if (!m_pURThruster->IsEmitting()) { + m_pURThruster->TriggerBurst(); + } + m_pURThruster->EnableEmission(true); + } + if (m_pULThruster) { + if (!m_pULThruster->IsEmitting()) { + m_pULThruster->TriggerBurst(); + } + m_pULThruster->EnableEmission(true); + } + } else { + if (m_pURThruster) { + m_pURThruster->EnableEmission(false); + } + if (m_pULThruster) { + m_pULThruster->EnableEmission(false); + } + } + } + if (m_pLThruster) { + if (m_Controller.IsState(MOVE_RIGHT)) { + if (!m_pLThruster->IsEmitting()) { + m_pLThruster->TriggerBurst(); + } + m_pLThruster->EnableEmission(true); + } else { + m_pLThruster->EnableEmission(false); + } + } + if (m_pRThruster) { + if (m_Controller.IsState(MOVE_LEFT)) { + if (!m_pRThruster->IsEmitting()) { + m_pRThruster->TriggerBurst(); + } + m_pRThruster->EnableEmission(true); + } else { + m_pRThruster->EnableEmission(false); + } + } + if (m_Controller.IsState(PRESS_FACEBUTTON)) { + if (m_HatchState == CLOSED) { + DropAllInventory(); + } else if (m_HatchState == OPEN) { CloseHatch(); - m_HatchTimer.Reset(); } - } else { + } + } else { + if (m_pMThruster) { m_pMThruster->EnableEmission(false); } - } - if (m_pULThruster || m_pURThruster) { - if (m_Controller.IsState(MOVE_DOWN) || m_Controller.IsState(AIM_DOWN)) { - if (m_pURThruster) { - if (!m_pURThruster->IsEmitting()) { m_pURThruster->TriggerBurst(); } - m_pURThruster->EnableEmission(true); + if (m_pRThruster) { + m_pRThruster->EnableEmission(false); + } + if (m_pLThruster) { + m_pLThruster->EnableEmission(false); + } + if (m_pURThruster) { + m_pURThruster->EnableEmission(false); + } + if (m_pULThruster) { + m_pULThruster->EnableEmission(false); + } + } + + /////////////////////////////////////////////////// + // Travel the landing gear AtomGroup:s + + if (m_pMThruster) { + m_GearState = m_pMThruster->IsEmitting() ? LandingGearState::RAISED : LandingGearState::LOWERED; + + m_Paths[RIGHT][m_GearState].SetHFlip(m_HFlipped); + m_Paths[LEFT][m_GearState].SetHFlip(!m_HFlipped); + + if (!m_LimbPushForcesAndCollisionsDisabled) { + if (m_pRLeg) { + m_pRFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pRLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHT][m_GearState], deltaTime, nullptr, true); } - if (m_pULThruster) { - if (!m_pULThruster->IsEmitting()) { m_pULThruster->TriggerBurst(); } - m_pULThruster->EnableEmission(true); + if (m_pLLeg) { + m_pLFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pLLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFT][m_GearState], deltaTime, nullptr, true); } } else { - if (m_pURThruster) { m_pURThruster->EnableEmission(false); } - if (m_pULThruster) { m_pULThruster->EnableEmission(false); } + if (m_pRLeg) { + m_pRFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pRLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHT][m_GearState], deltaTime, nullptr, true); + } + if (m_pLLeg) { + m_pLFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pLLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFT][m_GearState], deltaTime, nullptr, true); + } } } - if (m_pLThruster) { - if (m_Controller.IsState(MOVE_RIGHT)) { - if (!m_pLThruster->IsEmitting()) { m_pLThruster->TriggerBurst(); } - m_pLThruster->EnableEmission(true); - } else { - m_pLThruster->EnableEmission(false); + + ///////////////////////////////// + // Manage Attachable:s + if (m_pRLeg && m_pRLeg->IsAttached()) { + m_pRLeg->SetTargetPosition(m_pRFootGroup->GetLimbPos(m_HFlipped)); + } + + if (m_pLLeg && m_pLLeg->IsAttached()) { + m_pLLeg->SetTargetPosition(m_pLFootGroup->GetLimbPos(!m_HFlipped)); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + void ACRocket::Update() { + ACraft::Update(); + + //////////////////////////////////////// + // Hatch Operation + + unsigned int lastFrame = m_FrameCount - 1; + + if (m_HatchState == OPENING) { + if (m_HatchTimer.GetElapsedSimTimeMS() <= m_HatchDelay && m_HatchDelay) + m_Frame = static_cast(static_cast(lastFrame) * (m_HatchTimer.GetElapsedSimTimeMS() / static_cast(m_HatchDelay))); + else { + m_Frame = lastFrame; + m_HatchState = OPEN; + DropAllInventory(); + } + } else if (m_HatchState == CLOSING) { + if (m_HatchTimer.GetElapsedSimTimeMS() <= m_HatchDelay && m_HatchDelay) + m_Frame = lastFrame - static_cast(static_cast(lastFrame) * (m_HatchTimer.GetElapsedSimTimeMS() / static_cast(m_HatchDelay))); + else { + m_Frame = 0; + m_HatchState = CLOSED; } } - if (m_pRThruster) { - if (m_Controller.IsState(MOVE_LEFT)) { - if (!m_pRThruster->IsEmitting()) { m_pRThruster->TriggerBurst(); } - m_pRThruster->EnableEmission(true); - } else { - m_pRThruster->EnableEmission(false); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACRocket::SetRightLeg(Leg* newLeg) { + if (m_pRLeg && m_pRLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pRLeg); + } + if (newLeg == nullptr) { + m_pRLeg = nullptr; + } else { + m_pRLeg = newLeg; + AddAttachable(newLeg); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightLeg"); + dynamic_cast(parent)->SetRightLeg(castedAttachable); + }}); + + if (m_pRLeg->HasNoSetDamageMultiplier()) { + m_pRLeg->SetDamageMultiplier(1.0F); } } - if (m_Controller.IsState(PRESS_FACEBUTTON)) { - if (m_HatchState == CLOSED) { - DropAllInventory(); - } else if (m_HatchState == OPEN) { - CloseHatch(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACRocket::SetLeftLeg(Leg* newLeg) { + if (m_pLLeg && m_pLLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pLLeg); + } + if (newLeg == nullptr) { + m_pLLeg = nullptr; + } else { + m_pLLeg = newLeg; + AddAttachable(newLeg); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftLeg"); + dynamic_cast(parent)->SetLeftLeg(castedAttachable); + }}); + + if (m_pLLeg->HasNoSetDamageMultiplier()) { + m_pLLeg->SetDamageMultiplier(1.0F); } + m_pLLeg->SetInheritsHFlipped(-1); } - } else { - if (m_pMThruster) { m_pMThruster->EnableEmission(false); } - if (m_pRThruster) { m_pRThruster->EnableEmission(false); } - if (m_pLThruster) { m_pLThruster->EnableEmission(false); } - if (m_pURThruster) { m_pURThruster->EnableEmission(false); } - if (m_pULThruster) { m_pULThruster->EnableEmission(false); } - } + } - /////////////////////////////////////////////////// - // Travel the landing gear AtomGroup:s + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (m_pMThruster) { - m_GearState = m_pMThruster->IsEmitting() ? LandingGearState::RAISED : LandingGearState::LOWERED; + void ACRocket::SetMainThruster(AEmitter* newThruster) { + if (m_pMThruster && m_pMThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pMThruster); + } + if (newThruster == nullptr) { + m_pMThruster = nullptr; + } else { + m_pMThruster = newThruster; + AddAttachable(newThruster); - m_Paths[RIGHT][m_GearState].SetHFlip(m_HFlipped); - m_Paths[LEFT][m_GearState].SetHFlip(!m_HFlipped); + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetMainThruster"); + dynamic_cast(parent)->SetMainThruster(castedAttachable); + }}); - if (!m_LimbPushForcesAndCollisionsDisabled) { - if (m_pRLeg) { m_pRFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pRLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHT][m_GearState], deltaTime, nullptr, true); } - if (m_pLLeg) { m_pLFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pLLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFT][m_GearState], deltaTime, nullptr, true); } + if (m_pMThruster->HasNoSetDamageMultiplier()) { + m_pMThruster->SetDamageMultiplier(1.0F); + } + m_pMThruster->SetInheritedRotAngleOffset(-c_HalfPI); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACRocket::SetRightThruster(AEmitter* newThruster) { + if (m_pRThruster && m_pRThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pRThruster); + } + if (newThruster == nullptr) { + m_pRThruster = nullptr; } else { - if (m_pRLeg) { m_pRFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pRLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHT][m_GearState], deltaTime, nullptr, true); } - if (m_pLLeg) { m_pLFootGroup->PushAsLimb(m_Pos.GetFloored() + RotateOffset(m_pLLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFT][m_GearState], deltaTime, nullptr, true); } + m_pRThruster = newThruster; + AddAttachable(newThruster); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightThruster"); + dynamic_cast(parent)->SetRightThruster(castedAttachable); + }}); + + if (m_pRThruster->HasNoSetDamageMultiplier()) { + m_pRThruster->SetDamageMultiplier(1.0F); + } + m_pRThruster->SetInheritedRotAngleOffset(c_EighthPI); } } - ///////////////////////////////// - // Manage Attachable:s - if (m_pRLeg && m_pRLeg->IsAttached()) { - m_pRLeg->SetTargetPosition(m_pRFootGroup->GetLimbPos(m_HFlipped)); - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (m_pLLeg && m_pLLeg->IsAttached()) { - m_pLLeg->SetTargetPosition(m_pLFootGroup->GetLimbPos(!m_HFlipped)); - } -} + void ACRocket::SetLeftThruster(AEmitter* newThruster) { + if (m_pLThruster && m_pLThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pLThruster); + } + if (newThruster == nullptr) { + m_pLThruster = nullptr; + } else { + m_pLThruster = newThruster; + AddAttachable(newThruster); -////////////////////////////////////////////////////////////////////////////////////////// + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftThruster"); + dynamic_cast(parent)->SetLeftThruster(castedAttachable); + }}); + + if (m_pLThruster->HasNoSetDamageMultiplier()) { + m_pLThruster->SetDamageMultiplier(1.0F); + } + m_pLThruster->SetInheritedRotAngleOffset(c_PI - c_EighthPI); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACRocket::SetURightThruster(AEmitter* newThruster) { + if (m_pURThruster && m_pURThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pURThruster); + } + if (newThruster == nullptr) { + m_pURThruster = nullptr; + } else { + m_pURThruster = newThruster; + AddAttachable(newThruster); -void ACRocket::Update() -{ - ACraft::Update(); - - //////////////////////////////////////// - // Hatch Operation - - unsigned int lastFrame = m_FrameCount - 1; - - if (m_HatchState == OPENING) { - if (m_HatchTimer.GetElapsedSimTimeMS() <= m_HatchDelay && m_HatchDelay) - m_Frame = static_cast(static_cast(lastFrame) * (m_HatchTimer.GetElapsedSimTimeMS() / static_cast(m_HatchDelay))); - else - { - m_Frame = lastFrame; - m_HatchState = OPEN; - DropAllInventory(); - } - } - else if (m_HatchState == CLOSING) { - if (m_HatchTimer.GetElapsedSimTimeMS() <= m_HatchDelay && m_HatchDelay) - m_Frame = lastFrame - static_cast(static_cast(lastFrame) * (m_HatchTimer.GetElapsedSimTimeMS() / static_cast(m_HatchDelay))); - else - { - m_Frame = 0; - m_HatchState = CLOSED; - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::SetRightLeg(Leg *newLeg) { - if (m_pRLeg && m_pRLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pRLeg); } - if (newLeg == nullptr) { - m_pRLeg = nullptr; - } else { - m_pRLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightLeg"); - dynamic_cast(parent)->SetRightLeg(castedAttachable); - }}); - - if (m_pRLeg->HasNoSetDamageMultiplier()) { m_pRLeg->SetDamageMultiplier(1.0F); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::SetLeftLeg(Leg *newLeg) { - if (m_pLLeg && m_pLLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pLLeg); } - if (newLeg == nullptr) { - m_pLLeg = nullptr; - } else { - m_pLLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftLeg"); - dynamic_cast(parent)->SetLeftLeg(castedAttachable); - }}); - - if (m_pLLeg->HasNoSetDamageMultiplier()) { m_pLLeg->SetDamageMultiplier(1.0F); } - m_pLLeg->SetInheritsHFlipped(-1); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::SetMainThruster(AEmitter *newThruster) { - if (m_pMThruster && m_pMThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pMThruster); } - if (newThruster == nullptr) { - m_pMThruster = nullptr; - } else { - m_pMThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetMainThruster"); - dynamic_cast(parent)->SetMainThruster(castedAttachable); - }}); - - if (m_pMThruster->HasNoSetDamageMultiplier()) { m_pMThruster->SetDamageMultiplier(1.0F); } - m_pMThruster->SetInheritedRotAngleOffset(-c_HalfPI); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::SetRightThruster(AEmitter *newThruster) { - if (m_pRThruster && m_pRThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pRThruster); } - if (newThruster == nullptr) { - m_pRThruster = nullptr; - } else { - m_pRThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightThruster"); - dynamic_cast(parent)->SetRightThruster(castedAttachable); - }}); - - if (m_pRThruster->HasNoSetDamageMultiplier()) { m_pRThruster->SetDamageMultiplier(1.0F); } - m_pRThruster->SetInheritedRotAngleOffset(c_EighthPI); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::SetLeftThruster(AEmitter *newThruster) { - if (m_pLThruster && m_pLThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pLThruster); } - if (newThruster == nullptr) { - m_pLThruster = nullptr; - } else { - m_pLThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftThruster"); - dynamic_cast(parent)->SetLeftThruster(castedAttachable); - }}); - - if (m_pLThruster->HasNoSetDamageMultiplier()) { m_pLThruster->SetDamageMultiplier(1.0F); } - m_pLThruster->SetInheritedRotAngleOffset(c_PI - c_EighthPI); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::SetURightThruster(AEmitter *newThruster) { - if (m_pURThruster && m_pURThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pURThruster); } - if (newThruster == nullptr) { - m_pURThruster = nullptr; - } else { - m_pURThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetURightThruster"); - dynamic_cast(parent)->SetURightThruster(castedAttachable); - }}); - - if (m_pURThruster->HasNoSetDamageMultiplier()) { m_pURThruster->SetDamageMultiplier(1.0F); } - m_pURThruster->SetInheritedRotAngleOffset(c_HalfPI - c_EighthPI); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::SetULeftThruster(AEmitter *newThruster) { - if (m_pULThruster && m_pULThruster->IsAttached()) { RemoveAndDeleteAttachable(m_pULThruster); } - if (newThruster == nullptr) { - m_pULThruster = nullptr; - } else { - m_pULThruster = newThruster; - AddAttachable(newThruster); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEmitter *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetULeftThruster"); - dynamic_cast(parent)->SetULeftThruster(castedAttachable); - }}); - - if (m_pULThruster->HasNoSetDamageMultiplier()) { m_pULThruster->SetDamageMultiplier(1.0F); } - m_pULThruster->SetInheritedRotAngleOffset(c_HalfPI + c_EighthPI); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACRocket::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { - ACraft::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - - if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawHandAndFootGroupVisualizations()) { - m_pRFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - m_pLFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - } -} + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetURightThruster"); + dynamic_cast(parent)->SetURightThruster(castedAttachable); + }}); + + if (m_pURThruster->HasNoSetDamageMultiplier()) { + m_pURThruster->SetDamageMultiplier(1.0F); + } + m_pURThruster->SetInheritedRotAngleOffset(c_HalfPI - c_EighthPI); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACRocket::SetULeftThruster(AEmitter* newThruster) { + if (m_pULThruster && m_pULThruster->IsAttached()) { + RemoveAndDeleteAttachable(m_pULThruster); + } + if (newThruster == nullptr) { + m_pULThruster = nullptr; + } else { + m_pULThruster = newThruster; + AddAttachable(newThruster); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newThruster->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEmitter* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetULeftThruster"); + dynamic_cast(parent)->SetULeftThruster(castedAttachable); + }}); + + if (m_pULThruster->HasNoSetDamageMultiplier()) { + m_pULThruster->SetDamageMultiplier(1.0F); + } + m_pULThruster->SetInheritedRotAngleOffset(c_HalfPI + c_EighthPI); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACRocket::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + ACraft::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + + if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawHandAndFootGroupVisualizations()) { + m_pRFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + m_pLFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + } + } } // namespace RTE diff --git a/Source/Entities/ACRocket.h b/Source/Entities/ACRocket.h index 191fb8d79..9434db876 100644 --- a/Source/Entities/ACRocket.h +++ b/Source/Entities/ACRocket.h @@ -10,326 +10,305 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "ACraft.h" -namespace RTE -{ - -class Attachable; -class Arm; -class Leg; -//class LimbPath; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: ACRocket -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A rocket craft, with main engine and rotation of the whole body as a -// means of steering. -// Parent(s): ACraft. -// Class history: 09/02/2004 ARocket created. -// 12/13/2006 ARocket changed names to ACRocket, parent changed to ACraft - -class ACRocket : public ACraft { - friend struct EntityLuaBindings; - -enum LandingGearState -{ - RAISED = 0, - LOWERED, - LOWERING, - RAISING, - GearStateCount -}; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(ACRocket); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: ACRocket -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a ACRocket object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - ACRocket() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~ACRocket -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a ACRocket object before deletion -// from system memory. -// Arguments: None. - - ~ACRocket() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACRocket object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ACRocket to be identical to another, by deep copy. -// Arguments: A reference to the ACRocket to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const ACRocket &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire ACRocket, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); ACraft::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the altitide of this' pos (or appropriate low point) over the -// terrain, in pixels. -// Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. -// The accuracy within which measurement is acceptable. Higher number -// here means less calculation. -// Return value: The rough altitude over the terrain, in pixels. - - float GetAltitude(int max = 0, int accuracy = 0) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreControllerUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void PreControllerUpdate() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: Nosssssssne. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ACRocket's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMaxPassengers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The recomended, not absolute, maximum number of actors that fit in the -// invetory. Used by the activity AI. -// Arguments: None. -// Return value: An integer with the recomended number of actors that fit in the craft. -// Default is two. - - int GetMaxPassengers() const override { return m_MaxPassengers > -1 ? m_MaxPassengers : 2; } - - /// - /// Gets the right leg of this ACRocket. - /// - /// A pointer to the right Leg of this ACRocket. Ownership is NOT transferred. - Leg * GetRightLeg() const { return m_pRLeg; } - - /// - /// Sets the right Leg for this ACRocket. - /// - /// The new Leg to use. - void SetRightLeg(Leg *newLeg); - - /// - /// Gets the left Leg of this ACRocket. - /// - /// A pointer to the left Leg of this ACRocket. Ownership is NOT transferred. - Leg * GetLeftLeg() const { return m_pLLeg; } - - /// - /// Sets the left Leg for this ACRocket. - /// - /// The new Leg to use. - void SetLeftLeg(Leg *newLeg); - - /// - /// Gets the main thruster of this ACRocket. - /// - /// A pointer to the main thruster of this ACRocket. Ownership is NOT transferred. - AEmitter * GetMainThruster() const { return m_pMThruster; } - - /// - /// Sets the main thruster for this ACRocket. - /// - /// The new thruster to use. - void SetMainThruster(AEmitter *newThruster); - - /// - /// Gets the right side thruster of this ACRocket. - /// - /// A pointer to the right side thruster of this ACRocket. Ownership is NOT transferred. - AEmitter * GetRightThruster() const { return m_pRThruster; } - - /// - /// Sets the right side thruster for this ACRocket. - /// - /// The new thruster to use. - void SetRightThruster(AEmitter *newThruster); - - /// - /// Gets the left side thruster of this ACRocket. - /// - /// A pointer to the left side thruster of this ACRocket. Ownership is NOT transferred. - AEmitter * GetLeftThruster() const { return m_pLThruster; } - - /// - /// Sets the left side thruster for this ACRocket. - /// - /// The new thruster to use. - void SetLeftThruster(AEmitter *newThruster); - - /// - /// Gets the right side secondary thruster of this ACRocket. - /// - /// A pointer to the right side secondary thruster of this ACRocket. Ownership is NOT transferred. - AEmitter * GetURightThruster() const { return m_pURThruster; } - - /// - /// Sets the right side secondary thruster for this ACRocket. - /// - /// The new thruster to use. - void SetURightThruster(AEmitter *newThruster); - - /// - /// Gets the left side secondary thruster of this ACRocket. - /// - /// A pointer to the left side secondary thruster of this ACRocket. Ownership is NOT transferred. - AEmitter * GetULeftThruster() const { return m_pULThruster; } - - /// - /// Sets the left side secondary thruster for this ACRocket. - /// - /// The new thruster to use. - void SetULeftThruster(AEmitter *newThruster); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGearState -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the the landing gear state -// Arguments: None. -// Return value: Current landing gear state. - - unsigned int GetGearState() const { return m_GearState; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - - // Member variables - static Entity::ClassInfo m_sClass; - // Attached nosecone/capsule. -// Attachable *m_pCapsule; - // Right landing gear. - Leg *m_pRLeg; - // Left landing gear. - Leg *m_pLLeg; - // Body AtomGroups. - AtomGroup *m_pBodyAG; - // Limb AtomGroups. - AtomGroup *m_pRFootGroup; - AtomGroup *m_pLFootGroup; - // Thruster emitters. - AEmitter *m_pMThruster; - AEmitter *m_pRThruster; - AEmitter *m_pLThruster; - AEmitter *m_pURThruster; - AEmitter *m_pULThruster; - // Current landing gear action state. - unsigned int m_GearState; - // Limb paths for different movement states. - // [0] is for the right limbs, and [1] is for left. - LimbPath m_Paths[2][GearStateCount]; - float m_MaxGimbalAngle; //!< How much the main engine is able to tilt in order to stabilize the rocket. - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACRocket, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - // Disallow the use of some implicit methods. - ACRocket(const ACRocket &reference) = delete; - ACRocket & operator=(const ACRocket &rhs) = delete; - -}; +namespace RTE { + + class Attachable; + class Arm; + class Leg; + // class LimbPath; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: ACRocket + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A rocket craft, with main engine and rotation of the whole body as a + // means of steering. + // Parent(s): ACraft. + // Class history: 09/02/2004 ARocket created. + // 12/13/2006 ARocket changed names to ACRocket, parent changed to ACraft + + class ACRocket : public ACraft { + friend struct EntityLuaBindings; + + enum LandingGearState { + RAISED = 0, + LOWERED, + LOWERING, + RAISING, + GearStateCount + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(ACRocket); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: ACRocket + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a ACRocket object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + ACRocket() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~ACRocket + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a ACRocket object before deletion + // from system memory. + // Arguments: None. + + ~ACRocket() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACRocket object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACRocket to be identical to another, by deep copy. + // Arguments: A reference to the ACRocket to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const ACRocket& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire ACRocket, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + ACraft::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the altitide of this' pos (or appropriate low point) over the + // terrain, in pixels. + // Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. + // The accuracy within which measurement is acceptable. Higher number + // here means less calculation. + // Return value: The rough altitude over the terrain, in pixels. + + float GetAltitude(int max = 0, int accuracy = 0) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreControllerUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void PreControllerUpdate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: Nosssssssne. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ACRocket's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMaxPassengers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The recomended, not absolute, maximum number of actors that fit in the + // invetory. Used by the activity AI. + // Arguments: None. + // Return value: An integer with the recomended number of actors that fit in the craft. + // Default is two. + + int GetMaxPassengers() const override { return m_MaxPassengers > -1 ? m_MaxPassengers : 2; } + + /// + /// Gets the right leg of this ACRocket. + /// + /// A pointer to the right Leg of this ACRocket. Ownership is NOT transferred. + Leg* GetRightLeg() const { return m_pRLeg; } + + /// + /// Sets the right Leg for this ACRocket. + /// + /// The new Leg to use. + void SetRightLeg(Leg* newLeg); + + /// + /// Gets the left Leg of this ACRocket. + /// + /// A pointer to the left Leg of this ACRocket. Ownership is NOT transferred. + Leg* GetLeftLeg() const { return m_pLLeg; } + + /// + /// Sets the left Leg for this ACRocket. + /// + /// The new Leg to use. + void SetLeftLeg(Leg* newLeg); + + /// + /// Gets the main thruster of this ACRocket. + /// + /// A pointer to the main thruster of this ACRocket. Ownership is NOT transferred. + AEmitter* GetMainThruster() const { return m_pMThruster; } + + /// + /// Sets the main thruster for this ACRocket. + /// + /// The new thruster to use. + void SetMainThruster(AEmitter* newThruster); + + /// + /// Gets the right side thruster of this ACRocket. + /// + /// A pointer to the right side thruster of this ACRocket. Ownership is NOT transferred. + AEmitter* GetRightThruster() const { return m_pRThruster; } + + /// + /// Sets the right side thruster for this ACRocket. + /// + /// The new thruster to use. + void SetRightThruster(AEmitter* newThruster); + + /// + /// Gets the left side thruster of this ACRocket. + /// + /// A pointer to the left side thruster of this ACRocket. Ownership is NOT transferred. + AEmitter* GetLeftThruster() const { return m_pLThruster; } + + /// + /// Sets the left side thruster for this ACRocket. + /// + /// The new thruster to use. + void SetLeftThruster(AEmitter* newThruster); + + /// + /// Gets the right side secondary thruster of this ACRocket. + /// + /// A pointer to the right side secondary thruster of this ACRocket. Ownership is NOT transferred. + AEmitter* GetURightThruster() const { return m_pURThruster; } + + /// + /// Sets the right side secondary thruster for this ACRocket. + /// + /// The new thruster to use. + void SetURightThruster(AEmitter* newThruster); + + /// + /// Gets the left side secondary thruster of this ACRocket. + /// + /// A pointer to the left side secondary thruster of this ACRocket. Ownership is NOT transferred. + AEmitter* GetULeftThruster() const { return m_pULThruster; } + + /// + /// Sets the left side secondary thruster for this ACRocket. + /// + /// The new thruster to use. + void SetULeftThruster(AEmitter* newThruster); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGearState + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the the landing gear state + // Arguments: None. + // Return value: Current landing gear state. + + unsigned int GetGearState() const { return m_GearState; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + // Attached nosecone/capsule. + // Attachable *m_pCapsule; + // Right landing gear. + Leg* m_pRLeg; + // Left landing gear. + Leg* m_pLLeg; + // Body AtomGroups. + AtomGroup* m_pBodyAG; + // Limb AtomGroups. + AtomGroup* m_pRFootGroup; + AtomGroup* m_pLFootGroup; + // Thruster emitters. + AEmitter* m_pMThruster; + AEmitter* m_pRThruster; + AEmitter* m_pLThruster; + AEmitter* m_pURThruster; + AEmitter* m_pULThruster; + // Current landing gear action state. + unsigned int m_GearState; + // Limb paths for different movement states. + // [0] is for the right limbs, and [1] is for left. + LimbPath m_Paths[2][GearStateCount]; + float m_MaxGimbalAngle; //!< How much the main engine is able to tilt in order to stabilize the rocket. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACRocket, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + ACRocket(const ACRocket& reference) = delete; + ACRocket& operator=(const ACRocket& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/ACrab.cpp b/Source/Entities/ACrab.cpp index 7a563ec95..ddbcd6068 100644 --- a/Source/Entities/ACrab.cpp +++ b/Source/Entities/ACrab.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -35,1039 +34,1104 @@ namespace RTE { -ConcreteClassInfo(ACrab, Actor, 20); + ConcreteClassInfo(ACrab, Actor, 20); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACrab, effectively + // resetting the members of this abstraction level only. + + void ACrab::Clear() { + m_pTurret = 0; + m_pLFGLeg = 0; + m_pLBGLeg = 0; + m_pRFGLeg = 0; + m_pRBGLeg = 0; + m_pLFGFootGroup = 0; + m_BackupLFGFootGroup = nullptr; + m_pLBGFootGroup = 0; + m_BackupLBGFootGroup = nullptr; + m_pRFGFootGroup = 0; + m_BackupRFGFootGroup = nullptr; + m_pRBGFootGroup = 0; + m_BackupRBGFootGroup = nullptr; + m_StrideSound = nullptr; + m_pJetpack = nullptr; + m_MoveState = STAND; + m_StrideFrame = false; + for (int side = 0; side < SIDECOUNT; ++side) { + for (int layer = 0; layer < LAYERCOUNT; ++layer) { + for (int state = 0; state < MOVEMENTSTATECOUNT; ++state) { + m_Paths[side][layer][state].Reset(); + m_Paths[side][layer][state].Terminate(); + } + } + m_StrideStart[side] = false; + // m_StrideTimer[side].Reset(); + } + m_Aiming = false; + + m_DeviceState = SCANNING; + m_SweepState = NOSWEEP; + m_DigState = NOTDIGGING; + m_JumpState = NOTJUMPING; + m_JumpTarget.Reset(); + m_JumpingRight = true; + m_DigTunnelEndPos.Reset(); + m_SweepCenterAimAngle = 0; + m_SweepRange = c_EighthPI; + m_DigTarget.Reset(); + m_FireTimer.Reset(); + m_SweepTimer.Reset(); + m_PatrolTimer.Reset(); + m_JumpTimer.Reset(); + m_AimRangeUpperLimit = -1; + m_AimRangeLowerLimit = -1; + m_LockMouseAimInput = false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACrab object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACrab, effectively -// resetting the members of this abstraction level only. - -void ACrab::Clear() -{ - m_pTurret = 0; - m_pLFGLeg = 0; - m_pLBGLeg = 0; - m_pRFGLeg = 0; - m_pRBGLeg = 0; - m_pLFGFootGroup = 0; - m_BackupLFGFootGroup = nullptr; - m_pLBGFootGroup = 0; - m_BackupLBGFootGroup = nullptr; - m_pRFGFootGroup = 0; - m_BackupRFGFootGroup = nullptr; - m_pRBGFootGroup = 0; - m_BackupRBGFootGroup = nullptr; - m_StrideSound = nullptr; - m_pJetpack = nullptr; - m_MoveState = STAND; - m_StrideFrame = false; - for (int side = 0; side < SIDECOUNT; ++side) - { - for (int layer = 0; layer < LAYERCOUNT; ++layer) - { - for (int state = 0; state < MOVEMENTSTATECOUNT; ++state) - { - m_Paths[side][layer][state].Reset(); - m_Paths[side][layer][state].Terminate(); - } - } - m_StrideStart[side] = false; -// m_StrideTimer[side].Reset(); - } - m_Aiming = false; - - m_DeviceState = SCANNING; - m_SweepState = NOSWEEP; - m_DigState = NOTDIGGING; - m_JumpState = NOTJUMPING; - m_JumpTarget.Reset(); - m_JumpingRight = true; - m_DigTunnelEndPos.Reset(); - m_SweepCenterAimAngle = 0; - m_SweepRange = c_EighthPI; - m_DigTarget.Reset(); - m_FireTimer.Reset(); - m_SweepTimer.Reset(); - m_PatrolTimer.Reset(); - m_JumpTimer.Reset(); - m_AimRangeUpperLimit = -1; - m_AimRangeLowerLimit = -1; - m_LockMouseAimInput = false; -} + int ACrab::Create() { + // Read all the properties + if (Actor::Create() < 0) { + return -1; + } + if (m_AIMode == Actor::AIMODE_NONE) { + m_AIMode = Actor::AIMODE_BRAINHUNT; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACrab object ready for use. + // Create the background paths copied from the foreground ones which were already read in + for (int side = 0; side < SIDECOUNT; ++side) { + for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { + m_Paths[side][BGROUND][i].Destroy(); + m_Paths[side][BGROUND][i].Create(m_Paths[side][FGROUND][i]); + } + } + + // All ACrabs by default avoid hitting each other ont he same team + m_IgnoresTeamHits = true; + + // Check whether UpperLimit and LowerLimit are defined, if not, copy general AimRange value to preserve compatibility + if (m_AimRangeUpperLimit == -1 || m_AimRangeLowerLimit == -1) { + m_AimRangeUpperLimit = m_AimRange; + m_AimRangeLowerLimit = m_AimRange; + } -int ACrab::Create() -{ - // Read all the properties - if (Actor::Create() < 0) { - return -1; + return 0; } - if (m_AIMode == Actor::AIMODE_NONE) { - m_AIMode = Actor::AIMODE_BRAINHUNT; + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACrab object ready for use. + + int ACrab::Create(BITMAP *pSprite, + Controller *pController, + const float mass, + const Vector &position, + const Vector &velocity, + AtomGroup *hitBody, + const unsigned long lifetime, + Status status, + const int health) + { + + + return Actor::Create(pSprite, + pController, + mass, + position, + velocity, + hitBody, + lifetime, + status, + health); } + */ - // Create the background paths copied from the foreground ones which were already read in - for (int side = 0; side < SIDECOUNT; ++side) - { - for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) - { - m_Paths[side][BGROUND][i].Destroy(); - m_Paths[side][BGROUND][i].Create(m_Paths[side][FGROUND][i]); - } - } - - // All ACrabs by default avoid hitting each other ont he same team - m_IgnoresTeamHits = true; - - // Check whether UpperLimit and LowerLimit are defined, if not, copy general AimRange value to preserve compatibility - if (m_AimRangeUpperLimit == -1 || m_AimRangeLowerLimit == -1) - { - m_AimRangeUpperLimit = m_AimRange; - m_AimRangeLowerLimit = m_AimRange; - } - - return 0; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACrab object ready for use. - -int ACrab::Create(BITMAP *pSprite, - Controller *pController, - const float mass, - const Vector &position, - const Vector &velocity, - AtomGroup *hitBody, - const unsigned long lifetime, - Status status, - const int health) -{ - - - return Actor::Create(pSprite, - pController, - mass, - position, - velocity, - hitBody, - lifetime, - status, - health); -} -*/ + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACrab to be identical to another, by deep copy. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ACrab to be identical to another, by deep copy. - -int ACrab::Create(const ACrab &reference) { - if (reference.m_pLBGLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLBGLeg->GetUniqueID()); } - if (reference.m_pRBGLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRBGLeg->GetUniqueID()); } - if (reference.m_pJetpack) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pJetpack->GetUniqueID()); } - if (reference.m_pTurret) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pTurret->GetUniqueID()); } - if (reference.m_pLFGLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLFGLeg->GetUniqueID()); } - if (reference.m_pRFGLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRFGLeg->GetUniqueID()); } - - Actor::Create(reference); - - //Note - hardcoded attachable copying is organized based on desired draw order here. - if (reference.m_pLBGLeg) { SetLeftBGLeg(dynamic_cast(reference.m_pLBGLeg->Clone())); } - if (reference.m_pRBGLeg) { SetRightBGLeg(dynamic_cast(reference.m_pRBGLeg->Clone())); } - if (reference.m_pJetpack) { SetJetpack(dynamic_cast(reference.m_pJetpack->Clone())); } - if (reference.m_pTurret) { SetTurret(dynamic_cast(reference.m_pTurret->Clone())); } - if (reference.m_pLFGLeg) { SetLeftFGLeg(dynamic_cast(reference.m_pLFGLeg->Clone())); } - if (reference.m_pRFGLeg) { SetRightFGLeg(dynamic_cast(reference.m_pRFGLeg->Clone())); } - - AtomGroup *atomGroupToUseAsFootGroupLFG = reference.m_pLFGFootGroup ? dynamic_cast(reference.m_pLFGFootGroup->Clone()) : m_pLFGLeg->GetFootGroupFromFootAtomGroup(); - RTEAssert(atomGroupToUseAsFootGroupLFG, "Failed to fallback to using LFGFoot AtomGroup as LFGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a LFGFootGroup or LFGLeg Foot attachable!"); - - AtomGroup *atomGroupToUseAsFootGroupLBG = reference.m_pLBGFootGroup ? dynamic_cast(reference.m_pLBGFootGroup->Clone()) : m_pLBGLeg->GetFootGroupFromFootAtomGroup(); - RTEAssert(atomGroupToUseAsFootGroupLBG, "Failed to fallback to using LBGFoot AtomGroup as LBGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a LBGFootGroup or LBGLeg Foot attachable!"); - - AtomGroup *atomGroupToUseAsFootGroupRFG = reference.m_pRFGFootGroup ? dynamic_cast(reference.m_pRFGFootGroup->Clone()) : m_pRFGLeg->GetFootGroupFromFootAtomGroup(); - RTEAssert(atomGroupToUseAsFootGroupRFG, "Failed to fallback to using RFGFoot AtomGroup as RFGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a RFGFootGroup or RFGLeg Foot attachable!"); - - AtomGroup *atomGroupToUseAsFootGroupRBG = reference.m_pRBGFootGroup ? dynamic_cast(reference.m_pRBGFootGroup->Clone()) : m_pRBGLeg->GetFootGroupFromFootAtomGroup(); - RTEAssert(atomGroupToUseAsFootGroupRBG, "Failed to fallback to using RBGFoot AtomGroup as RBGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a RBGFootGroup or RBGLeg Foot attachable!"); - - m_pLFGFootGroup = atomGroupToUseAsFootGroupLFG; - m_pLFGFootGroup->SetOwner(this); - m_BackupLFGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupLFG->Clone()); - m_BackupLFGFootGroup->RemoveAllAtoms(); - m_BackupLFGFootGroup->SetOwner(this); - m_BackupLFGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); - m_pLBGFootGroup = atomGroupToUseAsFootGroupLBG; - m_pLBGFootGroup->SetOwner(this); - m_BackupLBGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupLBG->Clone()); - m_BackupLBGFootGroup->RemoveAllAtoms(); - m_BackupLBGFootGroup->SetOwner(this); - m_BackupLBGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); - m_pRFGFootGroup = atomGroupToUseAsFootGroupRFG; - m_pRFGFootGroup->SetOwner(this); - m_BackupRFGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupRFG->Clone()); - m_BackupRFGFootGroup->RemoveAllAtoms(); - m_BackupRFGFootGroup->SetOwner(this); - m_BackupRFGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); - m_pRBGFootGroup = atomGroupToUseAsFootGroupRBG; - m_pRBGFootGroup->SetOwner(this); - m_BackupRBGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupRBG->Clone()); - m_BackupRBGFootGroup->RemoveAllAtoms(); - m_BackupRBGFootGroup->SetOwner(this); - m_BackupRBGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); - - if (reference.m_StrideSound) { m_StrideSound = dynamic_cast(reference.m_StrideSound->Clone()); } - - m_MoveState = reference.m_MoveState; - - for (int side = 0; side < SIDECOUNT; ++side) { - for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { - m_Paths[side][FGROUND][i].Create(reference.m_Paths[side][FGROUND][i]); - m_Paths[side][BGROUND][i].Create(reference.m_Paths[side][BGROUND][i]); - } - } - - m_DeviceState = reference.m_DeviceState; - m_SweepState = reference.m_SweepState; - m_DigState = reference.m_DigState; - m_JumpState = reference.m_JumpState; - m_JumpTarget = reference.m_JumpTarget; - m_JumpingRight = reference.m_JumpingRight; - m_DigTunnelEndPos = reference.m_DigTunnelEndPos; - m_SweepCenterAimAngle = reference.m_SweepCenterAimAngle; - m_SweepRange = reference.m_SweepRange; - m_AimRangeUpperLimit = reference.m_AimRangeUpperLimit; - m_AimRangeLowerLimit = reference.m_AimRangeLowerLimit; - m_LockMouseAimInput = reference.m_LockMouseAimInput; - - return 0; -} + int ACrab::Create(const ACrab& reference) { + if (reference.m_pLBGLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLBGLeg->GetUniqueID()); + } + if (reference.m_pRBGLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRBGLeg->GetUniqueID()); + } + if (reference.m_pJetpack) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pJetpack->GetUniqueID()); + } + if (reference.m_pTurret) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pTurret->GetUniqueID()); + } + if (reference.m_pLFGLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pLFGLeg->GetUniqueID()); + } + if (reference.m_pRFGLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pRFGLeg->GetUniqueID()); + } + Actor::Create(reference); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int ACrab::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Actor::ReadProperty(propName, reader)); - - MatchProperty("Turret", { SetTurret(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("Jetpack", { SetJetpack(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("LFGLeg") MatchProperty("LeftFGLeg", { SetLeftFGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("LBGLeg") MatchProperty("LeftBGLeg", { SetLeftBGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("RFGLeg") MatchProperty("RightFGLeg", { SetRightFGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("RBGLeg") MatchProperty("RightBGLeg", { SetRightBGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchForwards("LFootGroup") MatchProperty("LeftFootGroup", { - delete m_pLFGFootGroup; - delete m_pLBGFootGroup; - delete m_BackupLFGFootGroup; - delete m_BackupLBGFootGroup; - m_pLFGFootGroup = new AtomGroup(); - m_pLBGFootGroup = new AtomGroup(); - reader >> m_pLFGFootGroup; - m_pLBGFootGroup->Create(*m_pLFGFootGroup); - m_pLFGFootGroup->SetOwner(this); - m_pLBGFootGroup->SetOwner(this); - m_BackupLFGFootGroup = new AtomGroup(*m_pLFGFootGroup); - m_BackupLFGFootGroup->RemoveAllAtoms(); - m_BackupLBGFootGroup = new AtomGroup(*m_BackupLFGFootGroup); - }); - MatchForwards("RFootGroup") MatchProperty("RightFootGroup", { - delete m_pRFGFootGroup; - delete m_pRBGFootGroup; - delete m_BackupRFGFootGroup; - delete m_BackupRBGFootGroup; - m_pRFGFootGroup = new AtomGroup(); - m_pRBGFootGroup = new AtomGroup(); - reader >> m_pRFGFootGroup; - m_pRBGFootGroup->Create(*m_pRFGFootGroup); - m_pRFGFootGroup->SetOwner(this); - m_pRBGFootGroup->SetOwner(this); - m_BackupRFGFootGroup = new AtomGroup(*m_pRFGFootGroup); - m_BackupRFGFootGroup->RemoveAllAtoms(); - m_BackupRBGFootGroup = new AtomGroup(*m_BackupRFGFootGroup); - }); - MatchForwards("LFGFootGroup") MatchProperty("LeftFGFootGroup", { - delete m_pLFGFootGroup; - delete m_BackupLFGFootGroup; - m_pLFGFootGroup = new AtomGroup(); - reader >> m_pLFGFootGroup; - m_pLFGFootGroup->SetOwner(this); - m_BackupLFGFootGroup = new AtomGroup(*m_pLFGFootGroup); - m_BackupLFGFootGroup->RemoveAllAtoms(); - }); - MatchForwards("LBGFootGroup") MatchProperty("LeftBGFootGroup", { - delete m_pLBGFootGroup; - delete m_BackupLBGFootGroup; - m_pLBGFootGroup = new AtomGroup(); - reader >> m_pLBGFootGroup; - m_pLBGFootGroup->SetOwner(this); - m_BackupLBGFootGroup = new AtomGroup(*m_pLBGFootGroup); - m_BackupLBGFootGroup->RemoveAllAtoms(); - }); - MatchForwards("RFGFootGroup") MatchProperty("RightFGFootGroup", { - delete m_pRFGFootGroup; - delete m_BackupRFGFootGroup; - m_pRFGFootGroup = new AtomGroup(); - reader >> m_pRFGFootGroup; - m_pRFGFootGroup->SetOwner(this); - m_BackupRFGFootGroup = new AtomGroup(*m_pRFGFootGroup); - m_BackupRFGFootGroup->RemoveAllAtoms(); - }); - MatchForwards("RBGFootGroup") MatchProperty("RightBGFootGroup", { - delete m_pRBGFootGroup; - delete m_BackupRBGFootGroup; - m_pRBGFootGroup = new AtomGroup(); - reader >> m_pRBGFootGroup; - m_pRBGFootGroup->SetOwner(this); - m_BackupRBGFootGroup = new AtomGroup(*m_pRBGFootGroup); - m_BackupRBGFootGroup->RemoveAllAtoms(); - }); - MatchProperty("StrideSound", { - m_StrideSound = new SoundContainer; - reader >> m_StrideSound; - }); - MatchForwards("LStandLimbPath") MatchProperty("LeftStandLimbPath", { reader >> m_Paths[LEFTSIDE][FGROUND][STAND]; }); - MatchForwards("LWalkLimbPath") MatchProperty("LeftWalkLimbPath", { reader >> m_Paths[LEFTSIDE][FGROUND][WALK]; }); - MatchForwards("LDislodgeLimbPath") MatchProperty("LeftDislodgeLimbPath", { reader >> m_Paths[LEFTSIDE][FGROUND][DISLODGE]; }); - MatchForwards("RStandLimbPath") MatchProperty("RightStandLimbPath", { reader >> m_Paths[RIGHTSIDE][FGROUND][STAND]; }); - MatchForwards("RWalkLimbPath") MatchProperty("RightWalkLimbPath", { reader >> m_Paths[RIGHTSIDE][FGROUND][WALK]; }); - MatchForwards("RDislodgeLimbPath") MatchProperty("RightDislodgeLimbPath", { reader >> m_Paths[RIGHTSIDE][FGROUND][DISLODGE]; }); - MatchProperty("AimRangeUpperLimit", { reader >> m_AimRangeUpperLimit; }); - MatchProperty("AimRangeLowerLimit", { reader >> m_AimRangeLowerLimit; }); - MatchProperty("LockMouseAimInput", { reader >> m_LockMouseAimInput; }); - - EndPropertyList; -} + // Note - hardcoded attachable copying is organized based on desired draw order here. + if (reference.m_pLBGLeg) { + SetLeftBGLeg(dynamic_cast(reference.m_pLBGLeg->Clone())); + } + if (reference.m_pRBGLeg) { + SetRightBGLeg(dynamic_cast(reference.m_pRBGLeg->Clone())); + } + if (reference.m_pJetpack) { + SetJetpack(dynamic_cast(reference.m_pJetpack->Clone())); + } + if (reference.m_pTurret) { + SetTurret(dynamic_cast(reference.m_pTurret->Clone())); + } + if (reference.m_pLFGLeg) { + SetLeftFGLeg(dynamic_cast(reference.m_pLFGLeg->Clone())); + } + if (reference.m_pRFGLeg) { + SetRightFGLeg(dynamic_cast(reference.m_pRFGLeg->Clone())); + } + AtomGroup* atomGroupToUseAsFootGroupLFG = reference.m_pLFGFootGroup ? dynamic_cast(reference.m_pLFGFootGroup->Clone()) : m_pLFGLeg->GetFootGroupFromFootAtomGroup(); + RTEAssert(atomGroupToUseAsFootGroupLFG, "Failed to fallback to using LFGFoot AtomGroup as LFGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a LFGFootGroup or LFGLeg Foot attachable!"); + + AtomGroup* atomGroupToUseAsFootGroupLBG = reference.m_pLBGFootGroup ? dynamic_cast(reference.m_pLBGFootGroup->Clone()) : m_pLBGLeg->GetFootGroupFromFootAtomGroup(); + RTEAssert(atomGroupToUseAsFootGroupLBG, "Failed to fallback to using LBGFoot AtomGroup as LBGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a LBGFootGroup or LBGLeg Foot attachable!"); + + AtomGroup* atomGroupToUseAsFootGroupRFG = reference.m_pRFGFootGroup ? dynamic_cast(reference.m_pRFGFootGroup->Clone()) : m_pRFGLeg->GetFootGroupFromFootAtomGroup(); + RTEAssert(atomGroupToUseAsFootGroupRFG, "Failed to fallback to using RFGFoot AtomGroup as RFGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a RFGFootGroup or RFGLeg Foot attachable!"); + + AtomGroup* atomGroupToUseAsFootGroupRBG = reference.m_pRBGFootGroup ? dynamic_cast(reference.m_pRBGFootGroup->Clone()) : m_pRBGLeg->GetFootGroupFromFootAtomGroup(); + RTEAssert(atomGroupToUseAsFootGroupRBG, "Failed to fallback to using RBGFoot AtomGroup as RBGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a RBGFootGroup or RBGLeg Foot attachable!"); + + m_pLFGFootGroup = atomGroupToUseAsFootGroupLFG; + m_pLFGFootGroup->SetOwner(this); + m_BackupLFGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupLFG->Clone()); + m_BackupLFGFootGroup->RemoveAllAtoms(); + m_BackupLFGFootGroup->SetOwner(this); + m_BackupLFGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); + m_pLBGFootGroup = atomGroupToUseAsFootGroupLBG; + m_pLBGFootGroup->SetOwner(this); + m_BackupLBGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupLBG->Clone()); + m_BackupLBGFootGroup->RemoveAllAtoms(); + m_BackupLBGFootGroup->SetOwner(this); + m_BackupLBGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); + m_pRFGFootGroup = atomGroupToUseAsFootGroupRFG; + m_pRFGFootGroup->SetOwner(this); + m_BackupRFGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupRFG->Clone()); + m_BackupRFGFootGroup->RemoveAllAtoms(); + m_BackupRFGFootGroup->SetOwner(this); + m_BackupRFGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); + m_pRBGFootGroup = atomGroupToUseAsFootGroupRBG; + m_pRBGFootGroup->SetOwner(this); + m_BackupRBGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupRBG->Clone()); + m_BackupRBGFootGroup->RemoveAllAtoms(); + m_BackupRBGFootGroup->SetOwner(this); + m_BackupRBGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupLFG->GetLimbPos()); + + if (reference.m_StrideSound) { + m_StrideSound = dynamic_cast(reference.m_StrideSound->Clone()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this ACrab with a Writer for -// later recreation with Create(Reader &reader); - -int ACrab::Save(Writer &writer) const -{ - Actor::Save(writer); - - writer.NewProperty("Turret"); - writer << m_pTurret; - writer.NewProperty("Jetpack"); - writer << m_pJetpack; - writer.NewProperty("LFGLeg"); - writer << m_pLFGLeg; - writer.NewProperty("LBGLeg"); - writer << m_pLBGLeg; - writer.NewProperty("RFGLeg"); - writer << m_pRFGLeg; - writer.NewProperty("RBGLeg"); - writer << m_pRBGLeg; - writer.NewProperty("LFGFootGroup"); - writer << m_pLFGFootGroup; - writer.NewProperty("LBGFootGroup"); - writer << m_pLBGFootGroup; - writer.NewProperty("RFGFootGroup"); - writer << m_pRFGFootGroup; - writer.NewProperty("RBGFootGroup"); - writer << m_pRBGFootGroup; - writer.NewProperty("StrideSound"); - writer << m_StrideSound; - - writer.NewProperty("LStandLimbPath"); - writer << m_Paths[LEFTSIDE][FGROUND][STAND]; - writer.NewProperty("LWalkLimbPath"); - writer << m_Paths[LEFTSIDE][FGROUND][WALK]; - writer.NewProperty("LDislodgeLimbPath"); - writer << m_Paths[LEFTSIDE][FGROUND][DISLODGE]; - writer.NewProperty("RStandLimbPath"); - writer << m_Paths[RIGHTSIDE][FGROUND][STAND]; - writer.NewProperty("RWalkLimbPath"); - writer << m_Paths[RIGHTSIDE][FGROUND][WALK]; - writer.NewProperty("RDislodgeLimbPath"); - writer << m_Paths[RIGHTSIDE][FGROUND][DISLODGE]; - - writer.NewProperty("AimRangeUpperLimit"); - writer << m_AimRangeUpperLimit; - writer.NewProperty("AimRangeLowerLimit"); - writer << m_AimRangeLowerLimit; - writer.NewProperty("LockMouseAimInput"); - writer << m_LockMouseAimInput; - - return 0; -} + m_MoveState = reference.m_MoveState; + for (int side = 0; side < SIDECOUNT; ++side) { + for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { + m_Paths[side][FGROUND][i].Create(reference.m_Paths[side][FGROUND][i]); + m_Paths[side][BGROUND][i].Create(reference.m_Paths[side][BGROUND][i]); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ACrab object. - -void ACrab::Destroy(bool notInherited) -{ - delete m_pLFGFootGroup; - delete m_pLBGFootGroup; - delete m_pRFGFootGroup; - delete m_pRBGFootGroup; - - delete m_StrideSound; -// for (deque::iterator itr = m_WalkPaths.begin(); -// itr != m_WalkPaths.end(); ++itr) -// delete *itr; - - if (!notInherited) - Actor::Destroy(); - Clear(); -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this Actor and all its carried -// gold and inventory. + m_DeviceState = reference.m_DeviceState; + m_SweepState = reference.m_SweepState; + m_DigState = reference.m_DigState; + m_JumpState = reference.m_JumpState; + m_JumpTarget = reference.m_JumpTarget; + m_JumpingRight = reference.m_JumpingRight; + m_DigTunnelEndPos = reference.m_DigTunnelEndPos; + m_SweepCenterAimAngle = reference.m_SweepCenterAimAngle; + m_SweepRange = reference.m_SweepRange; + m_AimRangeUpperLimit = reference.m_AimRangeUpperLimit; + m_AimRangeLowerLimit = reference.m_AimRangeLowerLimit; + m_LockMouseAimInput = reference.m_LockMouseAimInput; + + return 0; + } -float ACrab::GetTotalValue(int nativeModule, float foreignMult) const -{ - float totalValue = Actor::GetTotalValue(nativeModule, foreignMult); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int ACrab::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Actor::ReadProperty(propName, reader)); + + MatchProperty("Turret", { SetTurret(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("Jetpack", { SetJetpack(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("LFGLeg") MatchProperty("LeftFGLeg", { SetLeftFGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("LBGLeg") MatchProperty("LeftBGLeg", { SetLeftBGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("RFGLeg") MatchProperty("RightFGLeg", { SetRightFGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("RBGLeg") MatchProperty("RightBGLeg", { SetRightBGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchForwards("LFootGroup") MatchProperty("LeftFootGroup", { + delete m_pLFGFootGroup; + delete m_pLBGFootGroup; + delete m_BackupLFGFootGroup; + delete m_BackupLBGFootGroup; + m_pLFGFootGroup = new AtomGroup(); + m_pLBGFootGroup = new AtomGroup(); + reader >> m_pLFGFootGroup; + m_pLBGFootGroup->Create(*m_pLFGFootGroup); + m_pLFGFootGroup->SetOwner(this); + m_pLBGFootGroup->SetOwner(this); + m_BackupLFGFootGroup = new AtomGroup(*m_pLFGFootGroup); + m_BackupLFGFootGroup->RemoveAllAtoms(); + m_BackupLBGFootGroup = new AtomGroup(*m_BackupLFGFootGroup); + }); + MatchForwards("RFootGroup") MatchProperty("RightFootGroup", { + delete m_pRFGFootGroup; + delete m_pRBGFootGroup; + delete m_BackupRFGFootGroup; + delete m_BackupRBGFootGroup; + m_pRFGFootGroup = new AtomGroup(); + m_pRBGFootGroup = new AtomGroup(); + reader >> m_pRFGFootGroup; + m_pRBGFootGroup->Create(*m_pRFGFootGroup); + m_pRFGFootGroup->SetOwner(this); + m_pRBGFootGroup->SetOwner(this); + m_BackupRFGFootGroup = new AtomGroup(*m_pRFGFootGroup); + m_BackupRFGFootGroup->RemoveAllAtoms(); + m_BackupRBGFootGroup = new AtomGroup(*m_BackupRFGFootGroup); + }); + MatchForwards("LFGFootGroup") MatchProperty("LeftFGFootGroup", { + delete m_pLFGFootGroup; + delete m_BackupLFGFootGroup; + m_pLFGFootGroup = new AtomGroup(); + reader >> m_pLFGFootGroup; + m_pLFGFootGroup->SetOwner(this); + m_BackupLFGFootGroup = new AtomGroup(*m_pLFGFootGroup); + m_BackupLFGFootGroup->RemoveAllAtoms(); + }); + MatchForwards("LBGFootGroup") MatchProperty("LeftBGFootGroup", { + delete m_pLBGFootGroup; + delete m_BackupLBGFootGroup; + m_pLBGFootGroup = new AtomGroup(); + reader >> m_pLBGFootGroup; + m_pLBGFootGroup->SetOwner(this); + m_BackupLBGFootGroup = new AtomGroup(*m_pLBGFootGroup); + m_BackupLBGFootGroup->RemoveAllAtoms(); + }); + MatchForwards("RFGFootGroup") MatchProperty("RightFGFootGroup", { + delete m_pRFGFootGroup; + delete m_BackupRFGFootGroup; + m_pRFGFootGroup = new AtomGroup(); + reader >> m_pRFGFootGroup; + m_pRFGFootGroup->SetOwner(this); + m_BackupRFGFootGroup = new AtomGroup(*m_pRFGFootGroup); + m_BackupRFGFootGroup->RemoveAllAtoms(); + }); + MatchForwards("RBGFootGroup") MatchProperty("RightBGFootGroup", { + delete m_pRBGFootGroup; + delete m_BackupRBGFootGroup; + m_pRBGFootGroup = new AtomGroup(); + reader >> m_pRBGFootGroup; + m_pRBGFootGroup->SetOwner(this); + m_BackupRBGFootGroup = new AtomGroup(*m_pRBGFootGroup); + m_BackupRBGFootGroup->RemoveAllAtoms(); + }); + MatchProperty("StrideSound", { + m_StrideSound = new SoundContainer; + reader >> m_StrideSound; + }); + MatchForwards("LStandLimbPath") MatchProperty("LeftStandLimbPath", { reader >> m_Paths[LEFTSIDE][FGROUND][STAND]; }); + MatchForwards("LWalkLimbPath") MatchProperty("LeftWalkLimbPath", { reader >> m_Paths[LEFTSIDE][FGROUND][WALK]; }); + MatchForwards("LDislodgeLimbPath") MatchProperty("LeftDislodgeLimbPath", { reader >> m_Paths[LEFTSIDE][FGROUND][DISLODGE]; }); + MatchForwards("RStandLimbPath") MatchProperty("RightStandLimbPath", { reader >> m_Paths[RIGHTSIDE][FGROUND][STAND]; }); + MatchForwards("RWalkLimbPath") MatchProperty("RightWalkLimbPath", { reader >> m_Paths[RIGHTSIDE][FGROUND][WALK]; }); + MatchForwards("RDislodgeLimbPath") MatchProperty("RightDislodgeLimbPath", { reader >> m_Paths[RIGHTSIDE][FGROUND][DISLODGE]; }); + MatchProperty("AimRangeUpperLimit", { reader >> m_AimRangeUpperLimit; }); + MatchProperty("AimRangeLowerLimit", { reader >> m_AimRangeLowerLimit; }); + MatchProperty("LockMouseAimInput", { reader >> m_LockMouseAimInput; }); + + EndPropertyList; + } - return totalValue; -} -*/ -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetCPUPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' brain, or equivalent. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this ACrab with a Writer for + // later recreation with Create(Reader &reader); + + int ACrab::Save(Writer& writer) const { + Actor::Save(writer); + + writer.NewProperty("Turret"); + writer << m_pTurret; + writer.NewProperty("Jetpack"); + writer << m_pJetpack; + writer.NewProperty("LFGLeg"); + writer << m_pLFGLeg; + writer.NewProperty("LBGLeg"); + writer << m_pLBGLeg; + writer.NewProperty("RFGLeg"); + writer << m_pRFGLeg; + writer.NewProperty("RBGLeg"); + writer << m_pRBGLeg; + writer.NewProperty("LFGFootGroup"); + writer << m_pLFGFootGroup; + writer.NewProperty("LBGFootGroup"); + writer << m_pLBGFootGroup; + writer.NewProperty("RFGFootGroup"); + writer << m_pRFGFootGroup; + writer.NewProperty("RBGFootGroup"); + writer << m_pRBGFootGroup; + writer.NewProperty("StrideSound"); + writer << m_StrideSound; + + writer.NewProperty("LStandLimbPath"); + writer << m_Paths[LEFTSIDE][FGROUND][STAND]; + writer.NewProperty("LWalkLimbPath"); + writer << m_Paths[LEFTSIDE][FGROUND][WALK]; + writer.NewProperty("LDislodgeLimbPath"); + writer << m_Paths[LEFTSIDE][FGROUND][DISLODGE]; + writer.NewProperty("RStandLimbPath"); + writer << m_Paths[RIGHTSIDE][FGROUND][STAND]; + writer.NewProperty("RWalkLimbPath"); + writer << m_Paths[RIGHTSIDE][FGROUND][WALK]; + writer.NewProperty("RDislodgeLimbPath"); + writer << m_Paths[RIGHTSIDE][FGROUND][DISLODGE]; + + writer.NewProperty("AimRangeUpperLimit"); + writer << m_AimRangeUpperLimit; + writer.NewProperty("AimRangeLowerLimit"); + writer << m_AimRangeLowerLimit; + writer.NewProperty("LockMouseAimInput"); + writer << m_LockMouseAimInput; + + return 0; + } -Vector ACrab::GetCPUPos() const -{ - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->GetMountedMO()) - return m_pTurret->GetMountedMO()->GetPos(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ACrab object. + + void ACrab::Destroy(bool notInherited) { + delete m_pLFGFootGroup; + delete m_pLBGFootGroup; + delete m_pRFGFootGroup; + delete m_pRBGFootGroup; + + delete m_StrideSound; + // for (deque::iterator itr = m_WalkPaths.begin(); + // itr != m_WalkPaths.end(); ++itr) + // delete *itr; + + if (!notInherited) + Actor::Destroy(); + Clear(); + } - return m_Pos; -} -*/ + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this Actor and all its carried + // gold and inventory. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEyePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' eye, or equivalent, where look -// vector starts from. - -Vector ACrab::GetEyePos() const -{ - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - return m_pTurret->GetFirstMountedDevice()->GetPos(); - - return m_Pos; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACrab::SetTurret(Turret *newTurret) { - if (m_pTurret && m_pTurret->IsAttached()) { RemoveAndDeleteAttachable(m_pTurret); } - if (newTurret == nullptr) { - m_pTurret = nullptr; - } else { - m_pTurret = newTurret; - AddAttachable(newTurret); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newTurret->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Turret *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetTurret"); - dynamic_cast(parent)->SetTurret(castedAttachable); - }}); - - if (m_pTurret->HasNoSetDamageMultiplier()) { m_pTurret->SetDamageMultiplier(5.0F); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACrab::SetJetpack(AEJetpack *newJetpack) { - if (m_pJetpack && m_pJetpack->IsAttached()) { RemoveAndDeleteAttachable(m_pJetpack); } - if (newJetpack == nullptr) { - m_pJetpack = nullptr; - } else { - m_pJetpack = newJetpack; - AddAttachable(newJetpack); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newJetpack->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEJetpack *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetJetpack"); - dynamic_cast(parent)->SetJetpack(castedAttachable); - }}); - - if (m_pJetpack->HasNoSetDamageMultiplier()) { m_pJetpack->SetDamageMultiplier(0.0F); } - m_pJetpack->SetApplyTransferredForcesAtOffset(false); - m_pJetpack->SetDeleteWhenRemovedFromParent(true); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACrab::SetLeftFGLeg(Leg *newLeg) { - if (m_pLFGLeg && m_pLFGLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pLFGLeg); } - if (newLeg == nullptr) { - m_pLFGLeg = nullptr; - } else { - m_pLFGLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftFGLeg"); - dynamic_cast(parent)->SetLeftFGLeg(castedAttachable); - }}); - - if (m_pLFGLeg->HasNoSetDamageMultiplier()) { m_pLFGLeg->SetDamageMultiplier(1.0F); } - m_pLFGLeg->SetInheritsHFlipped(-1); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACrab::SetLeftBGLeg(Leg *newLeg) { - if (m_pLBGLeg && m_pLBGLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pLBGLeg); } - if (newLeg == nullptr) { - m_pLBGLeg = nullptr; - } else { - m_pLBGLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftBGLeg"); - dynamic_cast(parent)->SetLeftBGLeg(castedAttachable); - }}); - - if (m_pLBGLeg->HasNoSetDamageMultiplier()) { m_pLBGLeg->SetDamageMultiplier(1.0F); } - m_pLBGLeg->SetInheritsHFlipped(-1); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACrab::SetRightFGLeg(Leg *newLeg) { - if (m_pRFGLeg && m_pRFGLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pRFGLeg); } - if (newLeg == nullptr) { - m_pRFGLeg = nullptr; - } else { - m_pRFGLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightFGLeg"); - dynamic_cast(parent)->SetRightFGLeg(castedAttachable); - }}); - - if (m_pRFGLeg->HasNoSetDamageMultiplier()) { m_pRFGLeg->SetDamageMultiplier(1.0F); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACrab::SetRightBGLeg(Leg *newLeg) { - if (m_pRBGLeg && m_pRBGLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pRBGLeg); } - if (newLeg == nullptr) { - m_pRBGLeg = nullptr; - } else { - m_pRBGLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightBGLeg"); - dynamic_cast(parent)->SetRightBGLeg(castedAttachable); - }}); - - if (m_pRBGLeg->HasNoSetDamageMultiplier()) { m_pRBGLeg->SetDamageMultiplier(1.0F); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -BITMAP * ACrab::GetGraphicalIcon() const { - return m_GraphicalIcon ? m_GraphicalIcon : (m_pTurret ? m_pTurret->GetSpriteFrame(0) : GetSpriteFrame(0)); -} + float ACrab::GetTotalValue(int nativeModule, float foreignMult) const + { + float totalValue = Actor::GetTotalValue(nativeModule, foreignMult); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. - -bool ACrab::CollideAtPoint(HitData &hd) -{ - return Actor::CollideAtPoint(hd); - -/* - hd.ResImpulse[HITOR].Reset(); - hd.ResImpulse[HITEE].Reset(); - hd.HitRadius[HITEE] = (hd.HitPoint - m_Pos) * c_MPP; - hd.mass[HITEE] = m_Mass; - hd.MomInertia[HITEE] = m_pAtomGroup->GetMomentOfInertia(); - hd.HitVel[HITEE] = m_Vel + hd.HitRadius[HITEE].GetPerpendicular() * m_AngularVel; - hd.VelDiff = hd.HitVel[HITOR] - hd.HitVel[HITEE]; - Vector hitAcc = -hd.VelDiff * (1 + hd.Body[HITOR]->GetMaterial().restitution * GetMaterial().restitution); - - float hittorLever = hd.HitRadius[HITOR].GetPerpendicular().Dot(hd.BitmapNormal); - float hitteeLever = hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.BitmapNormal); - hittorLever *= hittorLever; - hitteeLever *= hitteeLever; - float impulse = hitAcc.Dot(hd.BitmapNormal) / (((1 / hd.mass[HITOR]) + (1 / hd.mass[HITEE])) + - (hittorLever / hd.MomInertia[HITOR]) + (hitteeLever / hd.MomInertia[HITEE])); - - hd.ResImpulse[HITOR] = hd.BitmapNormal * impulse * hd.ImpulseFactor[HITOR]; - hd.ResImpulse[HITEE] = hd.BitmapNormal * -impulse * hd.ImpulseFactor[HITEE]; - - //////////////////////////////////////////////////////////////////////////////// - // If a particle, which does not penetrate, but bounces, do any additional - // effects of that bounce. - if (!ParticlePenetration()) -// TODO: Add blunt trauma effects here!") - ; - } - - m_Vel += hd.ResImpulse[HITEE] / hd.mass[HITEE]; - m_AngularVel += hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.ResImpulse[HITEE]) / - hd.MomInertia[HITEE]; -*/ -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnBounce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// bounces off of something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. + return totalValue; + } + */ + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetCPUPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' brain, or equivalent. + + Vector ACrab::GetCPUPos() const + { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->GetMountedMO()) + return m_pTurret->GetMountedMO()->GetPos(); + + return m_Pos; + } + */ -bool ACrab::OnBounce(const Vector &pos) -{ - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEyePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' eye, or equivalent, where look + // vector starts from. + Vector ACrab::GetEyePos() const { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) + return m_pTurret->GetFirstMountedDevice()->GetPos(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnSink -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// sink into something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. - -bool ACrab::OnSink(const Vector &pos) -{ - return false; -} -*/ - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool ACrab::HandlePieCommand(PieSlice::SliceType pieSliceIndex) { - if (pieSliceIndex != PieSlice::SliceType::NoType) { - if (pieSliceIndex == PieSlice::SliceType::Reload) { - m_Controller.SetState(WEAPON_RELOAD); - } else if (pieSliceIndex == PieSlice::SliceType::Sentry) { - m_AIMode = AIMODE_SENTRY; - } else if (pieSliceIndex == PieSlice::SliceType::Patrol) { - m_AIMode = AIMODE_PATROL; - } else if (pieSliceIndex == PieSlice::SliceType::BrainHunt) { - m_AIMode = AIMODE_BRAINHUNT; - ClearAIWaypoints(); - } else if (pieSliceIndex == PieSlice::SliceType::GoTo) { - m_AIMode = AIMODE_GOTO; - ClearAIWaypoints(); - m_UpdateMovePath = true; - } else { - return Actor::HandlePieCommand(pieSliceIndex); - } - } - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return m_Pos; + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: GetEquippedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whatever is equipped in the turret, if anything. OWNERSHIP IS NOT TRANSFERRED! + void ACrab::SetTurret(Turret* newTurret) { + if (m_pTurret && m_pTurret->IsAttached()) { + RemoveAndDeleteAttachable(m_pTurret); + } + if (newTurret == nullptr) { + m_pTurret = nullptr; + } else { + m_pTurret = newTurret; + AddAttachable(newTurret); -MovableObject * ACrab::GetEquippedItem() const -{ - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - { - return m_pTurret->GetFirstMountedDevice(); - } + m_HardcodedAttachableUniqueIDsAndSetters.insert({newTurret->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Turret* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetTurret"); + dynamic_cast(parent)->SetTurret(castedAttachable); + }}); - return 0; -} + if (m_pTurret->HasNoSetDamageMultiplier()) { + m_pTurret->SetDamageMultiplier(5.0F); + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmIsReady -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held device's current mag is empty on -// ammo or not. + void ACrab::SetJetpack(AEJetpack* newJetpack) { + if (m_pJetpack && m_pJetpack->IsAttached()) { + RemoveAndDeleteAttachable(m_pJetpack); + } + if (newJetpack == nullptr) { + m_pJetpack = nullptr; + } else { + m_pJetpack = newJetpack; + AddAttachable(newJetpack); -bool ACrab::FirearmIsReady() const { - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { - for (const HeldDevice *mountedDevice : m_pTurret->GetMountedDevices()) { - if (const HDFirearm *mountedFirearm = dynamic_cast(mountedDevice); mountedFirearm && mountedFirearm->GetRoundInMagCount() != 0) { - return true; - } - } - } + m_HardcodedAttachableUniqueIDsAndSetters.insert({newJetpack->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEJetpack* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetJetpack"); + dynamic_cast(parent)->SetJetpack(castedAttachable); + }}); - return false; -} + if (m_pJetpack->HasNoSetDamageMultiplier()) { + m_pJetpack->SetDamageMultiplier(0.0F); + } + m_pJetpack->SetApplyTransferredForcesAtOffset(false); + m_pJetpack->SetDeleteWhenRemovedFromParent(true); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmIsEmpty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is out of ammo. + void ACrab::SetLeftFGLeg(Leg* newLeg) { + if (m_pLFGLeg && m_pLFGLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pLFGLeg); + } + if (newLeg == nullptr) { + m_pLFGLeg = nullptr; + } else { + m_pLFGLeg = newLeg; + AddAttachable(newLeg); -bool ACrab::FirearmIsEmpty() const { - return !FirearmIsReady() && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice(); -} + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftFGLeg"); + dynamic_cast(parent)->SetLeftFGLeg(castedAttachable); + }}); + if (m_pLFGLeg->HasNoSetDamageMultiplier()) { + m_pLFGLeg->SetDamageMultiplier(1.0F); + } + m_pLFGLeg->SetInheritsHFlipped(-1); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmNeedsReload -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is almost out of ammo. - -bool ACrab::FirearmsAreFull() const { - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { - for (const HeldDevice *mountedDevice : m_pTurret->GetMountedDevices()) { - if (const HDFirearm *mountedFirearm = dynamic_cast(mountedDevice); mountedFirearm && !mountedFirearm->IsFull()) { - return false; - } - } - } - return true; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// + void ACrab::SetLeftBGLeg(Leg* newLeg) { + if (m_pLBGLeg && m_pLBGLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pLBGLeg); + } + if (newLeg == nullptr) { + m_pLBGLeg = nullptr; + } else { + m_pLBGLeg = newLeg; + AddAttachable(newLeg); -bool ACrab::FirearmNeedsReload() const { - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { - for (const HeldDevice *mountedDevice : m_pTurret->GetMountedDevices()) { - if (const HDFirearm *mountedFirearm = dynamic_cast(mountedDevice); mountedFirearm && mountedFirearm->NeedsReloading()) { - return true; - } - } - } + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetLeftBGLeg"); + dynamic_cast(parent)->SetLeftBGLeg(castedAttachable); + }}); - return false; -} + if (m_pLBGLeg->HasNoSetDamageMultiplier()) { + m_pLBGLeg->SetDamageMultiplier(1.0F); + } + m_pLBGLeg->SetInheritsHFlipped(-1); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmIsSemiAuto -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is semi or full auto. + void ACrab::SetRightFGLeg(Leg* newLeg) { + if (m_pRFGLeg && m_pRFGLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pRFGLeg); + } + if (newLeg == nullptr) { + m_pRFGLeg = nullptr; + } else { + m_pRFGLeg = newLeg; + AddAttachable(newLeg); -bool ACrab::FirearmIsSemiAuto() const -{ - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - { - HDFirearm *pWeapon = dynamic_cast(m_pTurret->GetFirstMountedDevice()); - return pWeapon && !pWeapon->IsFullAuto(); - } - return false; -} + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightFGLeg"); + dynamic_cast(parent)->SetRightFGLeg(castedAttachable); + }}); + if (m_pRFGLeg->HasNoSetDamageMultiplier()) { + m_pRFGLeg->SetDamageMultiplier(1.0F); + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: ReloadFirearms -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the currently held firearms, if any. -// Arguments: None. -// Return value: None. - -void ACrab::ReloadFirearms() { - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { - for (HeldDevice *mountedDevice : m_pTurret->GetMountedDevices()) { - if (HDFirearm *mountedFirearm = dynamic_cast(mountedDevice)) { - mountedFirearm->Reload(); - } - } - } -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmActivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the currently held device's delay between pulling the trigger -// and activating. + void ACrab::SetRightBGLeg(Leg* newLeg) { + if (m_pRBGLeg && m_pRBGLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pRBGLeg); + } + if (newLeg == nullptr) { + m_pRBGLeg = nullptr; + } else { + m_pRBGLeg = newLeg; + AddAttachable(newLeg); -int ACrab::FirearmActivationDelay() const -{ - // Check if the currently held device is already the desired type - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - { - HDFirearm *pWeapon = dynamic_cast(m_pTurret->GetFirstMountedDevice()); - if (pWeapon) - return pWeapon->GetActivationDelay(); - } + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetRightBGLeg"); + dynamic_cast(parent)->SetRightBGLeg(castedAttachable); + }}); - return 0; -} + if (m_pRBGLeg->HasNoSetDamageMultiplier()) { + m_pRBGLeg->SetDamageMultiplier(1.0F); + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsWithinRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a point on the scene is within range of the currently -// used device and aiming status, if applicable. + BITMAP* ACrab::GetGraphicalIcon() const { + return m_GraphicalIcon ? m_GraphicalIcon : (m_pTurret ? m_pTurret->GetSpriteFrame(0) : GetSpriteFrame(0)); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + + bool ACrab::CollideAtPoint(HitData& hd) { + return Actor::CollideAtPoint(hd); + + /* + hd.ResImpulse[HITOR].Reset(); + hd.ResImpulse[HITEE].Reset(); + hd.HitRadius[HITEE] = (hd.HitPoint - m_Pos) * c_MPP; + hd.mass[HITEE] = m_Mass; + hd.MomInertia[HITEE] = m_pAtomGroup->GetMomentOfInertia(); + hd.HitVel[HITEE] = m_Vel + hd.HitRadius[HITEE].GetPerpendicular() * m_AngularVel; + hd.VelDiff = hd.HitVel[HITOR] - hd.HitVel[HITEE]; + Vector hitAcc = -hd.VelDiff * (1 + hd.Body[HITOR]->GetMaterial().restitution * GetMaterial().restitution); + + float hittorLever = hd.HitRadius[HITOR].GetPerpendicular().Dot(hd.BitmapNormal); + float hitteeLever = hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.BitmapNormal); + hittorLever *= hittorLever; + hitteeLever *= hitteeLever; + float impulse = hitAcc.Dot(hd.BitmapNormal) / (((1 / hd.mass[HITOR]) + (1 / hd.mass[HITEE])) + + (hittorLever / hd.MomInertia[HITOR]) + (hitteeLever / hd.MomInertia[HITEE])); + + hd.ResImpulse[HITOR] = hd.BitmapNormal * impulse * hd.ImpulseFactor[HITOR]; + hd.ResImpulse[HITEE] = hd.BitmapNormal * -impulse * hd.ImpulseFactor[HITEE]; + + //////////////////////////////////////////////////////////////////////////////// + // If a particle, which does not penetrate, but bounces, do any additional + // effects of that bounce. + if (!ParticlePenetration()) + // TODO: Add blunt trauma effects here!") + ; + } + + m_Vel += hd.ResImpulse[HITEE] / hd.mass[HITEE]; + m_AngularVel += hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.ResImpulse[HITEE]) / + hd.MomInertia[HITEE]; + */ + } -bool ACrab::IsWithinRange(Vector &point) const -{ - if (m_SharpAimMaxedOut) - return true; + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnBounce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // bounces off of something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. + + bool ACrab::OnBounce(const Vector &pos) + { + return false; + } - Vector diff = g_SceneMan.ShortestDistance(m_Pos, point, false); - float sqrDistance = diff.GetSqrMagnitude(); - // Really close! - if (sqrDistance <= (m_CharHeight * m_CharHeight)) { - return true; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnSink + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // sink into something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. + + bool ACrab::OnSink(const Vector &pos) + { + return false; + } + */ + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool ACrab::HandlePieCommand(PieSlice::SliceType pieSliceIndex) { + if (pieSliceIndex != PieSlice::SliceType::NoType) { + if (pieSliceIndex == PieSlice::SliceType::Reload) { + m_Controller.SetState(WEAPON_RELOAD); + } else if (pieSliceIndex == PieSlice::SliceType::Sentry) { + m_AIMode = AIMODE_SENTRY; + } else if (pieSliceIndex == PieSlice::SliceType::Patrol) { + m_AIMode = AIMODE_PATROL; + } else if (pieSliceIndex == PieSlice::SliceType::BrainHunt) { + m_AIMode = AIMODE_BRAINHUNT; + ClearAIWaypoints(); + } else if (pieSliceIndex == PieSlice::SliceType::GoTo) { + m_AIMode = AIMODE_GOTO; + ClearAIWaypoints(); + m_UpdateMovePath = true; + } else { + return Actor::HandlePieCommand(pieSliceIndex); + } + } + return false; } - // Start with the default aim distance - float range = m_AimDistance; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Add the sharp range of the equipped weapon - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - { - range += m_pTurret->GetFirstMountedDevice()->GetSharpLength() * m_SharpAimProgress; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: GetEquippedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whatever is equipped in the turret, if anything. OWNERSHIP IS NOT TRANSFERRED! - return sqrDistance <= (range * range); -} + MovableObject* ACrab::GetEquippedItem() const { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + return m_pTurret->GetFirstMountedDevice(); + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Look -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an unseen-revealing ray in the direction of where this is facing. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. - -bool ACrab::Look(float FOVSpread, float range) -{ - if (!g_SceneMan.AnythingUnseen(m_Team)) - return false; - - // Set the length of the look vector - float aimDistance = m_AimDistance + range; - Vector aimPos = GetCPUPos(); - - // If aiming down the barrel, look through that - if (m_Controller.IsState(AIM_SHARP) && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - { - aimPos = m_pTurret->GetFirstMountedDevice()->GetPos(); - aimDistance += m_pTurret->GetFirstMountedDevice()->GetSharpLength(); - } - // If just looking, use the sensors on the turret instead - else if (m_pTurret && m_pTurret->IsAttached()) - { - aimPos = GetEyePos(); - } - - // Create the vector to trace along - Vector lookVector(aimDistance, 0); - // Set the rotation to the actual aiming angle - Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); - aimMatrix.SetXFlipped(m_HFlipped); - lookVector *= aimMatrix; - // Add the spread - lookVector.DegRotate(FOVSpread * RandomNormalNum()); - - // TODO: generate an alarm event if we spot an enemy actor? - - Vector ignored; - // Cast the seeing ray, adjusting the skip to match the resolution of the unseen map - return g_SceneMan.CastSeeRay(m_Team, aimPos, lookVector, ignored, 25, (int)g_SceneMan.GetUnseenResolution(m_Team).GetSmallest() / 2); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmIsReady + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held device's current mag is empty on + // ammo or not. + + bool ACrab::FirearmIsReady() const { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + for (const HeldDevice* mountedDevice: m_pTurret->GetMountedDevices()) { + if (const HDFirearm* mountedFirearm = dynamic_cast(mountedDevice); mountedFirearm && mountedFirearm->GetRoundInMagCount() != 0) { + return true; + } + } + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: LookForMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an MO detecting ray in the direction of where the head is looking -// at the time. Factors including head rotation, sharp aim mode, and -// other variables determine how this ray is cast. - -MovableObject * ACrab::LookForMOs(float FOVSpread, unsigned char ignoreMaterial, bool ignoreAllTerrain) -{ - MovableObject *pSeenMO = 0; - Vector aimPos = m_Pos; - float aimDistance = m_AimDistance + g_FrameMan.GetPlayerScreenWidth() * 0.51; // Set the length of the look vector - - // If aiming down the barrel, look through that - if (m_Controller.IsState(AIM_SHARP) && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - { - aimPos = m_pTurret->GetFirstMountedDevice()->GetPos(); - aimDistance += m_pTurret->GetFirstMountedDevice()->GetSharpLength(); - } - // If just looking, use the sensors on the turret instead - else if (m_pTurret && m_pTurret->IsAttached()) - aimPos = GetEyePos(); - // If no turret... - else - aimPos = GetCPUPos(); - - // Create the vector to trace along - Vector lookVector(aimDistance, 0); - // Set the rotation to the actual aiming angle - Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); - aimMatrix.SetXFlipped(m_HFlipped); - lookVector *= aimMatrix; - // Add the spread - lookVector.DegRotate(FOVSpread * RandomNormalNum()); - - MOID seenMOID = g_SceneMan.CastMORay(aimPos, lookVector, m_MOID, IgnoresWhichTeam(), ignoreMaterial, ignoreAllTerrain, 5); - pSeenMO = g_MovableMan.GetMOFromID(seenMOID); - if (pSeenMO) - return pSeenMO->GetRootParent(); - - return pSeenMO; -} - -void ACrab::OnNewMovePath() -{ - Actor::OnNewMovePath(); - - // Process the new path we now have, if any - if (!m_MovePath.empty()) - { - // Smash all airborne waypoints down to just above the ground, except for when it makes the path intersect terrain or it is the final destination - std::list::iterator finalItr = m_MovePath.end(); - finalItr--; - Vector smashedPoint; - Vector previousPoint = *(m_MovePath.begin()); - std::list::iterator nextItr = m_MovePath.begin(); - for (std::list::iterator lItr = m_MovePath.begin(); lItr != finalItr; ++lItr) - { - nextItr++; - smashedPoint = g_SceneMan.MovePointToGround((*lItr), m_CharHeight*0.2, 7); - - // Only smash if the new location doesn't cause the path to intersect hard terrain ahead or behind of it - // Try three times to halve the height to see if that won't intersect - for (int i = 0; i < 3; i++) - { - Vector notUsed; - if (!g_SceneMan.CastStrengthRay(previousPoint, smashedPoint - previousPoint, 5, notUsed, 3, g_MaterialDoor) && - nextItr != m_MovePath.end() && !g_SceneMan.CastStrengthRay(smashedPoint, (*nextItr) - smashedPoint, 5, notUsed, 3, g_MaterialDoor)) - { - (*lItr) = smashedPoint; - break; - } - else - smashedPoint.m_Y -= ((smashedPoint.m_Y - (*lItr).m_Y) / 2); - } - - previousPoint = (*lItr); - } - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmIsEmpty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is out of ammo. -////////////////////////////////////////////////////////////////////////////////////////// + bool ACrab::FirearmIsEmpty() const { + return !FirearmIsReady() && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice(); + } -void ACrab::PreControllerUpdate() -{ - ZoneScoped; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmNeedsReload + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is almost out of ammo. - Actor::PreControllerUpdate(); + bool ACrab::FirearmsAreFull() const { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + for (const HeldDevice* mountedDevice: m_pTurret->GetMountedDevices()) { + if (const HDFirearm* mountedFirearm = dynamic_cast(mountedDevice); mountedFirearm && !mountedFirearm->IsFull()) { + return false; + } + } + } + return true; + } - float deltaTime = g_TimerMan.GetDeltaTimeSecs(); - float mass = GetMass(); + ////////////////////////////////////////////////////////////////////////////////////////// - Vector analogAim = m_Controller.GetAnalogAim(); - const float analogAimDeadzone = 0.1F; + bool ACrab::FirearmNeedsReload() const { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + for (const HeldDevice* mountedDevice: m_pTurret->GetMountedDevices()) { + if (const HDFirearm* mountedFirearm = dynamic_cast(mountedDevice); mountedFirearm && mountedFirearm->NeedsReloading()) { + return true; + } + } + } - // Set Default direction of all the paths! - for (int side = 0; side < SIDECOUNT; ++side) - { - for (int layer = 0; layer < LAYERCOUNT; ++layer) - { - m_Paths[side][layer][WALK].SetHFlip(m_HFlipped); - m_Paths[side][layer][STAND].SetHFlip(m_HFlipped); - } - } + return false; + } - if (m_pJetpack && m_pJetpack->IsAttached()) { - m_pJetpack->UpdateBurstState(*this); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmIsSemiAuto + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is semi or full auto. + + bool ACrab::FirearmIsSemiAuto() const { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + HDFirearm* pWeapon = dynamic_cast(m_pTurret->GetFirstMountedDevice()); + return pWeapon && !pWeapon->IsFullAuto(); + } + return false; } - //////////////////////////////////// - // Movement direction - const float movementThreshold = 1.0F; - bool isStill = (m_Vel + m_PrevVel).MagnitudeIsLessThan(movementThreshold); - - // If the pie menu is on, try to preserve whatever move state we had before it going into effect. - // This is only done for digital input, where the user needs to use the keyboard to choose pie slices. - // For analog input, this doesn't matter - the mouse or aiming analog stick controls the pie menu. - bool keepOldState = m_Controller.IsKeyboardOnlyControlled() && m_Controller.IsState(PIE_MENU_ACTIVE); - - if (!keepOldState) { - if (m_Controller.IsState(MOVE_RIGHT) || m_Controller.IsState(MOVE_LEFT) || m_MoveState == JUMP && m_Status != INACTIVE) { - if (m_MoveState != JUMP) - { - // Restart the stride if we're just starting to walk or crawl - if (m_MoveState != WALK) - { - m_StrideStart[LEFTSIDE] = true; - m_StrideStart[RIGHTSIDE] = true; - MoveOutOfTerrain(g_MaterialGrass); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: ReloadFirearms + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the currently held firearms, if any. + // Arguments: None. + // Return value: None. + + void ACrab::ReloadFirearms() { + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + for (HeldDevice* mountedDevice: m_pTurret->GetMountedDevices()) { + if (HDFirearm* mountedFirearm = dynamic_cast(mountedDevice)) { + mountedFirearm->Reload(); } + } + } + } - m_MoveState = WALK; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmActivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the currently held device's delay between pulling the trigger + // and activating. + + int ACrab::FirearmActivationDelay() const { + // Check if the currently held device is already the desired type + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + HDFirearm* pWeapon = dynamic_cast(m_pTurret->GetFirstMountedDevice()); + if (pWeapon) + return pWeapon->GetActivationDelay(); + } - for (int side = 0; side < SIDECOUNT; ++side) - { - m_Paths[side][FGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); - m_Paths[side][BGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsWithinRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a point on the scene is within range of the currently + // used device and aiming status, if applicable. + + bool ACrab::IsWithinRange(Vector& point) const { + if (m_SharpAimMaxedOut) + return true; + + Vector diff = g_SceneMan.ShortestDistance(m_Pos, point, false); + float sqrDistance = diff.GetSqrMagnitude(); + + // Really close! + if (sqrDistance <= (m_CharHeight * m_CharHeight)) { + return true; + } + + // Start with the default aim distance + float range = m_AimDistance; + + // Add the sharp range of the equipped weapon + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + range += m_pTurret->GetFirstMountedDevice()->GetSharpLength() * m_SharpAimProgress; + } + + return sqrDistance <= (range * range); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Look + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an unseen-revealing ray in the direction of where this is facing. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + + bool ACrab::Look(float FOVSpread, float range) { + if (!g_SceneMan.AnythingUnseen(m_Team)) + return false; + + // Set the length of the look vector + float aimDistance = m_AimDistance + range; + Vector aimPos = GetCPUPos(); + + // If aiming down the barrel, look through that + if (m_Controller.IsState(AIM_SHARP) && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + aimPos = m_pTurret->GetFirstMountedDevice()->GetPos(); + aimDistance += m_pTurret->GetFirstMountedDevice()->GetSharpLength(); + } + // If just looking, use the sensors on the turret instead + else if (m_pTurret && m_pTurret->IsAttached()) { + aimPos = GetEyePos(); + } + + // Create the vector to trace along + Vector lookVector(aimDistance, 0); + // Set the rotation to the actual aiming angle + Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); + aimMatrix.SetXFlipped(m_HFlipped); + lookVector *= aimMatrix; + // Add the spread + lookVector.DegRotate(FOVSpread * RandomNormalNum()); + + // TODO: generate an alarm event if we spot an enemy actor? + + Vector ignored; + // Cast the seeing ray, adjusting the skip to match the resolution of the unseen map + return g_SceneMan.CastSeeRay(m_Team, aimPos, lookVector, ignored, 25, (int)g_SceneMan.GetUnseenResolution(m_Team).GetSmallest() / 2); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: LookForMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an MO detecting ray in the direction of where the head is looking + // at the time. Factors including head rotation, sharp aim mode, and + // other variables determine how this ray is cast. + + MovableObject* ACrab::LookForMOs(float FOVSpread, unsigned char ignoreMaterial, bool ignoreAllTerrain) { + MovableObject* pSeenMO = 0; + Vector aimPos = m_Pos; + float aimDistance = m_AimDistance + g_FrameMan.GetPlayerScreenWidth() * 0.51; // Set the length of the look vector + + // If aiming down the barrel, look through that + if (m_Controller.IsState(AIM_SHARP) && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + aimPos = m_pTurret->GetFirstMountedDevice()->GetPos(); + aimDistance += m_pTurret->GetFirstMountedDevice()->GetSharpLength(); + } + // If just looking, use the sensors on the turret instead + else if (m_pTurret && m_pTurret->IsAttached()) + aimPos = GetEyePos(); + // If no turret... + else + aimPos = GetCPUPos(); + + // Create the vector to trace along + Vector lookVector(aimDistance, 0); + // Set the rotation to the actual aiming angle + Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); + aimMatrix.SetXFlipped(m_HFlipped); + lookVector *= aimMatrix; + // Add the spread + lookVector.DegRotate(FOVSpread * RandomNormalNum()); + + MOID seenMOID = g_SceneMan.CastMORay(aimPos, lookVector, m_MOID, IgnoresWhichTeam(), ignoreMaterial, ignoreAllTerrain, 5); + pSeenMO = g_MovableMan.GetMOFromID(seenMOID); + if (pSeenMO) + return pSeenMO->GetRootParent(); + + return pSeenMO; + } + + void ACrab::OnNewMovePath() { + Actor::OnNewMovePath(); + + // Process the new path we now have, if any + if (!m_MovePath.empty()) { + // Smash all airborne waypoints down to just above the ground, except for when it makes the path intersect terrain or it is the final destination + std::list::iterator finalItr = m_MovePath.end(); + finalItr--; + Vector smashedPoint; + Vector previousPoint = *(m_MovePath.begin()); + std::list::iterator nextItr = m_MovePath.begin(); + for (std::list::iterator lItr = m_MovePath.begin(); lItr != finalItr; ++lItr) { + nextItr++; + smashedPoint = g_SceneMan.MovePointToGround((*lItr), m_CharHeight * 0.2, 7); + + // Only smash if the new location doesn't cause the path to intersect hard terrain ahead or behind of it + // Try three times to halve the height to see if that won't intersect + for (int i = 0; i < 3; i++) { + Vector notUsed; + if (!g_SceneMan.CastStrengthRay(previousPoint, smashedPoint - previousPoint, 5, notUsed, 3, g_MaterialDoor) && + nextItr != m_MovePath.end() && !g_SceneMan.CastStrengthRay(smashedPoint, (*nextItr) - smashedPoint, 5, notUsed, 3, g_MaterialDoor)) { + (*lItr) = smashedPoint; + break; + } else + smashedPoint.m_Y -= ((smashedPoint.m_Y - (*lItr).m_Y) / 2); } + + previousPoint = (*lItr); } + } + } - // Walk backwards if the aiming is already focused in the opposite direction of travel. - if (std::abs(analogAim.m_X) > 0 || m_Controller.IsState(AIM_SHARP)) { - for (int side = 0; side < SIDECOUNT; ++side) { - m_Paths[side][FGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); - m_Paths[side][BGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); + ////////////////////////////////////////////////////////////////////////////////////////// + + void ACrab::PreControllerUpdate() { + ZoneScoped; + + Actor::PreControllerUpdate(); + + float deltaTime = g_TimerMan.GetDeltaTimeSecs(); + float mass = GetMass(); + + Vector analogAim = m_Controller.GetAnalogAim(); + const float analogAimDeadzone = 0.1F; + + // Set Default direction of all the paths! + for (int side = 0; side < SIDECOUNT; ++side) { + for (int layer = 0; layer < LAYERCOUNT; ++layer) { + m_Paths[side][layer][WALK].SetHFlip(m_HFlipped); + m_Paths[side][layer][STAND].SetHFlip(m_HFlipped); + } + } + + if (m_pJetpack && m_pJetpack->IsAttached()) { + m_pJetpack->UpdateBurstState(*this); + } + + //////////////////////////////////// + // Movement direction + const float movementThreshold = 1.0F; + bool isStill = (m_Vel + m_PrevVel).MagnitudeIsLessThan(movementThreshold); + + // If the pie menu is on, try to preserve whatever move state we had before it going into effect. + // This is only done for digital input, where the user needs to use the keyboard to choose pie slices. + // For analog input, this doesn't matter - the mouse or aiming analog stick controls the pie menu. + bool keepOldState = m_Controller.IsKeyboardOnlyControlled() && m_Controller.IsState(PIE_MENU_ACTIVE); + + if (!keepOldState) { + if (m_Controller.IsState(MOVE_RIGHT) || m_Controller.IsState(MOVE_LEFT) || m_MoveState == JUMP && m_Status != INACTIVE) { + if (m_MoveState != JUMP) { + // Restart the stride if we're just starting to walk or crawl + if (m_MoveState != WALK) { + m_StrideStart[LEFTSIDE] = true; + m_StrideStart[RIGHTSIDE] = true; + MoveOutOfTerrain(g_MaterialGrass); + } + + m_MoveState = WALK; + + for (int side = 0; side < SIDECOUNT; ++side) { + m_Paths[side][FGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); + m_Paths[side][BGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); + } + } + + // Walk backwards if the aiming is already focused in the opposite direction of travel. + if (std::abs(analogAim.m_X) > 0 || m_Controller.IsState(AIM_SHARP)) { + for (int side = 0; side < SIDECOUNT; ++side) { + m_Paths[side][FGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); + m_Paths[side][BGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); + } + } else if ((m_Controller.IsState(MOVE_RIGHT) && m_HFlipped) || (m_Controller.IsState(MOVE_LEFT) && !m_HFlipped)) { + m_HFlipped = !m_HFlipped; + m_CheckTerrIntersection = true; + MoveOutOfTerrain(g_MaterialGrass); + for (int side = 0; side < SIDECOUNT; ++side) { + for (int layer = 0; layer < LAYERCOUNT; ++layer) { + m_Paths[side][layer][m_MoveState].SetHFlip(m_HFlipped); + m_Paths[side][layer][WALK].Terminate(); + m_Paths[side][layer][STAND].Terminate(); + } + m_StrideStart[side] = true; + } } - } else if ((m_Controller.IsState(MOVE_RIGHT) && m_HFlipped) || (m_Controller.IsState(MOVE_LEFT) && !m_HFlipped)) { + } else { + m_MoveState = STAND; + } + } + + //////////////////////////////////// + // Reload held MO, if applicable + + if (m_Controller.IsState(WEAPON_RELOAD) && !FirearmsAreFull() && m_Status != INACTIVE) { + ReloadFirearms(); + + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + + // Interrupt sharp aiming + m_SharpAimTimer.Reset(); + m_SharpAimProgress = 0; + } + + //////////////////////////////////// + // Aiming + + // Get rotation angle of crab + float rotAngle = GetRotAngle(); + + // Adjust AimRange limits to crab rotation + float adjustedAimRangeUpperLimit = (m_HFlipped) ? m_AimRangeUpperLimit - rotAngle : m_AimRangeUpperLimit + rotAngle; + float adjustedAimRangeLowerLimit = (m_HFlipped) ? -m_AimRangeLowerLimit - rotAngle : -m_AimRangeLowerLimit + rotAngle; + + if (m_Controller.IsState(AIM_UP) && m_Status != INACTIVE) { + // Set the timer to a base number so we don't get a sluggish feeling at start. + if (m_AimState != AIMUP) { + m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); + } + m_AimState = AIMUP; + m_AimAngle += m_Controller.IsState(AIM_SHARP) ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); + + } else if (m_Controller.IsState(AIM_DOWN) && m_Status != INACTIVE) { + // Set the timer to a base number so we don't get a sluggish feeling at start. + if (m_AimState != AIMDOWN) { + m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); + } + m_AimState = AIMDOWN; + m_AimAngle -= m_Controller.IsState(AIM_SHARP) ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); + + } else if (analogAim.MagnitudeIsGreaterThan(analogAimDeadzone) && m_Status != INACTIVE) { + // Hack to avoid the GetAbsRadAngle to mangle an aim angle straight down + if (analogAim.m_X == 0) { + analogAim.m_X += 0.01F * GetFlipFactor(); + } + m_AimAngle = analogAim.GetAbsRadAngle(); + + // Check for flip change + if ((analogAim.m_X > 0 && m_HFlipped) || (analogAim.m_X < 0 && !m_HFlipped)) { m_HFlipped = !m_HFlipped; + // Instead of simply carving out a silhouette of the now flipped actor, isntead disable any atoms which are embedded int eh terrain until they emerge again + // m_ForceDeepCheck = true; m_CheckTerrIntersection = true; MoveOutOfTerrain(g_MaterialGrass); - for (int side = 0; side < SIDECOUNT; ++side) - { - for (int layer = 0; layer < LAYERCOUNT; ++layer) - { + for (int side = 0; side < SIDECOUNT; ++side) { + for (int layer = 0; layer < LAYERCOUNT; ++layer) { m_Paths[side][layer][m_MoveState].SetHFlip(m_HFlipped); m_Paths[side][layer][WALK].Terminate(); m_Paths[side][layer][STAND].Terminate(); @@ -1075,760 +1139,717 @@ void ACrab::PreControllerUpdate() m_StrideStart[side] = true; } } - } else { - m_MoveState = STAND; - } - } + // Correct angle based on flip + m_AimAngle = FacingAngle(m_AimAngle); + + // Clamp the analog aim too, so it doesn't feel "sticky" at the edges of the aim limit + if (m_Controller.IsPlayerControlled() && m_LockMouseAimInput) { + float mouseAngle = g_UInputMan.AnalogAimValues(m_Controller.GetPlayer()).GetAbsRadAngle(); + Clamp(mouseAngle, FacingAngle(adjustedAimRangeUpperLimit), FacingAngle(adjustedAimRangeLowerLimit)); + g_UInputMan.SetMouseValueAngle(mouseAngle, m_Controller.GetPlayer()); + } + } else + m_AimState = AIMSTILL; + + // Clamp aim angle so it's within adjusted limit ranges, for all control types + Clamp(m_AimAngle, adjustedAimRangeUpperLimit, adjustedAimRangeLowerLimit); - //////////////////////////////////// - // Reload held MO, if applicable - - if (m_Controller.IsState(WEAPON_RELOAD) && !FirearmsAreFull() && m_Status != INACTIVE) { - ReloadFirearms(); - - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } - - // Interrupt sharp aiming - m_SharpAimTimer.Reset(); - m_SharpAimProgress = 0; - } - - //////////////////////////////////// - // Aiming - - // Get rotation angle of crab - float rotAngle = GetRotAngle(); - - // Adjust AimRange limits to crab rotation - float adjustedAimRangeUpperLimit = (m_HFlipped) ? m_AimRangeUpperLimit - rotAngle : m_AimRangeUpperLimit + rotAngle; - float adjustedAimRangeLowerLimit = (m_HFlipped) ? -m_AimRangeLowerLimit - rotAngle : -m_AimRangeLowerLimit + rotAngle; - - if (m_Controller.IsState(AIM_UP) && m_Status != INACTIVE) { - // Set the timer to a base number so we don't get a sluggish feeling at start. - if (m_AimState != AIMUP) { m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); } - m_AimState = AIMUP; - m_AimAngle += m_Controller.IsState(AIM_SHARP) ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); - - } else if (m_Controller.IsState(AIM_DOWN) && m_Status != INACTIVE) { - // Set the timer to a base number so we don't get a sluggish feeling at start. - if (m_AimState != AIMDOWN) { m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); } - m_AimState = AIMDOWN; - m_AimAngle -= m_Controller.IsState(AIM_SHARP) ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); - - } else if (analogAim.MagnitudeIsGreaterThan(analogAimDeadzone) && m_Status != INACTIVE) { - // Hack to avoid the GetAbsRadAngle to mangle an aim angle straight down - if (analogAim.m_X == 0) { analogAim.m_X += 0.01F * GetFlipFactor(); } - m_AimAngle = analogAim.GetAbsRadAngle(); - - // Check for flip change - if ((analogAim.m_X > 0 && m_HFlipped) || (analogAim.m_X < 0 && !m_HFlipped)) { - m_HFlipped = !m_HFlipped; - // Instead of simply carving out a silhouette of the now flipped actor, isntead disable any atoms which are embedded int eh terrain until they emerge again - //m_ForceDeepCheck = true; - m_CheckTerrIntersection = true; - MoveOutOfTerrain(g_MaterialGrass); - for (int side = 0; side < SIDECOUNT; ++side) - { - for (int layer = 0; layer < LAYERCOUNT; ++layer) - { - m_Paths[side][layer][m_MoveState].SetHFlip(m_HFlipped); - m_Paths[side][layer][WALK].Terminate(); - m_Paths[side][layer][STAND].Terminate(); - } - m_StrideStart[side] = true; - } - } - // Correct angle based on flip - m_AimAngle = FacingAngle(m_AimAngle); - - // Clamp the analog aim too, so it doesn't feel "sticky" at the edges of the aim limit - if (m_Controller.IsPlayerControlled() && m_LockMouseAimInput) { - float mouseAngle = g_UInputMan.AnalogAimValues(m_Controller.GetPlayer()).GetAbsRadAngle(); - Clamp(mouseAngle, FacingAngle(adjustedAimRangeUpperLimit), FacingAngle(adjustedAimRangeLowerLimit)); - g_UInputMan.SetMouseValueAngle(mouseAngle, m_Controller.GetPlayer()); - } - } - else - m_AimState = AIMSTILL; - - // Clamp aim angle so it's within adjusted limit ranges, for all control types - Clamp(m_AimAngle, adjustedAimRangeUpperLimit, adjustedAimRangeLowerLimit); - - ////////////////////////////// - // Sharp aim calculation - - if (m_Controller.IsState(AIM_SHARP) && m_Status == STABLE && m_Vel.MagnitudeIsLessThan(5.0F)) { - float aimMag = analogAim.GetMagnitude(); - - // If aim sharp is being done digitally, then translate to full magnitude. - if (aimMag < 0.1F) { aimMag = 1.0F; } - if (m_MoveState == WALK) { aimMag *= 0.3F; } - - if (m_SharpAimTimer.IsPastSimMS(m_SharpAimDelay)) { - // Only go slower outward. - if (m_SharpAimProgress < aimMag) { - m_SharpAimProgress += (aimMag - m_SharpAimProgress) * 0.035F; + ////////////////////////////// + // Sharp aim calculation + + if (m_Controller.IsState(AIM_SHARP) && m_Status == STABLE && m_Vel.MagnitudeIsLessThan(5.0F)) { + float aimMag = analogAim.GetMagnitude(); + + // If aim sharp is being done digitally, then translate to full magnitude. + if (aimMag < 0.1F) { + aimMag = 1.0F; + } + if (m_MoveState == WALK) { + aimMag *= 0.3F; + } + + if (m_SharpAimTimer.IsPastSimMS(m_SharpAimDelay)) { + // Only go slower outward. + if (m_SharpAimProgress < aimMag) { + m_SharpAimProgress += (aimMag - m_SharpAimProgress) * 0.035F; + } else { + m_SharpAimProgress = aimMag; + } } else { - m_SharpAimProgress = aimMag; + m_SharpAimProgress *= 0.95F; } } else { - m_SharpAimProgress *= 0.95F; + m_SharpAimProgress = std::max(m_SharpAimProgress * 0.95F - 0.1F, 0.0F); } - } else { - m_SharpAimProgress = std::max(m_SharpAimProgress * 0.95F - 0.1F, 0.0F); - } - //////////////////////////////////// - // Fire/Activate held devices - - if (m_pTurret && m_pTurret->IsAttached() && m_Status != INACTIVE) { - for (HeldDevice *mountedDevice : m_pTurret->GetMountedDevices()) { - mountedDevice->SetSharpAim(m_SharpAimProgress); - if (m_Controller.IsState(WEAPON_FIRE)) { - mountedDevice->Activate(); - if (mountedDevice->IsEmpty()) { mountedDevice->Reload(); } - } else { - mountedDevice->Deactivate(); - } - } - } - - // Controller disabled - if (m_Controller.IsDisabled()) - { - m_MoveState = STAND; - if (m_pJetpack && m_pJetpack->IsAttached()) - m_pJetpack->EnableEmission(false); - } - -// m_aSprite->SetAngle((m_AimAngle / 180) * 3.141592654); -// m_aSprite->SetScale(2.0); - - - /////////////////////////////////////////////////// - // Travel the limb AtomGroup:s - - m_StrideFrame = false; - - if (m_Status == STABLE && !m_LimbPushForcesAndCollisionsDisabled) - { - // This exists to support disabling foot collisions if the limbpath has that flag set. - if ((m_pLFGFootGroup->GetAtomCount() == 0 && m_BackupLFGFootGroup->GetAtomCount() > 0) != m_Paths[LEFTSIDE][FGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { - m_BackupLFGFootGroup->SetLimbPos(m_pLFGFootGroup->GetLimbPos()); - std::swap(m_pLFGFootGroup, m_BackupLFGFootGroup); - } - if ((m_pLBGFootGroup->GetAtomCount() == 0 && m_BackupLBGFootGroup->GetAtomCount() > 0) != m_Paths[LEFTSIDE][BGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { - m_BackupLBGFootGroup->SetLimbPos(m_pLBGFootGroup->GetLimbPos()); - std::swap(m_pLBGFootGroup, m_BackupLBGFootGroup); - } - if ((m_pRFGFootGroup->GetAtomCount() == 0 && m_BackupRFGFootGroup->GetAtomCount() > 0) != m_Paths[RIGHTSIDE][FGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { - m_BackupRFGFootGroup->SetLimbPos(m_pRFGFootGroup->GetLimbPos()); - std::swap(m_pRFGFootGroup, m_BackupRFGFootGroup); - } - if ((m_pRBGFootGroup->GetAtomCount() == 0 && m_BackupRBGFootGroup->GetAtomCount() > 0) != m_Paths[RIGHTSIDE][BGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { - m_BackupRBGFootGroup->SetLimbPos(m_pRBGFootGroup->GetLimbPos()); - std::swap(m_pRBGFootGroup, m_BackupRBGFootGroup); - } - - // WALKING - if (m_MoveState == WALK) - { - for (int side = 0; side < SIDECOUNT; ++side) - for (int layer = 0; layer < LAYERCOUNT; ++layer) - m_Paths[side][layer][STAND].Terminate(); - - float LFGLegProg = m_Paths[LEFTSIDE][FGROUND][WALK].GetRegularProgress(); - float LBGLegProg = m_Paths[LEFTSIDE][BGROUND][WALK].GetRegularProgress(); - float RFGLegProg = m_Paths[RIGHTSIDE][FGROUND][WALK].GetRegularProgress(); - float RBGLegProg = m_Paths[RIGHTSIDE][BGROUND][WALK].GetRegularProgress(); - - bool restarted = false; - Matrix walkAngle(rotAngle * 0.5F); - - // Make sure we are starting a stride if we're basically stopped. - if (isStill) { m_StrideStart[LEFTSIDE] = true; } - - ////////////////// - // LEFT LEGS - - if (m_pLFGLeg && (!m_pLBGLeg || (!(m_Paths[LEFTSIDE][FGROUND][WALK].PathEnded() && LBGLegProg < 0.5F) || m_StrideStart[LEFTSIDE]))) { - m_StrideTimer[LEFTSIDE].Reset(); - m_pLFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLFGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[LEFTSIDE][FGROUND][WALK], deltaTime, &restarted); - } + //////////////////////////////////// + // Fire/Activate held devices - if (m_pLBGLeg) { - if (!m_pLFGLeg || !(m_Paths[LEFTSIDE][BGROUND][WALK].PathEnded() && LFGLegProg < 0.5F)) { - m_StrideStart[LEFTSIDE] = false; - m_StrideTimer[LEFTSIDE].Reset(); - m_pLBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLBGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[LEFTSIDE][BGROUND][WALK], deltaTime); + if (m_pTurret && m_pTurret->IsAttached() && m_Status != INACTIVE) { + for (HeldDevice* mountedDevice: m_pTurret->GetMountedDevices()) { + mountedDevice->SetSharpAim(m_SharpAimProgress); + if (m_Controller.IsState(WEAPON_FIRE)) { + mountedDevice->Activate(); + if (mountedDevice->IsEmpty()) { + mountedDevice->Reload(); + } } else { - m_pLBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLBGLeg->GetParentOffset()), m_pLBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pLBGLeg->GetMass(), deltaTime); + mountedDevice->Deactivate(); } } + } + + // Controller disabled + if (m_Controller.IsDisabled()) { + m_MoveState = STAND; + if (m_pJetpack && m_pJetpack->IsAttached()) + m_pJetpack->EnableEmission(false); + } - // Reset the left-side walking stride if it's taking longer than it should. - if (m_StrideTimer[LEFTSIDE].IsPastSimMS(static_cast(m_Paths[LEFTSIDE][FGROUND][WALK].GetTotalPathTime() * 1.1F))) { m_StrideStart[LEFTSIDE] = true; } + // m_aSprite->SetAngle((m_AimAngle / 180) * 3.141592654); + // m_aSprite->SetScale(2.0); - /////////////////// - // RIGHT LEGS + /////////////////////////////////////////////////// + // Travel the limb AtomGroup:s - if (m_pRFGLeg) { - if (!m_pRBGLeg || !(m_Paths[RIGHTSIDE][FGROUND][WALK].PathEnded() && RBGLegProg < 0.5F)) { - m_StrideStart[RIGHTSIDE] = false; + m_StrideFrame = false; + + if (m_Status == STABLE && !m_LimbPushForcesAndCollisionsDisabled) { + // This exists to support disabling foot collisions if the limbpath has that flag set. + if ((m_pLFGFootGroup->GetAtomCount() == 0 && m_BackupLFGFootGroup->GetAtomCount() > 0) != m_Paths[LEFTSIDE][FGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { + m_BackupLFGFootGroup->SetLimbPos(m_pLFGFootGroup->GetLimbPos()); + std::swap(m_pLFGFootGroup, m_BackupLFGFootGroup); + } + if ((m_pLBGFootGroup->GetAtomCount() == 0 && m_BackupLBGFootGroup->GetAtomCount() > 0) != m_Paths[LEFTSIDE][BGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { + m_BackupLBGFootGroup->SetLimbPos(m_pLBGFootGroup->GetLimbPos()); + std::swap(m_pLBGFootGroup, m_BackupLBGFootGroup); + } + if ((m_pRFGFootGroup->GetAtomCount() == 0 && m_BackupRFGFootGroup->GetAtomCount() > 0) != m_Paths[RIGHTSIDE][FGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { + m_BackupRFGFootGroup->SetLimbPos(m_pRFGFootGroup->GetLimbPos()); + std::swap(m_pRFGFootGroup, m_BackupRFGFootGroup); + } + if ((m_pRBGFootGroup->GetAtomCount() == 0 && m_BackupRBGFootGroup->GetAtomCount() > 0) != m_Paths[RIGHTSIDE][BGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { + m_BackupRBGFootGroup->SetLimbPos(m_pRBGFootGroup->GetLimbPos()); + std::swap(m_pRBGFootGroup, m_BackupRBGFootGroup); + } + + // WALKING + if (m_MoveState == WALK) { + for (int side = 0; side < SIDECOUNT; ++side) + for (int layer = 0; layer < LAYERCOUNT; ++layer) + m_Paths[side][layer][STAND].Terminate(); + + float LFGLegProg = m_Paths[LEFTSIDE][FGROUND][WALK].GetRegularProgress(); + float LBGLegProg = m_Paths[LEFTSIDE][BGROUND][WALK].GetRegularProgress(); + float RFGLegProg = m_Paths[RIGHTSIDE][FGROUND][WALK].GetRegularProgress(); + float RBGLegProg = m_Paths[RIGHTSIDE][BGROUND][WALK].GetRegularProgress(); + + bool restarted = false; + Matrix walkAngle(rotAngle * 0.5F); + + // Make sure we are starting a stride if we're basically stopped. + if (isStill) { + m_StrideStart[LEFTSIDE] = true; + } + + ////////////////// + // LEFT LEGS + + if (m_pLFGLeg && (!m_pLBGLeg || (!(m_Paths[LEFTSIDE][FGROUND][WALK].PathEnded() && LBGLegProg < 0.5F) || m_StrideStart[LEFTSIDE]))) { + m_StrideTimer[LEFTSIDE].Reset(); + m_pLFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLFGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[LEFTSIDE][FGROUND][WALK], deltaTime, &restarted); + } + + if (m_pLBGLeg) { + if (!m_pLFGLeg || !(m_Paths[LEFTSIDE][BGROUND][WALK].PathEnded() && LFGLegProg < 0.5F)) { + m_StrideStart[LEFTSIDE] = false; + m_StrideTimer[LEFTSIDE].Reset(); + m_pLBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLBGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[LEFTSIDE][BGROUND][WALK], deltaTime); + } else { + m_pLBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLBGLeg->GetParentOffset()), m_pLBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pLBGLeg->GetMass(), deltaTime); + } + } + + // Reset the left-side walking stride if it's taking longer than it should. + if (m_StrideTimer[LEFTSIDE].IsPastSimMS(static_cast(m_Paths[LEFTSIDE][FGROUND][WALK].GetTotalPathTime() * 1.1F))) { + m_StrideStart[LEFTSIDE] = true; + } + + /////////////////// + // RIGHT LEGS + + if (m_pRFGLeg) { + if (!m_pRBGLeg || !(m_Paths[RIGHTSIDE][FGROUND][WALK].PathEnded() && RBGLegProg < 0.5F)) { + m_StrideStart[RIGHTSIDE] = false; + m_StrideTimer[RIGHTSIDE].Reset(); + m_pRFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRFGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[RIGHTSIDE][FGROUND][WALK], deltaTime, &restarted); + } else { + m_pRFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRFGLeg->GetParentOffset()), m_pRFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pRFGLeg->GetMass(), deltaTime); + } + } + + if (m_pRBGLeg && (!m_pRFGLeg || (!(m_Paths[RIGHTSIDE][BGROUND][WALK].PathEnded() && RFGLegProg < 0.5F) || m_StrideStart[RIGHTSIDE]))) { m_StrideTimer[RIGHTSIDE].Reset(); - m_pRFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRFGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[RIGHTSIDE][FGROUND][WALK], deltaTime, &restarted); - } else { - m_pRFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRFGLeg->GetParentOffset()), m_pRFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pRFGLeg->GetMass(), deltaTime); + m_pRBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRBGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[RIGHTSIDE][BGROUND][WALK], deltaTime); } - } - if (m_pRBGLeg && (!m_pRFGLeg || (!(m_Paths[RIGHTSIDE][BGROUND][WALK].PathEnded() && RFGLegProg < 0.5F) || m_StrideStart[RIGHTSIDE]))) { - m_StrideTimer[RIGHTSIDE].Reset(); - m_pRBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRBGLeg->GetParentOffset()), m_Vel, walkAngle, m_Paths[RIGHTSIDE][BGROUND][WALK], deltaTime); - } + // Reset the right-side walking stride if it's taking longer than it should. + if (m_StrideTimer[RIGHTSIDE].IsPastSimMS(static_cast(m_Paths[RIGHTSIDE][FGROUND][WALK].GetTotalPathTime() * 1.1F))) { + m_StrideStart[RIGHTSIDE] = true; + } - // Reset the right-side walking stride if it's taking longer than it should. - if (m_StrideTimer[RIGHTSIDE].IsPastSimMS(static_cast(m_Paths[RIGHTSIDE][FGROUND][WALK].GetTotalPathTime() * 1.1F))) { m_StrideStart[RIGHTSIDE] = true; } - - if (m_StrideSound) { - m_StrideSound->SetPosition(m_Pos); - if (m_StrideSound->GetLoopSetting() < 0) { - if (!m_StrideSound->IsBeingPlayed()) { m_StrideSound->Play(); } - } else if (restarted) { - m_StrideSound->Play(); + if (m_StrideSound) { + m_StrideSound->SetPosition(m_Pos); + if (m_StrideSound->GetLoopSetting() < 0) { + if (!m_StrideSound->IsBeingPlayed()) { + m_StrideSound->Play(); + } + } else if (restarted) { + m_StrideSound->Play(); + } } - } - if (restarted) { - m_StrideFrame = true; - RunScriptedFunctionInAppropriateScripts("OnStride"); - } - } else if (m_pLFGLeg || m_pLBGLeg || m_pRFGLeg || m_pRBGLeg) { - if (m_MoveState == JUMP) { - // TODO: Utilize jump paths in an intuitive way? - if (m_pLFGLeg) { m_pLFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLFGLeg->GetParentOffset()), m_pLFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pLFGLeg->GetMass(), deltaTime); } - if (m_pLBGLeg) { m_pLBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLBGLeg->GetParentOffset()), m_pLBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pLBGLeg->GetMass(), deltaTime); } - if (m_pRFGLeg) { m_pRFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRFGLeg->GetParentOffset()), m_pRFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pRFGLeg->GetMass(), deltaTime); } - if (m_pRBGLeg) { m_pRBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRBGLeg->GetParentOffset()), m_pRBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pRBGLeg->GetMass(), deltaTime); } - - if (m_pJetpack == nullptr || m_pJetpack->IsOutOfFuel()) { - m_MoveState = STAND; - m_Paths[LEFTSIDE][FGROUND][JUMP].Terminate(); - m_Paths[LEFTSIDE][BGROUND][JUMP].Terminate(); - m_Paths[LEFTSIDE][FGROUND][STAND].Terminate(); - m_Paths[LEFTSIDE][BGROUND][STAND].Terminate(); - m_Paths[LEFTSIDE][FGROUND][WALK].Terminate(); - m_Paths[LEFTSIDE][BGROUND][WALK].Terminate(); - m_Paths[RIGHTSIDE][FGROUND][JUMP].Terminate(); - m_Paths[RIGHTSIDE][BGROUND][JUMP].Terminate(); - m_Paths[RIGHTSIDE][FGROUND][STAND].Terminate(); - m_Paths[RIGHTSIDE][BGROUND][STAND].Terminate(); - m_Paths[RIGHTSIDE][FGROUND][WALK].Terminate(); - m_Paths[RIGHTSIDE][BGROUND][WALK].Terminate(); + if (restarted) { + m_StrideFrame = true; + RunScriptedFunctionInAppropriateScripts("OnStride"); } - } else { - for (int side = 0; side < SIDECOUNT; ++side) { - for (int layer = 0; layer < LAYERCOUNT; ++layer) { - m_Paths[side][layer][WALK].Terminate(); + } else if (m_pLFGLeg || m_pLBGLeg || m_pRFGLeg || m_pRBGLeg) { + if (m_MoveState == JUMP) { + // TODO: Utilize jump paths in an intuitive way? + if (m_pLFGLeg) { + m_pLFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLFGLeg->GetParentOffset()), m_pLFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pLFGLeg->GetMass(), deltaTime); + } + if (m_pLBGLeg) { + m_pLBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLBGLeg->GetParentOffset()), m_pLBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pLBGLeg->GetMass(), deltaTime); + } + if (m_pRFGLeg) { + m_pRFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRFGLeg->GetParentOffset()), m_pRFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pRFGLeg->GetMass(), deltaTime); + } + if (m_pRBGLeg) { + m_pRBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRBGLeg->GetParentOffset()), m_pRBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pRBGLeg->GetMass(), deltaTime); + } + + if (m_pJetpack == nullptr || m_pJetpack->IsOutOfFuel()) { + m_MoveState = STAND; + m_Paths[LEFTSIDE][FGROUND][JUMP].Terminate(); + m_Paths[LEFTSIDE][BGROUND][JUMP].Terminate(); + m_Paths[LEFTSIDE][FGROUND][STAND].Terminate(); + m_Paths[LEFTSIDE][BGROUND][STAND].Terminate(); + m_Paths[LEFTSIDE][FGROUND][WALK].Terminate(); + m_Paths[LEFTSIDE][BGROUND][WALK].Terminate(); + m_Paths[RIGHTSIDE][FGROUND][JUMP].Terminate(); + m_Paths[RIGHTSIDE][BGROUND][JUMP].Terminate(); + m_Paths[RIGHTSIDE][FGROUND][STAND].Terminate(); + m_Paths[RIGHTSIDE][BGROUND][STAND].Terminate(); + m_Paths[RIGHTSIDE][FGROUND][WALK].Terminate(); + m_Paths[RIGHTSIDE][BGROUND][WALK].Terminate(); + } + } else { + for (int side = 0; side < SIDECOUNT; ++side) { + for (int layer = 0; layer < LAYERCOUNT; ++layer) { + m_Paths[side][layer][WALK].Terminate(); + } + } + if (m_pLFGLeg) { + m_pLFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLFGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFTSIDE][FGROUND][STAND], deltaTime, nullptr, !m_pRFGLeg); + } + + if (m_pLBGLeg) { + m_pLBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLBGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFTSIDE][BGROUND][STAND], deltaTime); + } + + if (m_pRFGLeg) { + m_pRFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRFGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHTSIDE][FGROUND][STAND], deltaTime, nullptr, !m_pLFGLeg); + } + + if (m_pRBGLeg) { + m_pRBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRBGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHTSIDE][BGROUND][STAND], deltaTime); } } - if (m_pLFGLeg) { m_pLFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLFGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFTSIDE][FGROUND][STAND], deltaTime, nullptr, !m_pRFGLeg); } + } + } else { + // Not stable/standing, so make sure the end of limbs are moving around limply in a ragdoll fashion. + // TODO: Make the limb atom groups fly around and react to terrain, without getting stuck etc. + if (m_pLFGLeg) { + m_pLFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLFGLeg->GetParentOffset()), m_pLFGLeg->GetMaxLength(), m_PrevVel * m_pLFGLeg->GetJointStiffness(), m_AngularVel, m_pLFGLeg->GetMass(), deltaTime); + } - if (m_pLBGLeg) { m_pLBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pLBGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[LEFTSIDE][BGROUND][STAND], deltaTime); } + if (m_pLBGLeg) { + m_pLBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLBGLeg->GetParentOffset()), m_pLBGLeg->GetMaxLength(), m_PrevVel * m_pLBGLeg->GetJointStiffness(), m_AngularVel, m_pLBGLeg->GetMass(), deltaTime); + } - if (m_pRFGLeg) { m_pRFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRFGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHTSIDE][FGROUND][STAND], deltaTime, nullptr, !m_pLFGLeg); } + if (m_pRFGLeg) { + m_pRFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRFGLeg->GetParentOffset()), m_pRFGLeg->GetMaxLength(), m_PrevVel * m_pRFGLeg->GetJointStiffness(), m_AngularVel, m_pRFGLeg->GetMass(), deltaTime); + } - if (m_pRBGLeg) { m_pRBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pRBGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[RIGHTSIDE][BGROUND][STAND], deltaTime); } + if (m_pRBGLeg) { + m_pRBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRBGLeg->GetParentOffset()), m_pRBGLeg->GetMaxLength(), m_PrevVel * m_pRBGLeg->GetJointStiffness(), m_AngularVel, m_pRBGLeg->GetMass(), deltaTime); } } - } else { - // Not stable/standing, so make sure the end of limbs are moving around limply in a ragdoll fashion. - // TODO: Make the limb atom groups fly around and react to terrain, without getting stuck etc. - if (m_pLFGLeg) { m_pLFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLFGLeg->GetParentOffset()), m_pLFGLeg->GetMaxLength(), m_PrevVel * m_pLFGLeg->GetJointStiffness(), m_AngularVel, m_pLFGLeg->GetMass(), deltaTime); } + if (m_MoveState != WALK && m_StrideSound && m_StrideSound->GetLoopSetting() < 0) { + m_StrideSound->Stop(); + } - if (m_pLBGLeg) { m_pLBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pLBGLeg->GetParentOffset()), m_pLBGLeg->GetMaxLength(), m_PrevVel * m_pLBGLeg->GetJointStiffness(), m_AngularVel, m_pLBGLeg->GetMass(), deltaTime); } + ///////////////////////////////// + // Manage Attachable:s + if (m_pTurret && m_pTurret->IsAttached()) { + m_pTurret->SetMountedDeviceRotationOffset((m_AimAngle * GetFlipFactor()) - m_Rotation.GetRadAngle()); + } - if (m_pRFGLeg) { m_pRFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRFGLeg->GetParentOffset()), m_pRFGLeg->GetMaxLength(), m_PrevVel * m_pRFGLeg->GetJointStiffness(), m_AngularVel, m_pRFGLeg->GetMass(), deltaTime); } + if (m_pLFGLeg && m_pLFGLeg->IsAttached()) { + m_pLFGLeg->EnableIdle(m_Status != UNSTABLE); + m_pLFGLeg->SetTargetPosition(m_pLFGFootGroup->GetLimbPos(m_HFlipped)); + } - if (m_pRBGLeg) { m_pRBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pRBGLeg->GetParentOffset()), m_pRBGLeg->GetMaxLength(), m_PrevVel * m_pRBGLeg->GetJointStiffness(), m_AngularVel, m_pRBGLeg->GetMass(), deltaTime); } + if (m_pLBGLeg && m_pLBGLeg->IsAttached()) { + m_pLBGLeg->EnableIdle(m_Status != UNSTABLE); + m_pLBGLeg->SetTargetPosition(m_pLBGFootGroup->GetLimbPos(m_HFlipped)); + } + + if (m_pRFGLeg && m_pRFGLeg->IsAttached()) { + m_pRFGLeg->EnableIdle(m_Status != UNSTABLE); + m_pRFGLeg->SetTargetPosition(m_pRFGFootGroup->GetLimbPos(m_HFlipped)); + } + + if (m_pRBGLeg && m_pRBGLeg->IsAttached()) { + m_pRBGLeg->EnableIdle(m_Status != UNSTABLE); + m_pRBGLeg->SetTargetPosition(m_pRBGFootGroup->GetLimbPos(m_HFlipped)); + } } - if (m_MoveState != WALK && m_StrideSound && m_StrideSound->GetLoopSetting() < 0) { - m_StrideSound->Stop(); - } - - ///////////////////////////////// - // Manage Attachable:s - if (m_pTurret && m_pTurret->IsAttached()) { - m_pTurret->SetMountedDeviceRotationOffset((m_AimAngle * GetFlipFactor()) - m_Rotation.GetRadAngle()); - } - - if (m_pLFGLeg && m_pLFGLeg->IsAttached()) { - m_pLFGLeg->EnableIdle(m_Status != UNSTABLE); - m_pLFGLeg->SetTargetPosition(m_pLFGFootGroup->GetLimbPos(m_HFlipped)); - } - - if (m_pLBGLeg && m_pLBGLeg->IsAttached()) { - m_pLBGLeg->EnableIdle(m_Status != UNSTABLE); - m_pLBGLeg->SetTargetPosition(m_pLBGFootGroup->GetLimbPos(m_HFlipped)); - } - - if (m_pRFGLeg && m_pRFGLeg->IsAttached()) { - m_pRFGLeg->EnableIdle(m_Status != UNSTABLE); - m_pRFGLeg->SetTargetPosition(m_pRFGFootGroup->GetLimbPos(m_HFlipped)); - } - - if (m_pRBGLeg && m_pRBGLeg->IsAttached()) { - m_pRBGLeg->EnableIdle(m_Status != UNSTABLE); - m_pRBGLeg->SetTargetPosition(m_pRBGFootGroup->GetLimbPos(m_HFlipped)); - } -} -////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// -void ACrab::Update() -{ - ZoneScoped; - - Actor::Update(); - - //////////////////////////////////// - // Update viewpoint - - // Set viewpoint based on how we are aiming etc. - Vector aimSight(m_AimDistance, 0); - Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); - aimMatrix.SetXFlipped(m_HFlipped); - // Reset this each frame - m_SharpAimMaxedOut = false; - - if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) - { - float maxLength = m_pTurret->GetFirstMountedDevice()->GetSharpLength(); - - // Use a non-terrain check ray to cap the magnitude, so we can't see into objects etc - if (m_SharpAimProgress > 0) - { - Vector notUsed; - Vector sharpAimVector(maxLength, 0); - sharpAimVector *= aimMatrix; - - // See how far along the sharp aim vector there is opaque air -// float result = g_SceneMan.CastNotMaterialRay(m_pLFGLeg->GetFirstMountedDevice()->GetMuzzlePos(), sharpAimVector, g_MaterialAir, 5); - float result = g_SceneMan.CastObstacleRay(m_pTurret->GetFirstMountedDevice()->GetMuzzlePos(), sharpAimVector, notUsed, notUsed, GetRootID(), IgnoresWhichTeam(), g_MaterialAir, 5); - // If we didn't find anything but air before the sharpdistance, then don't alter the sharp distance - if (result >= 0 && result < (maxLength * m_SharpAimProgress)) - { - m_SharpAimProgress = result / maxLength; - m_SharpAimMaxedOut = true; - } - } - // Indicate maxed outedness if we really are, too - if (m_SharpAimProgress > 0.9) - m_SharpAimMaxedOut = true; - -// sharpDistance *= m_Controller.GetAnalogAim().GetMagnitude(); - aimSight.m_X += maxLength * m_SharpAimProgress; - } - - // Rotate the aiming spot vector and add it to the view point - aimSight *= aimMatrix; - m_ViewPoint = m_Pos.GetFloored() + aimSight; - - // Add velocity also so the viewpoint moves ahead at high speeds - if (m_Vel.MagnitudeIsGreaterThan(10.0F)) - m_ViewPoint += m_Vel * std::sqrt(m_Vel.GetMagnitude() * 0.1F); - -/* Done by pie menu now, see HandlePieCommand() - //////////////////////////////////////// - // AI mode setting - - if (m_Controller.IsState(AI_MODE_SET)) - { - if (m_Controller.IsState(PRESS_RIGHT)) - { - m_AIMode = AIMODE_BRAINHUNT; - m_UpdateMovePath = true; - } - else if (m_Controller.IsState(PRESS_LEFT)) - { - m_AIMode = AIMODE_PATROL; - } - else if (m_Controller.IsState(PRESS_UP)) - { - m_AIMode = AIMODE_SENTRY; - } - else if (m_Controller.IsState(PRESS_DOWN)) - { - m_AIMode = AIMODE_GOLDDIG; - } - - m_DeviceState = SCANNING; - } -*/ - - //////////////////////////////////////// - // Balance stuff - - // Get the rotation in radians. - float rot = m_Rotation.GetRadAngle(); -// rot = fabs(rot) < c_QuarterPI ? rot : (rot > 0 ? c_QuarterPI : -c_QuarterPI); - // Eliminate full rotations - while (fabs(rot) > c_TwoPI) { - rot -= rot > 0 ? c_TwoPI : -c_TwoPI; - } - // Eliminate rotations over half a turn - if (fabs(rot) > c_PI) - { - rot = (rot > 0 ? -c_PI : c_PI) + (rot - (rot > 0 ? c_PI : -c_PI)); - // If we're upside down, we're unstable damnit - if (m_Status == STABLE) { m_Status = UNSTABLE; } - m_StableRecoverTimer.Reset(); - } - - // Rotational balancing spring calc - if (m_Status == STABLE) - { - // Upright body posture - m_AngularVel = m_AngularVel * 0.9F - (rot * 0.3F); - } - // While dying, pull body quickly toward down toward horizontal - else if (m_Status == DYING) - { - float rotTarget = rot > 0 ? c_HalfPI : -c_HalfPI; -// float rotTarget = m_HFlipped ? c_HalfPI : -c_HalfPI; - float rotDiff = rotTarget - rot; - if (!m_DeathTmr.IsPastSimMS(125) && fabs(rotDiff) > 0.1 && fabs(rotDiff) < c_PI) - { - m_AngularVel += rotDiff * 0.5;//fabs(rotDiff); -// m_Vel.m_X += (m_HFlipped ? -fabs(rotDiff) : fabs(rotDiff)) * 0.35; - m_Vel.m_X += (rotTarget > 0 ? -fabs(rotDiff) : fabs(rotDiff)) * 0.35; - } - else - m_Status = DEAD; - -// else if (fabs(m_AngularVel) > 0.1) -// m_AngularVel *= 0.5; - } - m_Rotation.SetRadAngle(rot); - - /////////////////////////////////////////////////// - // Death detection and handling - - // Losing all limbs should kill... eventually - if (!m_pLFGLeg && !m_pLBGLeg && !m_pRFGLeg && !m_pRBGLeg && m_Status != DYING && m_Status != DEAD) - m_Health -= 0.1; - - ///////////////////////////////////////// - // Misc. - -// m_DeepCheck = true/*m_Status == DEAD*/; -} - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void ACrab::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { - Actor::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - - if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawHandAndFootGroupVisualizations()) { - m_pLFGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - m_pLBGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - m_pRFGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - m_pRBGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - } - - if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawLimbPathVisualizations()) { - m_Paths[LEFTSIDE][BGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); - m_Paths[LEFTSIDE][FGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); - m_Paths[RIGHTSIDE][BGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); - m_Paths[RIGHTSIDE][FGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); - } -} + void ACrab::Update() { + ZoneScoped; + Actor::Update(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. + //////////////////////////////////// + // Update viewpoint -void ACrab::DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) { - m_HUDStack = -m_CharHeight / 2; + // Set viewpoint based on how we are aiming etc. + Vector aimSight(m_AimDistance, 0); + Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); + aimMatrix.SetXFlipped(m_HFlipped); + // Reset this each frame + m_SharpAimMaxedOut = false; - // Only do HUD if on a team - if (m_Team < 0) - return; + if (m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + float maxLength = m_pTurret->GetFirstMountedDevice()->GetSharpLength(); - // Only draw if the team viewing this is on the same team OR has seen the space where this is located. - int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); - if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { - return; - } + // Use a non-terrain check ray to cap the magnitude, so we can't see into objects etc + if (m_SharpAimProgress > 0) { + Vector notUsed; + Vector sharpAimVector(maxLength, 0); + sharpAimVector *= aimMatrix; + + // See how far along the sharp aim vector there is opaque air + // float result = g_SceneMan.CastNotMaterialRay(m_pLFGLeg->GetFirstMountedDevice()->GetMuzzlePos(), sharpAimVector, g_MaterialAir, 5); + float result = g_SceneMan.CastObstacleRay(m_pTurret->GetFirstMountedDevice()->GetMuzzlePos(), sharpAimVector, notUsed, notUsed, GetRootID(), IgnoresWhichTeam(), g_MaterialAir, 5); + // If we didn't find anything but air before the sharpdistance, then don't alter the sharp distance + if (result >= 0 && result < (maxLength * m_SharpAimProgress)) { + m_SharpAimProgress = result / maxLength; + m_SharpAimMaxedOut = true; + } + } + // Indicate maxed outedness if we really are, too + if (m_SharpAimProgress > 0.9) + m_SharpAimMaxedOut = true; - Actor::DrawHUD(pTargetBitmap, targetPos, whichScreen); + // sharpDistance *= m_Controller.GetAnalogAim().GetMagnitude(); + aimSight.m_X += maxLength * m_SharpAimProgress; + } - if (!m_HUDVisible) { - return; + // Rotate the aiming spot vector and add it to the view point + aimSight *= aimMatrix; + m_ViewPoint = m_Pos.GetFloored() + aimSight; + + // Add velocity also so the viewpoint moves ahead at high speeds + if (m_Vel.MagnitudeIsGreaterThan(10.0F)) + m_ViewPoint += m_Vel * std::sqrt(m_Vel.GetMagnitude() * 0.1F); + + /* Done by pie menu now, see HandlePieCommand() + //////////////////////////////////////// + // AI mode setting + + if (m_Controller.IsState(AI_MODE_SET)) + { + if (m_Controller.IsState(PRESS_RIGHT)) + { + m_AIMode = AIMODE_BRAINHUNT; + m_UpdateMovePath = true; + } + else if (m_Controller.IsState(PRESS_LEFT)) + { + m_AIMode = AIMODE_PATROL; + } + else if (m_Controller.IsState(PRESS_UP)) + { + m_AIMode = AIMODE_SENTRY; + } + else if (m_Controller.IsState(PRESS_DOWN)) + { + m_AIMode = AIMODE_GOLDDIG; + } + + m_DeviceState = SCANNING; + } + */ + + //////////////////////////////////////// + // Balance stuff + + // Get the rotation in radians. + float rot = m_Rotation.GetRadAngle(); + // rot = fabs(rot) < c_QuarterPI ? rot : (rot > 0 ? c_QuarterPI : -c_QuarterPI); + // Eliminate full rotations + while (fabs(rot) > c_TwoPI) { + rot -= rot > 0 ? c_TwoPI : -c_TwoPI; + } + // Eliminate rotations over half a turn + if (fabs(rot) > c_PI) { + rot = (rot > 0 ? -c_PI : c_PI) + (rot - (rot > 0 ? c_PI : -c_PI)); + // If we're upside down, we're unstable damnit + if (m_Status == STABLE) { + m_Status = UNSTABLE; + } + m_StableRecoverTimer.Reset(); + } + + // Rotational balancing spring calc + if (m_Status == STABLE) { + // Upright body posture + m_AngularVel = m_AngularVel * 0.9F - (rot * 0.3F); + } + // While dying, pull body quickly toward down toward horizontal + else if (m_Status == DYING) { + float rotTarget = rot > 0 ? c_HalfPI : -c_HalfPI; + // float rotTarget = m_HFlipped ? c_HalfPI : -c_HalfPI; + float rotDiff = rotTarget - rot; + if (!m_DeathTmr.IsPastSimMS(125) && fabs(rotDiff) > 0.1 && fabs(rotDiff) < c_PI) { + m_AngularVel += rotDiff * 0.5; // fabs(rotDiff); + // m_Vel.m_X += (m_HFlipped ? -fabs(rotDiff) : fabs(rotDiff)) * 0.35; + m_Vel.m_X += (rotTarget > 0 ? -fabs(rotDiff) : fabs(rotDiff)) * 0.35; + } else + m_Status = DEAD; + + // else if (fabs(m_AngularVel) > 0.1) + // m_AngularVel *= 0.5; + } + m_Rotation.SetRadAngle(rot); + + /////////////////////////////////////////////////// + // Death detection and handling + + // Losing all limbs should kill... eventually + if (!m_pLFGLeg && !m_pLBGLeg && !m_pRFGLeg && !m_pRBGLeg && m_Status != DYING && m_Status != DEAD) + m_Health -= 0.1; + + ///////////////////////////////////////// + // Misc. + + // m_DeepCheck = true/*m_Status == DEAD*/; } -/* -// TODO: REMOVE< THIS IS TEMP - // Draw the AI paths - list::iterator last = m_MovePath.begin(); - Vector waypoint, lastPoint, lineVec; - for (list::iterator lItr = m_MovePath.begin(); lItr != m_MovePath.end(); ++lItr) - { - lastPoint = (*last) - targetPos; - waypoint = lastPoint + g_SceneMan.ShortestDistance(lastPoint, (*lItr) - targetPos); - line(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, waypoint.m_X, waypoint.m_Y, g_RedColor); - last = lItr; - } - waypoint = m_MoveTarget - targetPos; - circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 3, g_RedColor); - lastPoint = m_PrevPathTarget - targetPos; - circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); - lastPoint = m_DigTunnelEndPos - targetPos; - circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); - // Raidus -// waypoint = m_Pos - targetPos; -// circle(pTargetBitmap, waypoint.m_X, waypoint.m_Y, m_MoveProximityLimit, g_RedColor); -// TODO: REMOVE THIS IS TEMP -*/ - - // Player AI drawing - - if ((m_Controller.IsState(AIM_SHARP) || (m_Controller.IsPlayerControlled() && !m_Controller.IsState(PIE_MENU_ACTIVE))) && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { - m_pTurret->GetFirstMountedDevice()->DrawHUD(pTargetBitmap, targetPos, whichScreen, m_Controller.IsState(AIM_SHARP) && m_Controller.IsPlayerControlled()); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACrab::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + Actor::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + + if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawHandAndFootGroupVisualizations()) { + m_pLFGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + m_pLBGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + m_pRFGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + m_pRBGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + } + + if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawLimbPathVisualizations()) { + m_Paths[LEFTSIDE][BGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); + m_Paths[LEFTSIDE][FGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); + m_Paths[RIGHTSIDE][BGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); + m_Paths[RIGHTSIDE][FGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); + } } - ////////////////////////////////////// - // Draw stat info HUD - char str[64]; - - GUIFont *pSymbolFont = g_FrameMan.GetLargeFont(); - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); - - // Only show extra HUD if this guy is controlled by the same player that this screen belongs to - if (m_Controller.IsPlayerControlled() && g_ActivityMan.GetActivity()->ScreenOfPlayer(m_Controller.GetPlayer()) == whichScreen && pSmallFont && pSymbolFont) - { - AllegroBitmap allegroBitmap(pTargetBitmap); - - Vector drawPos = m_Pos - targetPos; - - // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam - if (!targetPos.IsZero()) - { - // Spans vertical scene seam - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) - { - if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) - drawPos.m_X -= sceneWidth; - else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) - drawPos.m_X += sceneWidth; - } - // Spans horizontal scene seam - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) - { - if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) - drawPos.m_Y -= sceneHeight; - else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) - drawPos.m_Y += sceneHeight; - } - } - - // Held-related GUI stuff - if (m_pTurret) { - std::string textString; - for (const HeldDevice *mountedDevice : m_pTurret->GetMountedDevices()) { - if (const HDFirearm *mountedFirearm = dynamic_cast(mountedDevice)) { - if (!textString.empty()) { textString += " | "; } - int totalTextWidth = pSmallFont->CalculateWidth(textString); - if (mountedFirearm->IsReloading()) { - textString += "Reloading"; - rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, drawPos.GetFloorIntX() + 29 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 14, 245); - rectfill(pTargetBitmap, drawPos.GetFloorIntX() + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 12, drawPos.GetFloorIntX() + static_cast(28.0F * mountedFirearm->GetReloadProgress() + 0.5F) + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, 77); - } else { - textString += mountedFirearm->GetRoundInMagCount() < 0 ? "Infinite" : std::to_string(mountedFirearm->GetRoundInMagCount()); - } - } - } - if (!textString.empty()) { - str[0] = -56; str[1] = 0; - pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 10, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Left); - pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 0, drawPos.GetFloorIntY() + m_HUDStack + 3, textString, GUIFont::Left); - m_HUDStack -= 9; - } - } else { - std::snprintf(str, sizeof(str), "NO TURRET!"); - pSmallFont->DrawAligned(&allegroBitmap, drawPos.m_X + 2, drawPos.m_Y + m_HUDStack + 3, str, GUIFont::Centre); - m_HUDStack += -9; - } - - if (m_pJetpack && m_Status != INACTIVE && !m_Controller.IsState(PIE_MENU_ACTIVE) && (m_Controller.IsState(BODY_JUMP) || !m_pJetpack->IsFullyFueled())) { - if (m_pJetpack->GetJetTimeLeft() < 100.0F) { - str[0] = m_IconBlinkTimer.AlternateSim(100) ? -26 : -25; - } else if (m_pJetpack->IsEmitting()) { - float acceleration = m_pJetpack->EstimateImpulse(false) / std::max(GetMass(), 0.1F); - if (acceleration > 0.41F) { - str[0] = acceleration > 0.47F ? -31 : -30; - } else { - str[0] = acceleration > 0.35F ? -29 : -28; - if (m_IconBlinkTimer.AlternateSim(200)) { str[0] = -27; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. + + void ACrab::DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { + m_HUDStack = -m_CharHeight / 2; + + // Only do HUD if on a team + if (m_Team < 0) + return; + + // Only draw if the team viewing this is on the same team OR has seen the space where this is located. + int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); + if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { + return; + } + + Actor::DrawHUD(pTargetBitmap, targetPos, whichScreen); + + if (!m_HUDVisible) { + return; + } + /* + // TODO: REMOVE< THIS IS TEMP + // Draw the AI paths + list::iterator last = m_MovePath.begin(); + Vector waypoint, lastPoint, lineVec; + for (list::iterator lItr = m_MovePath.begin(); lItr != m_MovePath.end(); ++lItr) + { + lastPoint = (*last) - targetPos; + waypoint = lastPoint + g_SceneMan.ShortestDistance(lastPoint, (*lItr) - targetPos); + line(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, waypoint.m_X, waypoint.m_Y, g_RedColor); + last = lItr; + } + waypoint = m_MoveTarget - targetPos; + circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 3, g_RedColor); + lastPoint = m_PrevPathTarget - targetPos; + circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); + lastPoint = m_DigTunnelEndPos - targetPos; + circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); + // Raidus + // waypoint = m_Pos - targetPos; + // circle(pTargetBitmap, waypoint.m_X, waypoint.m_Y, m_MoveProximityLimit, g_RedColor); + // TODO: REMOVE THIS IS TEMP + */ + + // Player AI drawing + + if ((m_Controller.IsState(AIM_SHARP) || (m_Controller.IsPlayerControlled() && !m_Controller.IsState(PIE_MENU_ACTIVE))) && m_pTurret && m_pTurret->IsAttached() && m_pTurret->HasMountedDevice()) { + m_pTurret->GetFirstMountedDevice()->DrawHUD(pTargetBitmap, targetPos, whichScreen, m_Controller.IsState(AIM_SHARP) && m_Controller.IsPlayerControlled()); + } + ////////////////////////////////////// + // Draw stat info HUD + char str[64]; + + GUIFont* pSymbolFont = g_FrameMan.GetLargeFont(); + GUIFont* pSmallFont = g_FrameMan.GetSmallFont(); + + // Only show extra HUD if this guy is controlled by the same player that this screen belongs to + if (m_Controller.IsPlayerControlled() && g_ActivityMan.GetActivity()->ScreenOfPlayer(m_Controller.GetPlayer()) == whichScreen && pSmallFont && pSymbolFont) { + AllegroBitmap allegroBitmap(pTargetBitmap); + + Vector drawPos = m_Pos - targetPos; + + // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam + if (!targetPos.IsZero()) { + // Spans vertical scene seam + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) + drawPos.m_X -= sceneWidth; + else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) + drawPos.m_X += sceneWidth; + } + // Spans horizontal scene seam + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) + drawPos.m_Y -= sceneHeight; + else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) + drawPos.m_Y += sceneHeight; + } + } + + // Held-related GUI stuff + if (m_pTurret) { + std::string textString; + for (const HeldDevice* mountedDevice: m_pTurret->GetMountedDevices()) { + if (const HDFirearm* mountedFirearm = dynamic_cast(mountedDevice)) { + if (!textString.empty()) { + textString += " | "; + } + int totalTextWidth = pSmallFont->CalculateWidth(textString); + if (mountedFirearm->IsReloading()) { + textString += "Reloading"; + rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, drawPos.GetFloorIntX() + 29 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 14, 245); + rectfill(pTargetBitmap, drawPos.GetFloorIntX() + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 12, drawPos.GetFloorIntX() + static_cast(28.0F * mountedFirearm->GetReloadProgress() + 0.5F) + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, 77); + } else { + textString += mountedFirearm->GetRoundInMagCount() < 0 ? "Infinite" : std::to_string(mountedFirearm->GetRoundInMagCount()); + } + } + } + if (!textString.empty()) { + str[0] = -56; + str[1] = 0; + pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 10, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Left); + pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 0, drawPos.GetFloorIntY() + m_HUDStack + 3, textString, GUIFont::Left); + m_HUDStack -= 9; } } else { - str[0] = -27; + std::snprintf(str, sizeof(str), "NO TURRET!"); + pSmallFont->DrawAligned(&allegroBitmap, drawPos.m_X + 2, drawPos.m_Y + m_HUDStack + 3, str, GUIFont::Centre); + m_HUDStack += -9; } - str[1] = 0; - pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 7, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Centre); - - rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 7, drawPos.GetFloorIntX() + 15, drawPos.GetFloorIntY() + m_HUDStack + 8, 245); - if (m_pJetpack->GetJetTimeTotal() > 0.0F) { - float jetTimeRatio = m_pJetpack->GetJetTimeRatio(); - int gaugeColor; - if (jetTimeRatio > 0.75F) { - gaugeColor = 149; - } else if (jetTimeRatio > 0.5F) { - gaugeColor = 133; - } else if (jetTimeRatio > 0.375F) { - gaugeColor = 77; - } else if (jetTimeRatio > 0.25F) { - gaugeColor = 48; + + if (m_pJetpack && m_Status != INACTIVE && !m_Controller.IsState(PIE_MENU_ACTIVE) && (m_Controller.IsState(BODY_JUMP) || !m_pJetpack->IsFullyFueled())) { + if (m_pJetpack->GetJetTimeLeft() < 100.0F) { + str[0] = m_IconBlinkTimer.AlternateSim(100) ? -26 : -25; + } else if (m_pJetpack->IsEmitting()) { + float acceleration = m_pJetpack->EstimateImpulse(false) / std::max(GetMass(), 0.1F); + if (acceleration > 0.41F) { + str[0] = acceleration > 0.47F ? -31 : -30; + } else { + str[0] = acceleration > 0.35F ? -29 : -28; + if (m_IconBlinkTimer.AlternateSim(200)) { + str[0] = -27; + } + } } else { - gaugeColor = 13; + str[0] = -27; + } + str[1] = 0; + pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 7, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Centre); + + rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 7, drawPos.GetFloorIntX() + 15, drawPos.GetFloorIntY() + m_HUDStack + 8, 245); + if (m_pJetpack->GetJetTimeTotal() > 0.0F) { + float jetTimeRatio = m_pJetpack->GetJetTimeRatio(); + int gaugeColor; + if (jetTimeRatio > 0.75F) { + gaugeColor = 149; + } else if (jetTimeRatio > 0.5F) { + gaugeColor = 133; + } else if (jetTimeRatio > 0.375F) { + gaugeColor = 77; + } else if (jetTimeRatio > 0.25F) { + gaugeColor = 48; + } else { + gaugeColor = 13; + } + rectfill(pTargetBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 6, drawPos.GetFloorIntX() + static_cast(15.0F * jetTimeRatio), drawPos.GetFloorIntY() + m_HUDStack + 7, gaugeColor); } - rectfill(pTargetBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 6, drawPos.GetFloorIntX() + static_cast(15.0F * jetTimeRatio), drawPos.GetFloorIntY() + m_HUDStack + 7, gaugeColor); + m_HUDStack -= 9; } - m_HUDStack -= 9; - } - - // Print aim angle and rot angle stoff - /*{ - std::snprintf(str, sizeof(str), "Aim %.2f Rot %.2f Lim %.2f", m_AimAngle, GetRotAngle(), m_AimRange + GetRotAngle()); - pSmallFont->DrawAligned(&allegroBitmap, drawPos.m_X - 0, drawPos.m_Y + m_HUDStack + 3, str, GUIFont::Centre); - - m_HUDStack += -10; - }*/ - -/* - // AI Mode select GUI HUD - if (m_Controller.IsState(AI_MODE_SET)) - { - int iconOff = m_apAIIcons[0]->w + 2; - int iconColor = m_Team == Activity::TeamOne ? AIICON_RED : AIICON_GREEN; - Vector iconPos = GetCPUPos() - targetPos; - - if (m_AIMode == AIMODE_SENTRY) - { - std::snprintf(str, sizeof(str), "%s", "Sentry"); - pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X, iconPos.m_Y - 18, str, GUIFont::Centre); - } - else if (m_AIMode == AIMODE_PATROL) - { - std::snprintf(str, sizeof(str), "%s", "Patrol"); - pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X - 9, iconPos.m_Y - 5, str, GUIFont::Right); - } - else if (m_AIMode == AIMODE_BRAINHUNT) - { - std::snprintf(str, sizeof(str), "%s", "Brainhunt"); - pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X + 9, iconPos.m_Y - 5, str, GUIFont::Left); - } - else if (m_AIMode == AIMODE_GOLDDIG) - { - std::snprintf(str, sizeof(str), "%s", "Gold Dig"); - pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X, iconPos.m_Y + 8, str, GUIFont::Centre); - } - - // Draw the mode alternatives if they are not the current one - if (m_AIMode != AIMODE_SENTRY) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_SENTRY], iconPos.m_X - 6, iconPos.m_Y - 6 - iconOff); - } - if (m_AIMode != AIMODE_PATROL) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_PATROL], iconPos.m_X - 6 - iconOff, iconPos.m_Y - 6); - } - if (m_AIMode != AIMODE_BRAINHUNT) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_BRAINHUNT], iconPos.m_X - 6 + iconOff, iconPos.m_Y - 6); - } - if (m_AIMode != AIMODE_GOLDDIG) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_GOLDDIG], iconPos.m_X - 6, iconPos.m_Y - 6 + iconOff); - } - } -*/ - } -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get walking limb path speed for the specified preset. + // Print aim angle and rot angle stoff + /*{ + std::snprintf(str, sizeof(str), "Aim %.2f Rot %.2f Lim %.2f", m_AimAngle, GetRotAngle(), m_AimRange + GetRotAngle()); + pSmallFont->DrawAligned(&allegroBitmap, drawPos.m_X - 0, drawPos.m_Y + m_HUDStack + 3, str, GUIFont::Centre); + + m_HUDStack += -10; + }*/ + + /* + // AI Mode select GUI HUD + if (m_Controller.IsState(AI_MODE_SET)) + { + int iconOff = m_apAIIcons[0]->w + 2; + int iconColor = m_Team == Activity::TeamOne ? AIICON_RED : AIICON_GREEN; + Vector iconPos = GetCPUPos() - targetPos; + + if (m_AIMode == AIMODE_SENTRY) + { + std::snprintf(str, sizeof(str), "%s", "Sentry"); + pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X, iconPos.m_Y - 18, str, GUIFont::Centre); + } + else if (m_AIMode == AIMODE_PATROL) + { + std::snprintf(str, sizeof(str), "%s", "Patrol"); + pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X - 9, iconPos.m_Y - 5, str, GUIFont::Right); + } + else if (m_AIMode == AIMODE_BRAINHUNT) + { + std::snprintf(str, sizeof(str), "%s", "Brainhunt"); + pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X + 9, iconPos.m_Y - 5, str, GUIFont::Left); + } + else if (m_AIMode == AIMODE_GOLDDIG) + { + std::snprintf(str, sizeof(str), "%s", "Gold Dig"); + pSmallFont->DrawAligned(&allegroBitmap, iconPos.m_X, iconPos.m_Y + 8, str, GUIFont::Centre); + } + + // Draw the mode alternatives if they are not the current one + if (m_AIMode != AIMODE_SENTRY) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_SENTRY], iconPos.m_X - 6, iconPos.m_Y - 6 - iconOff); + } + if (m_AIMode != AIMODE_PATROL) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_PATROL], iconPos.m_X - 6 - iconOff, iconPos.m_Y - 6); + } + if (m_AIMode != AIMODE_BRAINHUNT) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_BRAINHUNT], iconPos.m_X - 6 + iconOff, iconPos.m_Y - 6); + } + if (m_AIMode != AIMODE_GOLDDIG) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_GOLDDIG], iconPos.m_X - 6, iconPos.m_Y - 6 + iconOff); + } + } + */ + } + } -float ACrab::GetLimbPathSpeed(int speedPreset) const -{ - return m_Paths[LEFTSIDE][FGROUND][WALK].GetSpeed(speedPreset); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get walking limb path speed for the specified preset. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Set walking limb path speed for the specified preset. + float ACrab::GetLimbPathSpeed(int speedPreset) const { + return m_Paths[LEFTSIDE][FGROUND][WALK].GetSpeed(speedPreset); + } -void ACrab::SetLimbPathSpeed(int speedPreset, float speed) -{ - m_Paths[LEFTSIDE][FGROUND][WALK].OverrideSpeed(speedPreset, speed); - m_Paths[RIGHTSIDE][FGROUND][WALK].OverrideSpeed(speedPreset, speed); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Set walking limb path speed for the specified preset. - m_Paths[LEFTSIDE][BGROUND][WALK].OverrideSpeed(speedPreset, speed); - m_Paths[RIGHTSIDE][BGROUND][WALK].OverrideSpeed(speedPreset, speed); -} + void ACrab::SetLimbPathSpeed(int speedPreset, float speed) { + m_Paths[LEFTSIDE][FGROUND][WALK].OverrideSpeed(speedPreset, speed); + m_Paths[RIGHTSIDE][FGROUND][WALK].OverrideSpeed(speedPreset, speed); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the force that a limb traveling walking LimbPath can push against -// stuff in the scene with. + m_Paths[LEFTSIDE][BGROUND][WALK].OverrideSpeed(speedPreset, speed); + m_Paths[RIGHTSIDE][BGROUND][WALK].OverrideSpeed(speedPreset, speed); + } -float ACrab::GetLimbPathPushForce() const -{ - return m_Paths[LEFTSIDE][FGROUND][WALK].GetDefaultPushForce(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the force that a limb traveling walking LimbPath can push against + // stuff in the scene with. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the default force that a limb traveling walking LimbPath can push against -// stuff in the scene with. + float ACrab::GetLimbPathPushForce() const { + return m_Paths[LEFTSIDE][FGROUND][WALK].GetDefaultPushForce(); + } -void ACrab::SetLimbPathPushForce(float force) -{ - m_Paths[LEFTSIDE][FGROUND][WALK].OverridePushForce(force); - m_Paths[RIGHTSIDE][FGROUND][WALK].OverridePushForce(force); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the default force that a limb traveling walking LimbPath can push against + // stuff in the scene with. - m_Paths[LEFTSIDE][BGROUND][WALK].OverridePushForce(force); - m_Paths[RIGHTSIDE][BGROUND][WALK].OverridePushForce(force); -} + void ACrab::SetLimbPathPushForce(float force) { + m_Paths[LEFTSIDE][FGROUND][WALK].OverridePushForce(force); + m_Paths[RIGHTSIDE][FGROUND][WALK].OverridePushForce(force); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m_Paths[LEFTSIDE][BGROUND][WALK].OverridePushForce(force); + m_Paths[RIGHTSIDE][BGROUND][WALK].OverridePushForce(force); + } -int ACrab::WhilePieMenuOpenListener(const PieMenu *pieMenu) { - int result = Actor::WhilePieMenuOpenListener(pieMenu); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - for (PieSlice *pieSlice : GetPieMenu()->GetPieSlices()) { - if (pieSlice->GetType() == PieSlice::SliceType::Reload) { - if (m_pTurret && m_pTurret->HasMountedDevice()) { - pieSlice->SetDescription("Reload"); - pieSlice->SetEnabled(!FirearmsAreFull()); - } else { - pieSlice->SetDescription(m_pTurret ? "No Weapons" : "No Turret"); - pieSlice->SetEnabled(false); + int ACrab::WhilePieMenuOpenListener(const PieMenu* pieMenu) { + int result = Actor::WhilePieMenuOpenListener(pieMenu); + + for (PieSlice* pieSlice: GetPieMenu()->GetPieSlices()) { + if (pieSlice->GetType() == PieSlice::SliceType::Reload) { + if (m_pTurret && m_pTurret->HasMountedDevice()) { + pieSlice->SetDescription("Reload"); + pieSlice->SetEnabled(!FirearmsAreFull()); + } else { + pieSlice->SetDescription(m_pTurret ? "No Weapons" : "No Turret"); + pieSlice->SetEnabled(false); + } + break; } - break; } + return result; } - return result; -} - } // namespace RTE diff --git a/Source/Entities/ACrab.h b/Source/Entities/ACrab.h index c915c0a72..8258f884c 100644 --- a/Source/Entities/ACrab.h +++ b/Source/Entities/ACrab.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,639 +19,605 @@ struct BITMAP; -namespace RTE -{ - -class Turret; -class AEJetpack; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: ACrab -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A crab-like actor with four legs. -// Parent(s): Actor. -// Class history: 10/24/2007 ACrab created. - -class ACrab : public Actor { - friend struct EntityLuaBindings; - - enum Side { - LEFTSIDE = 0, - RIGHTSIDE, - SIDECOUNT - }; - - enum Layer { - FGROUND = 0, - BGROUND, - LAYERCOUNT - }; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions - EntityAllocation(ACrab); - AddScriptFunctionNames(Actor, "OnStride"); - SerializableOverrideMethods; - ClassInfoGetters; - DefaultPieMenuNameGetter(HasObjectInGroup("Turrets") ? "Default Turret Pie Menu" : "Default Crab Pie Menu"); - - ////////////////////////////////////////////////////////////////////////////////////////// - // Constructor: ACrab - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Constructor method used to instantiate a ACrab object in system - // memory. Create() should be called before using the object. - // Arguments: None. - - ACrab() { Clear(); } +namespace RTE { + class Turret; + class AEJetpack; ////////////////////////////////////////////////////////////////////////////////////////// - // Destructor: ~ACrab + // Class: ACrab ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Destructor method used to clean up a ACrab object before deletion - // from system memory. - // Arguments: None. - - ~ACrab() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACrab object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Creates a ACrab to be identical to another, by deep copy. - // Arguments: A reference to the ACrab to deep copy. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create(const ACrab &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire ACrab, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Actor::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEyePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' eye, or equivalent, where look -// vector starts from. -// Arguments: None. -// Return value: A Vector with the absolute position of this' eye or view point. - - Vector GetEyePos() const override; - - - /// - /// Gets the Turret of this ACrab. - /// - /// A pointer to Turret of this ACrab. Ownership is NOT transferred! - Turret * GetTurret() const { return m_pTurret; } - - /// - /// Sets the Turret for this ACrab. Ownership IS transferred! - /// - /// The new Turret to use. - void SetTurret(Turret *newTurret); - - /// - /// Gets the jetpack of this ACrab. - /// - /// A pointer to the jetpack of this ACrab. Ownership is NOT transferred! - AEJetpack * GetJetpack() const { return m_pJetpack; } - - /// - /// Sets the jetpack for this ACrab. Ownership IS Transferred! - /// - /// The new jetpack to use. - void SetJetpack(AEJetpack *newJetpack); - - /// - /// Gets the left foreground Leg of this ACrab. - /// - /// A pointer to the left foreground Leg of this ACrab. Ownership is NOT transferred! - Leg * GetLeftFGLeg() const { return m_pLFGLeg; } - - /// - /// Sets the left foreground Leg for this ACrab. Ownership IS transferred! - /// - /// The new Leg to use. - void SetLeftFGLeg(Leg *newLeg); - - /// - /// Gets the left background Leg of this ACrab. - /// - /// A pointer to the left background Leg of this ACrab. Ownership is NOT transferred! - Leg * GetLeftBGLeg() const { return m_pLBGLeg; } - - /// - /// Sets the left background Leg for this ACrab. Ownership IS transferred! - /// - /// The new Leg to use. - void SetLeftBGLeg(Leg *newLeg); - - /// - /// Gets the right foreground Leg of this ACrab. - /// - /// A pointer to the right foreground Leg of this ACrab. Ownership is NOT transferred! - Leg * GetRightFGLeg() const { return m_pRFGLeg; } - - /// - /// Sets the right foreground Leg for this ACrab. Ownership IS transferred! - /// - /// The new Leg to use. - void SetRightFGLeg(Leg *newLeg); - - /// - /// Gets the right BG Leg of this ACrab. - /// - /// A pointer to the right background Leg of this ACrab. Ownership is NOT transferred! - Leg * GetRightBGLeg() const { return m_pRBGLeg; } - - /// - /// Sets the right background Leg for this ACrab. Ownership IS transferred! - /// - /// The new Leg to use. - void SetRightBGLeg(Leg *newLeg); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. -// Arguments: Reference to the HitData struct which describes the collision. This -// will be modified to represent the results of the collision. -// Return value: Whether the collision has been deemed valid. If false, then disregard -// any impulses in the Hitdata. - - bool CollideAtPoint(HitData &hitData) override; - - /// - /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. - /// - /// The SliceType of the PieSlice being handled. - /// Whether or not the activated PieSlice SliceType was able to be handled. - bool HandlePieCommand(PieSlice::SliceType pieSliceType) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEquippedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whatever is equipped in the turret, if anything. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: None. -// Return value: The currently equipped item, if any. - - MovableObject * GetEquippedItem() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmIsReady -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is ready for use, and has -// ammo etc. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) is ready for use. - - bool FirearmIsReady() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmIsEmpty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is out of ammo. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) is out of ammo. - - bool FirearmIsEmpty() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmNeedsReload -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is almost out of ammo. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) has less than half of ammo left. - - bool FirearmNeedsReload() const; - - /// - /// Gets whether or not all of this ACrab's Turret's HDFirearms are full. - /// - /// Whether or not all of this ACrab's Turret's HDFirearms are full. Will return true if there is no Turret or no HDFirearms. - bool FirearmsAreFull() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmIsSemiAuto -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is semi or full auto. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) is a semi auto device. - - bool FirearmIsSemiAuto() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmActivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the currently held device's delay between pulling the trigger -// and activating. -// Arguments: None. -// Return value: Delay in ms or zero if not a HDFirearm. - -int FirearmActivationDelay() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReloadFirearms -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the currently held firearms, if any. -// Arguments: None. -// Return value: None. - - void ReloadFirearms(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsWithinRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a point on the scene is within close range of the currently -// used device and aiming status, if applicable. -// Arguments: A Vector witht he aboslute coordinates of a point to check. -// Return value: Whether the point is within close range of this. - - bool IsWithinRange(Vector &point) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Look -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an unseen-revealing ray in the direction of where this is facing. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. -// The range, in pixels, beyond the actors sharp aim that the ray will have. -// Return value: Whether any unseen pixels were revealed by this look. - - bool Look(float FOVSpread, float range) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LookForMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an MO detecting ray in the direction of where the head is looking -// at the time. Factors including head rotation, sharp aim mode, and -// other variables determine how this ray is cast. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. -// A specific material ID to ignore (see through) -// Whether to ignore all terrain or not (true means 'x-ray vision'). -// Return value: A pointer to the MO seen while looking. - - MovableObject * LookForMOs(float FOVSpread = 45, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false); - - - /// - /// Gets the GUI representation of this ACrab, only defaulting to its Turret or body if no GraphicalIcon has been defined. - /// - /// The graphical representation of this ACrab as a BITMAP. - BITMAP * GetGraphicalIcon() const override; - - - /// - /// Gets whether this ACrab has just taken a stride this frame. - /// - /// Whether this ACrab has taken a stride this frame or not. - bool StrideFrame() const { return m_StrideFrame; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreControllerUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void PreControllerUpdate() override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this ACrab's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// Which player's screen this is being drawn to. May affect what HUD elements -// get drawn etc. -// Return value: None. - - void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; - - - /// - /// Gets the LimbPath corresponding to the passed in Side, Layer and MovementState values. - /// - /// Whether to get the left or right side. - /// Whether to get foreground or background LimbPath. - /// Which movement state to get the LimbPath for. - /// The LimbPath corresponding to the passed in Layer and MovementState values. - LimbPath *GetLimbPath(Side side, Layer layer, MovementState movementState) { return &m_Paths[side][layer][movementState]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get walking limb path speed for the specified preset. -// Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST -// Return value: Limb path speed for the specified preset in m/s. - - float GetLimbPathSpeed(int speedPreset) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Set walking limb path speed for the specified preset. -// Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST. New speed value in m/s. -// Return value: None. - - void SetLimbPathSpeed(int speedPreset, float speed); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the default force that a limb traveling walking LimbPath can push against -// stuff in the scene with. -// Arguments: None. -// Return value: The default set force maximum, in kg * m/s^2. - - float GetLimbPathPushForce() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the default force that a limb traveling walking LimbPath can push against -// stuff in the scene with. -// Arguments: The default set force maximum, in kg * m/s^2. -// Return value: None - - void SetLimbPathPushForce(float force); - - - /// - /// Gets this ACrab's stride sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this ACrab's stride sound. - SoundContainer * GetStrideSound() const { return m_StrideSound; } - - /// - /// Sets this ACrab's stride sound. Ownership IS transferred! - /// - /// The new SoundContainer for this ACrab's stride sound. - void SetStrideSound(SoundContainer *newSound) { m_StrideSound = newSound; } - - /// - /// Gets the upper limit of this ACrab's aim range. - /// - /// The upper limit of this ACrab's aim range. - float GetAimRangeUpperLimit() const { return m_AimRangeUpperLimit; } - - /// - /// Sets the upper limit of this ACrab's aim range. - /// - /// The new upper limit of this ACrab's aim range. - void SetAimRangeUpperLimit(float aimRangeUpperLimit) { m_AimRangeUpperLimit = aimRangeUpperLimit; } - - /// - /// Gets the lower limit of this ACrab's aim range. - /// - /// The lower limit of this ACrab's aim range. - float GetAimRangeLowerLimit() const { return m_AimRangeLowerLimit; } - - /// - /// Sets the lower limit of this ACrab's aim range. - /// - /// The new lower limit of this ACrab's aim range. - void SetAimRangeLowerLimit(float aimRangeLowerLimit) { m_AimRangeLowerLimit = aimRangeLowerLimit; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Function that is called when we get a new movepath. - /// This processes and cleans up the movepath. - /// - void OnNewMovePath() override; - - // Member variables - static Entity::ClassInfo m_sClass; - - // Turret which can be mounted with a weapon - Turret *m_pTurret; - //TODO when this class is cleaned up these legs and footgroups should probably be renamed. L and R should be expanded to Left and Right. I think FG and BG can stay as is cause they're everywhere. - // Left Foreground leg. - Leg *m_pLFGLeg; - // Left Background leg. - Leg *m_pLBGLeg; - // Right Foreground leg. - Leg *m_pRFGLeg; - // Right Background leg. - Leg *m_pRBGLeg; - // Limb AtomGroups. - AtomGroup *m_pLFGFootGroup; - AtomGroup *m_BackupLFGFootGroup; - AtomGroup *m_pLBGFootGroup; - AtomGroup *m_BackupLBGFootGroup; - AtomGroup *m_pRFGFootGroup; - AtomGroup *m_BackupRFGFootGroup; - AtomGroup *m_pRBGFootGroup; - AtomGroup *m_BackupRBGFootGroup; - // The sound of the actor taking a step (think robot servo) - SoundContainer *m_StrideSound; - // Jetpack booster. - AEJetpack *m_pJetpack; - // Blink timer - Timer m_IconBlinkTimer; - // Whether a stride was taken this frame or not. - bool m_StrideFrame = false; - // Limb paths for different movement states. - // First which side, then which background/foreground, then the movement state - LimbPath m_Paths[SIDECOUNT][LAYERCOUNT][MOVEMENTSTATECOUNT]; - // Whether was aiming during the last frame too. - bool m_Aiming; - // Controls the start of leg synch. - bool m_StrideStart[SIDECOUNT]; - // Times the strides to make sure they get restarted if they end up too long - Timer m_StrideTimer[SIDECOUNT]; - // The maximum angle MountedMO can be aimed up, positive values only, in radians - float m_AimRangeUpperLimit; - // The maximum angle MountedMO can be aimed down, positive values only, in radians - float m_AimRangeLowerLimit; - - //////////////// - // AI States - - enum DeviceHandlingState { - STILL = 0, - POINTING, - SCANNING, - AIMING, - FIRING, - THROWING, - DIGGING - }; - - enum SweepState { - NOSWEEP = 0, - SWEEPINGUP, - SWEEPUPPAUSE, - SWEEPINGDOWN, - SWEEPDOWNPAUSE - }; - - enum DigState { - NOTDIGGING = 0, - PREDIG, - STARTDIG, - TUNNELING, - FINISHINGDIG, - PAUSEDIGGER - }; - - enum JumpState { - NOTJUMPING = 0, - FORWARDJUMP, - PREUPJUMP, - UPJUMP, - APEXJUMP, - LANDJUMP - }; - - // What the AI is doing with its held devices - DeviceHandlingState m_DeviceState; - // What we are doing with a device sweeping - SweepState m_SweepState; - // The current digging state - DigState m_DigState; - // The current jumping state - JumpState m_JumpState; - // Jumping target, overshoot this and the jump is completed - Vector m_JumpTarget; - // Jumping left or right - bool m_JumpingRight; - // The position of the end of the current tunnel being dug. When it is reached, digging can stop. - Vector m_DigTunnelEndPos; - // The center angle (in rads) for the sweeping motion done duing scannign and digging - float m_SweepCenterAimAngle; - // The range to each direction of the center that the sweeping motion will be done in - float m_SweepRange; - // The absolute coordinates of the last detected gold deposits - Vector m_DigTarget; - // Timer for how long to be shooting at a seen enemy target - Timer m_FireTimer; - // Timer for how long to be shooting at a seen enemy target - Timer m_SweepTimer; - // Timer for how long to be patrolling in a direction - Timer m_PatrolTimer; - // Timer for how long to be firing the jetpack in a direction - Timer m_JumpTimer; - // Whether mouse input should be locked to the aim range, or whether we can "wander" out. For static emplacements like turrets, this is good, but for moving things it's a bit sticky. - bool m_LockMouseAimInput; + // Description: A crab-like actor with four legs. + // Parent(s): Actor. + // Class history: 10/24/2007 ACrab created. + + class ACrab : public Actor { + friend struct EntityLuaBindings; + + enum Side { + LEFTSIDE = 0, + RIGHTSIDE, + SIDECOUNT + }; + + enum Layer { + FGROUND = 0, + BGROUND, + LAYERCOUNT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(ACrab); + AddScriptFunctionNames(Actor, "OnStride"); + SerializableOverrideMethods; + ClassInfoGetters; + DefaultPieMenuNameGetter(HasObjectInGroup("Turrets") ? "Default Turret Pie Menu" : "Default Crab Pie Menu"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: ACrab + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a ACrab object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + ACrab() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~ACrab + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a ACrab object before deletion + // from system memory. + // Arguments: None. + + ~ACrab() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACrab object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACrab to be identical to another, by deep copy. + // Arguments: A reference to the ACrab to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const ACrab& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire ACrab, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Actor::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEyePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' eye, or equivalent, where look + // vector starts from. + // Arguments: None. + // Return value: A Vector with the absolute position of this' eye or view point. + + Vector GetEyePos() const override; + + /// + /// Gets the Turret of this ACrab. + /// + /// A pointer to Turret of this ACrab. Ownership is NOT transferred! + Turret* GetTurret() const { return m_pTurret; } + + /// + /// Sets the Turret for this ACrab. Ownership IS transferred! + /// + /// The new Turret to use. + void SetTurret(Turret* newTurret); + + /// + /// Gets the jetpack of this ACrab. + /// + /// A pointer to the jetpack of this ACrab. Ownership is NOT transferred! + AEJetpack* GetJetpack() const { return m_pJetpack; } + + /// + /// Sets the jetpack for this ACrab. Ownership IS Transferred! + /// + /// The new jetpack to use. + void SetJetpack(AEJetpack* newJetpack); + + /// + /// Gets the left foreground Leg of this ACrab. + /// + /// A pointer to the left foreground Leg of this ACrab. Ownership is NOT transferred! + Leg* GetLeftFGLeg() const { return m_pLFGLeg; } + + /// + /// Sets the left foreground Leg for this ACrab. Ownership IS transferred! + /// + /// The new Leg to use. + void SetLeftFGLeg(Leg* newLeg); + + /// + /// Gets the left background Leg of this ACrab. + /// + /// A pointer to the left background Leg of this ACrab. Ownership is NOT transferred! + Leg* GetLeftBGLeg() const { return m_pLBGLeg; } + + /// + /// Sets the left background Leg for this ACrab. Ownership IS transferred! + /// + /// The new Leg to use. + void SetLeftBGLeg(Leg* newLeg); + + /// + /// Gets the right foreground Leg of this ACrab. + /// + /// A pointer to the right foreground Leg of this ACrab. Ownership is NOT transferred! + Leg* GetRightFGLeg() const { return m_pRFGLeg; } + + /// + /// Sets the right foreground Leg for this ACrab. Ownership IS transferred! + /// + /// The new Leg to use. + void SetRightFGLeg(Leg* newLeg); + + /// + /// Gets the right BG Leg of this ACrab. + /// + /// A pointer to the right background Leg of this ACrab. Ownership is NOT transferred! + Leg* GetRightBGLeg() const { return m_pRBGLeg; } + + /// + /// Sets the right background Leg for this ACrab. Ownership IS transferred! + /// + /// The new Leg to use. + void SetRightBGLeg(Leg* newLeg); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + // Arguments: Reference to the HitData struct which describes the collision. This + // will be modified to represent the results of the collision. + // Return value: Whether the collision has been deemed valid. If false, then disregard + // any impulses in the Hitdata. + + bool CollideAtPoint(HitData& hitData) override; + + /// + /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. + /// + /// The SliceType of the PieSlice being handled. + /// Whether or not the activated PieSlice SliceType was able to be handled. + bool HandlePieCommand(PieSlice::SliceType pieSliceType) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEquippedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whatever is equipped in the turret, if anything. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: None. + // Return value: The currently equipped item, if any. + + MovableObject* GetEquippedItem() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmIsReady + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is ready for use, and has + // ammo etc. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) is ready for use. + + bool FirearmIsReady() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmIsEmpty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is out of ammo. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) is out of ammo. + + bool FirearmIsEmpty() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmNeedsReload + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is almost out of ammo. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) has less than half of ammo left. + + bool FirearmNeedsReload() const; + + /// + /// Gets whether or not all of this ACrab's Turret's HDFirearms are full. + /// + /// Whether or not all of this ACrab's Turret's HDFirearms are full. Will return true if there is no Turret or no HDFirearms. + bool FirearmsAreFull() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmIsSemiAuto + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is semi or full auto. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) is a semi auto device. + + bool FirearmIsSemiAuto() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmActivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the currently held device's delay between pulling the trigger + // and activating. + // Arguments: None. + // Return value: Delay in ms or zero if not a HDFirearm. + + int FirearmActivationDelay() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReloadFirearms + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the currently held firearms, if any. + // Arguments: None. + // Return value: None. + + void ReloadFirearms(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsWithinRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a point on the scene is within close range of the currently + // used device and aiming status, if applicable. + // Arguments: A Vector witht he aboslute coordinates of a point to check. + // Return value: Whether the point is within close range of this. + + bool IsWithinRange(Vector& point) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Look + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an unseen-revealing ray in the direction of where this is facing. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + // The range, in pixels, beyond the actors sharp aim that the ray will have. + // Return value: Whether any unseen pixels were revealed by this look. + + bool Look(float FOVSpread, float range) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LookForMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an MO detecting ray in the direction of where the head is looking + // at the time. Factors including head rotation, sharp aim mode, and + // other variables determine how this ray is cast. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + // A specific material ID to ignore (see through) + // Whether to ignore all terrain or not (true means 'x-ray vision'). + // Return value: A pointer to the MO seen while looking. + + MovableObject* LookForMOs(float FOVSpread = 45, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false); + + /// + /// Gets the GUI representation of this ACrab, only defaulting to its Turret or body if no GraphicalIcon has been defined. + /// + /// The graphical representation of this ACrab as a BITMAP. + BITMAP* GetGraphicalIcon() const override; + + /// + /// Gets whether this ACrab has just taken a stride this frame. + /// + /// Whether this ACrab has taken a stride this frame or not. + bool StrideFrame() const { return m_StrideFrame; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreControllerUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void PreControllerUpdate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this ACrab's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // Which player's screen this is being drawn to. May affect what HUD elements + // get drawn etc. + // Return value: None. + + void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + + /// + /// Gets the LimbPath corresponding to the passed in Side, Layer and MovementState values. + /// + /// Whether to get the left or right side. + /// Whether to get foreground or background LimbPath. + /// Which movement state to get the LimbPath for. + /// The LimbPath corresponding to the passed in Layer and MovementState values. + LimbPath* GetLimbPath(Side side, Layer layer, MovementState movementState) { return &m_Paths[side][layer][movementState]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get walking limb path speed for the specified preset. + // Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST + // Return value: Limb path speed for the specified preset in m/s. + + float GetLimbPathSpeed(int speedPreset) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Set walking limb path speed for the specified preset. + // Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST. New speed value in m/s. + // Return value: None. + + void SetLimbPathSpeed(int speedPreset, float speed); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the default force that a limb traveling walking LimbPath can push against + // stuff in the scene with. + // Arguments: None. + // Return value: The default set force maximum, in kg * m/s^2. + + float GetLimbPathPushForce() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the default force that a limb traveling walking LimbPath can push against + // stuff in the scene with. + // Arguments: The default set force maximum, in kg * m/s^2. + // Return value: None + + void SetLimbPathPushForce(float force); + + /// + /// Gets this ACrab's stride sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this ACrab's stride sound. + SoundContainer* GetStrideSound() const { return m_StrideSound; } + + /// + /// Sets this ACrab's stride sound. Ownership IS transferred! + /// + /// The new SoundContainer for this ACrab's stride sound. + void SetStrideSound(SoundContainer* newSound) { m_StrideSound = newSound; } + + /// + /// Gets the upper limit of this ACrab's aim range. + /// + /// The upper limit of this ACrab's aim range. + float GetAimRangeUpperLimit() const { return m_AimRangeUpperLimit; } + + /// + /// Sets the upper limit of this ACrab's aim range. + /// + /// The new upper limit of this ACrab's aim range. + void SetAimRangeUpperLimit(float aimRangeUpperLimit) { m_AimRangeUpperLimit = aimRangeUpperLimit; } + + /// + /// Gets the lower limit of this ACrab's aim range. + /// + /// The lower limit of this ACrab's aim range. + float GetAimRangeLowerLimit() const { return m_AimRangeLowerLimit; } + + /// + /// Sets the lower limit of this ACrab's aim range. + /// + /// The new lower limit of this ACrab's aim range. + void SetAimRangeLowerLimit(float aimRangeLowerLimit) { m_AimRangeLowerLimit = aimRangeLowerLimit; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Function that is called when we get a new movepath. + /// This processes and cleans up the movepath. + /// + void OnNewMovePath() override; + + // Member variables + static Entity::ClassInfo m_sClass; + + // Turret which can be mounted with a weapon + Turret* m_pTurret; + // TODO when this class is cleaned up these legs and footgroups should probably be renamed. L and R should be expanded to Left and Right. I think FG and BG can stay as is cause they're everywhere. + // Left Foreground leg. + Leg* m_pLFGLeg; + // Left Background leg. + Leg* m_pLBGLeg; + // Right Foreground leg. + Leg* m_pRFGLeg; + // Right Background leg. + Leg* m_pRBGLeg; + // Limb AtomGroups. + AtomGroup* m_pLFGFootGroup; + AtomGroup* m_BackupLFGFootGroup; + AtomGroup* m_pLBGFootGroup; + AtomGroup* m_BackupLBGFootGroup; + AtomGroup* m_pRFGFootGroup; + AtomGroup* m_BackupRFGFootGroup; + AtomGroup* m_pRBGFootGroup; + AtomGroup* m_BackupRBGFootGroup; + // The sound of the actor taking a step (think robot servo) + SoundContainer* m_StrideSound; + // Jetpack booster. + AEJetpack* m_pJetpack; + // Blink timer + Timer m_IconBlinkTimer; + // Whether a stride was taken this frame or not. + bool m_StrideFrame = false; + // Limb paths for different movement states. + // First which side, then which background/foreground, then the movement state + LimbPath m_Paths[SIDECOUNT][LAYERCOUNT][MOVEMENTSTATECOUNT]; + // Whether was aiming during the last frame too. + bool m_Aiming; + // Controls the start of leg synch. + bool m_StrideStart[SIDECOUNT]; + // Times the strides to make sure they get restarted if they end up too long + Timer m_StrideTimer[SIDECOUNT]; + // The maximum angle MountedMO can be aimed up, positive values only, in radians + float m_AimRangeUpperLimit; + // The maximum angle MountedMO can be aimed down, positive values only, in radians + float m_AimRangeLowerLimit; + + //////////////// + // AI States + + enum DeviceHandlingState { + STILL = 0, + POINTING, + SCANNING, + AIMING, + FIRING, + THROWING, + DIGGING + }; + + enum SweepState { + NOSWEEP = 0, + SWEEPINGUP, + SWEEPUPPAUSE, + SWEEPINGDOWN, + SWEEPDOWNPAUSE + }; + + enum DigState { + NOTDIGGING = 0, + PREDIG, + STARTDIG, + TUNNELING, + FINISHINGDIG, + PAUSEDIGGER + }; + + enum JumpState { + NOTJUMPING = 0, + FORWARDJUMP, + PREUPJUMP, + UPJUMP, + APEXJUMP, + LANDJUMP + }; + + // What the AI is doing with its held devices + DeviceHandlingState m_DeviceState; + // What we are doing with a device sweeping + SweepState m_SweepState; + // The current digging state + DigState m_DigState; + // The current jumping state + JumpState m_JumpState; + // Jumping target, overshoot this and the jump is completed + Vector m_JumpTarget; + // Jumping left or right + bool m_JumpingRight; + // The position of the end of the current tunnel being dug. When it is reached, digging can stop. + Vector m_DigTunnelEndPos; + // The center angle (in rads) for the sweeping motion done duing scannign and digging + float m_SweepCenterAimAngle; + // The range to each direction of the center that the sweeping motion will be done in + float m_SweepRange; + // The absolute coordinates of the last detected gold deposits + Vector m_DigTarget; + // Timer for how long to be shooting at a seen enemy target + Timer m_FireTimer; + // Timer for how long to be shooting at a seen enemy target + Timer m_SweepTimer; + // Timer for how long to be patrolling in a direction + Timer m_PatrolTimer; + // Timer for how long to be firing the jetpack in a direction + Timer m_JumpTimer; + // Whether mouse input should be locked to the aim range, or whether we can "wander" out. For static emplacements like turrets, this is good, but for moving things it's a bit sticky. + bool m_LockMouseAimInput; #pragma region Event Handling - /// - /// Event listener to be run while this ACrab's PieMenu is opened. - /// - /// The PieMenu this event listener needs to listen to. This will always be this' m_PieMenu and only exists for std::bind. - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int WhilePieMenuOpenListener(const PieMenu *pieMenu) override; + /// + /// Event listener to be run while this ACrab's PieMenu is opened. + /// + /// The PieMenu this event listener needs to listen to. This will always be this' m_PieMenu and only exists for std::bind. + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + int WhilePieMenuOpenListener(const PieMenu* pieMenu) override; #pragma endregion + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACrab, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACrab, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. - void Clear(); + void Clear(); - // Disallow the use of some implicit methods. - ACrab(const ACrab &reference) = delete; - ACrab & operator=(const ACrab &rhs) = delete; - -}; + // Disallow the use of some implicit methods. + ACrab(const ACrab& reference) = delete; + ACrab& operator=(const ACrab& rhs) = delete; + }; } // namespace RTE diff --git a/Source/Entities/ACraft.cpp b/Source/Entities/ACraft.cpp index 5518f5983..4d7754271 100644 --- a/Source/Entities/ACraft.cpp +++ b/Source/Entities/ACraft.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -30,1062 +29,993 @@ namespace RTE { -AbstractClassInfo(ACraft, Actor); -const std::string ACraft::Exit::c_ClassName = "Exit"; + AbstractClassInfo(ACraft, Actor); + const std::string ACraft::Exit::c_ClassName = "Exit"; -bool ACraft::s_CrabBombInEffect = false; + bool ACraft::s_CrabBombInEffect = false; #define EXITLINESPACING 7 #define EXITSUCKDELAYMS 1500 + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Exit, effectively + // resetting the members of this abstraction level only. + + void ACraft::Exit::Clear() { + m_Offset.Reset(); + m_Velocity.Reset(); + m_VelSpread = 0.2f; + m_Radius = 10; + m_Range = 35; + m_Clear = true; + m_pIncomingMO = 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Exit, effectively -// resetting the members of this abstraction level only. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Exit to be identical to another, by deep copy. -void ACraft::Exit::Clear() -{ - m_Offset.Reset(); - m_Velocity.Reset(); - m_VelSpread = 0.2f; - m_Radius = 10; - m_Range = 35; - m_Clear = true; - m_pIncomingMO = 0; -} + int ACraft::Exit::Create(const Exit& reference) { + m_Offset = reference.m_Offset; + m_Velocity = reference.m_Velocity; + m_VelSpread = reference.m_VelSpread; + m_Radius = reference.m_Radius; + m_Range = reference.m_Range; + m_Clear = reference.m_Clear; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Exit to be identical to another, by deep copy. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Exit object ready for use. -int ACraft::Exit::Create(const Exit &reference) -{ - m_Offset = reference.m_Offset; - m_Velocity = reference.m_Velocity; - m_VelSpread = reference.m_VelSpread; - m_Radius = reference.m_Radius; - m_Range = reference.m_Range; - m_Clear = reference.m_Clear; + int ACraft::Exit::Create() { + if (Serializable::Create() < 0) + return -1; - return 0; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Exit object ready for use. + int ACraft::Exit::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Serializable::ReadProperty(propName, reader)); -int ACraft::Exit::Create() -{ - if (Serializable::Create() < 0) - return -1; + MatchProperty("Offset", { reader >> m_Offset; }); + MatchProperty("Velocity", { reader >> m_Velocity; }); + MatchProperty("VelocitySpread", { reader >> m_VelSpread; }); + MatchProperty("Radius", { reader >> m_Radius; }); + MatchProperty("Range", { reader >> m_Range; }); - return 0; -} + EndPropertyList; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Exit with a Writer for + // later recreation with Create(Reader &reader); + + int ACraft::Exit::Save(Writer& writer) const { + Serializable::Save(writer); + + writer.NewProperty("Offset"); + writer << m_Offset; + writer.NewProperty("Velocity"); + writer << m_Velocity; + writer.NewProperty("VelocitySpread"); + writer << m_VelSpread; + writer.NewProperty("Radius"); + writer << m_Radius; + writer.NewProperty("Range"); + writer << m_Range; + + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CheckIfClear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates whether this exit is currently clear enough of terrain to + // safely put things through without them ending up in the terrain. + + bool ACraft::Exit::CheckIfClear(const Vector& pos, Matrix& rot, float size) { + Vector notUsed; + Vector ray = m_Velocity; + ray.SetMagnitude(size); + return m_Clear = !g_SceneMan.CastNotMaterialRay(pos + (m_Offset * rot), ray * rot, g_MaterialAir, notUsed); + } -int ACraft::Exit::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Serializable::ReadProperty(propName, reader)); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SuckInMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Uses cast MO rays to see if anyhting is able to be drawn into this + // exit. If so, it will alter the positiona nd velocity of the objet so + // it flies into the exit until it is sufficiently inside and then it'll + // return the MO here, OWNERHIP NOT TRANSFERRED! It is still in MovableMan! + + MOSRotating* ACraft::Exit::SuckInMOs(ACraft* pExitOwner) { + if (!pExitOwner || !m_Clear) + return 0; + + Vector exitPos = pExitOwner->GetPos() + pExitOwner->RotateOffset(m_Offset); + Vector exitRadius; + Vector exitCorner; + Vector rayVec = pExitOwner->RotateOffset(m_Velocity); + + // If we're sucking on an MO already + if (m_pIncomingMO) { + const float suckageRange = m_Range * 1.5F; + + // Check that it's still active and valid (not destroyed) + if (!(g_MovableMan.IsDevice(m_pIncomingMO) || g_MovableMan.IsActor(m_pIncomingMO))) { + m_pIncomingMO = 0; + } + // See if it's now out of range of suckage + else if ((exitPos - m_pIncomingMO->GetPos()).MagnitudeIsGreaterThan(suckageRange)) { + m_pIncomingMO = 0; + } + // See if the object has been sucked in far enough to be considered picked up by the exit + else if ((m_pIncomingMO->GetPos() - exitPos).Dot(rayVec) < 0) { + // Yes, the object has been sucked in beyond the offset position of the exit itself, so we're done picking it up + // Zero out the incoming member pointer to show that we're not sucking on anyhting anymore + MOSRotating* pReturnMO = m_pIncomingMO; + m_pIncomingMO = 0; + return pReturnMO; + } + // Ok it's not quite there yet, so keep sucking it in + else { + // Figure the distance left for the object to go to reach the exit + Vector toGo = exitPos - m_pIncomingMO->GetPos(); + // If the object is still a bit away from the exit goal, override velocity of the object to head straight into the exit + const float threshold = 1.0F; + if (toGo.MagnitudeIsGreaterThan(threshold)) { + m_pIncomingMO->SetVel(toGo.SetMagnitude(m_Velocity.GetMagnitude())); + } - MatchProperty("Offset", { reader >> m_Offset; }); - MatchProperty("Velocity", { reader >> m_Velocity; }); - MatchProperty("VelocitySpread", { reader >> m_VelSpread; }); - MatchProperty("Radius", { reader >> m_Radius; }); - MatchProperty("Range", { reader >> m_Range; }); + // Turn off collisions between the object and the craft sucking it in + m_pIncomingMO->SetWhichMOToNotHit(pExitOwner, 3); + pExitOwner->SetWhichMOToNotHit(m_pIncomingMO, 3); + } + } - EndPropertyList; -} + // Not sucking in anything, so see if there's anyhting to start doing it to + if (!m_pIncomingMO) { + exitRadius = pExitOwner->RotateOffset(m_Velocity.GetPerpendicular().SetMagnitude(m_Radius)); + exitCorner = exitPos + exitRadius; + rayVec = pExitOwner->RotateOffset(m_Velocity); + rayVec.SetMagnitude(m_Range); + + MOID itemMOID = g_SceneMan.CastMORay(exitCorner, rayVec, pExitOwner->GetRootID(), Activity::NoTeam, g_MaterialGrass, true, 4); + // Try the other side if we didn't find anything + if (itemMOID == g_NoMOID) { + exitCorner -= exitRadius * 2; + itemMOID = g_SceneMan.CastMORay(exitCorner, rayVec, pExitOwner->GetRootID(), Activity::NoTeam, g_MaterialGrass, true, 4); + } + // Try center beam if we STILL didn't find anything + if (itemMOID == g_NoMOID) { + exitCorner += exitRadius; + itemMOID = g_SceneMan.CastMORay(exitCorner, rayVec, pExitOwner->GetRootID(), Activity::NoTeam, g_MaterialGrass, true, 4); + } + // See if we caught anything + MovableObject* pItem = g_MovableMan.GetMOFromID(itemMOID); + if (pItem) { + // We did! Now start sucking it in (next frame) + m_pIncomingMO = dynamic_cast(pItem->GetRootParent()); + // Don't suck in other ACraft! + if (dynamic_cast(m_pIncomingMO)) + m_pIncomingMO = 0; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Exit with a Writer for -// later recreation with Create(Reader &reader); + // Nothing was sucked in far enough to be returned as done + return 0; + } -int ACraft::Exit::Save(Writer &writer) const -{ - Serializable::Save(writer); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACraft, effectively + // resetting the members of this abstraction level only. + + void ACraft::Clear() { + m_AIMode = AIMODE_DELIVER; + + m_MoveState = 0; + m_HatchState = CLOSED; + m_HatchTimer.Reset(); + m_HatchDelay = 0; + m_HatchOpenSound = nullptr; + m_HatchCloseSound = nullptr; + m_CollectedInventory.clear(); + m_Exits.clear(); + m_CurrentExit = m_Exits.begin(); + m_ExitInterval = 1000; + m_ExitTimer.Reset(); + m_ExitLinePhase = 0; + m_HasDelivered = false; + m_LandingCraft = true; + m_FlippedTimer.Reset(); + m_CrashTimer.Reset(); + m_CrashSound = nullptr; - writer.NewProperty("Offset"); - writer << m_Offset; - writer.NewProperty("Velocity"); - writer << m_Velocity; - writer.NewProperty("VelocitySpread"); - writer << m_VelSpread; - writer.NewProperty("Radius"); - writer << m_Radius; - writer.NewProperty("Range"); - writer << m_Range; + m_DeliveryState = FALL; + m_AltitudeMoveState = HOVER; + m_AltitudeControl = 0; + m_MaxPassengers = -1; - return 0; -} + m_DeliveryDelayMultiplier = 1.0; + m_ScuttleIfFlippedTime = 4000; + m_ScuttleOnDeath = true; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACraft object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CheckIfClear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates whether this exit is currently clear enough of terrain to -// safely put things through without them ending up in the terrain. + int ACraft::Create() { + // Read all the properties + if (Actor::Create() < 0) + return -1; -bool ACraft::Exit::CheckIfClear(const Vector &pos, Matrix &rot, float size) -{ - Vector notUsed; - Vector ray = m_Velocity; - ray.SetMagnitude(size); - return m_Clear = !g_SceneMan.CastNotMaterialRay(pos + (m_Offset * rot), ray * rot, g_MaterialAir, notUsed); -} + if (m_AIMode == Actor::AIMODE_NONE) { + m_AIMode = Actor::AIMODE_DELIVER; + } + m_CurrentExit = m_Exits.begin(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SuckInMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Uses cast MO rays to see if anyhting is able to be drawn into this -// exit. If so, it will alter the positiona nd velocity of the objet so -// it flies into the exit until it is sufficiently inside and then it'll -// return the MO here, OWNERHIP NOT TRANSFERRED! It is still in MovableMan! - -MOSRotating * ACraft::Exit::SuckInMOs(ACraft *pExitOwner) -{ - if (!pExitOwner || !m_Clear) - return 0; - - Vector exitPos = pExitOwner->GetPos() + pExitOwner->RotateOffset(m_Offset); - Vector exitRadius; - Vector exitCorner; - Vector rayVec = pExitOwner->RotateOffset(m_Velocity); - - // If we're sucking on an MO already - if (m_pIncomingMO) - { - const float suckageRange = m_Range * 1.5F; - - // Check that it's still active and valid (not destroyed) - if (!(g_MovableMan.IsDevice(m_pIncomingMO) || g_MovableMan.IsActor(m_pIncomingMO))) - { - m_pIncomingMO = 0; - } - // See if it's now out of range of suckage - else if ((exitPos - m_pIncomingMO->GetPos()).MagnitudeIsGreaterThan(suckageRange)) - { - m_pIncomingMO = 0; - } - // See if the object has been sucked in far enough to be considered picked up by the exit - else if ((m_pIncomingMO->GetPos() - exitPos).Dot(rayVec) < 0) - { - // Yes, the object has been sucked in beyond the offset position of the exit itself, so we're done picking it up - // Zero out the incoming member pointer to show that we're not sucking on anyhting anymore - MOSRotating *pReturnMO = m_pIncomingMO; - m_pIncomingMO = 0; - return pReturnMO; - } - // Ok it's not quite there yet, so keep sucking it in - else - { - // Figure the distance left for the object to go to reach the exit - Vector toGo = exitPos - m_pIncomingMO->GetPos(); - // If the object is still a bit away from the exit goal, override velocity of the object to head straight into the exit - const float threshold = 1.0F; - if (toGo.MagnitudeIsGreaterThan(threshold)) - { - m_pIncomingMO->SetVel(toGo.SetMagnitude(m_Velocity.GetMagnitude())); - } - - // Turn off collisions between the object and the craft sucking it in - m_pIncomingMO->SetWhichMOToNotHit(pExitOwner, 3); - pExitOwner->SetWhichMOToNotHit(m_pIncomingMO, 3); - } - } - - // Not sucking in anything, so see if there's anyhting to start doing it to - if (!m_pIncomingMO) - { - exitRadius = pExitOwner->RotateOffset(m_Velocity.GetPerpendicular().SetMagnitude(m_Radius)); - exitCorner = exitPos + exitRadius; - rayVec = pExitOwner->RotateOffset(m_Velocity); - rayVec.SetMagnitude(m_Range); - - MOID itemMOID = g_SceneMan.CastMORay(exitCorner, rayVec, pExitOwner->GetRootID(), Activity::NoTeam, g_MaterialGrass, true, 4); - // Try the other side if we didn't find anything - if (itemMOID == g_NoMOID) - { - exitCorner -= exitRadius * 2; - itemMOID = g_SceneMan.CastMORay(exitCorner, rayVec, pExitOwner->GetRootID(), Activity::NoTeam, g_MaterialGrass, true, 4); - } - // Try center beam if we STILL didn't find anything - if (itemMOID == g_NoMOID) - { - exitCorner += exitRadius; - itemMOID = g_SceneMan.CastMORay(exitCorner, rayVec, pExitOwner->GetRootID(), Activity::NoTeam, g_MaterialGrass, true, 4); - } - - // See if we caught anything - MovableObject *pItem = g_MovableMan.GetMOFromID(itemMOID); - if (pItem) - { - // We did! Now start sucking it in (next frame) - m_pIncomingMO = dynamic_cast(pItem->GetRootParent()); - // Don't suck in other ACraft! - if (dynamic_cast(m_pIncomingMO)) - m_pIncomingMO = 0; - } - } - - // Nothing was sucked in far enough to be returned as done - return 0; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACraft to be identical to another, by deep copy. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACraft, effectively -// resetting the members of this abstraction level only. - -void ACraft::Clear() -{ - m_AIMode = AIMODE_DELIVER; - - m_MoveState = 0; - m_HatchState = CLOSED; - m_HatchTimer.Reset(); - m_HatchDelay = 0; - m_HatchOpenSound = nullptr; - m_HatchCloseSound = nullptr; - m_CollectedInventory.clear(); - m_Exits.clear(); - m_CurrentExit = m_Exits.begin(); - m_ExitInterval = 1000; - m_ExitTimer.Reset(); - m_ExitLinePhase = 0; - m_HasDelivered = false; - m_LandingCraft = true; - m_FlippedTimer.Reset(); - m_CrashTimer.Reset(); - m_CrashSound = nullptr; - - m_DeliveryState = FALL; - m_AltitudeMoveState = HOVER; - m_AltitudeControl = 0; - m_MaxPassengers = -1; - - m_DeliveryDelayMultiplier = 1.0; - m_ScuttleIfFlippedTime = 4000; - m_ScuttleOnDeath = true; -} + int ACraft::Create(const ACraft& reference) { + Actor::Create(reference); + m_MoveState = reference.m_MoveState; + m_HatchState = reference.m_HatchState; + m_HatchDelay = reference.m_HatchDelay; + if (reference.m_HatchOpenSound) { + m_HatchOpenSound = dynamic_cast(reference.m_HatchOpenSound->Clone()); + } + if (reference.m_HatchCloseSound) { + m_HatchCloseSound = dynamic_cast(reference.m_HatchCloseSound->Clone()); + } else if (reference.m_HatchOpenSound) { + m_HatchCloseSound = dynamic_cast(reference.m_HatchOpenSound->Clone()); + } + for (std::deque::const_iterator niItr = reference.m_CollectedInventory.begin(); niItr != reference.m_CollectedInventory.end(); ++niItr) + m_CollectedInventory.push_back(dynamic_cast((*niItr)->Clone())); + for (std::list::const_iterator eItr = reference.m_Exits.begin(); eItr != reference.m_Exits.end(); ++eItr) + m_Exits.push_back(*eItr); + m_CurrentExit = m_Exits.begin(); + m_ExitInterval = reference.m_ExitInterval; + m_HasDelivered = reference.m_HasDelivered; + m_LandingCraft = reference.m_LandingCraft; + if (reference.m_CrashSound) { + m_CrashSound = dynamic_cast(reference.m_CrashSound->Clone()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACraft object ready for use. + m_DeliveryState = reference.m_DeliveryState; + m_AltitudeMoveState = reference.m_AltitudeMoveState; + m_AltitudeControl = reference.m_AltitudeControl; + m_MaxPassengers = reference.m_MaxPassengers; -int ACraft::Create() -{ - // Read all the properties - if (Actor::Create() < 0) - return -1; + m_DeliveryDelayMultiplier = reference.m_DeliveryDelayMultiplier; + m_ScuttleIfFlippedTime = reference.m_ScuttleIfFlippedTime; + m_ScuttleOnDeath = reference.m_ScuttleOnDeath; - if (m_AIMode == Actor::AIMODE_NONE) { - m_AIMode = Actor::AIMODE_DELIVER; + return 0; } - m_CurrentExit = m_Exits.begin(); - - return 0; -} - + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int ACraft::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Actor::ReadProperty(propName, reader)); + + MatchProperty("HatchDelay", { reader >> m_HatchDelay; }); + MatchProperty("HatchOpenSound", { + m_HatchOpenSound = new SoundContainer; + reader >> m_HatchOpenSound; + }); + MatchProperty("HatchCloseSound", { + m_HatchCloseSound = new SoundContainer; + reader >> m_HatchCloseSound; + }); + MatchProperty("CrashSound", { + m_CrashSound = new SoundContainer; + reader >> m_CrashSound; + }); + MatchProperty("AddExit", + { + Exit exit; + reader >> exit; + m_Exits.push_back(exit); + }); + MatchProperty("DeliveryDelayMultiplier", { reader >> m_DeliveryDelayMultiplier; }); + MatchProperty("ExitInterval", { reader >> m_ExitInterval; }); + MatchProperty("CanLand", { reader >> m_LandingCraft; }); + MatchProperty("MaxPassengers", { reader >> m_MaxPassengers; }); + MatchProperty("ScuttleIfFlippedTime", { reader >> m_ScuttleIfFlippedTime; }); + MatchProperty("ScuttleOnDeath", { reader >> m_ScuttleOnDeath; }); + + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ACraft to be identical to another, by deep copy. - -int ACraft::Create(const ACraft &reference) -{ - Actor::Create(reference); - - m_MoveState = reference.m_MoveState; - m_HatchState = reference.m_HatchState; - m_HatchDelay = reference.m_HatchDelay; - if (reference.m_HatchOpenSound) { m_HatchOpenSound = dynamic_cast(reference.m_HatchOpenSound->Clone()); } - if (reference.m_HatchCloseSound) { - m_HatchCloseSound = dynamic_cast(reference.m_HatchCloseSound->Clone()); - } else if (reference.m_HatchOpenSound) { - m_HatchCloseSound = dynamic_cast(reference.m_HatchOpenSound->Clone()); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this ACraft with a Writer for + // later recreation with Create(Reader &reader); + + int ACraft::Save(Writer& writer) const { + Actor::Save(writer); + + writer.NewProperty("HatchDelay"); + writer << m_HatchDelay; + writer.NewProperty("HatchOpenSound"); + writer << m_HatchOpenSound; + writer.NewProperty("HatchCloseSound"); + writer << m_HatchCloseSound; + for (std::list::const_iterator itr = m_Exits.begin(); itr != m_Exits.end(); ++itr) { + writer.NewProperty("AddExit"); + writer << (*itr); + } + writer.NewProperty("DeliveryDelayMultiplier"); + writer << m_DeliveryDelayMultiplier; + writer.NewProperty("ExitInterval"); + writer << m_ExitInterval; + writer.NewProperty("CanLand"); + writer << m_LandingCraft; + + writer.NewProperty("CrashSound"); + writer << m_CrashSound; + + writer.NewProperty("MaxPassengers"); + writer << m_MaxPassengers; + writer.NewProperty("ScuttleIfFlippedTime"); + writer << m_ScuttleIfFlippedTime; + writer.NewProperty("ScuttleOnDeath"); + writer << m_ScuttleOnDeath; + + return 0; } - for (std::deque::const_iterator niItr = reference.m_CollectedInventory.begin(); niItr != reference.m_CollectedInventory.end(); ++niItr) - m_CollectedInventory.push_back(dynamic_cast((*niItr)->Clone())); - for (std::list::const_iterator eItr = reference.m_Exits.begin(); eItr != reference.m_Exits.end(); ++eItr) - m_Exits.push_back(*eItr); - m_CurrentExit = m_Exits.begin(); - m_ExitInterval = reference.m_ExitInterval; - m_HasDelivered = reference.m_HasDelivered; - m_LandingCraft = reference.m_LandingCraft; - if (reference.m_CrashSound) { m_CrashSound = dynamic_cast(reference.m_CrashSound->Clone()); } - m_DeliveryState = reference.m_DeliveryState; - m_AltitudeMoveState = reference.m_AltitudeMoveState; - m_AltitudeControl = reference.m_AltitudeControl; - m_MaxPassengers = reference.m_MaxPassengers; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ACraft object. - m_DeliveryDelayMultiplier = reference.m_DeliveryDelayMultiplier; - m_ScuttleIfFlippedTime = reference.m_ScuttleIfFlippedTime; - m_ScuttleOnDeath = reference.m_ScuttleOnDeath; + void ACraft::Destroy(bool notInherited) { + delete m_HatchOpenSound; + delete m_HatchCloseSound; + delete m_CrashSound; - return 0; -} + if (!notInherited) + Actor::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this Actor and all its carried + // gold and inventory. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int ACraft::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Actor::ReadProperty(propName, reader)); - - MatchProperty("HatchDelay", { reader >> m_HatchDelay; }); - MatchProperty("HatchOpenSound", { - m_HatchOpenSound = new SoundContainer; - reader >> m_HatchOpenSound; - }); - MatchProperty("HatchCloseSound", { - m_HatchCloseSound = new SoundContainer; - reader >> m_HatchCloseSound; - }); - MatchProperty("CrashSound", { - m_CrashSound = new SoundContainer; - reader >> m_CrashSound; - }); - MatchProperty("AddExit", - { - Exit exit; - reader >> exit; - m_Exits.push_back(exit); - }); - MatchProperty("DeliveryDelayMultiplier", { reader >> m_DeliveryDelayMultiplier; }); - MatchProperty("ExitInterval", { reader >> m_ExitInterval; }); - MatchProperty("CanLand", { reader >> m_LandingCraft; }); - MatchProperty("MaxPassengers", { reader >> m_MaxPassengers; }); - MatchProperty("ScuttleIfFlippedTime", { reader >> m_ScuttleIfFlippedTime; }); - MatchProperty("ScuttleOnDeath", { reader >> m_ScuttleOnDeath; }); - - EndPropertyList; -} + float ACraft::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const { + float totalValue = Actor::GetTotalValue(nativeModule, foreignMult, nativeMult); + MOSprite* pItem = 0; + for (std::deque::const_iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) { + pItem = dynamic_cast(*itr); + if (pItem) + totalValue += pItem->GetTotalValue(nativeModule, foreignMult, nativeMult); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this ACraft with a Writer for -// later recreation with Create(Reader &reader); - -int ACraft::Save(Writer &writer) const -{ - Actor::Save(writer); - - writer.NewProperty("HatchDelay"); - writer << m_HatchDelay; - writer.NewProperty("HatchOpenSound"); - writer << m_HatchOpenSound; - writer.NewProperty("HatchCloseSound"); - writer << m_HatchCloseSound; - for (std::list::const_iterator itr = m_Exits.begin(); itr != m_Exits.end(); ++itr) - { - writer.NewProperty("AddExit"); - writer << (*itr); - } - writer.NewProperty("DeliveryDelayMultiplier"); - writer << m_DeliveryDelayMultiplier; - writer.NewProperty("ExitInterval"); - writer << m_ExitInterval; - writer.NewProperty("CanLand"); - writer << m_LandingCraft; - - writer.NewProperty("CrashSound"); - writer << m_CrashSound; - - writer.NewProperty("MaxPassengers"); - writer << m_MaxPassengers; - writer.NewProperty("ScuttleIfFlippedTime"); - writer << m_ScuttleIfFlippedTime; - writer.NewProperty("ScuttleOnDeath"); - writer << m_ScuttleOnDeath; - - return 0; -} + return totalValue; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this carries a specifically named object in its inventory. + // Also looks through the inventories of potential passengers, as applicable. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ACraft object. + bool ACraft::HasObject(std::string objectName) const { + if (Actor::HasObject(objectName)) + return true; -void ACraft::Destroy(bool notInherited) -{ - delete m_HatchOpenSound; - delete m_HatchCloseSound; - delete m_CrashSound; + for (std::deque::const_iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) { + if ((*itr) && (*itr)->HasObject(objectName)) + return true; + } - if (!notInherited) - Actor::Destroy(); - Clear(); -} + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObjectInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically grouped object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this Actor and all its carried -// gold and inventory. + bool ACraft::HasObjectInGroup(std::string groupName) const { + if (Actor::HasObjectInGroup(groupName)) + return true; -float ACraft::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const -{ - float totalValue = Actor::GetTotalValue(nativeModule, foreignMult, nativeMult); + for (std::deque::const_iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) { + if ((*itr) && (*itr)->HasObjectInGroup(groupName)) + return true; + } - MOSprite *pItem = 0; - for (std::deque::const_iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) - { - pItem = dynamic_cast(*itr); - if (pItem) - totalValue += pItem->GetTotalValue(nativeModule, foreignMult, nativeMult); - } + return false; + } - return totalValue; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this belongs to, and all its inventory too. + void ACraft::SetTeam(int team) { + Actor::SetTeam(team); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this carries a specifically named object in its inventory. -// Also looks through the inventories of potential passengers, as applicable. + // Also set all actors in the new inventory + Actor* pActor = 0; + for (std::deque::iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) { + pActor = dynamic_cast(*itr); + if (pActor) + pActor->SetTeam(team); + } + } -bool ACraft::HasObject(std::string objectName) const -{ - if (Actor::HasObject(objectName)) - return true; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool ACraft::HandlePieCommand(PieSlice::SliceType pieSliceIndex) { + if (pieSliceIndex != PieSlice::SliceType::NoType) { + if (pieSliceIndex == PieSlice::SliceType::Deliver) { + m_AIMode = AIMODE_DELIVER; + m_DeliveryState = FALL; + m_HasDelivered = false; + } else if (pieSliceIndex == PieSlice::SliceType::Return) { + m_AIMode = AIMODE_RETURN; + m_DeliveryState = LAUNCH; + } else if (pieSliceIndex == PieSlice::SliceType::Stay) { + m_AIMode = AIMODE_STAY; + m_DeliveryState = FALL; + } else if (pieSliceIndex == PieSlice::SliceType::Sentry) { + m_AIMode = AIMODE_SENTRY; + m_DeliveryState = FALL; + } else if (pieSliceIndex == PieSlice::SliceType::Return) { + m_AIMode = AIMODE_RETURN; + m_DeliveryState = LAUNCH; + } else if (pieSliceIndex == PieSlice::SliceType::GoTo) { + m_AIMode = AIMODE_GOTO; + m_DeliveryState = FALL; + ClearAIWaypoints(); + m_UpdateMovePath = true; + } else if (pieSliceIndex == PieSlice::SliceType::Scuttle) { + m_AIMode = AIMODE_SCUTTLE; + } else { + return Actor::HandlePieCommand(pieSliceIndex); + } + } + return false; + } - for (std::deque::const_iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) - { - if ((*itr) && (*itr)->HasObject(objectName)) - return true; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OpenHatch + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Opens the hatch doors, if they're closed. + // Arguments: None. + // Return value: None. + void ACraft::OpenHatch() { + if (m_HatchState == CLOSED || m_HatchState == CLOSING) { + m_HatchState = OPENING; + m_HatchTimer.Reset(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObjectInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically grouped object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. + // PSCHHT + if (m_HatchOpenSound) { + m_HatchOpenSound->Play(m_Pos); + } + } + } -bool ACraft::HasObjectInGroup(std::string groupName) const -{ - if (Actor::HasObjectInGroup(groupName)) - return true; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CloseHatch + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Closes the hatch doors, if they're open. + // Arguments: None. + // Return value: None. - for (std::deque::const_iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) - { - if ((*itr) && (*itr)->HasObjectInGroup(groupName)) - return true; - } + void ACraft::CloseHatch() { + if (m_HatchState == OPEN || m_HatchState == OPENING) { + m_HatchState = CLOSING; + m_HatchTimer.Reset(); - return false; -} + // When closing, move all newly added inventory to the regular inventory list so it'll be ejected next time doors open + for (std::deque::const_iterator niItr = m_CollectedInventory.begin(); niItr != m_CollectedInventory.end(); ++niItr) { + AddToInventoryBack(*niItr); + } + // Clear the new inventory hold, it's all been moved to the regular inventory + m_CollectedInventory.clear(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this belongs to, and all its inventory too. - -void ACraft::SetTeam(int team) -{ - Actor::SetTeam(team); - - // Also set all actors in the new inventory - Actor *pActor = 0; - for (std::deque::iterator itr = m_CollectedInventory.begin(); itr != m_CollectedInventory.end(); ++itr) - { - pActor = dynamic_cast(*itr); - if (pActor) - pActor->SetTeam(team); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool ACraft::HandlePieCommand(PieSlice::SliceType pieSliceIndex) { - if (pieSliceIndex != PieSlice::SliceType::NoType) { - if (pieSliceIndex == PieSlice::SliceType::Deliver) { - m_AIMode = AIMODE_DELIVER; - m_DeliveryState = FALL; - m_HasDelivered = false; - } else if (pieSliceIndex == PieSlice::SliceType::Return) { - m_AIMode = AIMODE_RETURN; - m_DeliveryState = LAUNCH; - } else if (pieSliceIndex == PieSlice::SliceType::Stay) { - m_AIMode = AIMODE_STAY; - m_DeliveryState = FALL; - } else if (pieSliceIndex == PieSlice::SliceType::Sentry) { - m_AIMode = AIMODE_SENTRY; - m_DeliveryState = FALL; - } else if (pieSliceIndex == PieSlice::SliceType::Return) { - m_AIMode = AIMODE_RETURN; - m_DeliveryState = LAUNCH; - } else if (pieSliceIndex == PieSlice::SliceType::GoTo) { - m_AIMode = AIMODE_GOTO; - m_DeliveryState = FALL; - ClearAIWaypoints(); - m_UpdateMovePath = true; - } else if (pieSliceIndex == PieSlice::SliceType::Scuttle) { - m_AIMode = AIMODE_SCUTTLE; - } else { - return Actor::HandlePieCommand(pieSliceIndex); - } - } - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // PSCHHT + if (m_HatchCloseSound) { + m_HatchCloseSound->Play(m_Pos); + } + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: AddInventoryItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an inventory item to this Actor. + // Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! + // Return value: None.. + + void ACraft::AddInventoryItem(MovableObject* pItemToAdd) { + if (pItemToAdd) { + // If the hatch is open, then only add the new item to the intermediate new inventory list + // so that it doesn't get chucked out right away again + if (m_HatchState == OPEN || m_HatchState == OPENING) { + m_CollectedInventory.push_back(pItemToAdd); + } else { + // If doors are already closed, it's safe to put the item directly the regular inventory + AddToInventoryBack(pItemToAdd); + } + if (Actor* itemAsActor = dynamic_cast(pItemToAdd); itemAsActor && itemAsActor->GetGoldCarried() > 0) { + m_GoldCarried += itemAsActor->GetGoldCarried(); + itemAsActor->SetGoldCarried(0); + m_GoldPicked = true; + if (g_ActivityMan.GetActivity()->IsHumanTeam(m_Team)) { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { + if (g_ActivityMan.GetActivity()->GetTeamOfPlayer(player) == m_Team) { + g_GUISound.FundsChangedSound()->Play(player); + } + } + } + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OpenHatch -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Opens the hatch doors, if they're closed. -// Arguments: None. -// Return value: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DropAllInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Opens the hatches and makes everything in the Rocket fly out, including + // the passenger Actors, one after another. It may not happen + // instantaneously, so check for ejection being complete with + // IsInventoryEmpty(). + + void ACraft::DropAllInventory() { + if (m_HatchState == OPEN && !m_Exits.empty()) { + // Cancel if we're not due to release + if (!m_ExitTimer.IsPastSimMS(m_ExitInterval)) + return; + + bool exitExists = false; + std::list::iterator exit = m_Exits.begin(); + // Check which exits are clear of the terrain, if any + for (; exit != m_Exits.end(); ++exit) { + if (exit->CheckIfClear(m_Pos, m_Rotation, 18)) + exitExists = true; + } -void ACraft::OpenHatch() -{ - if (m_HatchState == CLOSED || m_HatchState == CLOSING) - { - m_HatchState = OPENING; - m_HatchTimer.Reset(); + // Cancel if no exits are clear + if (!exitExists) { + // TODO: give some kind of audio feedback to user + return; + } - // PSCHHT - if (m_HatchOpenSound) { m_HatchOpenSound->Play(m_Pos); } - } -} + // Eject inventory and passengers, through alternating clear exits + Vector exitVel, exitVelNorm, gravityNorm; + float antiGravBoost = 0; + Actor* pPassenger = 0; + bool droppedSomething = false; + for (std::deque::iterator exitee = m_Inventory.begin(); exitee != m_Inventory.end(); ++exitee) { + // Select next clear exit + do { + if (++m_CurrentExit == m_Exits.end()) + m_CurrentExit = m_Exits.begin(); + } while (!m_CurrentExit->IsClear()); + + //(*exitee)->SetPos(m_Pos + m_CurrentExit->GetOffset() * m_Rotation); + (*exitee)->SetPos(m_Pos + RotateOffset(m_CurrentExit->GetOffset())); + // Reset all the timers of the object being shot out so it doesn't emit a bunch of particles that have been backed up while dormant in inventory + (*exitee)->ResetAllTimers(); + // exitVel = m_CurrentExit->GetVelocity() * m_Rotation; + exitVel = RotateOffset(m_CurrentExit->GetVelocity()); + + // Boost against gravity + // Normalize the gravity and exit velocity vectors + exitVelNorm = exitVel; + exitVelNorm.SetMagnitude(1.0); + gravityNorm = g_SceneMan.GetGlobalAcc(); + gravityNorm.SetMagnitude(1.0); + // Make the gravity boost be proportional to counteract gravity + antiGravBoost = 1.0 + 1.0 * exitVelNorm.Dot(-gravityNorm); + if (antiGravBoost < 1.0) + antiGravBoost = 1.0; + + // Detect whether we're dealing with a passenger and add it as Actor instead + pPassenger = dynamic_cast(*exitee); + if (pPassenger && m_ExitTimer.IsPastSimMS(m_ExitInterval)) { + pPassenger->SetVel(m_Vel + exitVel * antiGravBoost); + // pPassenger->SetRotAngle(m_Rotation + exitVel.GetAbsRadAngle() (ejectDir > 0 ? -c_HalfPI : c_HalfPI)); + // pPassenger->SetHFlipped(ejectDir <= 0); + // Avoid having immediate collisions with this + pPassenger->SetWhichMOToNotHit(this, 0.5f); + // Avoid this immediate collisions with it + SetWhichMOToNotHit(pPassenger, 0.5f); + // Add to scene + g_MovableMan.AddActor(pPassenger); + + // If this craft is being directly controlled by a player, and has landed, switch control to the first guy out + if (pPassenger->GetTeam() == m_Team && m_Controller.IsPlayerControlled() && g_ActivityMan.GetActivity()->GetControlledActor(m_Controller.GetPlayer()) == this && m_LandingCraft) { + g_ActivityMan.GetActivity()->SwitchToActor(pPassenger, m_Controller.GetPlayer(), m_Team); + // To avoid jump in the view, Update the passenger so its viewpoint is next to it and not at 0,0 + pPassenger->Update(); + } + + // Remove from inventory + m_Inventory.erase(exitee); + // Reset timer interval and quit until next one is due + m_ExitTimer.Reset(); + break; + } else { + (*exitee)->SetVel(m_Vel + exitVel * antiGravBoost); + (*exitee)->SetAngularVel(5.0F * RandomNormalNum()); + // Avoid it having immediate collisions with this + (*exitee)->SetWhichMOToNotHit(this, 0.5f); + // Avoid this immediate collisions with it + SetWhichMOToNotHit(*exitee, 0.5f); + // Add to scene + g_MovableMan.AddMO(*exitee); + // Remove passenger from inventory + m_Inventory.erase(exitee); + // Reset timer interval and quit until next one is due + m_ExitTimer.Reset(); + break; + } + droppedSomething = true; + } + if (m_Inventory.empty()) { + m_HasDelivered = true; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CloseHatch -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Closes the hatch doors, if they're open. -// Arguments: None. -// Return value: None. - -void ACraft::CloseHatch() -{ - if (m_HatchState == OPEN || m_HatchState == OPENING) - { - m_HatchState = CLOSING; - m_HatchTimer.Reset(); - - // When closing, move all newly added inventory to the regular inventory list so it'll be ejected next time doors open - for (std::deque::const_iterator niItr = m_CollectedInventory.begin(); niItr != m_CollectedInventory.end(); ++niItr) { - AddToInventoryBack(*niItr); - } - - // Clear the new inventory hold, it's all been moved to the regular inventory - m_CollectedInventory.clear(); - - // PSCHHT - if (m_HatchCloseSound) { m_HatchCloseSound->Play(m_Pos); } + // Kill craft if it is lying down. + if (std::fabs(m_Rotation.GetRadAngle()) > c_HalfPI && m_Status != DYING) { + m_Status = DYING; + m_DeathTmr.Reset(); + } + // Reset exit timer so we can time until when we should start sucking things in again + // Don't reset it if inventory is empty but we didn't drop anyhting, it means that doors just opened and nothing was inside, so immediately start sucking + if (droppedSomething) + m_ExitTimer.Reset(); + } + } else { + if (m_HatchState != OPENING) { + if (m_HatchOpenSound) { + m_HatchOpenSound->Play(m_Pos); + } + g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, 0.4)); + m_HatchTimer.Reset(); + } + m_HatchState = OPENING; + } } -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: AddInventoryItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an inventory item to this Actor. -// Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! -// Return value: None.. - -void ACraft::AddInventoryItem(MovableObject *pItemToAdd) -{ - if (pItemToAdd) - { - // If the hatch is open, then only add the new item to the intermediate new inventory list - // so that it doesn't get chucked out right away again - if (m_HatchState == OPEN || m_HatchState == OPENING) { - m_CollectedInventory.push_back(pItemToAdd); - } else { - // If doors are already closed, it's safe to put the item directly the regular inventory - AddToInventoryBack(pItemToAdd); + float ACraft::GetCollectedInventoryMass() const { + float inventoryMass = 0.0F; + for (const MovableObject* inventoryItem: m_CollectedInventory) { + inventoryMass += inventoryItem->GetMass(); } - if (Actor *itemAsActor = dynamic_cast(pItemToAdd); itemAsActor && itemAsActor->GetGoldCarried() > 0) { - m_GoldCarried += itemAsActor->GetGoldCarried(); - itemAsActor->SetGoldCarried(0); - m_GoldPicked = true; - if (g_ActivityMan.GetActivity()->IsHumanTeam(m_Team)) { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { - if (g_ActivityMan.GetActivity()->GetTeamOfPlayer(player) == m_Team) { g_GUISound.FundsChangedSound()->Play(player); } + return inventoryMass; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ACraft::GibThis(const Vector& impactImpulse, MovableObject* movableObjectToIgnore) { + if (g_SettingsMan.CrabBombsEnabled() && !s_CrabBombInEffect) { + s_CrabBombInEffect = true; + int crabCount = 0; + for (const MovableObject* inventoryEntry: m_Inventory) { + if (inventoryEntry->GetPresetName() == "Crab") { + crabCount++; } } + if (crabCount >= g_SettingsMan.GetCrabBombThreshold()) { + for (int moid = 1; moid < g_MovableMan.GetMOIDCount() - 1; moid++) { + Actor* actor = dynamic_cast(g_MovableMan.GetMOFromID(moid)); + if (actor && actor != this && actor->GetClassName() != "ADoor" && !actor->IsInGroup("Brains")) { + actor->GibThis(); + } + } + } + s_CrabBombInEffect = false; } - } -} + Actor::GibThis(impactImpulse, movableObjectToIgnore); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DropAllInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Opens the hatches and makes everything in the Rocket fly out, including -// the passenger Actors, one after another. It may not happen -// instantaneously, so check for ejection being complete with -// IsInventoryEmpty(). - -void ACraft::DropAllInventory() -{ - if (m_HatchState == OPEN && !m_Exits.empty()) - { - // Cancel if we're not due to release - if (!m_ExitTimer.IsPastSimMS(m_ExitInterval)) - return; - - bool exitExists = false; - std::list::iterator exit = m_Exits.begin(); - // Check which exits are clear of the terrain, if any - for (; exit != m_Exits.end(); ++exit) - { - if (exit->CheckIfClear(m_Pos, m_Rotation, 18)) - exitExists = true; - } - - // Cancel if no exits are clear - if (!exitExists) - { -// TODO: give some kind of audio feedback to user - return; - } - - // Eject inventory and passengers, through alternating clear exits - Vector exitVel, exitVelNorm, gravityNorm; - float antiGravBoost = 0; - Actor *pPassenger = 0; - bool droppedSomething = false; - for (std::deque::iterator exitee = m_Inventory.begin(); exitee != m_Inventory.end(); ++exitee) - { - // Select next clear exit - do - { - if (++m_CurrentExit == m_Exits.end()) - m_CurrentExit = m_Exits.begin(); - } - while (!m_CurrentExit->IsClear()); - - //(*exitee)->SetPos(m_Pos + m_CurrentExit->GetOffset() * m_Rotation); - (*exitee)->SetPos(m_Pos + RotateOffset(m_CurrentExit->GetOffset())); - // Reset all the timers of the object being shot out so it doesn't emit a bunch of particles that have been backed up while dormant in inventory - (*exitee)->ResetAllTimers(); - //exitVel = m_CurrentExit->GetVelocity() * m_Rotation; - exitVel = RotateOffset(m_CurrentExit->GetVelocity()); - - // Boost against gravity - // Normalize the gravity and exit velocity vectors - exitVelNorm = exitVel; - exitVelNorm.SetMagnitude(1.0); - gravityNorm = g_SceneMan.GetGlobalAcc(); - gravityNorm.SetMagnitude(1.0); - // Make the gravity boost be proportional to counteract gravity - antiGravBoost = 1.0 + 1.0 * exitVelNorm.Dot(-gravityNorm); - if (antiGravBoost < 1.0) - antiGravBoost = 1.0; - - // Detect whether we're dealing with a passenger and add it as Actor instead - pPassenger = dynamic_cast(*exitee); - if (pPassenger && m_ExitTimer.IsPastSimMS(m_ExitInterval)) - { - pPassenger->SetVel(m_Vel + exitVel * antiGravBoost); -// pPassenger->SetRotAngle(m_Rotation + exitVel.GetAbsRadAngle() (ejectDir > 0 ? -c_HalfPI : c_HalfPI)); -// pPassenger->SetHFlipped(ejectDir <= 0); - // Avoid having immediate collisions with this - pPassenger->SetWhichMOToNotHit(this, 0.5f); - // Avoid this immediate collisions with it - SetWhichMOToNotHit(pPassenger, 0.5f); - // Add to scene - g_MovableMan.AddActor(pPassenger); - - // If this craft is being directly controlled by a player, and has landed, switch control to the first guy out - if (pPassenger->GetTeam() == m_Team && m_Controller.IsPlayerControlled() && g_ActivityMan.GetActivity()->GetControlledActor(m_Controller.GetPlayer()) == this && m_LandingCraft) - { - g_ActivityMan.GetActivity()->SwitchToActor(pPassenger, m_Controller.GetPlayer(), m_Team); - // To avoid jump in the view, Update the passenger so its viewpoint is next to it and not at 0,0 - pPassenger->Update(); - } - - // Remove from inventory - m_Inventory.erase(exitee); - // Reset timer interval and quit until next one is due - m_ExitTimer.Reset(); - break; - } - else - { - (*exitee)->SetVel(m_Vel + exitVel * antiGravBoost); - (*exitee)->SetAngularVel(5.0F * RandomNormalNum()); - // Avoid it having immediate collisions with this - (*exitee)->SetWhichMOToNotHit(this, 0.5f); - // Avoid this immediate collisions with it - SetWhichMOToNotHit(*exitee, 0.5f); - // Add to scene - g_MovableMan.AddMO(*exitee); - // Remove passenger from inventory - m_Inventory.erase(exitee); - // Reset timer interval and quit until next one is due - m_ExitTimer.Reset(); - break; - } - droppedSomething = true; - } - - if (m_Inventory.empty()) - { - m_HasDelivered = true; - - // Kill craft if it is lying down. - if (std::fabs(m_Rotation.GetRadAngle()) > c_HalfPI && m_Status != DYING) { - m_Status = DYING; - m_DeathTmr.Reset(); - } - // Reset exit timer so we can time until when we should start sucking things in again - // Don't reset it if inventory is empty but we didn't drop anyhting, it means that doors just opened and nothing was inside, so immediately start sucking - if (droppedSomething) - m_ExitTimer.Reset(); - } - } - else - { - if (m_HatchState != OPENING) - { - if (m_HatchOpenSound) { m_HatchOpenSound->Play(m_Pos); } - g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, 0.4)); - m_HatchTimer.Reset(); - } - m_HatchState = OPENING; - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float ACraft::GetCollectedInventoryMass() const { - float inventoryMass = 0.0F; - for (const MovableObject *inventoryItem : m_CollectedInventory) { - inventoryMass += inventoryItem->GetMass(); + void ACraft::ResetAllTimers() { + MOSRotating::ResetAllTimers(); + + m_FlippedTimer.Reset(); } - return inventoryMass; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this ACraft. Supposed to be done every frame. + + void ACraft::Update() { + Actor::Update(); -void ACraft::GibThis(const Vector &impactImpulse, MovableObject *movableObjectToIgnore) { - if (g_SettingsMan.CrabBombsEnabled() && !s_CrabBombInEffect) { - s_CrabBombInEffect = true; - int crabCount = 0; - for (const MovableObject *inventoryEntry : m_Inventory) { - if (inventoryEntry->GetPresetName() == "Crab") { crabCount++; } + //////////////////////////////////// + // Update viewpoint + + // Set viewpoint based on how we are aiming etc. + m_ViewPoint = m_Pos.GetFloored(); + // Add velocity also so the viewpoint moves ahead at high speeds + if (m_Vel.MagnitudeIsGreaterThan(10.0F)) { + m_ViewPoint += m_Vel * std::sqrt(m_Vel.GetMagnitude() * 0.1F); } - if (crabCount >= g_SettingsMan.GetCrabBombThreshold()) { - for (int moid = 1; moid < g_MovableMan.GetMOIDCount() - 1; moid++) { - Actor *actor = dynamic_cast(g_MovableMan.GetMOFromID(moid)); - if (actor && actor != this && actor->GetClassName() != "ADoor" && !actor->IsInGroup("Brains")) { actor->GibThis(); } + + /////////////////////////////////////////////////// + // Crash detection and handling + const float crashSpeedThreshold = 1.0F; + if (m_DeepHardness > 5 && m_Vel.MagnitudeIsGreaterThan(crashSpeedThreshold)) { + m_Health -= m_DeepHardness * 0.03; + // TODO: HELLA GHETTO, REWORK + if (m_CrashTimer.GetElapsedSimTimeMS() > 500) { + if (m_CrashSound) { + m_CrashSound->Play(m_Pos); + } + m_CrashTimer.Reset(); } } - s_CrabBombInEffect = false; - } - Actor::GibThis(impactImpulse, movableObjectToIgnore); -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////// + // Doors open logic + + if (m_HatchState == OPEN) { + // Keep ejecting things if hatch is open and inventory isn't empty + if (!IsInventoryEmpty()) + DropAllInventory(); + // If doors are open and all inventory is ejected (and they have had a chance to fall away), then actively look for things to suck in through the exits. + else if (m_Status == STABLE && m_ExitTimer.IsPastSimMS(EXITSUCKDELAYMS)) { + // See if any of the exits have sucked in an MO + for (std::list::iterator exit = m_Exits.begin(); exit != m_Exits.end(); ++exit) { + // If exit sucked in an MO, add it to invetory + MOSRotating* pNewObject = exit->SuckInMOs(this); + if (pNewObject && !pNewObject->IsSetToDelete()) { + // Did we catch an Actor? If so, we need to do special controller switching in case it's player controlled atm + Actor* pCaughtActor = 0; + if (pCaughtActor = dynamic_cast(pNewObject)) { + // Switch control to this craft if the Actor we just caught is on our team and currently player controlled + // Set AI controller of the Actor going into the ship + if (pCaughtActor->GetTeam() == m_Team && g_ActivityMan.GetActivity() && pCaughtActor->GetController()->IsPlayerControlled()) + g_ActivityMan.GetActivity()->SwitchToActor(this, pCaughtActor->GetController()->GetPlayer(), pCaughtActor->GetTeam()); + // Add (copy) of caught Actor to this' inventory + AddInventoryItem(dynamic_cast(pCaughtActor->Clone())); + // Delete the original from scene - this is safer than 'removing' or handing over ownership halfway through MovableMan's update + pCaughtActor->SetToDelete(); + // Negate the team 'loss' that will be reported when the deletion is done + g_ActivityMan.GetActivity()->ReportDeath(pCaughtActor->GetTeam(), -1); + } + // Any other MO has been caught, jsut add it to inventory + // TODO: do we need special case for Attachables?? (so we can detach them first? - probably no because SuckInMOs is unlikely to return an attahced thing) + else { + // Add (copy) of caught Actor to this' inventory + AddInventoryItem(dynamic_cast(pNewObject->Clone())); + // Delete the original from scene - this is safer than 'removing' or handing over ownership halfway through MovableMan's update + pNewObject->SetToDelete(); + } + pNewObject = 0; + } + } + } + } -void ACraft::ResetAllTimers() { - MOSRotating::ResetAllTimers(); + ///////////////////////////////////////// + // Check for having gone into orbit - m_FlippedTimer.Reset(); -} + if (m_Pos.m_Y < -m_CharHeight || m_Pos.m_Y > g_SceneMan.GetSceneHeight() + m_CharHeight) { + g_ActivityMan.GetActivity()->HandleCraftEnteringOrbit(this); + // Play fading away thruster sound + // if (m_pMThruster && m_pMThruster->IsEmitting()) + // m_pMThruster->(pTargetBitmap, targetPos, mode, onlyPhysical); + m_ToDelete = true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this ACraft. Supposed to be done every frame. - -void ACraft::Update() -{ - Actor::Update(); - - //////////////////////////////////// - // Update viewpoint - - // Set viewpoint based on how we are aiming etc. - m_ViewPoint = m_Pos.GetFloored(); - // Add velocity also so the viewpoint moves ahead at high speeds - if (m_Vel.MagnitudeIsGreaterThan(10.0F)) { m_ViewPoint += m_Vel * std::sqrt(m_Vel.GetMagnitude() * 0.1F); } - - /////////////////////////////////////////////////// - // Crash detection and handling - const float crashSpeedThreshold = 1.0F; - if (m_DeepHardness > 5 && m_Vel.MagnitudeIsGreaterThan(crashSpeedThreshold)) - { - m_Health -= m_DeepHardness * 0.03; -// TODO: HELLA GHETTO, REWORK - if (m_CrashTimer.GetElapsedSimTimeMS() > 500) - { - if (m_CrashSound) { m_CrashSound->Play(m_Pos); } - m_CrashTimer.Reset(); - } - } - - /////////////////////////////////////////////////// - // Doors open logic - - if (m_HatchState == OPEN) - { - // Keep ejecting things if hatch is open and inventory isn't empty - if (!IsInventoryEmpty()) - DropAllInventory(); - // If doors are open and all inventory is ejected (and they have had a chance to fall away), then actively look for things to suck in through the exits. - else if (m_Status == STABLE && m_ExitTimer.IsPastSimMS(EXITSUCKDELAYMS)) - { - // See if any of the exits have sucked in an MO - for (std::list::iterator exit = m_Exits.begin(); exit != m_Exits.end(); ++exit) - { - // If exit sucked in an MO, add it to invetory - MOSRotating *pNewObject = exit->SuckInMOs(this); - if (pNewObject && !pNewObject->IsSetToDelete()) - { - // Did we catch an Actor? If so, we need to do special controller switching in case it's player controlled atm - Actor *pCaughtActor = 0; - if (pCaughtActor = dynamic_cast(pNewObject)) - { - // Switch control to this craft if the Actor we just caught is on our team and currently player controlled - // Set AI controller of the Actor going into the ship - if (pCaughtActor->GetTeam() == m_Team && g_ActivityMan.GetActivity() && pCaughtActor->GetController()->IsPlayerControlled()) - g_ActivityMan.GetActivity()->SwitchToActor(this, pCaughtActor->GetController()->GetPlayer(), pCaughtActor->GetTeam()); - // Add (copy) of caught Actor to this' inventory - AddInventoryItem(dynamic_cast(pCaughtActor->Clone())); - // Delete the original from scene - this is safer than 'removing' or handing over ownership halfway through MovableMan's update - pCaughtActor->SetToDelete(); - // Negate the team 'loss' that will be reported when the deletion is done - g_ActivityMan.GetActivity()->ReportDeath(pCaughtActor->GetTeam(), -1); - } - // Any other MO has been caught, jsut add it to inventory -// TODO: do we need special case for Attachables?? (so we can detach them first? - probably no because SuckInMOs is unlikely to return an attahced thing) - else - { - // Add (copy) of caught Actor to this' inventory - AddInventoryItem(dynamic_cast(pNewObject->Clone())); - // Delete the original from scene - this is safer than 'removing' or handing over ownership halfway through MovableMan's update - pNewObject->SetToDelete(); - } - pNewObject = 0; - } - } - } - } - - ///////////////////////////////////////// - // Check for having gone into orbit - - if (m_Pos.m_Y < -m_CharHeight || m_Pos.m_Y > g_SceneMan.GetSceneHeight() + m_CharHeight) - { - g_ActivityMan.GetActivity()->HandleCraftEnteringOrbit(this); - // Play fading away thruster sound -// if (m_pMThruster && m_pMThruster->IsEmitting()) -// m_pMThruster->(pTargetBitmap, targetPos, mode, onlyPhysical); - m_ToDelete = true; - } - - if (g_ActivityMan.GetActivity()->GetCraftOrbitAtTheEdge()) - { - if (g_SceneMan.GetScene() && !g_SceneMan.GetScene()->WrapsX()) - { - if (m_Pos.m_X < -GetSpriteWidth() || m_Pos.m_X > g_SceneMan.GetSceneWidth() + GetSpriteWidth()) - { - g_ActivityMan.GetActivity()->HandleCraftEnteringOrbit(this); - m_ToDelete = true; + if (g_ActivityMan.GetActivity()->GetCraftOrbitAtTheEdge()) { + if (g_SceneMan.GetScene() && !g_SceneMan.GetScene()->WrapsX()) { + if (m_Pos.m_X < -GetSpriteWidth() || m_Pos.m_X > g_SceneMan.GetSceneWidth() + GetSpriteWidth()) { + g_ActivityMan.GetActivity()->HandleCraftEnteringOrbit(this); + m_ToDelete = true; + } } } - } - if (m_Status == DEAD) { - if (m_ScuttleOnDeath || m_AIMode == AIMODE_SCUTTLE) { GibThis(); } - } else if (m_Status == DYING) { - if ((m_ScuttleOnDeath || m_AIMode == AIMODE_SCUTTLE) && m_DeathTmr.IsPastSimMS(500) && m_DeathTmr.AlternateSim(100)) { FlashWhite(10); } - } else if (m_Health <= 0 || m_AIMode == AIMODE_SCUTTLE || (m_ScuttleIfFlippedTime >= 0 && m_FlippedTimer.IsPastSimMS(m_ScuttleIfFlippedTime))) { - m_Status = DYING; - m_DeathTmr.Reset(); - DropAllInventory(); - } + if (m_Status == DEAD) { + if (m_ScuttleOnDeath || m_AIMode == AIMODE_SCUTTLE) { + GibThis(); + } + } else if (m_Status == DYING) { + if ((m_ScuttleOnDeath || m_AIMode == AIMODE_SCUTTLE) && m_DeathTmr.IsPastSimMS(500) && m_DeathTmr.AlternateSim(100)) { + FlashWhite(10); + } + } else if (m_Health <= 0 || m_AIMode == AIMODE_SCUTTLE || (m_ScuttleIfFlippedTime >= 0 && m_FlippedTimer.IsPastSimMS(m_ScuttleIfFlippedTime))) { + m_Status = DYING; + m_DeathTmr.Reset(); + DropAllInventory(); + } - // Get the rotation in radians. - float rot = m_Rotation.GetRadAngle(); + // Get the rotation in radians. + float rot = m_Rotation.GetRadAngle(); - // Eliminate rotations over half a turn. - if (std::abs(rot) > c_PI) { - rot += (rot > 0) ? -c_TwoPI : c_TwoPI; - m_Rotation.SetRadAngle(rot); - } - if (rot < c_HalfPI && rot > -c_HalfPI) { - m_FlippedTimer.Reset(); + // Eliminate rotations over half a turn. + if (std::abs(rot) > c_PI) { + rot += (rot > 0) ? -c_TwoPI : c_TwoPI; + m_Rotation.SetRadAngle(rot); + } + if (rot < c_HalfPI && rot > -c_HalfPI) { + m_FlippedTimer.Reset(); + } + + ///////////////////////////////////////// + // Misc. + + m_DeepCheck = true /*m_Status == DEAD*/; } - ///////////////////////////////////////// - // Misc. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. - m_DeepCheck = true/*m_Status == DEAD*/; -} + void ACraft::DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { + m_HUDStack = -m_CharHeight / 2; + // Only do HUD if on a team + if (m_Team < 0) + return; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. - -void ACraft::DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) { - m_HUDStack = -m_CharHeight / 2; - - // Only do HUD if on a team - if (m_Team < 0) - return; - - // Only draw if the team viewing this is on the same team OR has seen the space where this is located. - int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); - if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { - return; - } + // Only draw if the team viewing this is on the same team OR has seen the space where this is located. + int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); + if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { + return; + } - Actor::DrawHUD(pTargetBitmap, targetPos, whichScreen); + Actor::DrawHUD(pTargetBitmap, targetPos, whichScreen); - if (!m_HUDVisible) { - return; - } + if (!m_HUDVisible) { + return; + } + + GUIFont* pSymbolFont = g_FrameMan.GetLargeFont(); + GUIFont* pSmallFont = g_FrameMan.GetSmallFont(); - GUIFont *pSymbolFont = g_FrameMan.GetLargeFont(); - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); - - // Draw hud guides for the Exits, depending on whether the doors are open - if (m_HatchState == OPEN)// || m_HatchState == OPENING) - { - // Doors open and inventory not empty yet, so show arrows pointing out of the exits since things are still coming out - if (!IsInventoryEmpty()) - { - // -------- - // | \ \ + // Draw hud guides for the Exits, depending on whether the doors are open + if (m_HatchState == OPEN) // || m_HatchState == OPENING) + { + // Doors open and inventory not empty yet, so show arrows pointing out of the exits since things are still coming out + if (!IsInventoryEmpty()) { + // -------- + // | \ \ // -+- | | - // | / / - // -------- - // Make the dotted lines crawl out of the exit, indicating that things are still coming out - if (--m_ExitLinePhase < 0) - m_ExitLinePhase = EXITLINESPACING - 1; - } - // Inventory empty and doors open, so show arrows pointing into the exits IF the delay to allow for things to eject away all the way has passed - else if (m_ExitTimer.IsPastSimMS(EXITSUCKDELAYMS)) - { - // Make the dotted lines crawl back into the exit, inviting people to jump in - if (++m_ExitLinePhase >= EXITLINESPACING) - m_ExitLinePhase = 0; - } - - Vector exitRadius; - Vector exitCorner; - Vector arrowVec; - // Draw the actual dotted lines - for (std::list::iterator exit = m_Exits.begin(); exit != m_Exits.end(); ++exit) - { - if (exit->CheckIfClear(m_Pos, m_Rotation, 18)) - { - exitRadius = RotateOffset(exit->GetVelocity().GetPerpendicular().SetMagnitude(exit->GetRadius())); - exitCorner = m_Pos - targetPos + RotateOffset(exit->GetOffset()) + exitRadius; - arrowVec = RotateOffset(exit->GetVelocity().SetMagnitude(exit->GetRange())); - g_FrameMan.DrawLine(pTargetBitmap, exitCorner, exitCorner + arrowVec, 120, 120, EXITLINESPACING, m_ExitLinePhase); - exitCorner -= exitRadius * 2; - g_FrameMan.DrawLine(pTargetBitmap, exitCorner, exitCorner + arrowVec, 120, 120, EXITLINESPACING, m_ExitLinePhase); - } - } - } - - // Only show extra HUD if this guy is controlled by a player - if (m_Controller.IsPlayerControlled() && pSmallFont && pSymbolFont) - { - AllegroBitmap pBitmapInt(pTargetBitmap); -/* - // AI Mode select GUI HUD - if (m_Controller && m_Controller.IsState(PIE_MENU_ACTIVE)) - { - char str[64]; - int iconOff = m_apAIIcons[0]->w + 2; - int iconColor = m_Team == Activity::TeamOne ? AIICON_RED : AIICON_GREEN; - Vector iconPos = GetCPUPos() - targetPos; - - if (m_AIMode == AIMODE_RETURN) - { - std::snprintf(str, sizeof(str), "%s", "Return"); - pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X, iconPos.m_Y - 18, str, GUIFont::Centre); - } - else if (m_AIMode == AIMODE_DELIVER) - { - std::snprintf(str, sizeof(str), "%s", "Deliver"); - pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X - 9, iconPos.m_Y - 5, str, GUIFont::Right); - } - else if (m_AIMode == AIMODE_SCUTTLE) - { - std::snprintf(str, sizeof(str), "%s", "Scuttle"); - pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X + 9, iconPos.m_Y - 5, str, GUIFont::Left); - } - else if (m_AIMode == AIMODE_STAY) - { - std::snprintf(str, sizeof(str), "%s", "Stay"); - pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X, iconPos.m_Y + 8, str, GUIFont::Centre); - } - - // Draw the mode alternatives if they are not the current one - if (m_AIMode != AIMODE_RETURN) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_RETURN], iconPos.m_X - 6, iconPos.m_Y - 6 - iconOff); - } - if (m_AIMode != AIMODE_DELIVER) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_DELIVER], iconPos.m_X - 6 - iconOff, iconPos.m_Y - 6); - } - if (m_AIMode != AIMODE_SCUTTLE) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_SCUTTLE], iconPos.m_X - 6 + iconOff, iconPos.m_Y - 6); - } - if (m_AIMode != AIMODE_STAY) - { - draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_STAY], iconPos.m_X - 6, iconPos.m_Y - 6 + iconOff); - } - } -*/ - } -} - -} // namespace RTE \ No newline at end of file + // | / / + // -------- + // Make the dotted lines crawl out of the exit, indicating that things are still coming out + if (--m_ExitLinePhase < 0) + m_ExitLinePhase = EXITLINESPACING - 1; + } + // Inventory empty and doors open, so show arrows pointing into the exits IF the delay to allow for things to eject away all the way has passed + else if (m_ExitTimer.IsPastSimMS(EXITSUCKDELAYMS)) { + // Make the dotted lines crawl back into the exit, inviting people to jump in + if (++m_ExitLinePhase >= EXITLINESPACING) + m_ExitLinePhase = 0; + } + + Vector exitRadius; + Vector exitCorner; + Vector arrowVec; + // Draw the actual dotted lines + for (std::list::iterator exit = m_Exits.begin(); exit != m_Exits.end(); ++exit) { + if (exit->CheckIfClear(m_Pos, m_Rotation, 18)) { + exitRadius = RotateOffset(exit->GetVelocity().GetPerpendicular().SetMagnitude(exit->GetRadius())); + exitCorner = m_Pos - targetPos + RotateOffset(exit->GetOffset()) + exitRadius; + arrowVec = RotateOffset(exit->GetVelocity().SetMagnitude(exit->GetRange())); + g_FrameMan.DrawLine(pTargetBitmap, exitCorner, exitCorner + arrowVec, 120, 120, EXITLINESPACING, m_ExitLinePhase); + exitCorner -= exitRadius * 2; + g_FrameMan.DrawLine(pTargetBitmap, exitCorner, exitCorner + arrowVec, 120, 120, EXITLINESPACING, m_ExitLinePhase); + } + } + } + + // Only show extra HUD if this guy is controlled by a player + if (m_Controller.IsPlayerControlled() && pSmallFont && pSymbolFont) { + AllegroBitmap pBitmapInt(pTargetBitmap); + /* + // AI Mode select GUI HUD + if (m_Controller && m_Controller.IsState(PIE_MENU_ACTIVE)) + { + char str[64]; + int iconOff = m_apAIIcons[0]->w + 2; + int iconColor = m_Team == Activity::TeamOne ? AIICON_RED : AIICON_GREEN; + Vector iconPos = GetCPUPos() - targetPos; + + if (m_AIMode == AIMODE_RETURN) + { + std::snprintf(str, sizeof(str), "%s", "Return"); + pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X, iconPos.m_Y - 18, str, GUIFont::Centre); + } + else if (m_AIMode == AIMODE_DELIVER) + { + std::snprintf(str, sizeof(str), "%s", "Deliver"); + pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X - 9, iconPos.m_Y - 5, str, GUIFont::Right); + } + else if (m_AIMode == AIMODE_SCUTTLE) + { + std::snprintf(str, sizeof(str), "%s", "Scuttle"); + pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X + 9, iconPos.m_Y - 5, str, GUIFont::Left); + } + else if (m_AIMode == AIMODE_STAY) + { + std::snprintf(str, sizeof(str), "%s", "Stay"); + pSmallFont->DrawAligned(&pBitmapInt, iconPos.m_X, iconPos.m_Y + 8, str, GUIFont::Centre); + } + + // Draw the mode alternatives if they are not the current one + if (m_AIMode != AIMODE_RETURN) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_RETURN], iconPos.m_X - 6, iconPos.m_Y - 6 - iconOff); + } + if (m_AIMode != AIMODE_DELIVER) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_DELIVER], iconPos.m_X - 6 - iconOff, iconPos.m_Y - 6); + } + if (m_AIMode != AIMODE_SCUTTLE) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_SCUTTLE], iconPos.m_X - 6 + iconOff, iconPos.m_Y - 6); + } + if (m_AIMode != AIMODE_STAY) + { + draw_sprite(pTargetBitmap, m_apAIIcons[AIMODE_STAY], iconPos.m_X - 6, iconPos.m_Y - 6 + iconOff); + } + } + */ + } + } + +} // namespace RTE diff --git a/Source/Entities/ACraft.h b/Source/Entities/ACraft.h index f381da800..28398613b 100644 --- a/Source/Entities/ACraft.h +++ b/Source/Entities/ACraft.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,682 +18,627 @@ struct BITMAP; -namespace RTE -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: ACraft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A flying Actor which carries other things and can drop them. -// Parent(s): Actor. -// Class history: 12/13/2006 ACraft created. - -class ACraft : public Actor { - friend struct EntityLuaBindings; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableOverrideMethods; - ClassInfoGetters; - DefaultPieMenuNameGetter("Default Craft Pie Menu"); - +namespace RTE { -enum HatchState -{ - CLOSED = 0, - OPENING, - OPEN, - CLOSING, - HatchStateCount -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: ACraft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A flying Actor which carries other things and can drop them. + // Parent(s): Actor. + // Class history: 12/13/2006 ACraft created. -enum Side -{ - RIGHT = 0, - LEFT -}; + class ACraft : public Actor { + friend struct EntityLuaBindings; - ////////////////////////////////////////////////////////////////////////////////////////// - // Nested class: Exit - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Something to bundle the properties of ACraft exits together. - // Parent(s): Serializable. - // Class history: 12/19/2006 Exit created. + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations - class Exit: - public Serializable - { - - friend class ACraft; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Public member variable, method and friend function declarations - - public: - - SerializableClassNameGetter; + public: SerializableOverrideMethods; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Constructor: Exit - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Constructor method used to instantiate a Exit object in system - // memory. Create() should be called before using the object. - // Arguments: None. - - Exit() { Clear(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Makes the Exit object ready for use. - // Arguments: None. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. + ClassInfoGetters; + DefaultPieMenuNameGetter("Default Craft Pie Menu"); + + enum HatchState { + CLOSED = 0, + OPENING, + OPEN, + CLOSING, + HatchStateCount + }; + + enum Side { + RIGHT = 0, + LEFT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Nested class: Exit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Something to bundle the properties of ACraft exits together. + // Parent(s): Serializable. + // Class history: 12/19/2006 Exit created. + + class Exit : + public Serializable { + + friend class ACraft; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableClassNameGetter; + SerializableOverrideMethods; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Exit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Exit object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Exit() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Exit object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Exit to be identical to another, by deep copy. + // Arguments: A reference to the Exit to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Exit& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Serializable, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the position offset of this exit from the position of its ACraft. + // Arguments: None. + // Return value: The coordinates relative to the m_Pos of this' ACraft. + + Vector GetOffset() const { return m_Offset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetVelocity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the velocity of anything that exits through this. + // Arguments: None. + // Return value: The velocity vector for anything exiting through this. + + Vector GetVelocity() const { return m_Velocity * (1.0F + m_VelSpread * RandomNormalNum()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRadius + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the width from the center tanget created by the velocity vector + // out from the offet point. This times two gives the total width of the + // opening. + // Arguments: None. + // Return value: Half the total width of the opening. + + float GetRadius() const { return m_Radius; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the distance this exit can suck in objects from. + // Arguments: None. + // Return value: The sucking range of this. + + float GetRange() const { return m_Range; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CheckIfClear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates whether this exit is currently clear enough of terrain to + // safely put things through without them ending up in the terrain. + // Arguments: The position of the parent ACraft of this. + // The rotation of the parent ACraft of this. + // How large (radius) the item is that is supposed to fit. + // Return value: If this has been determined clear to put anything through. + + bool CheckIfClear(const Vector& pos, Matrix& rot, float size = 20); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsClear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells if this is clear of the terrain to put things through. Faster than + // CheckIfClear(). + // Arguments: None. + // Return value: If this has been determined clear to put anything through. + + bool IsClear() const { return m_Clear; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SuckInMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Uses cast MO rays to see if anyhting is able to be drawn into this + // exit. If so, it will alter the positiona nd velocity of the objet so + // it flies into the exit until it is sufficiently inside and then it'll + // return the MO here, OWNERHIP NOT TRANSFERRED! It is still in MovableMan! + // Arguments: A pointer to the ACraft owner of this Exit. OWNERSHIP IS NOT TRANSFERRED! + // Return value: If an MO has been fully drawn into the exit, it will be returned here, + // OWNERSHIP NOT TRANSFERRED! + + MOSRotating* SuckInMOs(ACraft* pExitOwner); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // The offset of this exit relative the position of its ACraft + Vector m_Offset; + // The exiting velocity of anyhting exiting through this + Vector m_Velocity; + // The spread in velocity, ratio + float m_VelSpread; + // The width from the center tanget created by the velocity vector out from the offet point. This times two gives the total width of the opening. + float m_Radius; + // How far away the exit cna suck objects in from + float m_Range; + // Temporary var to check if this is clear of terrain for putting things through + bool m_Clear; + // Movable Object that is being drawn into this exit + MOSRotating* m_pIncomingMO; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Exit, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; + + // Concrete allocation and cloning definitions + // EntityAllocation(ACraft) + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: ACraft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a ACraft object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + ACraft() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~ACraft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a ACraft object before deletion + // from system memory. + // Arguments: None. + + ~ACraft() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ACraft object ready for use. + // Arguments: A Reader that the ACraft will create itself with. + // Whether there is a class name in the stream to check against to make + // sure the correct type is being read from the stream. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. int Create() override; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Creates a Exit to be identical to another, by deep copy. - // Arguments: A reference to the Exit to deep copy. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create(const Exit &reference); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Reset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Resets the entire Serializable, including its inherited members, to their - // default settings or values. - // Arguments: None. - // Return value: None. - - void Reset() override { Clear(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetOffset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the position offset of this exit from the position of its ACraft. - // Arguments: None. - // Return value: The coordinates relative to the m_Pos of this' ACraft. - - Vector GetOffset() const { return m_Offset; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetVelocity - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the velocity of anything that exits through this. - // Arguments: None. - // Return value: The velocity vector for anything exiting through this. - - Vector GetVelocity() const { return m_Velocity * (1.0F + m_VelSpread * RandomNormalNum()); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: GetRadius - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the width from the center tanget created by the velocity vector - // out from the offet point. This times two gives the total width of the - // opening. - // Arguments: None. - // Return value: Half the total width of the opening. - - float GetRadius() const { return m_Radius; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetRange - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the distance this exit can suck in objects from. - // Arguments: None. - // Return value: The sucking range of this. - - float GetRange() const { return m_Range; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: CheckIfClear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Calculates whether this exit is currently clear enough of terrain to - // safely put things through without them ending up in the terrain. - // Arguments: The position of the parent ACraft of this. - // The rotation of the parent ACraft of this. - // How large (radius) the item is that is supposed to fit. - // Return value: If this has been determined clear to put anything through. - - bool CheckIfClear(const Vector &pos, Matrix &rot, float size = 20); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: IsClear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Tells if this is clear of the terrain to put things through. Faster than - // CheckIfClear(). - // Arguments: None. - // Return value: If this has been determined clear to put anything through. - - bool IsClear() const { return m_Clear; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SuckInMOs - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Uses cast MO rays to see if anyhting is able to be drawn into this - // exit. If so, it will alter the positiona nd velocity of the objet so - // it flies into the exit until it is sufficiently inside and then it'll - // return the MO here, OWNERHIP NOT TRANSFERRED! It is still in MovableMan! - // Arguments: A pointer to the ACraft owner of this Exit. OWNERSHIP IS NOT TRANSFERRED! - // Return value: If an MO has been fully drawn into the exit, it will be returned here, - // OWNERSHIP NOT TRANSFERRED! - - MOSRotating * SuckInMOs(ACraft *pExitOwner); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Protected member variable and method declarations - - protected: - - // The offset of this exit relative the position of its ACraft - Vector m_Offset; - // The exiting velocity of anyhting exiting through this - Vector m_Velocity; - // The spread in velocity, ratio - float m_VelSpread; - // The width from the center tanget created by the velocity vector out from the offet point. This times two gives the total width of the opening. - float m_Radius; - // How far away the exit cna suck objects in from - float m_Range; - // Temporary var to check if this is clear of terrain for putting things through - bool m_Clear; - // Movable Object that is being drawn into this exit - MOSRotating *m_pIncomingMO; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Private member variable and method declarations - - private: - - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Clear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Clears all the member variables of this Exit, effectively - // resetting the members of this abstraction level only. - // Arguments: None. - // Return value: None. - - void Clear(); - - }; - - -// Concrete allocation and cloning definitions -//EntityAllocation(ACraft) - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: ACraft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a ACraft object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - ACraft() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~ACraft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a ACraft object before deletion -// from system memory. -// Arguments: None. - - ~ACraft() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ACraft object ready for use. -// Arguments: A Reader that the ACraft will create itself with. -// Whether there is a class name in the stream to check against to make -// sure the correct type is being read from the stream. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a ACraft to be identical to another, by deep copy. -// Arguments: A reference to the ACraft to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const ACraft &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire ACraft, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Actor::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this Actor and all its carried -// gold and inventory. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// Return value: The current value of this Actor and all his carried assets. - - float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically named object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The Preset name of the object to look for. -// Return value: Whetehr the object was found carried by this. - - bool HasObject(std::string objectName) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObjectInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically grouped object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The name of the group to look for. -// Return value: Whetehr the object in the group was found carried by this. - - bool HasObjectInGroup(std::string groupName) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetHatchState -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current state of the hatch. -// Arguments: None. -// Return value: An int encoding the hatch state. See the HatchState enum. - - unsigned int GetHatchState() const { return m_HatchState; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this belongs to, and all its inventory too. -// Arguments: The assigned team number. -// Return value: None. - - void SetTeam(int team) override; - - /// - /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. - /// - /// The SliceType of the PieSlice being handled. - /// Whether or not the activated PieSlice SliceType was able to be handled. - bool HandlePieCommand(PieSlice::SliceType pieSliceType) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AutoStabilizing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this has the means and will try to right itself, or if -// that's up to the Controller to do. -// Arguments: None. -// Return value: Wheter this will try to auto stabilize. - - virtual bool AutoStabilizing() { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OpenHatch -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Opens the hatch doors, if they're closed or closing. -// Arguments: None. -// Return value: None. - - void OpenHatch(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CloseHatch -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Closes the hatch doors, if they're open or opening. -// Arguments: None. -// Return value: None. - - void CloseHatch(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: AddInventoryItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an inventory item to this Actor. -// Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! -// Return value: None.. - - void AddInventoryItem(MovableObject *pItemToAdd) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DropAllInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Opens the hatches and makes everything in the Rocket fly out, including -// the passenger Actors, one after another. It may not happen -// instantaneously, so check for ejection being complete with -// IsInventoryEmpty(). -// Arguments: None. -// Return value: None. - - void DropAllInventory() override; - - /// - /// Gets the mass of this ACraft's inventory of newly collected items. - /// - /// The mass of this ACraft's newly collected inventory. - float GetCollectedInventoryMass() const; - - /// - /// Gets the mass of this ACraft, including the mass of its Attachables, wounds and inventory. - /// - /// The mass of this ACraft, its inventory and all its Attachables and wounds in Kilograms (kg). - float GetMass() const override { return Actor::GetMass() + GetCollectedInventoryMass(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasDelivered -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicated whether this has landed and delivered yet on its current run. -// Arguments: None. -// Return value: Whether this has delivered yet. - - bool HasDelivered() { return m_HasDelivered; } - - /// - /// Resets all the timers related to this, including the scuttle timer. - /// - void ResetAllTimers() override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// Which player's screen this is being drawn to. May affect what HUD elements -// get drawn etc. -// Return value: None. - - void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMaxPassengers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The recomended, not absolute, maximum number of actors that fit in the -// invetory. Used by the activity AI. -// Arguments: None. -// Return value: An integer with the recomended number of actors that fit in the craft. -// Default is -1 (unknown). - - virtual int GetMaxPassengers() const { return m_MaxPassengers; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetMaxPassengers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the recomended, not absolute, maximum number of actors that fit in the -// invetory. Used by the activity AI. -// Arguments: An integer with the recomended number of actors that fit in the craft. -// Default is -1 (unknown). -// Return value: None. - - virtual void SetMaxPassengers(int max) { m_MaxPassengers = max; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeliveryDelayMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns delivery delay multiplier. -// Arguments: None. -// Return value: Delivery delay multiplier. - - float GetDeliveryDelayMultiplier() const { return m_DeliveryDelayMultiplier; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDeliveryDelayMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets delivery delay multiplier. -// Arguments: Delivery delay multiplier. -// Return value: None. - - void SetDeliveryDelayMultiplier(float newValue) { m_DeliveryDelayMultiplier = newValue; } - - - /// - /// Gets whether this ACraft will scuttle automatically on death. - /// - /// Whether this ACraft will scuttle automatically on death. - bool GetScuttleOnDeath() const { return m_ScuttleOnDeath; } - - /// - /// Sets whether this ACraft will scuttle automatically on death. - /// - /// Whether this ACraft will scuttle automatically on death. - void SetScuttleOnDeath(bool scuttleOnDeath) { m_ScuttleOnDeath = scuttleOnDeath; } - - /// - /// Gets the hatch opening/closing delay of this ACraft. - /// - /// The hatch delay of this ACraft. - int GetHatchDelay() const { return m_HatchDelay; } - - /// - /// Sets the hatch opening/closing delay of this ACraft. - /// - /// The new hatch delay of this ACraft. - void SetHatchDelay(int newDelay) { m_HatchDelay = newDelay; } - - /// - /// Destroys this ACraft and creates its specified Gibs in its place with appropriate velocities. Any Attachables are removed and also given appropriate velocities. - /// - /// The impulse (kg * m/s) of the impact causing the gibbing to happen. - /// A pointer to an MO which the Gibs and Attachables should not be colliding with. - void GibThis(const Vector &impactImpulse = Vector(), MovableObject *movableObjectToIgnore = nullptr) override; - - /// - /// Gets this ACraft's hatch opening sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this ACraft's hatch opening sound. - SoundContainer * GetHatchOpenSound() const { return m_HatchOpenSound; } - - /// - /// Sets this ACraft's hatch opening sound. Ownership IS transferred! - /// - /// The new SoundContainer for this ACraft's hatch opening sound. - void SetHatchOpenSound(SoundContainer *newSound) { m_HatchOpenSound = newSound; } - - /// - /// Gets this ACraft's hatch closing sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this ACraft's hatch closing sound. - SoundContainer * GetHatchCloseSound() const { return m_HatchCloseSound; } - - /// - /// Sets this ACraft's hatch closing sound. Ownership IS transferred! - /// - /// The new SoundContainer for this ACraft's hatch closing sound. - void SetHatchCloseSound(SoundContainer *newSound) { m_HatchCloseSound = newSound; } - - /// - /// Gets this ACraft's crash sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this ACraft's crash sound. - SoundContainer * GetCrashSound() const { return m_CrashSound; } - - /// - /// Sets this ACraft's crash sound. Ownership IS transferred! - /// - /// The new SoundContainer for this ACraft's crash sound. - void SetCrashSound(SoundContainer *newSound) { m_CrashSound = newSound; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - // Current movement state. - unsigned int m_MoveState; - // Current hatch action state. - unsigned int m_HatchState; - // Timer for opening and closing hatches - Timer m_HatchTimer; - // The time it takes to open or close the hatch, in ms. - int m_HatchDelay; - // Sound for opening the hatch - SoundContainer *m_HatchOpenSound; - // Sound for closing the hatch - SoundContainer *m_HatchCloseSound; - std::deque m_CollectedInventory; //!< A separate inventory to temporarily store newly collected items, so that they don't get immediately ejected from the main inventory while the hatch is still open. - // All the possible exits for when ejecting stuff out of this. - std::list m_Exits; - // Last used exit so we can alternate/cycle - std::list::iterator m_CurrentExit; - // The delay between each exiting passenger Actor - long m_ExitInterval; - // Times the exit interval - Timer m_ExitTimer; - // The phase of the exit lines animation - int m_ExitLinePhase; - // Whether this has landed and delivered yet on its current run - bool m_HasDelivered; - // Whether this is capable of landing on the ground at all - bool m_LandingCraft; - // Timer for checking if craft is hopelessly flipped and should die - Timer m_FlippedTimer; - // Timer to measure how long ago a crash sound was played - Timer m_CrashTimer; - // Crash sound - SoundContainer *m_CrashSound; - // The maximum number of actors that fit in the inventory - int m_MaxPassengers; - int m_ScuttleIfFlippedTime; //!< The time after which the craft will scuttle automatically, if tipped over. - bool m_ScuttleOnDeath; //!< Whether the craft will self-destruct at zero health. - - static bool s_CrabBombInEffect; //!< Flag to determine if a craft is triggering the Crab Bomb effect. - - //////// - // AI states - - enum CraftDeliverySequence - { - FALL = 0, - LAND, - STANDBY, - UNLOAD, - LAUNCH, - UNSTICK - }; - - enum AltitudeMoveState - { - HOVER = 0, - DESCEND, - ASCEND - }; - - // What the rocket/ship is currently doing in an AI landing sequence - int m_DeliveryState; - // Whether the AI is trying to go higher, lower, or stand still in altitude - int m_AltitudeMoveState; - // Controls the altitude gain/loss the AI is trying to achieve. Normalized -1.0 (max rise) to 1.0 (max drop). 0 is approximate hover. - float m_AltitudeControl; - // Mutliplier to apply to default delivery time - float m_DeliveryDelayMultiplier; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ACraft, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - ACraft(const ACraft &reference) = delete; - ACraft & operator=(const ACraft &rhs) = delete; - -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a ACraft to be identical to another, by deep copy. + // Arguments: A reference to the ACraft to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const ACraft& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire ACraft, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Actor::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this Actor and all its carried + // gold and inventory. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // Return value: The current value of this Actor and all his carried assets. + + float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically named object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The Preset name of the object to look for. + // Return value: Whetehr the object was found carried by this. + + bool HasObject(std::string objectName) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObjectInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically grouped object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The name of the group to look for. + // Return value: Whetehr the object in the group was found carried by this. + + bool HasObjectInGroup(std::string groupName) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetHatchState + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current state of the hatch. + // Arguments: None. + // Return value: An int encoding the hatch state. See the HatchState enum. + + unsigned int GetHatchState() const { return m_HatchState; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this belongs to, and all its inventory too. + // Arguments: The assigned team number. + // Return value: None. + + void SetTeam(int team) override; + + /// + /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. + /// + /// The SliceType of the PieSlice being handled. + /// Whether or not the activated PieSlice SliceType was able to be handled. + bool HandlePieCommand(PieSlice::SliceType pieSliceType) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AutoStabilizing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this has the means and will try to right itself, or if + // that's up to the Controller to do. + // Arguments: None. + // Return value: Wheter this will try to auto stabilize. + + virtual bool AutoStabilizing() { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OpenHatch + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Opens the hatch doors, if they're closed or closing. + // Arguments: None. + // Return value: None. + + void OpenHatch(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CloseHatch + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Closes the hatch doors, if they're open or opening. + // Arguments: None. + // Return value: None. + + void CloseHatch(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: AddInventoryItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an inventory item to this Actor. + // Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! + // Return value: None.. + + void AddInventoryItem(MovableObject* pItemToAdd) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DropAllInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Opens the hatches and makes everything in the Rocket fly out, including + // the passenger Actors, one after another. It may not happen + // instantaneously, so check for ejection being complete with + // IsInventoryEmpty(). + // Arguments: None. + // Return value: None. + + void DropAllInventory() override; + + /// + /// Gets the mass of this ACraft's inventory of newly collected items. + /// + /// The mass of this ACraft's newly collected inventory. + float GetCollectedInventoryMass() const; + + /// + /// Gets the mass of this ACraft, including the mass of its Attachables, wounds and inventory. + /// + /// The mass of this ACraft, its inventory and all its Attachables and wounds in Kilograms (kg). + float GetMass() const override { return Actor::GetMass() + GetCollectedInventoryMass(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasDelivered + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicated whether this has landed and delivered yet on its current run. + // Arguments: None. + // Return value: Whether this has delivered yet. + + bool HasDelivered() { return m_HasDelivered; } + + /// + /// Resets all the timers related to this, including the scuttle timer. + /// + void ResetAllTimers() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // Which player's screen this is being drawn to. May affect what HUD elements + // get drawn etc. + // Return value: None. + + void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMaxPassengers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The recomended, not absolute, maximum number of actors that fit in the + // invetory. Used by the activity AI. + // Arguments: None. + // Return value: An integer with the recomended number of actors that fit in the craft. + // Default is -1 (unknown). + + virtual int GetMaxPassengers() const { return m_MaxPassengers; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetMaxPassengers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the recomended, not absolute, maximum number of actors that fit in the + // invetory. Used by the activity AI. + // Arguments: An integer with the recomended number of actors that fit in the craft. + // Default is -1 (unknown). + // Return value: None. + + virtual void SetMaxPassengers(int max) { m_MaxPassengers = max; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeliveryDelayMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns delivery delay multiplier. + // Arguments: None. + // Return value: Delivery delay multiplier. + + float GetDeliveryDelayMultiplier() const { return m_DeliveryDelayMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDeliveryDelayMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets delivery delay multiplier. + // Arguments: Delivery delay multiplier. + // Return value: None. + + void SetDeliveryDelayMultiplier(float newValue) { m_DeliveryDelayMultiplier = newValue; } + + /// + /// Gets whether this ACraft will scuttle automatically on death. + /// + /// Whether this ACraft will scuttle automatically on death. + bool GetScuttleOnDeath() const { return m_ScuttleOnDeath; } + + /// + /// Sets whether this ACraft will scuttle automatically on death. + /// + /// Whether this ACraft will scuttle automatically on death. + void SetScuttleOnDeath(bool scuttleOnDeath) { m_ScuttleOnDeath = scuttleOnDeath; } + + /// + /// Gets the hatch opening/closing delay of this ACraft. + /// + /// The hatch delay of this ACraft. + int GetHatchDelay() const { return m_HatchDelay; } + + /// + /// Sets the hatch opening/closing delay of this ACraft. + /// + /// The new hatch delay of this ACraft. + void SetHatchDelay(int newDelay) { m_HatchDelay = newDelay; } + + /// + /// Destroys this ACraft and creates its specified Gibs in its place with appropriate velocities. Any Attachables are removed and also given appropriate velocities. + /// + /// The impulse (kg * m/s) of the impact causing the gibbing to happen. + /// A pointer to an MO which the Gibs and Attachables should not be colliding with. + void GibThis(const Vector& impactImpulse = Vector(), MovableObject* movableObjectToIgnore = nullptr) override; + + /// + /// Gets this ACraft's hatch opening sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this ACraft's hatch opening sound. + SoundContainer* GetHatchOpenSound() const { return m_HatchOpenSound; } + + /// + /// Sets this ACraft's hatch opening sound. Ownership IS transferred! + /// + /// The new SoundContainer for this ACraft's hatch opening sound. + void SetHatchOpenSound(SoundContainer* newSound) { m_HatchOpenSound = newSound; } + + /// + /// Gets this ACraft's hatch closing sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this ACraft's hatch closing sound. + SoundContainer* GetHatchCloseSound() const { return m_HatchCloseSound; } + + /// + /// Sets this ACraft's hatch closing sound. Ownership IS transferred! + /// + /// The new SoundContainer for this ACraft's hatch closing sound. + void SetHatchCloseSound(SoundContainer* newSound) { m_HatchCloseSound = newSound; } + + /// + /// Gets this ACraft's crash sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this ACraft's crash sound. + SoundContainer* GetCrashSound() const { return m_CrashSound; } + + /// + /// Sets this ACraft's crash sound. Ownership IS transferred! + /// + /// The new SoundContainer for this ACraft's crash sound. + void SetCrashSound(SoundContainer* newSound) { m_CrashSound = newSound; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + // Current movement state. + unsigned int m_MoveState; + // Current hatch action state. + unsigned int m_HatchState; + // Timer for opening and closing hatches + Timer m_HatchTimer; + // The time it takes to open or close the hatch, in ms. + int m_HatchDelay; + // Sound for opening the hatch + SoundContainer* m_HatchOpenSound; + // Sound for closing the hatch + SoundContainer* m_HatchCloseSound; + std::deque m_CollectedInventory; //!< A separate inventory to temporarily store newly collected items, so that they don't get immediately ejected from the main inventory while the hatch is still open. + // All the possible exits for when ejecting stuff out of this. + std::list m_Exits; + // Last used exit so we can alternate/cycle + std::list::iterator m_CurrentExit; + // The delay between each exiting passenger Actor + long m_ExitInterval; + // Times the exit interval + Timer m_ExitTimer; + // The phase of the exit lines animation + int m_ExitLinePhase; + // Whether this has landed and delivered yet on its current run + bool m_HasDelivered; + // Whether this is capable of landing on the ground at all + bool m_LandingCraft; + // Timer for checking if craft is hopelessly flipped and should die + Timer m_FlippedTimer; + // Timer to measure how long ago a crash sound was played + Timer m_CrashTimer; + // Crash sound + SoundContainer* m_CrashSound; + // The maximum number of actors that fit in the inventory + int m_MaxPassengers; + int m_ScuttleIfFlippedTime; //!< The time after which the craft will scuttle automatically, if tipped over. + bool m_ScuttleOnDeath; //!< Whether the craft will self-destruct at zero health. + + static bool s_CrabBombInEffect; //!< Flag to determine if a craft is triggering the Crab Bomb effect. + + //////// + // AI states + + enum CraftDeliverySequence { + FALL = 0, + LAND, + STANDBY, + UNLOAD, + LAUNCH, + UNSTICK + }; + + enum AltitudeMoveState { + HOVER = 0, + DESCEND, + ASCEND + }; + + // What the rocket/ship is currently doing in an AI landing sequence + int m_DeliveryState; + // Whether the AI is trying to go higher, lower, or stand still in altitude + int m_AltitudeMoveState; + // Controls the altitude gain/loss the AI is trying to achieve. Normalized -1.0 (max rise) to 1.0 (max drop). 0 is approximate hover. + float m_AltitudeControl; + // Mutliplier to apply to default delivery time + float m_DeliveryDelayMultiplier; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ACraft, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + ACraft(const ACraft& reference) = delete; + ACraft& operator=(const ACraft& rhs) = delete; + }; } // namespace RTE diff --git a/Source/Entities/ADSensor.cpp b/Source/Entities/ADSensor.cpp index 1e2488587..f20266864 100644 --- a/Source/Entities/ADSensor.cpp +++ b/Source/Entities/ADSensor.cpp @@ -5,7 +5,7 @@ namespace RTE { const std::string ADSensor::c_ClassName = "Sensor"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADSensor::Clear() { m_StartOffset.Reset(); @@ -13,9 +13,9 @@ namespace RTE { m_Skip = 3; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ADSensor::Create(const ADSensor &reference) { + int ADSensor::Create(const ADSensor& reference) { m_StartOffset = reference.m_StartOffset; m_SensorRay = reference.m_SensorRay; m_Skip = reference.m_Skip; @@ -23,11 +23,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ADSensor::ReadProperty(const std::string_view &propName, Reader &reader) { + int ADSensor::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("StartOffset", { reader >> m_StartOffset; }); MatchProperty("SensorRay", { reader >> m_SensorRay; }); MatchProperty("SkipPixels", { reader >> m_Skip; }); @@ -35,9 +35,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ADSensor::Save(Writer &writer) const { + int ADSensor::Save(Writer& writer) const { Serializable::Save(writer); writer.NewProperty("StartOffset"); @@ -50,22 +50,24 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Actor * ADSensor::SenseActor(const Vector &doorPos, const Matrix &doorRot, bool doorHFlipped, MOID ignoreMOID) { - Actor *sensedActor = 0; + Actor* ADSensor::SenseActor(const Vector& doorPos, const Matrix& doorRot, bool doorHFlipped, MOID ignoreMOID) { + Actor* sensedActor = 0; MOID foundMOID = g_SceneMan.CastMORay(doorPos + m_StartOffset.GetXFlipped(doorHFlipped) * doorRot, m_SensorRay.GetXFlipped(doorHFlipped) * doorRot, ignoreMOID, Activity::NoTeam, 0, true, m_Skip); if (foundMOID) { - sensedActor = dynamic_cast(g_MovableMan.GetMOFromID(g_MovableMan.GetRootMOID(foundMOID))); + sensedActor = dynamic_cast(g_MovableMan.GetMOFromID(g_MovableMan.GetRootMOID(foundMOID))); // Reverse the ray direction if the sensed actor was not valid, to see if we hit anything else relevant. if (!sensedActor || !sensedActor->IsControllable()) { foundMOID = g_SceneMan.CastMORay(doorPos + (m_StartOffset.GetXFlipped(doorHFlipped) + m_SensorRay.GetXFlipped(doorHFlipped)) * doorRot, (-m_SensorRay.GetXFlipped(doorHFlipped)) * doorRot, ignoreMOID, Activity::NoTeam, 0, true, m_Skip); - if (foundMOID) { sensedActor = dynamic_cast(g_MovableMan.GetMOFromID(g_MovableMan.GetRootMOID(foundMOID))); } + if (foundMOID) { + sensedActor = dynamic_cast(g_MovableMan.GetMOFromID(g_MovableMan.GetRootMOID(foundMOID))); + } } } return sensedActor; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/ADSensor.h b/Source/Entities/ADSensor.h index c6ce4a690..579592081 100644 --- a/Source/Entities/ADSensor.h +++ b/Source/Entities/ADSensor.h @@ -14,7 +14,6 @@ namespace RTE { class ADSensor : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -35,7 +34,7 @@ namespace RTE { /// /// A reference to the ADSensor to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const ADSensor &reference); + int Create(const ADSensor& reference); #pragma endregion #pragma region Destruction @@ -62,7 +61,7 @@ namespace RTE { /// Sets the starting position offset of this ADSensor from the owning ADoor position. /// /// The new starting coordinates relative to the m_Pos of this' ADoor. - void SetStartOffset(const Vector &startOffsetValue) { m_StartOffset = startOffsetValue; } + void SetStartOffset(const Vector& startOffsetValue) { m_StartOffset = startOffsetValue; } /// /// Gets the sensor ray vector out from the start offset's position. @@ -74,7 +73,7 @@ namespace RTE { /// Sets the sensor ray vector out from the start offset's position. /// /// The new sensor ray vector. - void SetSensorRay(const Vector &sensorRayValue) { m_SensorRay = sensorRayValue; } + void SetSensorRay(const Vector& sensorRayValue) { m_SensorRay = sensorRayValue; } #pragma endregion #pragma region Concrete Methods @@ -86,18 +85,16 @@ namespace RTE { /// Flipping of this ADSensor's ADoor. /// Which MOID to ignore, if any. /// The root Actor of the first MOID hit by the sensor ray. 0 if none. - Actor * SenseActor(const Vector &doorPos, const Matrix &doorRot, bool doorHFlipped = false, MOID ignoreMOID = g_NoMOID); + Actor* SenseActor(const Vector& doorPos, const Matrix& doorRot, bool doorHFlipped = false, MOID ignoreMOID = g_NoMOID); #pragma endregion protected: - Vector m_StartOffset; //!< The offset of the sensor ray start relative to the position of its ADoor. Vector m_SensorRay; //!< The ray out from the offset. - + short m_Skip; //!< How many pixels to skip between sensing pixels. private: - static const std::string c_ClassName; //!< A string with the friendly formatted type name of this object. /// @@ -105,5 +102,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/ADoor.cpp b/Source/Entities/ADoor.cpp index b2907ae84..beb9d20b7 100644 --- a/Source/Entities/ADoor.cpp +++ b/Source/Entities/ADoor.cpp @@ -12,7 +12,7 @@ namespace RTE { ConcreteClassInfo(ADoor, Actor, 20); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::Clear() { m_InitialSpriteAnimDuration = 0; @@ -53,18 +53,22 @@ namespace RTE { m_CanBeSquished = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ADoor::Create(const ADoor &reference) { - if (reference.m_Door) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_Door->GetUniqueID()); } + int ADoor::Create(const ADoor& reference) { + if (reference.m_Door) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_Door->GetUniqueID()); + } Actor::Create(reference); - if (reference.m_Door) { SetDoor(dynamic_cast(reference.m_Door->Clone())); } + if (reference.m_Door) { + SetDoor(dynamic_cast(reference.m_Door->Clone())); + } m_InitialSpriteAnimDuration = reference.m_SpriteAnimDuration; - for (const ADSensor &sensor : reference.m_Sensors) { + for (const ADSensor& sensor: reference.m_Sensors) { m_Sensors.push_back(sensor); } m_SensorInterval = reference.m_SensorInterval; @@ -81,20 +85,28 @@ namespace RTE { m_DrawMaterialLayerWhenClosed = reference.m_DrawMaterialLayerWhenClosed; m_DoorMaterialID = reference.m_DoorMaterialID; - if (reference.m_DoorMoveStartSound) { m_DoorMoveStartSound.reset(dynamic_cast(reference.m_DoorMoveStartSound->Clone())); } - if (reference.m_DoorMoveSound) { m_DoorMoveSound.reset(dynamic_cast(reference.m_DoorMoveSound->Clone())); } - if (reference.m_DoorDirectionChangeSound) { m_DoorDirectionChangeSound.reset(dynamic_cast(reference.m_DoorDirectionChangeSound->Clone())); } - if (reference.m_DoorMoveEndSound) { m_DoorMoveEndSound.reset(dynamic_cast(reference.m_DoorMoveEndSound->Clone())); } + if (reference.m_DoorMoveStartSound) { + m_DoorMoveStartSound.reset(dynamic_cast(reference.m_DoorMoveStartSound->Clone())); + } + if (reference.m_DoorMoveSound) { + m_DoorMoveSound.reset(dynamic_cast(reference.m_DoorMoveSound->Clone())); + } + if (reference.m_DoorDirectionChangeSound) { + m_DoorDirectionChangeSound.reset(dynamic_cast(reference.m_DoorDirectionChangeSound->Clone())); + } + if (reference.m_DoorMoveEndSound) { + m_DoorMoveEndSound.reset(dynamic_cast(reference.m_DoorMoveEndSound->Clone())); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ADoor::ReadProperty(const std::string_view &propName, Reader &reader) { + int ADoor::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Actor::ReadProperty(propName, reader)); - - MatchProperty("Door", { SetDoor(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + + MatchProperty("Door", { SetDoor(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); MatchProperty("OpenOffset", { reader >> m_OpenOffset; }); MatchProperty("ClosedOffset", { reader >> m_ClosedOffset; }); MatchProperty("OpenClosedOffset", { @@ -105,13 +117,17 @@ namespace RTE { Matrix rotation; reader >> rotation; m_OpenAngle = rotation.GetRadAngle(); - if (m_OpenAngle < 0) { reader.ReportError("Door OpenAngle cannot be less than 0."); } + if (m_OpenAngle < 0) { + reader.ReportError("Door OpenAngle cannot be less than 0."); + } }); MatchProperty("ClosedAngle", { Matrix rotation; reader >> rotation; m_ClosedAngle = rotation.GetRadAngle(); - if (m_ClosedAngle < 0) { reader.ReportError("Door ClosedAngle cannot be less than 0."); } + if (m_ClosedAngle < 0) { + reader.ReportError("Door ClosedAngle cannot be less than 0."); + } }); MatchProperty("OpenClosedAngle", { Matrix rotation; @@ -130,18 +146,17 @@ namespace RTE { }); MatchProperty("DrawMaterialLayerWhenOpen", { reader >> m_DrawMaterialLayerWhenOpen; }); MatchProperty("DrawMaterialLayerWhenClosed", { reader >> m_DrawMaterialLayerWhenClosed; }); - MatchProperty("DoorMoveStartSound", { m_DoorMoveStartSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("DoorMoveSound", { m_DoorMoveSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("DoorDirectionChangeSound", { m_DoorDirectionChangeSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("DoorMoveEndSound", { m_DoorMoveEndSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - - + MatchProperty("DoorMoveStartSound", { m_DoorMoveStartSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("DoorMoveSound", { m_DoorMoveSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("DoorDirectionChangeSound", { m_DoorDirectionChangeSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("DoorMoveEndSound", { m_DoorMoveEndSound.reset(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ADoor::Save(Writer &writer) const { + int ADoor::Save(Writer& writer) const { Actor::Save(writer); writer.NewProperty("Door"); @@ -162,7 +177,7 @@ namespace RTE { writer << m_ResetToDefaultStateDelay; writer.NewProperty("SensorInterval"); writer << m_SensorInterval; - for (const ADSensor &sensor : m_Sensors) { + for (const ADSensor& sensor: m_Sensors) { writer.NewProperty("AddSensor"); writer << sensor; } @@ -182,16 +197,26 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::Destroy(bool notInherited) { - if (m_DoorMoveStartSound) { m_DoorMoveStartSound->Stop(); } - if (m_DoorMoveSound) { m_DoorMoveSound->Stop(); } - if (m_DoorDirectionChangeSound) { m_DoorDirectionChangeSound->Stop(); } - if (m_DoorMoveEndSound) { m_DoorMoveEndSound->Stop(); } - if (!notInherited) { Actor::Destroy(); } + if (m_DoorMoveStartSound) { + m_DoorMoveStartSound->Stop(); + } + if (m_DoorMoveSound) { + m_DoorMoveSound->Stop(); + } + if (m_DoorDirectionChangeSound) { + m_DoorDirectionChangeSound->Stop(); + } + if (m_DoorMoveEndSound) { + m_DoorMoveEndSound->Stop(); + } + if (!notInherited) { + Actor::Destroy(); + } - for (ADSensor &sensor : m_Sensors) { + for (ADSensor& sensor: m_Sensors) { sensor.Destroy(); } if (m_DoorMaterialDrawn) { @@ -200,40 +225,40 @@ namespace RTE { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ADoor::SetDoor(Attachable *newDoor) { + void ADoor::SetDoor(Attachable* newDoor) { if (m_DoorMaterialDrawn) { RTEAssert(m_Door, "Door material drawn without an m_Door! This should've been cleared when the door was!"); - EraseDoorMaterial(); + EraseDoorMaterial(); } - if (m_Door && m_Door->IsAttached()) { - RemoveAndDeleteAttachable(m_Door); + if (m_Door && m_Door->IsAttached()) { + RemoveAndDeleteAttachable(m_Door); } m_Door = newDoor; if (m_Door) { AddAttachable(m_Door); - m_HardcodedAttachableUniqueIDsAndSetters.insert({m_Door->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - dynamic_cast(parent)->SetDoor(attachable); - }}); + m_HardcodedAttachableUniqueIDsAndSetters.insert({m_Door->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + dynamic_cast(parent)->SetDoor(attachable); + }}); m_Door->SetInheritsRotAngle(false); m_DoorMaterialID = m_Door->GetMaterial()->GetIndex(); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::DrawDoorMaterial(bool disallowErasingMaterialBeforeDrawing, bool updateMaterialArea) { if (!m_Door || m_DoorMaterialTempErased || !g_SceneMan.GetTerrain() || !g_SceneMan.GetTerrain()->GetMaterialBitmap()) { return; } - if (!disallowErasingMaterialBeforeDrawing && m_DoorMaterialDrawn) { - EraseDoorMaterial(updateMaterialArea); + if (!disallowErasingMaterialBeforeDrawing && m_DoorMaterialDrawn) { + EraseDoorMaterial(updateMaterialArea); } m_Door->Draw(g_SceneMan.GetTerrain()->GetMaterialBitmap(), Vector(), g_DrawDoor, true); @@ -245,7 +270,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ADoor::EraseDoorMaterial(bool updateMaterialArea) { if (!g_SceneMan.GetTerrain() || !g_SceneMan.GetTerrain()->GetMaterialBitmap()) { @@ -261,8 +286,8 @@ namespace RTE { if (g_SceneMan.GetTerrMatter(fillX, fillY) != g_MaterialAir) { floodfill(g_SceneMan.GetTerrain()->GetMaterialBitmap(), fillX, fillY, g_MaterialAir); - if (m_Door && updateMaterialArea) { - g_SceneMan.GetTerrain()->AddUpdatedMaterialArea(m_Door->GetBoundingBox()); + if (m_Door && updateMaterialArea) { + g_SceneMan.GetTerrain()->AddUpdatedMaterialArea(m_Door->GetBoundingBox()); } return true; @@ -270,7 +295,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::TempEraseOrRedrawDoorMaterial(bool erase) { if (!g_SceneMan.GetTerrain() || !g_SceneMan.GetTerrain()->GetMaterialBitmap()) { @@ -289,9 +314,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ADoor::GibThis(const Vector &impactImpulse, MovableObject *movableObjectToIgnore) { + void ADoor::GibThis(const Vector& impactImpulse, MovableObject* movableObjectToIgnore) { if (m_Door && m_Door->IsAttached()) { EraseDoorMaterial(); m_Door->DeepCheck(true); @@ -300,7 +325,7 @@ namespace RTE { Actor::GibThis(impactImpulse, movableObjectToIgnore); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::CorrectAttachableAndWoundPositionsAndRotations() const { if (m_Door) { @@ -310,7 +335,7 @@ namespace RTE { MOSRotating::CorrectAttachableAndWoundPositionsAndRotations(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::OpenDoor() { if (m_DoorState == STOPPED) { @@ -325,7 +350,7 @@ namespace RTE { m_ResetToDefaultStateTimer.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::CloseDoor() { if (m_DoorState == STOPPED) { @@ -340,59 +365,79 @@ namespace RTE { m_ResetToDefaultStateTimer.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::StopDoor() { if (m_DoorState == OPENING || m_DoorState == CLOSING) { - if (m_DrawMaterialLayerWhenOpen || m_DrawMaterialLayerWhenClosed) { DrawDoorMaterial(true); } + if (m_DrawMaterialLayerWhenOpen || m_DrawMaterialLayerWhenClosed) { + DrawDoorMaterial(true); + } m_DoorMoveStopTime = m_DoorMoveTime - m_DoorMoveTimer.GetElapsedSimTimeMS(); m_DoorStateOnStop = m_DoorState; - if (m_DoorMoveSound) { m_DoorMoveSound->Stop(); } - if (m_DoorMoveEndSound) { m_DoorMoveEndSound->Play(m_Pos); } + if (m_DoorMoveSound) { + m_DoorMoveSound->Stop(); + } + if (m_DoorMoveEndSound) { + m_DoorMoveEndSound->Play(m_Pos); + } m_DoorState = STOPPED; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::SharedDoorControls() { if (m_DoorState == OPEN || m_DoorState == CLOSED) { - if (m_DoorMoveStartSound) { m_DoorMoveStartSound->Play(m_Pos); } + if (m_DoorMoveStartSound) { + m_DoorMoveStartSound->Play(m_Pos); + } m_DoorMoveTimer.Reset(); - if (m_DoorMaterialDrawn) { EraseDoorMaterial(); } - if (m_Door) { m_Door->DeepCheck(true); } + if (m_DoorMaterialDrawn) { + EraseDoorMaterial(); + } + if (m_Door) { + m_Door->DeepCheck(true); + } } else if (m_DoorState == OPENING || m_DoorState == CLOSING) { - if (m_DoorMoveSound) { m_DoorMoveSound->Stop(); } + if (m_DoorMoveSound) { + m_DoorMoveSound->Stop(); + } if (!m_ResumeAfterStop) { - if (m_DoorDirectionChangeSound) { m_DoorDirectionChangeSound->Play(m_Pos); } + if (m_DoorDirectionChangeSound) { + m_DoorDirectionChangeSound->Play(m_Pos); + } m_DoorMoveTimer.SetElapsedSimTimeMS(m_DoorMoveTime - m_DoorMoveTimer.GetElapsedSimTimeMS()); } else { - if (m_DoorMoveStartSound) { m_DoorMoveStartSound->Play(m_Pos); } + if (m_DoorMoveStartSound) { + m_DoorMoveStartSound->Play(m_Pos); + } m_DoorMoveTimer.SetElapsedSimTimeMS(m_ChangedDirectionAfterStop ? m_DoorMoveTime - m_DoorMoveStopTime : m_DoorMoveStopTime); m_ChangedDirectionAfterStop = false; m_ResumeAfterStop = false; } } else if (m_DoorState == STOPPED) { - if (m_DoorMaterialDrawn) { EraseDoorMaterial(); } + if (m_DoorMaterialDrawn) { + EraseDoorMaterial(); + } m_ResumeAfterStop = true; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::Update() { ZoneScoped; if (m_Door) { - if (m_DoorState != STOPPED && m_Status != Actor::Status::INACTIVE && m_SensorTimer.IsPastSimMS(m_SensorInterval)) { - UpdateSensors(); + if (m_DoorState != STOPPED && m_Status != Actor::Status::INACTIVE && m_SensorTimer.IsPastSimMS(m_SensorInterval)) { + UpdateSensors(); } UpdateDoorAttachableActions(); bool shouldDrawDoorMaterial = ((m_DrawMaterialLayerWhenOpen && m_DoorState == OPEN) || - (m_DrawMaterialLayerWhenClosed && m_DoorState == CLOSED) || - ((m_DrawMaterialLayerWhenOpen || m_DrawMaterialLayerWhenClosed) && m_DoorState == STOPPED)) && - m_DoorMaterialRedrawTimer.IsPastSimTimeLimit(); + (m_DrawMaterialLayerWhenClosed && m_DoorState == CLOSED) || + ((m_DrawMaterialLayerWhenOpen || m_DrawMaterialLayerWhenClosed) && m_DoorState == STOPPED)) && + m_DoorMaterialRedrawTimer.IsPastSimTimeLimit(); if (shouldDrawDoorMaterial) { DrawDoorMaterial(true); m_DoorMaterialRedrawTimer.Reset(); @@ -402,8 +447,8 @@ namespace RTE { Actor::Update(); // Start the spinning out of control animation for the motor, start it slow - if (!m_Door) { - m_SpriteAnimDuration *= 4; + if (!m_Door) { + m_SpriteAnimDuration *= 4; } if (m_SpriteAnimMode == LOOPWHENOPENCLOSE && m_FrameCount > 1 && (m_DoorState == OPENING || m_DoorState == CLOSING) && m_SpriteAnimTimer.IsPastSimMS(m_SpriteAnimDuration)) { @@ -417,25 +462,27 @@ namespace RTE { m_SpriteAnimDuration = static_cast(LERP(0, m_MaxHealth, 10.0F, static_cast(m_InitialSpriteAnimDuration), m_Health)); if (m_DoorMoveSound) { - if (!m_DoorMoveSound->IsBeingPlayed()) { m_DoorMoveSound->Play(m_Pos); } + if (!m_DoorMoveSound->IsBeingPlayed()) { + m_DoorMoveSound->Play(m_Pos); + } m_DoorMoveSound->SetPitch(LERP(10.0F, static_cast(m_InitialSpriteAnimDuration), 2.0F, 1.0F, static_cast(m_SpriteAnimDuration))); } m_Health -= 0.4F; } - if (m_Status == DEAD) { - GibThis(); + if (m_Status == DEAD) { + GibThis(); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ADoor::UpdateSensors() { - const Actor *foundActor = nullptr; + void ADoor::UpdateSensors() { + const Actor* foundActor = nullptr; bool anySensorInput = false; - for (ADSensor &sensor : m_Sensors) { + for (ADSensor& sensor: m_Sensors) { foundActor = sensor.SenseActor(m_Pos, m_Rotation, m_HFlipped, m_MOID); if (foundActor && foundActor->IsControllable()) { anySensorInput = true; @@ -443,11 +490,11 @@ namespace RTE { if (m_Team == Activity::NoTeam) { OpenDoor(); break; - // If a sensor has found an enemy Actor, close the door and stop looking, so we don't accidentally open it for a friendly Actor. + // If a sensor has found an enemy Actor, close the door and stop looking, so we don't accidentally open it for a friendly Actor. } else if (foundActor->GetTeam() != m_Team) { CloseDoor(); break; - } else if (foundActor->GetTeam() == m_Team) { + } else if (foundActor->GetTeam() == m_Team) { OpenDoor(); } } @@ -462,7 +509,7 @@ namespace RTE { m_SensorTimer.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ADoor::UpdateDoorAttachableActions() { Vector startOffset; @@ -486,7 +533,9 @@ namespace RTE { m_Door->SetParentOffset(endOffset); m_Door->SetRotAngle(m_Rotation.GetRadAngle() + (endAngle * GetFlipFactor())); } else if (m_DoorState == OPENING || m_DoorState == CLOSING) { - if (m_DoorMoveSound && !m_DoorMoveSound->IsBeingPlayed()) { m_DoorMoveSound->Play(m_Pos); } + if (m_DoorMoveSound && !m_DoorMoveSound->IsBeingPlayed()) { + m_DoorMoveSound->Play(m_Pos); + } if (m_DoorMoveTimer.IsPastSimMS(m_DoorMoveTime)) { m_ResetToDefaultStateTimer.Reset(); @@ -494,23 +543,27 @@ namespace RTE { m_Door->SetParentOffset(endOffset); m_Door->SetRotAngle(m_Rotation.GetRadAngle() + (endAngle * GetFlipFactor())); - if (m_DoorMoveSound) { m_DoorMoveSound->Stop(); } - if (m_DoorMoveEndSound) { m_DoorMoveEndSound->Play(m_Pos); } + if (m_DoorMoveSound) { + m_DoorMoveSound->Stop(); + } + if (m_DoorMoveEndSound) { + m_DoorMoveEndSound->Play(m_Pos); + } if (m_DoorState == OPENING) { - if (m_DrawMaterialLayerWhenOpen) { - DrawDoorMaterial(); + if (m_DrawMaterialLayerWhenOpen) { + DrawDoorMaterial(); } m_DoorState = OPEN; } else if (m_DoorState == CLOSING) { - if (m_DrawMaterialLayerWhenClosed) { - DrawDoorMaterial(); + if (m_DrawMaterialLayerWhenClosed) { + DrawDoorMaterial(); } m_DoorState = CLOSED; } } else { Vector updatedOffset(LERP(0, m_DoorMoveTime, startOffset.m_X, endOffset.m_X, m_DoorMoveTimer.GetElapsedSimTimeMS()), LERP(0, m_DoorMoveTime, startOffset.m_Y, endOffset.m_Y, m_DoorMoveTimer.GetElapsedSimTimeMS())); - + // TODO: Make this work across rotation 0. Probably the best solution would be to setup an angle LERP that properly handles the 2PI border and +- angles. // TODO_MULTITHREAD: multithread branch has lerped rotation, so once that's done! float updatedAngle = LERP(0, m_DoorMoveTime, startAngle, endAngle, m_DoorMoveTimer.GetElapsedSimTimeMS()); @@ -519,16 +572,16 @@ namespace RTE { m_Door->SetRotAngle(m_Rotation.GetRadAngle() + (updatedAngle * GetFlipFactor())); // Clear away any terrain debris when the door is moving but only after a short delay so it doesn't take a chunk out of the ground. - if (m_DoorMoveTimer.IsPastSimMS(50)) { - m_Door->DeepCheck(true); + if (m_DoorMoveTimer.IsPastSimMS(50)) { + m_Door->DeepCheck(true); } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ADoor::DrawHUD(BITMAP *targetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) { + void ADoor::DrawHUD(BITMAP* targetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { m_HUDStack = -static_cast(m_CharHeight) / 2; if (!m_HUDVisible) { @@ -540,4 +593,4 @@ namespace RTE { return; } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/ADoor.h b/Source/Entities/ADoor.h index d7db3766a..3fc5fac83 100644 --- a/Source/Entities/ADoor.h +++ b/Source/Entities/ADoor.h @@ -14,7 +14,6 @@ namespace RTE { class ADoor : public Actor { public: - EntityAllocation(ADoor); SerializableOverrideMethods; ClassInfoGetters; @@ -45,7 +44,7 @@ namespace RTE { /// /// A reference to the ADoor to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const ADoor &reference); + int Create(const ADoor& reference); #pragma endregion #pragma region Destruction @@ -63,7 +62,10 @@ namespace RTE { /// /// Resets the entire ADoor, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Actor::Reset(); } + void Reset() override { + Clear(); + Actor::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -71,13 +73,13 @@ namespace RTE { /// Gets the moving door Attachable of this ADoor /// /// A pointer to the door Attachable of this. Ownership is NOT transferred! - Attachable * GetDoor() const { return m_Door; } + Attachable* GetDoor() const { return m_Door; } /// /// Sets the moving door Attachable for this ADoor. /// /// The new moving door attachable to use. - void SetDoor(Attachable *newDoor); + void SetDoor(Attachable* newDoor); /// /// Gets the current state of the door. @@ -107,49 +109,49 @@ namespace RTE { /// Gets this ADoor's door move start sound. Ownership is NOT transferred! /// /// The SoundContainer for this ADoor's door move start sound. - SoundContainer * GetDoorMoveStartSound() const { return m_DoorMoveStartSound.get(); } + SoundContainer* GetDoorMoveStartSound() const { return m_DoorMoveStartSound.get(); } /// /// Sets this ADoor's door move start sound. Ownership IS transferred! /// /// The new SoundContainer for this ADoor's door move start sound. - void SetDoorMoveStartSound(SoundContainer *newSound) { m_DoorMoveStartSound.reset(newSound); } + void SetDoorMoveStartSound(SoundContainer* newSound) { m_DoorMoveStartSound.reset(newSound); } /// /// Gets this ADoor's door move sound. Ownership is NOT transferred! /// /// The SoundContainer for this ADoor's door move sound. - SoundContainer * GetDoorMoveSound() const { return m_DoorMoveSound.get(); } + SoundContainer* GetDoorMoveSound() const { return m_DoorMoveSound.get(); } /// /// Sets this ADoor's door move sound. Ownership IS transferred! /// /// The new SoundContainer for this ADoor's door move sound. - void SetDoorMoveSound(SoundContainer *newSound) { m_DoorMoveSound.reset(newSound); } + void SetDoorMoveSound(SoundContainer* newSound) { m_DoorMoveSound.reset(newSound); } /// /// Gets this ADoor's door direction change sound. Ownership is NOT transferred! /// /// The SoundContainer for this ADoor's door direction change sound. - SoundContainer * GetDoorDirectionChangeSound() const { return m_DoorDirectionChangeSound.get(); } + SoundContainer* GetDoorDirectionChangeSound() const { return m_DoorDirectionChangeSound.get(); } /// /// Sets this ADoor's door direction change sound. Ownership IS transferred! /// /// The new SoundContainer for this ADoor's door direction change sound. - void SetDoorDirectionChangeSound(SoundContainer *newSound) { m_DoorDirectionChangeSound.reset(newSound); } + void SetDoorDirectionChangeSound(SoundContainer* newSound) { m_DoorDirectionChangeSound.reset(newSound); } /// /// Gets this ADoor's door move end sound. Ownership is NOT transferred! /// /// The SoundContainer for this ADoor's door move end sound. - SoundContainer * GetDoorMoveEndSound() const { return m_DoorMoveEndSound.get(); } + SoundContainer* GetDoorMoveEndSound() const { return m_DoorMoveEndSound.get(); } /// /// Sets this ADoor's door move end sound. Ownership IS transferred! /// /// The new SoundContainer for this ADoor's door move end sound. - void SetDoorMoveEndSound(SoundContainer *newSound) { m_DoorMoveEndSound.reset(newSound); } + void SetDoorMoveEndSound(SoundContainer* newSound) { m_DoorMoveEndSound.reset(newSound); } #pragma endregion #pragma region Concrete Methods @@ -187,7 +189,7 @@ namespace RTE { /// /// The impulse (kg * m/s) of the impact causing the gibbing to happen. /// A pointer to an MO which the Gibs and Attachables should not be colliding with. - void GibThis(const Vector &impactImpulse = Vector(), MovableObject *movableObjectToIgnore = nullptr) override; + void GibThis(const Vector& impactImpulse = Vector(), MovableObject* movableObjectToIgnore = nullptr) override; /// /// Ensures all attachables and wounds are positioned and rotated correctly. Must be run when this ADoor is added to MovableMan to avoid issues with Attachables spawning in at (0, 0). @@ -206,11 +208,10 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// Which player's screen this is being drawn to. May affect what HUD elements get drawn etc. /// Whether or not this MovableObject is currently player controlled (not applicable for ADoor) - void DrawHUD(BITMAP *targetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + void DrawHUD(BITMAP* targetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. int m_InitialSpriteAnimDuration; //!< This stores the original SpriteAnimDuration value so we can drive the death spin-up animation using LERP. For internal use only. @@ -219,7 +220,7 @@ namespace RTE { Timer m_SensorTimer; //!< Times the exit interval. long m_SensorInterval; //!< The delay between each sensing pass in ms. - Attachable *m_Door; //!< Actual door module that moves. Owned by this. + Attachable* m_Door; //!< Actual door module that moves. Owned by this. DoorState m_DoorState; //!< Current door action state. DoorState m_DoorStateOnStop; //!< The state this door was in when it was stopped. For internal use only. @@ -238,7 +239,7 @@ namespace RTE { bool m_ResumeAfterStop; //!< Whether the door is starting movement after being forced stopped. For internal use only. bool m_ChangedDirectionAfterStop; //!< Whether the door changed directions while moving between states. For internal use only. double m_DoorMoveStopTime; //!< The elapsed time of m_DoorMoveTimer when the door was forced stopped. For internal use only. - + Timer m_ResetToDefaultStateTimer; //!< Timer for the resetting to the default state. int m_ResetToDefaultStateDelay; //!< How long the door stays in the non-default state before returning to the default state. @@ -253,11 +254,10 @@ namespace RTE { std::unique_ptr m_DoorMoveStartSound; //!< Sound played when the door starts moving from fully open/closed position towards the opposite end. std::unique_ptr m_DoorMoveSound; //!< Sound played while the door is moving between open/closed position. - std::unique_ptr m_DoorDirectionChangeSound; //!< Sound played when the door is interrupted while moving and changes directions. + std::unique_ptr m_DoorDirectionChangeSound; //!< Sound played when the door is interrupted while moving and changes directions. std::unique_ptr m_DoorMoveEndSound; //!< Sound played when the door stops moving and is at fully open/closed position. private: - #pragma region Update Breakdown /// /// Iterates through the sensor list looking for actors and acts accordingly. Resets to the default state if none are found and past the delay timer. This is called from Update(). @@ -296,8 +296,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - ADoor(const ADoor &reference) = delete; - ADoor & operator=(const ADoor &rhs) = delete; + ADoor(const ADoor& reference) = delete; + ADoor& operator=(const ADoor& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/AEJetpack.cpp b/Source/Entities/AEJetpack.cpp index 6a67efca1..d66fcf09c 100644 --- a/Source/Entities/AEJetpack.cpp +++ b/Source/Entities/AEJetpack.cpp @@ -5,58 +5,58 @@ namespace RTE { - ConcreteClassInfo(AEJetpack, AEmitter, 20); + ConcreteClassInfo(AEJetpack, AEmitter, 20); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AEJetpack::Clear() { m_JetpackType = JetpackType::Standard; m_JetTimeTotal = 0.0F; - m_JetTimeLeft = 0.0F; + m_JetTimeLeft = 0.0F; m_JetThrustBonusMultiplier = 1.0F; - m_JetReplenishRate = 1.0F; + m_JetReplenishRate = 1.0F; m_MinimumFuelRatio = 0.0F; - m_JetAngleRange = 0.25F; + m_JetAngleRange = 0.25F; m_CanAdjustAngleWhileFiring = true; m_AdjustsThrottleForWeight = true; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int AEJetpack::Create() { - if (Attachable::Create() < 0) { - return -1; - } + int AEJetpack::Create() { + if (Attachable::Create() < 0) { + return -1; + } - // Initalize the jump time left - m_JetTimeLeft = m_JetTimeTotal; + // Initalize the jump time left + m_JetTimeLeft = m_JetTimeTotal; EnableEmission(false); return 0; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int AEJetpack::Create(const AEJetpack &reference) { - AEmitter::Create(reference); + int AEJetpack::Create(const AEJetpack& reference) { + AEmitter::Create(reference); m_JetpackType = reference.m_JetpackType; - m_JetTimeTotal = reference.m_JetTimeTotal; - m_JetTimeLeft = reference.m_JetTimeLeft; - m_JetReplenishRate = reference.m_JetReplenishRate; + m_JetTimeTotal = reference.m_JetTimeTotal; + m_JetTimeLeft = reference.m_JetTimeLeft; + m_JetReplenishRate = reference.m_JetReplenishRate; m_MinimumFuelRatio = reference.m_MinimumFuelRatio; - m_JetAngleRange = reference.m_JetAngleRange; + m_JetAngleRange = reference.m_JetAngleRange; m_CanAdjustAngleWhileFiring = reference.m_CanAdjustAngleWhileFiring; m_AdjustsThrottleForWeight = reference.m_AdjustsThrottleForWeight; return 0; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int AEJetpack::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return AEmitter::ReadProperty(propName, reader)); - + MatchProperty("JetpackType", { std::string jetpackType; reader >> jetpackType; @@ -70,14 +70,14 @@ namespace RTE { } }); MatchForwards("JumpTime") MatchProperty("JetTime", { - reader >> m_JetTimeTotal; - m_JetTimeTotal *= 1000.0f; // Convert to ms - }); + reader >> m_JetTimeTotal; + m_JetTimeTotal *= 1000.0f; // Convert to ms + }); MatchForwards("JumpReplenishRate") MatchProperty("JetReplenishRate", { reader >> m_JetReplenishRate; }); MatchProperty("MinimumFuelRatio", { reader >> m_MinimumFuelRatio; m_MinimumFuelRatio = std::clamp(m_MinimumFuelRatio, 0.0F, 1.0F); - }); + }); MatchForwards("JumpAngleRange") MatchProperty("JetAngleRange", { reader >> m_JetAngleRange; }); MatchProperty("CanAdjustAngleWhileFiring", { reader >> m_CanAdjustAngleWhileFiring; }); MatchProperty("AdjustsThrottleForWeight", { reader >> m_AdjustsThrottleForWeight; }); @@ -85,20 +85,20 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int AEJetpack::Save(Writer& writer) const { AEmitter::Save(writer); writer.NewProperty("JetpackType"); switch (m_JetpackType) { - default: - case JetpackType::Standard: - writer << "Standard"; - break; - case JetpackType::JumpPack: - writer << "JumpPack"; - break; + default: + case JetpackType::Standard: + writer << "Standard"; + break; + case JetpackType::JumpPack: + writer << "JumpPack"; + break; } writer.NewPropertyWithValue("JumpTime", m_JetTimeTotal / 1000.0f); // Convert to seconds @@ -111,10 +111,10 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AEJetpack::UpdateBurstState(Actor &parentActor) { - const Controller &controller = *parentActor.GetController(); + void AEJetpack::UpdateBurstState(Actor& parentActor) { + const Controller& controller = *parentActor.GetController(); if (parentActor.GetStatus() == Actor::INACTIVE) { Recharge(parentActor); @@ -140,27 +140,26 @@ namespace RTE { // So enforce a minimum time we must be able to thrust for (in ms) const float minimumTimeToBeginThrusting = 250.0f * fuelUseMultiplier; if (m_JetTimeLeft > minimumTimeToBeginThrusting || wasEmittingLastFrame || IsFullyFueled()) { - switch (m_JetpackType) - { - case JetpackType::Standard: - if (controller.IsState(BODY_JUMPSTART) && !IsOutOfFuel()) { - Burst(parentActor, fuelUseMultiplier); - } else if (controller.IsState(BODY_JUMP) && !IsOutOfFuel() && (GetJetTimeRatio() >= m_MinimumFuelRatio || wasEmittingLastFrame)) { - Thrust(parentActor, fuelUseMultiplier); - } else { - Recharge(parentActor); - } - break; - - case JetpackType::JumpPack: - if (wasEmittingLastFrame && !IsOutOfFuel()) { - Thrust(parentActor, fuelUseMultiplier); - } else if (controller.IsState(BODY_JUMPSTART) && GetJetTimeRatio() >= m_MinimumFuelRatio) { - Burst(parentActor, fuelUseMultiplier); - } else { - Recharge(parentActor); - } - break; + switch (m_JetpackType) { + case JetpackType::Standard: + if (controller.IsState(BODY_JUMPSTART) && !IsOutOfFuel()) { + Burst(parentActor, fuelUseMultiplier); + } else if (controller.IsState(BODY_JUMP) && !IsOutOfFuel() && (GetJetTimeRatio() >= m_MinimumFuelRatio || wasEmittingLastFrame)) { + Thrust(parentActor, fuelUseMultiplier); + } else { + Recharge(parentActor); + } + break; + + case JetpackType::JumpPack: + if (wasEmittingLastFrame && !IsOutOfFuel()) { + Thrust(parentActor, fuelUseMultiplier); + } else if (controller.IsState(BODY_JUMPSTART) && GetJetTimeRatio() >= m_MinimumFuelRatio) { + Burst(parentActor, fuelUseMultiplier); + } else { + Recharge(parentActor); + } + break; } } else { Recharge(parentActor); @@ -173,7 +172,7 @@ namespace RTE { if (canAdjustAngle) { // Direct the jetpack nozzle according to either analog stick input or aim angle. float maxAngle = c_HalfPI * m_JetAngleRange; - const float analogDeadzone = 0.1F; + const float analogDeadzone = 0.1F; if (controller.GetAnalogMove().MagnitudeIsGreaterThan(analogDeadzone)) { float jetAngle = std::clamp(controller.GetAnalogMove().GetAbsRadAngle() - c_HalfPI, -maxAngle, maxAngle); SetEmitAngle(parentActor.FacingAngle(jetAngle - c_HalfPI)); @@ -181,20 +180,20 @@ namespace RTE { // Thrust in the opposite direction when strafing. float flip = ((parentActor.IsHFlipped() && controller.IsState(MOVE_RIGHT)) || (!parentActor.IsHFlipped() && controller.IsState(MOVE_LEFT))) ? -1.0F : 1.0F; // Halve the jet angle when looking downwards so the actor isn't forced to go sideways - // TODO: don't hardcode this ratio? - float aimAngle = parentActor.GetAimAngle(false); + // TODO: don't hardcode this ratio? + float aimAngle = parentActor.GetAimAngle(false); float jetAngle = (aimAngle > 0 ? aimAngle * m_JetAngleRange : -aimAngle * m_JetAngleRange * 0.5F) - maxAngle; // FacingAngle isn't needed because it's already been applied to AimAngle since last update. SetEmitAngle(jetAngle * flip - c_HalfPI); } } - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AEJetpack::Burst(Actor& parentActor, float fuelUseMultiplier) { parentActor.SetMovementState(Actor::JUMP); - + // TODO - find a better solution! This stops the actor getting stuck, but it's awful... parentActor.ForceDeepCheck(); @@ -207,7 +206,7 @@ namespace RTE { m_JetTimeLeft -= fuelUsage; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AEJetpack::Thrust(Actor& parentActor, float fuelUseMultiplier) { parentActor.SetMovementState(Actor::JUMP); @@ -219,7 +218,7 @@ namespace RTE { m_JetTimeLeft -= fuelUsage; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AEJetpack::Recharge(Actor& parentActor) { EnableEmission(false); @@ -229,4 +228,4 @@ namespace RTE { m_JetTimeLeft += g_TimerMan.GetDeltaTimeMS() * m_JetReplenishRate; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/AEJetpack.h b/Source/Entities/AEJetpack.h index 0db1c0791..305b4191f 100644 --- a/Source/Entities/AEJetpack.h +++ b/Source/Entities/AEJetpack.h @@ -3,221 +3,222 @@ #include "AEmitter.h" -namespace RTE -{ - - /// - /// A jetpack MO, which can be used to generate thrust - /// - class AEJetpack : public AEmitter { - friend struct EntityLuaBindings; - - public: - - // Concrete allocation and cloning definitions - EntityAllocation(AEJetpack); - SerializableOverrideMethods; - ClassInfoGetters; - - enum JetpackType { - Standard, // Can be intermittently tapped to produce small amounts of thrust - JumpPack // Spends all of it's fuel until empty, and cannot fire again until recharged - }; - - #pragma region Creation - /// - /// Constructor method used to instantiate a AEJetpack object in system memory. Create() should be called before using the object. - /// - AEJetpack() { Clear(); } - - /// - /// Makes the AEJetpack object ready for use. - /// - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create() override; - - /// - /// Creates a AEJetpack to be identical to another, by deep copy. - /// - /// A reference to the AEJetpack to deep copy. - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const AEJetpack &reference); - #pragma endregion - - #pragma region Destruction - /// - /// Destructor method used to clean up a AEJetpack object before deletion from system memory. - /// - ~AEJetpack() override { Destroy(true); } - - /// - /// Resets the entire AEJetpack, including its inherited members, to their default settings or values. - /// - void Reset() override { Clear(); AEmitter::Reset(); } - #pragma endregion +namespace RTE { + + /// + /// A jetpack MO, which can be used to generate thrust + /// + class AEJetpack : public AEmitter { + friend struct EntityLuaBindings; + + public: + // Concrete allocation and cloning definitions + EntityAllocation(AEJetpack); + SerializableOverrideMethods; + ClassInfoGetters; + + enum JetpackType { + Standard, // Can be intermittently tapped to produce small amounts of thrust + JumpPack // Spends all of it's fuel until empty, and cannot fire again until recharged + }; + +#pragma region Creation + /// + /// Constructor method used to instantiate a AEJetpack object in system memory. Create() should be called before using the object. + /// + AEJetpack() { Clear(); } + + /// + /// Makes the AEJetpack object ready for use. + /// + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + int Create() override; + + /// + /// Creates a AEJetpack to be identical to another, by deep copy. + /// + /// A reference to the AEJetpack to deep copy. + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + int Create(const AEJetpack& reference); +#pragma endregion + +#pragma region Destruction + /// + /// Destructor method used to clean up a AEJetpack object before deletion from system memory. + /// + ~AEJetpack() override { Destroy(true); } + + /// + /// Resets the entire AEJetpack, including its inherited members, to their default settings or values. + /// + void Reset() override { + Clear(); + AEmitter::Reset(); + } +#pragma endregion /// /// Updates this AEJetpack from our parent actor. /// - void UpdateBurstState(Actor &parentActor); - - /// - /// Returns whether or not this jetpack is fully fueled. - /// - /// Whether or not this jetpack is fully fueled. - bool IsFullyFueled() const { return m_JetTimeLeft >= m_JetTimeTotal - (m_JetTimeTotal * std::numeric_limits::epsilon()); } - - /// - /// Returns whether or not this jetpack is out of fuel. - /// - /// Whether or not this jetpack is out of fuel. - bool IsOutOfFuel() const { return m_JetTimeLeft <= std::numeric_limits::epsilon(); } - - /// - /// Gets the amount of time this jetpack can fire when filled, in ms. - /// - /// The amount of time this jetpack can fire when it's at max. - float GetJetTimeTotal() const { return m_JetTimeTotal; } - - /// - /// Sets the amount of time this' jetpack can fire when filled, in ms. - /// - /// The amount of time this jetpack can fire when it's at max. - void SetJetTimeTotal(float newValue) { m_JetTimeTotal = newValue; } - - /// - /// Gets the amount of time this jetpack can still fire until out, in ms. - /// - /// The amount of time this jetpack can still fire before running out. - float GetJetTimeLeft() const { return m_JetTimeLeft; } - - /// - /// Sets the amount of time this' jetpack can still fire until out, in ms. - /// - /// The amount of time this' jetpack can still fire before running out. - void SetJetTimeLeft(float newValue) { m_JetTimeLeft = newValue < m_JetTimeTotal ? newValue : m_JetTimeTotal; } - - /// - /// Gets the ratio of jetpack time that is left. - /// - /// The ratio of jetpack time that is left. - float GetJetTimeRatio() { return m_JetTimeLeft / m_JetTimeTotal; } - - /// - /// Gets the rate at which this AHuman's jetpack is replenished during downtime. - /// - /// The rate at which the jetpack is replenished. - float GetJetReplenishRate() const { return m_JetReplenishRate; } - - /// - /// Sets the rate at which this AHuman's jetpack is replenished during downtime. - /// - /// The rate at which the jetpack is replenished. - void SetJetReplenishRate(float newValue) { m_JetReplenishRate = newValue; } - - /// - /// Gets the rate at which this AHuman's jetpack is replenished during downtime. - /// - /// The rate at which the jetpack is replenished. - float GetMinimumFuelRatio() const { return m_MinimumFuelRatio; } - - /// - /// Sets the rate at which this AHuman's jetpack is replenished during downtime. - /// - /// The rate at which the jetpack is replenished. - void SetMinimumFuelRatio(float newValue) { m_MinimumFuelRatio = newValue; } - - /// - /// Gets the scalar ratio at which this jetpack's thrust angle follows the aim angle of the user. - /// - /// The ratio at which this jetpack follows the aim angle of the user. - float GetJetAngleRange() const { return m_JetAngleRange; } - - /// - /// Sets the scalar ratio at which this jetpack's thrust angle follows the aim angle of the user. - /// - /// The ratio at which this jetpack follows the aim angle of the user. - void SetJetAngleRange(float newValue) { m_JetAngleRange = newValue; } - - /// - /// Gets the type of this jetpack. - /// - /// The type of this jetpack. - JetpackType GetJetpackType() const { return m_JetpackType; } - - /// - /// Sets the type of this jetpack. - /// - /// The new type of this jetpack. - void SetJetpackType(JetpackType newType) { m_JetpackType = newType; } - - /// - /// Returns whether the angle of this jetpack can adjust while firing, or if it can only be aimed while off. - /// - /// Whether the angle of this jetpack can adjust while firing. - bool GetCanAdjustAngleWhileFiring() const { return m_CanAdjustAngleWhileFiring; } - - /// - /// Sets whether the angle of this can adjust while firing, or if it can only be aimed while off. - /// - /// The new value for whether the angle of this jetpack can adjust while firing. - void SetCanAdjustAngleWhileFiring(bool newValue) { m_CanAdjustAngleWhileFiring = newValue; } - - /// - /// Returns whether this jetpack adjusts it's throttle to balance for extra weight. - /// - /// Whether this jetpack adjusts it's throttle to balance for extra weight. - bool GetAdjustsThrottleForWeight() const { return m_AdjustsThrottleForWeight; } - - /// - /// Sets whether this jetpack adjusts it's throttle to balance for extra weight. - /// - /// The new value for whether this jetpack adjusts it's throttle to balance for extra weight. - void SetAdjustsThrottleForWeight(bool newValue) { m_AdjustsThrottleForWeight = newValue; } - - protected: - static Entity::ClassInfo m_sClass; - - JetpackType m_JetpackType; //!< The type of jetpack - float m_JetTimeTotal; //!< The max total time, in ms, that the jetpack can be used without pause - float m_JetTimeLeft; //!< How much time left the jetpack can go, in ms - float m_JetThrustBonusMultiplier; //!< A multiplier bonus to our produced thrust, which doesn't cost extra fuel. Used for AI buffs. - float m_JetReplenishRate; //!< A multiplier affecting how fast the jetpack fuel will replenish when not in use. 1 means that jet time replenishes at 2x speed in relation to depletion. - float m_MinimumFuelRatio; // Minimum ratio of current fuel to max fuel to be able to initiate the jetpack. - float m_JetAngleRange; //!< Ratio at which the jetpack angle follows aim angle - bool m_CanAdjustAngleWhileFiring; //!< Whether or not the angle of the thrust can change while firing, or if it can only be adjusted while the jetpack is off - bool m_AdjustsThrottleForWeight; //!< Whether or not the jetpack throttle auto-adjusts for weight, at the cost of fuel usage. - - private: - /// - /// The logic to run when bursting. - /// - /// The parent actor using this jetpack. - /// The multiplier to fuel usage rate. - void Burst(Actor& parentActor, float fuelUseMultiplier); - - /// - /// The logic to run when thrusting. - /// - /// The parent actor using this jetpack. - /// The multiplier to fuel usage rate. - void Thrust(Actor& parentActor, float fuelUseMultiplier); - - /// - /// The logic to run when recharging. - /// - /// The parent actor using this jetpack. - void Recharge(Actor& parentActor); - - /// + void UpdateBurstState(Actor& parentActor); + + /// + /// Returns whether or not this jetpack is fully fueled. + /// + /// Whether or not this jetpack is fully fueled. + bool IsFullyFueled() const { return m_JetTimeLeft >= m_JetTimeTotal - (m_JetTimeTotal * std::numeric_limits::epsilon()); } + + /// + /// Returns whether or not this jetpack is out of fuel. + /// + /// Whether or not this jetpack is out of fuel. + bool IsOutOfFuel() const { return m_JetTimeLeft <= std::numeric_limits::epsilon(); } + + /// + /// Gets the amount of time this jetpack can fire when filled, in ms. + /// + /// The amount of time this jetpack can fire when it's at max. + float GetJetTimeTotal() const { return m_JetTimeTotal; } + + /// + /// Sets the amount of time this' jetpack can fire when filled, in ms. + /// + /// The amount of time this jetpack can fire when it's at max. + void SetJetTimeTotal(float newValue) { m_JetTimeTotal = newValue; } + + /// + /// Gets the amount of time this jetpack can still fire until out, in ms. + /// + /// The amount of time this jetpack can still fire before running out. + float GetJetTimeLeft() const { return m_JetTimeLeft; } + + /// + /// Sets the amount of time this' jetpack can still fire until out, in ms. + /// + /// The amount of time this' jetpack can still fire before running out. + void SetJetTimeLeft(float newValue) { m_JetTimeLeft = newValue < m_JetTimeTotal ? newValue : m_JetTimeTotal; } + + /// + /// Gets the ratio of jetpack time that is left. + /// + /// The ratio of jetpack time that is left. + float GetJetTimeRatio() { return m_JetTimeLeft / m_JetTimeTotal; } + + /// + /// Gets the rate at which this AHuman's jetpack is replenished during downtime. + /// + /// The rate at which the jetpack is replenished. + float GetJetReplenishRate() const { return m_JetReplenishRate; } + + /// + /// Sets the rate at which this AHuman's jetpack is replenished during downtime. + /// + /// The rate at which the jetpack is replenished. + void SetJetReplenishRate(float newValue) { m_JetReplenishRate = newValue; } + + /// + /// Gets the rate at which this AHuman's jetpack is replenished during downtime. + /// + /// The rate at which the jetpack is replenished. + float GetMinimumFuelRatio() const { return m_MinimumFuelRatio; } + + /// + /// Sets the rate at which this AHuman's jetpack is replenished during downtime. + /// + /// The rate at which the jetpack is replenished. + void SetMinimumFuelRatio(float newValue) { m_MinimumFuelRatio = newValue; } + + /// + /// Gets the scalar ratio at which this jetpack's thrust angle follows the aim angle of the user. + /// + /// The ratio at which this jetpack follows the aim angle of the user. + float GetJetAngleRange() const { return m_JetAngleRange; } + + /// + /// Sets the scalar ratio at which this jetpack's thrust angle follows the aim angle of the user. + /// + /// The ratio at which this jetpack follows the aim angle of the user. + void SetJetAngleRange(float newValue) { m_JetAngleRange = newValue; } + + /// + /// Gets the type of this jetpack. + /// + /// The type of this jetpack. + JetpackType GetJetpackType() const { return m_JetpackType; } + + /// + /// Sets the type of this jetpack. + /// + /// The new type of this jetpack. + void SetJetpackType(JetpackType newType) { m_JetpackType = newType; } + + /// + /// Returns whether the angle of this jetpack can adjust while firing, or if it can only be aimed while off. + /// + /// Whether the angle of this jetpack can adjust while firing. + bool GetCanAdjustAngleWhileFiring() const { return m_CanAdjustAngleWhileFiring; } + + /// + /// Sets whether the angle of this can adjust while firing, or if it can only be aimed while off. + /// + /// The new value for whether the angle of this jetpack can adjust while firing. + void SetCanAdjustAngleWhileFiring(bool newValue) { m_CanAdjustAngleWhileFiring = newValue; } + + /// + /// Returns whether this jetpack adjusts it's throttle to balance for extra weight. + /// + /// Whether this jetpack adjusts it's throttle to balance for extra weight. + bool GetAdjustsThrottleForWeight() const { return m_AdjustsThrottleForWeight; } + + /// + /// Sets whether this jetpack adjusts it's throttle to balance for extra weight. + /// + /// The new value for whether this jetpack adjusts it's throttle to balance for extra weight. + void SetAdjustsThrottleForWeight(bool newValue) { m_AdjustsThrottleForWeight = newValue; } + + protected: + static Entity::ClassInfo m_sClass; + + JetpackType m_JetpackType; //!< The type of jetpack + float m_JetTimeTotal; //!< The max total time, in ms, that the jetpack can be used without pause + float m_JetTimeLeft; //!< How much time left the jetpack can go, in ms + float m_JetThrustBonusMultiplier; //!< A multiplier bonus to our produced thrust, which doesn't cost extra fuel. Used for AI buffs. + float m_JetReplenishRate; //!< A multiplier affecting how fast the jetpack fuel will replenish when not in use. 1 means that jet time replenishes at 2x speed in relation to depletion. + float m_MinimumFuelRatio; // Minimum ratio of current fuel to max fuel to be able to initiate the jetpack. + float m_JetAngleRange; //!< Ratio at which the jetpack angle follows aim angle + bool m_CanAdjustAngleWhileFiring; //!< Whether or not the angle of the thrust can change while firing, or if it can only be adjusted while the jetpack is off + bool m_AdjustsThrottleForWeight; //!< Whether or not the jetpack throttle auto-adjusts for weight, at the cost of fuel usage. + + private: + /// + /// The logic to run when bursting. + /// + /// The parent actor using this jetpack. + /// The multiplier to fuel usage rate. + void Burst(Actor& parentActor, float fuelUseMultiplier); + + /// + /// The logic to run when thrusting. + /// + /// The parent actor using this jetpack. + /// The multiplier to fuel usage rate. + void Thrust(Actor& parentActor, float fuelUseMultiplier); + + /// + /// The logic to run when recharging. + /// + /// The parent actor using this jetpack. + void Recharge(Actor& parentActor); + + /// /// Clears all the member variables of this AEJetpack, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - AEJetpack(const AEJetpack &reference) = delete; - AEJetpack & operator=(const AEJetpack &rhs) = delete; - }; -} + AEJetpack(const AEJetpack& reference) = delete; + AEJetpack& operator=(const AEJetpack& rhs) = delete; + }; +} // namespace RTE -#endif \ No newline at end of file +#endif diff --git a/Source/Entities/AEmitter.cpp b/Source/Entities/AEmitter.cpp index 4e93697d5..3b50228d3 100644 --- a/Source/Entities/AEmitter.cpp +++ b/Source/Entities/AEmitter.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -18,612 +17,621 @@ namespace RTE { -ConcreteClassInfo(AEmitter, Attachable, 100); + ConcreteClassInfo(AEmitter, Attachable, 100); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AEmitter, effectively + // resetting the members of this abstraction level only. + + void AEmitter::Clear() { + m_EmissionList.clear(); + m_EmissionSound = nullptr; + m_BurstSound = nullptr; + m_EndSound = nullptr; + m_EmitEnabled = false; + m_WasEmitting = false; + m_EmitCount = 0; + m_EmitCountLimit = 0; + m_NegativeThrottleMultiplier = 1.0F; + m_PositiveThrottleMultiplier = 1.0F; + m_Throttle = 0; + m_EmissionsIgnoreThis = false; + m_BurstScale = 1.0F; + m_BurstDamage = 0; + m_EmitterDamageMultiplier = 1.0F; + m_BurstTriggered = false; + m_BurstSpacing = 0; + // Set this to really long so an initial burst will be possible + m_BurstTimer.SetElapsedSimTimeS(50000); + m_BurstTimer.SetElapsedRealTimeS(50000); + m_EmitAngle.Reset(); + m_EmissionOffset.Reset(); + m_EmitDamage = 0; + m_LastEmitTmr.Reset(); + m_pFlash = 0; + m_FlashScale = 1.0F; + m_AvgBurstImpulse = -1.0F; + m_AvgImpulse = -1.0F; + m_FlashOnlyOnBurst = true; + m_SustainBurstSound = false; + m_BurstSoundFollowsEmitter = true; + m_LoudnessOnEmit = 1.0F; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AEmitter, effectively -// resetting the members of this abstraction level only. - -void AEmitter::Clear() -{ - m_EmissionList.clear(); - m_EmissionSound = nullptr; - m_BurstSound = nullptr; - m_EndSound = nullptr; - m_EmitEnabled = false; - m_WasEmitting = false; - m_EmitCount = 0; - m_EmitCountLimit = 0; - m_NegativeThrottleMultiplier = 1.0F; - m_PositiveThrottleMultiplier = 1.0F; - m_Throttle = 0; - m_EmissionsIgnoreThis = false; - m_BurstScale = 1.0F; - m_BurstDamage = 0; - m_EmitterDamageMultiplier = 1.0F; - m_BurstTriggered = false; - m_BurstSpacing = 0; - // Set this to really long so an initial burst will be possible - m_BurstTimer.SetElapsedSimTimeS(50000); - m_BurstTimer.SetElapsedRealTimeS(50000); - m_EmitAngle.Reset(); - m_EmissionOffset.Reset(); - m_EmitDamage = 0; - m_LastEmitTmr.Reset(); - m_pFlash = 0; - m_FlashScale = 1.0F; - m_AvgBurstImpulse = -1.0F; - m_AvgImpulse = -1.0F; - m_FlashOnlyOnBurst = true; - m_SustainBurstSound = false; - m_BurstSoundFollowsEmitter = true; - m_LoudnessOnEmit = 1.0F; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AEmitter to be identical to another, by deep copy. + int AEmitter::Create(const AEmitter& reference) { + if (reference.m_pFlash) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFlash->GetUniqueID()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AEmitter to be identical to another, by deep copy. + Attachable::Create(reference); -int AEmitter::Create(const AEmitter &reference) { - if (reference.m_pFlash) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFlash->GetUniqueID()); } + if (reference.m_pFlash) { + SetFlash(dynamic_cast(reference.m_pFlash->Clone())); + } - Attachable::Create(reference); + for (auto itr = reference.m_EmissionList.begin(); itr != reference.m_EmissionList.end(); ++itr) { + m_EmissionList.push_back(*itr); + } + if (reference.m_EmissionSound) { + m_EmissionSound = dynamic_cast(reference.m_EmissionSound->Clone()); + } + if (reference.m_BurstSound) { + m_BurstSound = dynamic_cast(reference.m_BurstSound->Clone()); + } + if (reference.m_EndSound) { + m_EndSound = dynamic_cast(reference.m_EndSound->Clone()); + } + m_EmitEnabled = reference.m_EmitEnabled; + m_EmitCount = reference.m_EmitCount; + m_EmitCountLimit = reference.m_EmitCountLimit; + m_NegativeThrottleMultiplier = reference.m_NegativeThrottleMultiplier; + m_PositiveThrottleMultiplier = reference.m_PositiveThrottleMultiplier; + m_Throttle = reference.m_Throttle; + m_EmissionsIgnoreThis = reference.m_EmissionsIgnoreThis; + m_BurstScale = reference.m_BurstScale; + m_BurstDamage = reference.m_BurstDamage; + m_EmitterDamageMultiplier = reference.m_EmitterDamageMultiplier; + m_BurstSpacing = reference.m_BurstSpacing; + m_BurstTriggered = reference.m_BurstTriggered; + m_EmitAngle = reference.m_EmitAngle; + m_EmissionOffset = reference.m_EmissionOffset; + m_EmitDamage = reference.m_EmitDamage; + m_FlashScale = reference.m_FlashScale; + m_FlashOnlyOnBurst = reference.m_FlashOnlyOnBurst; + m_SustainBurstSound = reference.m_SustainBurstSound; + m_BurstSoundFollowsEmitter = reference.m_BurstSoundFollowsEmitter; + m_LoudnessOnEmit = reference.m_LoudnessOnEmit; + + return 0; + } - if (reference.m_pFlash) { SetFlash(dynamic_cast(reference.m_pFlash->Clone())); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int AEmitter::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Attachable::ReadProperty(propName, reader)); + + MatchProperty("AddEmission", { + Emission emission; + reader >> emission; + m_EmissionList.push_back(emission); + }); + MatchProperty("EmissionSound", { + m_EmissionSound = new SoundContainer; + reader >> m_EmissionSound; + }); + MatchProperty("BurstSound", { + m_BurstSound = new SoundContainer; + reader >> m_BurstSound; + }); + MatchProperty("EndSound", { + m_EndSound = new SoundContainer; + reader >> m_EndSound; + }); + MatchProperty("EmissionEnabled", { reader >> m_EmitEnabled; }); + MatchProperty("EmissionCount", { reader >> m_EmitCount; }); + MatchProperty("EmissionCountLimit", { reader >> m_EmitCountLimit; }); + MatchProperty("ParticlesPerMinute", { + float ppm; + reader >> ppm; + // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility. + for (Emission& emission: m_EmissionList) { + emission.m_PPM = ppm / static_cast(m_EmissionList.size()); + } + }); + MatchProperty("NegativeThrottleMultiplier", { reader >> m_NegativeThrottleMultiplier; }); + MatchProperty("PositiveThrottleMultiplier", { reader >> m_PositiveThrottleMultiplier; }); + MatchProperty("Throttle", { reader >> m_Throttle; }); + MatchProperty("EmissionsIgnoreThis", { reader >> m_EmissionsIgnoreThis; }); + MatchProperty("BurstSize", { + int burstSize; + reader >> burstSize; + // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility. + for (Emission& emission: m_EmissionList) { + emission.m_BurstSize = std::ceil(static_cast(burstSize) / static_cast(m_EmissionList.size())); + } + }); + MatchProperty("BurstScale", { reader >> m_BurstScale; }); + MatchProperty("BurstDamage", { reader >> m_BurstDamage; }); + MatchProperty("EmitterDamageMultiplier", { reader >> m_EmitterDamageMultiplier; }); + MatchProperty("BurstSpacing", { reader >> m_BurstSpacing; }); + MatchProperty("BurstTriggered", { reader >> m_BurstTriggered; }); + MatchProperty("EmissionAngle", { reader >> m_EmitAngle; }); + MatchProperty("EmissionOffset", { reader >> m_EmissionOffset; }); + MatchProperty("EmissionDamage", { reader >> m_EmitDamage; }); + MatchProperty("Flash", { SetFlash(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("FlashScale", { reader >> m_FlashScale; }); + MatchProperty("FlashOnlyOnBurst", { reader >> m_FlashOnlyOnBurst; }); + MatchProperty("SustainBurstSound", { reader >> m_SustainBurstSound; }); + MatchProperty("BurstSoundFollowsEmitter", { reader >> m_BurstSoundFollowsEmitter; }); + MatchProperty("LoudnessOnEmit", { reader >> m_LoudnessOnEmit; }); + + EndPropertyList; + } - for (auto itr = reference.m_EmissionList.begin(); itr != reference.m_EmissionList.end(); ++itr) { - m_EmissionList.push_back(*itr); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this AEmitter with a Writer for + // later recreation with Create(Reader &reader); + + int AEmitter::Save(Writer& writer) const { + Attachable::Save(writer); + + for (auto itr = m_EmissionList.begin(); itr != m_EmissionList.end(); ++itr) { + writer.NewProperty("AddEmission"); + writer << *itr; + } + writer.NewProperty("EmissionSound"); + writer << m_EmissionSound; + writer.NewProperty("BurstSound"); + writer << m_BurstSound; + writer.NewProperty("EndSound"); + writer << m_EndSound; + writer.NewProperty("EmissionEnabled"); + writer << m_EmitEnabled; + writer.NewProperty("EmissionCount"); + writer << m_EmitCount; + writer.NewProperty("EmissionCountLimit"); + writer << m_EmitCountLimit; + writer.NewProperty("EmissionsIgnoreThis"); + writer << m_EmissionsIgnoreThis; + writer.NewProperty("NegativeThrottleMultiplier"); + writer << m_NegativeThrottleMultiplier; + writer.NewProperty("PositiveThrottleMultiplier"); + writer << m_PositiveThrottleMultiplier; + writer.NewProperty("Throttle"); + writer << m_Throttle; + writer.NewProperty("BurstScale"); + writer << m_BurstScale; + writer.NewProperty("BurstDamage"); + writer << m_BurstDamage; + writer.NewProperty("EmitterDamageMultiplier"); + writer << m_EmitterDamageMultiplier; + writer.NewProperty("BurstSpacing"); + writer << m_BurstSpacing; + writer.NewProperty("BurstTriggered"); + writer << m_BurstTriggered; + writer.NewProperty("EmissionAngle"); + writer << m_EmitAngle; + writer.NewProperty("EmissionOffset"); + writer << m_EmissionOffset; + writer.NewProperty("EmissionDamage"); + writer << m_EmitDamage; + writer.NewProperty("Flash"); + writer << m_pFlash; + writer.NewProperty("FlashScale"); + writer << m_FlashScale; + writer.NewProperty("FlashOnlyOnBurst"); + writer << m_FlashOnlyOnBurst; + writer.NewProperty("SustainBurstSound"); + writer << m_SustainBurstSound; + writer.NewProperty("BurstSoundFollowsEmitter"); + writer << m_BurstSoundFollowsEmitter; + writer.NewProperty("LoudnessOnEmit"); + writer << m_LoudnessOnEmit; + + return 0; } - if (reference.m_EmissionSound) { m_EmissionSound = dynamic_cast(reference.m_EmissionSound->Clone()); } - if (reference.m_BurstSound) { m_BurstSound = dynamic_cast(reference.m_BurstSound->Clone()); } - if (reference.m_EndSound) { m_EndSound = dynamic_cast(reference.m_EndSound->Clone()); } - m_EmitEnabled = reference.m_EmitEnabled; - m_EmitCount = reference.m_EmitCount; - m_EmitCountLimit = reference.m_EmitCountLimit; - m_NegativeThrottleMultiplier = reference.m_NegativeThrottleMultiplier; - m_PositiveThrottleMultiplier = reference.m_PositiveThrottleMultiplier; - m_Throttle = reference.m_Throttle; - m_EmissionsIgnoreThis = reference.m_EmissionsIgnoreThis; - m_BurstScale = reference.m_BurstScale; - m_BurstDamage = reference.m_BurstDamage; - m_EmitterDamageMultiplier = reference.m_EmitterDamageMultiplier; - m_BurstSpacing = reference.m_BurstSpacing; - m_BurstTriggered = reference.m_BurstTriggered; - m_EmitAngle = reference.m_EmitAngle; - m_EmissionOffset = reference.m_EmissionOffset; - m_EmitDamage = reference.m_EmitDamage; - m_FlashScale = reference.m_FlashScale; - m_FlashOnlyOnBurst = reference.m_FlashOnlyOnBurst; - m_SustainBurstSound = reference.m_SustainBurstSound; - m_BurstSoundFollowsEmitter = reference.m_BurstSoundFollowsEmitter; - m_LoudnessOnEmit = reference.m_LoudnessOnEmit; - - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AEmitter object. + + void AEmitter::Destroy(bool notInherited) { + // Stop playback of sounds gracefully + if (m_EmissionSound) { + if (m_EndSound) { + m_EmissionSound->IsBeingPlayed() ? m_EndSound->Play(m_Pos) : m_EndSound->Stop(); + } + m_EmissionSound->Stop(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int AEmitter::ReadProperty(const std::string_view &propName, Reader &reader) { - StartPropertyList(return Attachable::ReadProperty(propName, reader)); - - MatchProperty("AddEmission", { - Emission emission; - reader >> emission; - m_EmissionList.push_back(emission); - }); - MatchProperty("EmissionSound", { - m_EmissionSound = new SoundContainer; - reader >> m_EmissionSound; - }); - MatchProperty("BurstSound", { - m_BurstSound = new SoundContainer; - reader >> m_BurstSound; - }); - MatchProperty("EndSound", { - m_EndSound = new SoundContainer; - reader >> m_EndSound; - }); - MatchProperty("EmissionEnabled", { reader >> m_EmitEnabled; }); - MatchProperty("EmissionCount", { reader >> m_EmitCount; }); - MatchProperty("EmissionCountLimit", { reader >> m_EmitCountLimit; }); - MatchProperty("ParticlesPerMinute", { - float ppm; - reader >> ppm; - // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility. - for (Emission &emission : m_EmissionList) { emission.m_PPM = ppm / static_cast(m_EmissionList.size()); } - }); - MatchProperty("NegativeThrottleMultiplier", { reader >> m_NegativeThrottleMultiplier; }); - MatchProperty("PositiveThrottleMultiplier", { reader >> m_PositiveThrottleMultiplier; }); - MatchProperty("Throttle", { reader >> m_Throttle; }); - MatchProperty("EmissionsIgnoreThis", { reader >> m_EmissionsIgnoreThis; }); - MatchProperty("BurstSize", { - int burstSize; - reader >> burstSize; - // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility. - for (Emission &emission : m_EmissionList) { emission.m_BurstSize = std::ceil(static_cast(burstSize) / static_cast(m_EmissionList.size())); } - }); - MatchProperty("BurstScale", { reader >> m_BurstScale; }); - MatchProperty("BurstDamage", { reader >> m_BurstDamage; }); - MatchProperty("EmitterDamageMultiplier", { reader >> m_EmitterDamageMultiplier; }); - MatchProperty("BurstSpacing", { reader >> m_BurstSpacing; }); - MatchProperty("BurstTriggered", { reader >> m_BurstTriggered; }); - MatchProperty("EmissionAngle", { reader >> m_EmitAngle; }); - MatchProperty("EmissionOffset", { reader >> m_EmissionOffset; }); - MatchProperty("EmissionDamage", { reader >> m_EmitDamage; }); - MatchProperty("Flash", { SetFlash(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("FlashScale", { reader >> m_FlashScale; }); - MatchProperty("FlashOnlyOnBurst", { reader >> m_FlashOnlyOnBurst; }); - MatchProperty("SustainBurstSound", { reader >> m_SustainBurstSound; }); - MatchProperty("BurstSoundFollowsEmitter", { reader >> m_BurstSoundFollowsEmitter; }); - MatchProperty("LoudnessOnEmit", { reader >> m_LoudnessOnEmit; }); - - EndPropertyList; -} + delete m_EmissionSound; + delete m_BurstSound; + delete m_EndSound; + // m_BurstSound.Stop(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this AEmitter with a Writer for -// later recreation with Create(Reader &reader); - -int AEmitter::Save(Writer &writer) const -{ - Attachable::Save(writer); - - for (auto itr = m_EmissionList.begin(); itr != m_EmissionList.end(); ++itr) - { - writer.NewProperty("AddEmission"); - writer << *itr; - } - writer.NewProperty("EmissionSound"); - writer << m_EmissionSound; - writer.NewProperty("BurstSound"); - writer << m_BurstSound; - writer.NewProperty("EndSound"); - writer << m_EndSound; - writer.NewProperty("EmissionEnabled"); - writer << m_EmitEnabled; - writer.NewProperty("EmissionCount"); - writer << m_EmitCount; - writer.NewProperty("EmissionCountLimit"); - writer << m_EmitCountLimit; - writer.NewProperty("EmissionsIgnoreThis"); - writer << m_EmissionsIgnoreThis; - writer.NewProperty("NegativeThrottleMultiplier"); - writer << m_NegativeThrottleMultiplier; - writer.NewProperty("PositiveThrottleMultiplier"); - writer << m_PositiveThrottleMultiplier; - writer.NewProperty("Throttle"); - writer << m_Throttle; - writer.NewProperty("BurstScale"); - writer << m_BurstScale; - writer.NewProperty("BurstDamage"); - writer << m_BurstDamage; - writer.NewProperty("EmitterDamageMultiplier"); - writer << m_EmitterDamageMultiplier; - writer.NewProperty("BurstSpacing"); - writer << m_BurstSpacing; - writer.NewProperty("BurstTriggered"); - writer << m_BurstTriggered; - writer.NewProperty("EmissionAngle"); - writer << m_EmitAngle; - writer.NewProperty("EmissionOffset"); - writer << m_EmissionOffset; - writer.NewProperty("EmissionDamage"); - writer << m_EmitDamage; - writer.NewProperty("Flash"); - writer << m_pFlash; - writer.NewProperty("FlashScale"); - writer << m_FlashScale; - writer.NewProperty("FlashOnlyOnBurst"); - writer << m_FlashOnlyOnBurst; - writer.NewProperty("SustainBurstSound"); - writer << m_SustainBurstSound; - writer.NewProperty("BurstSoundFollowsEmitter"); - writer << m_BurstSoundFollowsEmitter; - writer.NewProperty("LoudnessOnEmit"); - writer << m_LoudnessOnEmit; - - return 0; -} + if (!notInherited) + Attachable::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResetEmissionTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reset the timers of all emissions so they will start/stop at the + // correct relative offsets from now. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AEmitter object. - -void AEmitter::Destroy(bool notInherited) -{ - // Stop playback of sounds gracefully - if (m_EmissionSound) { - if (m_EndSound) { m_EmissionSound->IsBeingPlayed() ? m_EndSound->Play(m_Pos) : m_EndSound->Stop(); } - m_EmissionSound->Stop(); + void AEmitter::ResetEmissionTimers() { + m_LastEmitTmr.Reset(); + for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) + (*eItr).ResetEmissionTimers(); } - delete m_EmissionSound; - delete m_BurstSound; - delete m_EndSound; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableEmission + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this AEmitter to start emitting at the set rate, or to stop. + + void AEmitter::EnableEmission(bool enable) { + if (!m_EmitEnabled && enable) { + m_LastEmitTmr.Reset(); + // Reset counter + m_EmitCount = 0; + // Reset animation + m_Frame = 0; + } + m_EmitEnabled = enable; + } -// m_BurstSound.Stop(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EstimateImpulse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the forces this emitter applies on any parent. + + float AEmitter::EstimateImpulse(bool burst) { + // Calculate the impulse generated by the emissions, once and store the result + if ((!burst && m_AvgImpulse < 0) || (burst && m_AvgBurstImpulse < 0)) { + float impulse = 0; + float velMin, velMax, velRange, spread; + + // Go through all emissions and emit them according to their respective rates + for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) { + // Only check emissions that push the emitter + if ((*eItr).PushesEmitter()) { + double emissions = (*eItr).GetRate() * g_TimerMan.GetDeltaTimeSecs() / 60.0f; + if (burst) { + emissions *= (*eItr).GetBurstSize(); + } - if (!notInherited) - Attachable::Destroy(); - Clear(); -} + velMin = std::min((*eItr).GetMinVelocity(), (*eItr).GetMaxVelocity()); + velMax = std::max((*eItr).GetMinVelocity(), (*eItr).GetMaxVelocity()); + velRange = (velMax - velMin) * 0.5; + spread = std::max(static_cast(c_PI) - (*eItr).GetSpread(), .0f) / c_PI; // A large spread will cause the forces to cancel eachother out -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ResetEmissionTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reset the timers of all emissions so they will start/stop at the -// correct relative offsets from now. + // Add to accumulative recoil impulse generated, F = m * a. + impulse += (velMin + velRange) * spread * (*eItr).m_pEmission->GetMass() * emissions; + } + } -void AEmitter::ResetEmissionTimers() -{ - m_LastEmitTmr.Reset(); - for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) - (*eItr).ResetEmissionTimers(); -} + if (burst) + m_AvgBurstImpulse = impulse; + else + m_AvgImpulse = impulse; + } + // Scale the emission rate up or down according to the appropriate throttle multiplier. + float throttleFactor = GetThrottleFactor(); + // Apply the throttle factor to the emission rate per update + if (burst) { + return m_AvgBurstImpulse * throttleFactor; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnableEmission -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this AEmitter to start emitting at the set rate, or to stop. - -void AEmitter::EnableEmission(bool enable) -{ - if (!m_EmitEnabled && enable) - { - m_LastEmitTmr.Reset(); - // Reset counter - m_EmitCount = 0; - // Reset animation - m_Frame = 0; - } - m_EmitEnabled = enable; -} + return m_AvgImpulse * throttleFactor; + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EstimateImpulse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the forces this emitter applies on any parent. - -float AEmitter::EstimateImpulse(bool burst) -{ - // Calculate the impulse generated by the emissions, once and store the result - if ((!burst && m_AvgImpulse < 0) || (burst && m_AvgBurstImpulse < 0)) - { - float impulse = 0; - float velMin, velMax, velRange, spread; - - // Go through all emissions and emit them according to their respective rates - for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) - { - // Only check emissions that push the emitter - if ((*eItr).PushesEmitter()) - { - double emissions = (*eItr).GetRate() * g_TimerMan.GetDeltaTimeSecs() / 60.0f; - if (burst) { - emissions *= (*eItr).GetBurstSize(); - } - - velMin = std::min((*eItr).GetMinVelocity(), (*eItr).GetMaxVelocity()); - velMax = std::max((*eItr).GetMinVelocity(), (*eItr).GetMaxVelocity()); - velRange = (velMax - velMin) * 0.5; - spread = std::max(static_cast(c_PI) - (*eItr).GetSpread(), .0f) / c_PI; // A large spread will cause the forces to cancel eachother out - - // Add to accumulative recoil impulse generated, F = m * a. - impulse += (velMin + velRange) * spread * (*eItr).m_pEmission->GetMass() * emissions; - } - } - - if (burst) - m_AvgBurstImpulse = impulse; - else - m_AvgImpulse = impulse; - - } - - // Scale the emission rate up or down according to the appropriate throttle multiplier. - float throttleFactor = GetThrottleFactor(); - // Apply the throttle factor to the emission rate per update - if (burst) { return m_AvgBurstImpulse * throttleFactor; } - - return m_AvgImpulse * throttleFactor; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float AEmitter::GetTotalParticlesPerMinute() const { - float totalPPM = 0; - for (const Emission &emission : m_EmissionList) { - totalPPM += emission.m_PPM; + float AEmitter::GetTotalParticlesPerMinute() const { + float totalPPM = 0; + for (const Emission& emission: m_EmissionList) { + totalPPM += emission.m_PPM; + } + return totalPPM; } - return totalPPM; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int AEmitter::GetTotalBurstSize() const { - int totalBurstSize = 0; - for (const Emission &emission : m_EmissionList) { - totalBurstSize += emission.m_BurstSize; + int AEmitter::GetTotalBurstSize() const { + int totalBurstSize = 0; + for (const Emission& emission: m_EmissionList) { + totalBurstSize += emission.m_BurstSize; + } + return totalBurstSize; } - return totalBurstSize; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -float AEmitter::GetScaledThrottle(float throttle, float multiplier) const { - float throttleFactor = LERP(-1.0f, 1.0f, m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, throttle); - return LERP(m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, -1.0f, 1.0f, throttleFactor * multiplier); -} + float AEmitter::GetScaledThrottle(float throttle, float multiplier) const { + float throttleFactor = LERP(-1.0f, 1.0f, m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, throttle); + return LERP(m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, -1.0f, 1.0f, throttleFactor * multiplier); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void AEmitter::SetFlash(Attachable *newFlash) { - if (m_pFlash && m_pFlash->IsAttached()) { RemoveAndDeleteAttachable(m_pFlash); } - if (newFlash == nullptr) { - m_pFlash = nullptr; - } else { - // Note - this is done here because setting mass on attached Attachables causes values to be updated on the parent (and its parent, and so on), which isn't ideal. Better to do it before the new flash is attached, so there are fewer calculations. - newFlash->SetMass(0.0F); + void AEmitter::SetFlash(Attachable* newFlash) { + if (m_pFlash && m_pFlash->IsAttached()) { + RemoveAndDeleteAttachable(m_pFlash); + } + if (newFlash == nullptr) { + m_pFlash = nullptr; + } else { + // Note - this is done here because setting mass on attached Attachables causes values to be updated on the parent (and its parent, and so on), which isn't ideal. Better to do it before the new flash is attached, so there are fewer calculations. + newFlash->SetMass(0.0F); + + m_pFlash = newFlash; + AddAttachable(newFlash); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newFlash->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + dynamic_cast(parent)->SetFlash(attachable); + }}); + + m_pFlash->SetDrawnNormallyByParent(false); + m_pFlash->SetInheritsRotAngle(false); + m_pFlash->SetDeleteWhenRemovedFromParent(true); + m_pFlash->SetCollidesWithTerrainWhileAttached(false); + } + } - m_pFlash = newFlash; - AddAttachable(newFlash); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - m_HardcodedAttachableUniqueIDsAndSetters.insert({newFlash->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - dynamic_cast(parent)->SetFlash(attachable); - }}); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this AEmitter. Supposed to be done every frame. - m_pFlash->SetDrawnNormallyByParent(false); - m_pFlash->SetInheritsRotAngle(false); - m_pFlash->SetDeleteWhenRemovedFromParent(true); - m_pFlash->SetCollidesWithTerrainWhileAttached(false); - } -} + void AEmitter::Update() { + Attachable::PreUpdate(); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (m_FrameCount > 1) { + if (m_EmitEnabled && m_SpriteAnimMode == NOANIM) { + m_SpriteAnimMode = ALWAYSLOOP; + } else if (!m_EmitEnabled) { + m_SpriteAnimMode = NOANIM; + m_Frame = 0; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this AEmitter. Supposed to be done every frame. - -void AEmitter::Update() -{ - Attachable::PreUpdate(); - - if (m_FrameCount > 1) { - if (m_EmitEnabled && m_SpriteAnimMode == NOANIM) { - m_SpriteAnimMode = ALWAYSLOOP; - } else if (!m_EmitEnabled) { - m_SpriteAnimMode = NOANIM; - m_Frame = 0; - } - } - - // Update and show flash if there is one - if (m_pFlash && (!m_FlashOnlyOnBurst || m_BurstTriggered)) { - m_pFlash->SetParentOffset(m_EmissionOffset); - m_pFlash->SetRotAngle(m_Rotation.GetRadAngle() + (m_EmitAngle.GetRadAngle() * GetFlipFactor())); - m_pFlash->SetScale(m_FlashScale); - m_pFlash->SetNextFrame(); - } - - Attachable::Update(); - - if (m_BurstSoundFollowsEmitter && m_BurstSound) { - m_BurstSound->SetPosition(m_Pos); - } - - if (m_EmitEnabled) - { - if (!m_WasEmitting) - { - // Start playing the sound - if (m_EmissionSound) { m_EmissionSound->Play(m_Pos); } - - // Reset the timers of all emissions so they will start/stop at the correct relative offsets from now - for (Emission &emission : m_EmissionList) - emission.ResetEmissionTimers(); - } - // Update the distance attenuation - else - if (m_EmissionSound) { m_EmissionSound->SetPosition(m_Pos); } - - // Get the parent root of this AEmitter -// TODO: Potentially get this once outside instead, like in attach/detach") - MovableObject *pRootParent = GetRootParent(); + // Update and show flash if there is one + if (m_pFlash && (!m_FlashOnlyOnBurst || m_BurstTriggered)) { + m_pFlash->SetParentOffset(m_EmissionOffset); + m_pFlash->SetRotAngle(m_Rotation.GetRadAngle() + (m_EmitAngle.GetRadAngle() * GetFlipFactor())); + m_pFlash->SetScale(m_FlashScale); + m_pFlash->SetNextFrame(); + } - float throttleFactor = GetThrottleFactor(); - m_FlashScale = throttleFactor; - // Check burst triggering against whether the spacing is fulfilled - if (m_BurstTriggered && CanTriggerBurst()) { - // Play burst sound - if (m_BurstSound) { m_BurstSound->Play(m_Pos); } - // Start timing until next burst - m_BurstTimer.Reset(); - } - // Not enough spacing, cancel the triggering if there was any - else - m_BurstTriggered = false; - - int emissionCountTotal = 0; - float velMin, velRange, spread; - double currentPPM, SPE; - MovableObject *pParticle = 0; - Vector parentVel, emitVel, pushImpulses; - // Go through all emissions and emit them according to their respective rates - for (Emission &emission : m_EmissionList) - { - // Make sure the emissions only happen between the start time and end time - if (emission.IsEmissionTime()) - { - // Apply the throttle factor to the emission rate - currentPPM = emission.GetRate() * throttleFactor; - int emissionCount = 0; - - // Only do all this if the PPM is actually above zero - if (currentPPM > 0) - { - // Calculate secs per emission - SPE = 60.0 / currentPPM; - - // Add the last elapsed time to the accumulator - emission.m_Accumulator += m_LastEmitTmr.GetElapsedSimTimeS(); - - // Now figure how many full emissions can fit in the current accumulator - emissionCount = std::floor(emission.m_Accumulator / SPE); - // Deduct the about to be emitted emissions from the accumulator - emission.m_Accumulator -= emissionCount * SPE; - - RTEAssert(emission.m_Accumulator >= 0, "Emission accumulator negative!"); - } - else { - emission.m_Accumulator = 0; + Attachable::Update(); + + if (m_BurstSoundFollowsEmitter && m_BurstSound) { + m_BurstSound->SetPosition(m_Pos); + } + + if (m_EmitEnabled) { + if (!m_WasEmitting) { + // Start playing the sound + if (m_EmissionSound) { + m_EmissionSound->Play(m_Pos); } - float scale = 1.0F; - // Add extra emissions if bursting. - if (m_BurstTriggered) { - emissionCount += emission.GetBurstSize() * std::floor(throttleFactor); - scale = m_BurstScale; + + // Reset the timers of all emissions so they will start/stop at the correct relative offsets from now + for (Emission& emission: m_EmissionList) + emission.ResetEmissionTimers(); + } + // Update the distance attenuation + else if (m_EmissionSound) { + m_EmissionSound->SetPosition(m_Pos); + } + + // Get the parent root of this AEmitter + // TODO: Potentially get this once outside instead, like in attach/detach") + MovableObject* pRootParent = GetRootParent(); + + float throttleFactor = GetThrottleFactor(); + m_FlashScale = throttleFactor; + // Check burst triggering against whether the spacing is fulfilled + if (m_BurstTriggered && CanTriggerBurst()) { + // Play burst sound + if (m_BurstSound) { + m_BurstSound->Play(m_Pos); } - emissionCountTotal += emissionCount; - pParticle = 0; - emitVel.Reset(); - parentVel = pRootParent->GetVel() * emission.InheritsVelocity(); - - for (int i = 0; i < emissionCount; ++i) - { - velMin = emission.GetMinVelocity() * scale; - velRange = emission.GetMaxVelocity() - emission.GetMinVelocity() * scale; - spread = emission.GetSpread() * scale; - // Make a copy after the reference particle - pParticle = dynamic_cast(emission.GetEmissionParticlePreset()->Clone()); - // Set up its position and velocity according to the parameters of this. - // Emission point offset not set - - if (emission.GetOffset().IsZero()) { - if (m_EmissionOffset.IsZero()) { - pParticle->SetPos(m_Pos); - } else { - pParticle->SetPos(m_Pos + RotateOffset(m_EmissionOffset)); - } + // Start timing until next burst + m_BurstTimer.Reset(); + } + // Not enough spacing, cancel the triggering if there was any + else + m_BurstTriggered = false; + + int emissionCountTotal = 0; + float velMin, velRange, spread; + double currentPPM, SPE; + MovableObject* pParticle = 0; + Vector parentVel, emitVel, pushImpulses; + // Go through all emissions and emit them according to their respective rates + for (Emission& emission: m_EmissionList) { + // Make sure the emissions only happen between the start time and end time + if (emission.IsEmissionTime()) { + // Apply the throttle factor to the emission rate + currentPPM = emission.GetRate() * throttleFactor; + int emissionCount = 0; + + // Only do all this if the PPM is actually above zero + if (currentPPM > 0) { + // Calculate secs per emission + SPE = 60.0 / currentPPM; + + // Add the last elapsed time to the accumulator + emission.m_Accumulator += m_LastEmitTmr.GetElapsedSimTimeS(); + + // Now figure how many full emissions can fit in the current accumulator + emissionCount = std::floor(emission.m_Accumulator / SPE); + // Deduct the about to be emitted emissions from the accumulator + emission.m_Accumulator -= emissionCount * SPE; + + RTEAssert(emission.m_Accumulator >= 0, "Emission accumulator negative!"); } else { - pParticle->SetPos(m_Pos + RotateOffset(emission.GetOffset())); + emission.m_Accumulator = 0; } - // TODO: Optimize making the random angles!") - emitVel.SetXY(velMin + RandomNum(0.0F, velRange), 0.0F); - emitVel.RadRotate(m_EmitAngle.GetRadAngle() + spread * RandomNormalNum()); - emitVel = RotateOffset(emitVel); - pParticle->SetVel(parentVel + emitVel); - pParticle->SetRotAngle(emitVel.GetAbsRadAngle() + (m_HFlipped ? -c_PI : 0)); - pParticle->SetHFlipped(m_HFlipped); - - //Scale the particle's lifetime based on life variation and throttle, as long as it's not 0 - if (pParticle->GetLifetime() != 0) { - pParticle->SetLifetime(std::max(static_cast(static_cast(pParticle->GetLifetime()) * (1.0F + (emission.GetLifeVariation() * RandomNormalNum()))), 1)); - pParticle->SetLifetime(std::max(static_cast(pParticle->GetLifetime() * throttleFactor), 1)); + float scale = 1.0F; + // Add extra emissions if bursting. + if (m_BurstTriggered) { + emissionCount += emission.GetBurstSize() * std::floor(throttleFactor); + scale = m_BurstScale; } - pParticle->SetTeam(m_Team); - pParticle->SetIgnoresTeamHits(true); - - // Add to accumulative recoil impulse generated, F = m * a - // If enabled, that is - if (emission.PushesEmitter() && (GetParent() || GetMass() > 0)) { pushImpulses -= emitVel * pParticle->GetMass(); } - - // Set the emitted particle to not hit this emitter's parent, if applicable - if (m_EmissionsIgnoreThis) - pParticle->SetWhichMOToNotHit(pRootParent); - - // Let particle loose into the world! - g_MovableMan.AddMO(pParticle); - pParticle = 0; - } - } - } - m_LastEmitTmr.Reset(); + emissionCountTotal += emissionCount; + pParticle = 0; + emitVel.Reset(); + parentVel = pRootParent->GetVel() * emission.InheritsVelocity(); + + for (int i = 0; i < emissionCount; ++i) { + velMin = emission.GetMinVelocity() * scale; + velRange = emission.GetMaxVelocity() - emission.GetMinVelocity() * scale; + spread = emission.GetSpread() * scale; + // Make a copy after the reference particle + pParticle = dynamic_cast(emission.GetEmissionParticlePreset()->Clone()); + // Set up its position and velocity according to the parameters of this. + // Emission point offset not set + + if (emission.GetOffset().IsZero()) { + if (m_EmissionOffset.IsZero()) { + pParticle->SetPos(m_Pos); + } else { + pParticle->SetPos(m_Pos + RotateOffset(m_EmissionOffset)); + } + } else { + pParticle->SetPos(m_Pos + RotateOffset(emission.GetOffset())); + } + // TODO: Optimize making the random angles!") + emitVel.SetXY(velMin + RandomNum(0.0F, velRange), 0.0F); + emitVel.RadRotate(m_EmitAngle.GetRadAngle() + spread * RandomNormalNum()); + emitVel = RotateOffset(emitVel); + pParticle->SetVel(parentVel + emitVel); + pParticle->SetRotAngle(emitVel.GetAbsRadAngle() + (m_HFlipped ? -c_PI : 0)); + pParticle->SetHFlipped(m_HFlipped); + + // Scale the particle's lifetime based on life variation and throttle, as long as it's not 0 + if (pParticle->GetLifetime() != 0) { + pParticle->SetLifetime(std::max(static_cast(static_cast(pParticle->GetLifetime()) * (1.0F + (emission.GetLifeVariation() * RandomNormalNum()))), 1)); + pParticle->SetLifetime(std::max(static_cast(pParticle->GetLifetime() * throttleFactor), 1)); + } + pParticle->SetTeam(m_Team); + pParticle->SetIgnoresTeamHits(true); + + // Add to accumulative recoil impulse generated, F = m * a + // If enabled, that is + if (emission.PushesEmitter() && (GetParent() || GetMass() > 0)) { + pushImpulses -= emitVel * pParticle->GetMass(); + } - // Apply recoil/push effects. Joint stiffness will take effect when these are transferred to the parent. - if (!pushImpulses.IsZero()) { AddImpulseForce(pushImpulses); } + // Set the emitted particle to not hit this emitter's parent, if applicable + if (m_EmissionsIgnoreThis) + pParticle->SetWhichMOToNotHit(pRootParent); - // Count the the damage caused by the emissions, and only if we're not bursting - if (!m_BurstTriggered) { - m_DamageCount += static_cast(emissionCountTotal) * m_EmitDamage * m_EmitterDamageMultiplier; - } else { // Count the the damage caused by the burst - m_DamageCount += m_BurstDamage * m_EmitterDamageMultiplier; + // Let particle loose into the world! + g_MovableMan.AddMO(pParticle); + pParticle = 0; + } + } + } + m_LastEmitTmr.Reset(); + + // Apply recoil/push effects. Joint stiffness will take effect when these are transferred to the parent. + if (!pushImpulses.IsZero()) { + AddImpulseForce(pushImpulses); + } + + // Count the the damage caused by the emissions, and only if we're not bursting + if (!m_BurstTriggered) { + m_DamageCount += static_cast(emissionCountTotal) * m_EmitDamage * m_EmitterDamageMultiplier; + } else { // Count the the damage caused by the burst + m_DamageCount += m_BurstDamage * m_EmitterDamageMultiplier; + } + + // Count the total emissions since enabling, and stop emitting if beyond limit (and limit is also enabled) + m_EmitCount += emissionCountTotal; + if (m_EmitCountLimit > 0 && m_EmitCount > m_EmitCountLimit) { + EnableEmission(false); + } + + if (m_BurstTriggered) { + m_BurstTriggered = false; + } + + m_WasEmitting = true; + } + // Do stuff to stop emission + else { + if (m_WasEmitting) { + if (m_EmissionSound) { + m_EmissionSound->Stop(); + } + if (m_BurstSound && !m_SustainBurstSound) { + m_BurstSound->Stop(); + } + if (m_EndSound) { + m_EndSound->Play(m_Pos); + } + m_WasEmitting = false; + } } - // Count the total emissions since enabling, and stop emitting if beyond limit (and limit is also enabled) - m_EmitCount += emissionCountTotal; - if (m_EmitCountLimit > 0 && m_EmitCount > m_EmitCountLimit) { EnableEmission(false); } - - if (m_BurstTriggered) { m_BurstTriggered = false; } - - m_WasEmitting = true; - } - // Do stuff to stop emission - else - { - if (m_WasEmitting) - { - if (m_EmissionSound) { m_EmissionSound->Stop(); } - if (m_BurstSound && !m_SustainBurstSound) { m_BurstSound->Stop(); } - if (m_EndSound) { m_EndSound->Play(m_Pos); } - m_WasEmitting = false; + // Set the screen flash effect to draw at the final post processing stage + if (m_EmitEnabled && (!m_FlashOnlyOnBurst || m_BurstTriggered) && m_pFlash && m_pFlash->GetScreenEffect()) { + // Fudge the glow pos forward a bit so it aligns nicely with the flash + Vector emitPos(m_pFlash->GetScreenEffect()->w * 0.3F * m_FlashScale, 0); + emitPos.RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); + emitPos = m_Pos + RotateOffset(m_EmissionOffset) + emitPos; + if (m_EffectAlwaysShows || !g_SceneMan.ObscuredPoint(emitPos)) { + g_PostProcessMan.RegisterPostEffect(emitPos, m_pFlash->GetScreenEffect(), m_pFlash->GetScreenEffectHash(), RandomNum(m_pFlash->GetEffectStopStrength(), m_pFlash->GetEffectStartStrength()) * std::clamp(m_FlashScale, 0.0F, 1.0F), m_pFlash->GetEffectRotAngle()); + } } } - // Set the screen flash effect to draw at the final post processing stage - if (m_EmitEnabled && (!m_FlashOnlyOnBurst || m_BurstTriggered) && m_pFlash && m_pFlash->GetScreenEffect()) { - // Fudge the glow pos forward a bit so it aligns nicely with the flash - Vector emitPos(m_pFlash->GetScreenEffect()->w * 0.3F * m_FlashScale, 0); - emitPos.RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); - emitPos = m_Pos + RotateOffset(m_EmissionOffset) + emitPos; - if (m_EffectAlwaysShows || !g_SceneMan.ObscuredPoint(emitPos)) { - g_PostProcessMan.RegisterPostEffect(emitPos, m_pFlash->GetScreenEffect(), m_pFlash->GetScreenEffectHash(), RandomNum(m_pFlash->GetEffectStopStrength(), m_pFlash->GetEffectStartStrength()) * std::clamp(m_FlashScale, 0.0F, 1.0F), m_pFlash->GetEffectRotAngle()); - } - } -} - + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this AEmitter's current graphical representation to a + // BITMAP of choice. + + void AEmitter::Draw(BITMAP* pTargetBitmap, + const Vector& targetPos, + DrawMode mode, + bool onlyPhysical) const { + // Draw flash if there is one + if (m_pFlash && !m_pFlash->IsDrawnAfterParent() && + !onlyPhysical && mode == g_DrawColor && m_EmitEnabled && (!m_FlashOnlyOnBurst || m_BurstTriggered)) + m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + + Attachable::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + + // Update and Draw flash if there is one + if (m_pFlash && m_pFlash->IsDrawnAfterParent() && + !onlyPhysical && mode == g_DrawColor && m_EmitEnabled && (!m_FlashOnlyOnBurst || m_BurstTriggered)) + m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this AEmitter's current graphical representation to a -// BITMAP of choice. - -void AEmitter::Draw(BITMAP *pTargetBitmap, - const Vector &targetPos, - DrawMode mode, - bool onlyPhysical) const -{ - // Draw flash if there is one - if (m_pFlash && !m_pFlash->IsDrawnAfterParent() && - !onlyPhysical && mode == g_DrawColor && m_EmitEnabled && (!m_FlashOnlyOnBurst || m_BurstTriggered)) - m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - - Attachable::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - - // Update and Draw flash if there is one - if (m_pFlash && m_pFlash->IsDrawnAfterParent() && - !onlyPhysical && mode == g_DrawColor && m_EmitEnabled && (!m_FlashOnlyOnBurst || m_BurstTriggered)) - m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); -} - -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/AEmitter.h b/Source/Entities/AEmitter.h index 94fb8b6fd..545948098 100644 --- a/Source/Entities/AEmitter.h +++ b/Source/Entities/AEmitter.h @@ -10,753 +10,722 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "Attachable.h" #include "Emission.h" -namespace RTE -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: AEmitter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: An attachable MO that creates and emits particle MO's. -// Parent(s): Attachable. -// Class history: 02/29/2004 AEmitter created. - -class AEmitter : public Attachable { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - friend struct EntityLuaBindings; - -// Concrete allocation and cloning definitions -EntityAllocation(AEmitter); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: AEmitter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a AEmitter object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - AEmitter() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~AEmitter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a AEmitter object before deletion -// from system memory. -// Arguments: None. - - ~AEmitter() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AEmitter to be identical to another, by deep copy. -// Arguments: A reference to the AEmitter to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const AEmitter &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire AEmitter, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); MOSRotating::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsEmitting -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this AEmitter is currently enabled and emitting. -// Arguments: None. -// Return value: Whether it's emitting or not. - - bool IsEmitting() const { return m_EmitEnabled; } - - /// - /// Returns whether this emitter was emitting last frame. - /// - /// Whether this emitter was emitting last frame. - bool WasEmitting() const { return m_WasEmitting; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ResetEmissionTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reset the timers of all emissions so they will start/stop at the -// correct relative offsets from now. -// Arguments: None. -// Return value: None. - - void ResetEmissionTimers(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnableEmission -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this AEmitter to start emitting at the set rate, or to stop. -// Arguments: Whether to enable or disable emission. -// Return value: None. - - void EnableEmission(bool enable = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EstimateImpulse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the forces this emitter applies on any parent. -// Arguments: Whether to calculate a burst update or not. -// Return value: The approximate impulse generated by the emitter. - - float EstimateImpulse(bool burst = false); - - /// - /// Gets the rate at which all of the Emissions of this AEmitter, combined, emit their particles. - /// - /// The combined particles per minute of all Emissions in this AEmitter. - float GetTotalParticlesPerMinute() const; - - /// - /// Gets the number of particles that will be emitted by all the Emissions of this AEmitter combined, in one shot when a burst is triggered. - /// - /// The combined burst size of all Emissions in this AEmitter. - int GetTotalBurstSize() const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBurstScale -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the scale factor that will be applied to the regular spread and -// emission velocity to get the burst particle parameters. -// Arguments: None. -// Return value: The scale factor. - - float GetBurstScale() const { return m_BurstScale; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the angle of direction that the emitted particles will be shot at. -// Arguments: None. -// Return value: A float with the angle in radians. - - float GetEmitAngle() const { return m_EmitAngle.GetRadAngle(); } - - const Matrix & GetEmitAngleMatrix() const { return m_EmitAngle; } - - /// - /// Gets the offset of the emission point from this' sprite center, which gets rotated with this. - /// - /// The emission offset. - Vector GetEmitOffset() const { return m_EmissionOffset; } - - /// - /// Sets the offset of the emission point from this' sprite center, which gets rotated with this. - /// - /// The new emission offset. - void SetEmitOffset(const Vector &newOffset) { m_EmissionOffset = newOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitVector -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A vector in the direction, including the rotation of the emitter, that -// the emitted particles will be shot at. -// Arguments: None. -// Return value: A unit vector. - - Vector GetEmitVector() const { return Vector(1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRecoilVector -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A vector in the opposite direction, including the rotation of the -// emitter, that the emitted particles will be shot at. -// Arguments: None. -// Return value: A unit vector. - - Vector GetRecoilVector() const { return Vector(-1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBurstSpacing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the BurstSpacing for this emitter. -// Arguments: None. -// Return value: The BurstSpacing in ms. - - float GetBurstSpacing() const { return m_BurstSpacing; } - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitSpread -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the angle spread of velocity of the emitted MO's to each side of -// the angle of emission of this AEmitter. -// Arguments: None. -// Return value: A float with the spread in r's. PI/2 would mean that MO's fly out to -// one side only, with the m_EmitAngle defining the middle of that half -// circle. - - float GetEmitSpread() const { return m_Spread; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitVelMin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the min end of the range the velocity of a particle being emitted -// by this AEmitter can have. -// Arguments: None. -// Return value: A float with the min vel possible for an emitted particle. - - float GetEmitVelMin() const { return m_MinVelocity; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitVelMax -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the max end of the range the velocity of a particle being emitted -// by this AEmitter can have. -// Arguments: None. -// Return value: A float with the max vel possible for an emitted particle. - - float GetEmitVelMax() const { return m_MaxVelocity; } -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetThrottle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the normalized throttle scalar which controls how to affect the -// emission rate as per the emisison rate range. Depricated for Lua, use -// the Throttle property instead. -// Arguments: None. -// Return value: A float with the normalized throttle scalar. 1.0 means max throttle, -// 0 means normal, -1.0 means least emission rate. - - float GetThrottle() const { return m_Throttle; } - - /// - /// Gets the adjusted throttle multiplier that is factored into the emission rate of this AEmitter. - /// - /// The throttle strength as a multiplier. - float GetThrottleFactor() const { return LERP(-1.0f, 1.0f, m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, m_Throttle); } - - /// - /// Gets the throttle value that will achieve a given throttle factor that is factored into the emission rate of this AEmitter. - /// - /// The throttle value that will achieve the given throttle factor. - float GetThrottleForThrottleFactor(float throttleFactor) const { return LERP(m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, -1.0f, 1.0f, throttleFactor); } - - /// - /// Returns a scaled throttle value that represents a linear increase of force. - /// Because of (bad) reasons, throttle is in the range -1.0F to 1.0F, where -1.0F is "minimum force" and 1.0F is "maximum force". - /// 0.0F is "whoever the fuck knows?" force. As such, multiplying throttle by 2 does not mean twice the force emitted, instead it means "whoever the fuck knows?" additional force emitted. - /// All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. - /// ...this helper function lets us apply a scale to throttle and get a sensible result. - /// - /// The throttle value to be considered. - /// The multiplier to scale by, in terms of absolute force emitted. - /// Adjusted throttle value scaled by the multiplier value. - float GetScaledThrottle(float throttle, float multiplier) const; - - /// - /// Gets the negative throttle multiplier of this AEmitter. - /// - /// The negative throttle multiplier of this AEmitter. - float GetNegativeThrottleMultiplier() const { return m_NegativeThrottleMultiplier; } - - /// - /// Gets the positive throttle multiplier of this AEmitter. - /// - /// The positive throttle multiplier of this AEmitter. - float GetPositiveThrottleMultiplier() const { return m_PositiveThrottleMultiplier; } - - /// - /// Sets the negative throttle multiplier of this AEmitter. - /// - /// The new throttle multiplier of this AEmitter. - void SetNegativeThrottleMultiplier(float newValue) { m_NegativeThrottleMultiplier = newValue; } - - /// - /// Sets the positive throttle multiplier of this AEmitter. - /// - /// The new throttle multiplier of this AEmitter. - void SetPositiveThrottleMultiplier(float newValue) { m_PositiveThrottleMultiplier = newValue; } - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitRate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the rate at which this AEmitter emits its particles. -// Arguments: A float with the rate in #/min. -// Return value: None. - - void SetEmitRate(const float rate) { m_PPM = rate; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBurstCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the number of particles that will be emitted in one shot upon -// a triggered burst of this AEmitter. -// Arguments: The number of emitted particles a burst should have. 0 means burst -// are disabled. -// Return value: None. - - void SetBurstCount(const int count) { m_BurstSize = count; } -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBurstScale -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the scale factor that will be applied to the regular spread and -// emission velocity to get the burst particle parameters. -// Arguments: The scale factor. -// Return value: None. - - void SetBurstScale(const float scale) { m_BurstScale = scale; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBurstSpacing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the BurstSpacing for this emitter. -// Arguments: The BurstSpacing in ms. -// Return value: None. - - void SetBurstSpacing(const float spacing) { m_BurstSpacing = spacing; } - - - /// - /// Gets the flash of this AEmitter. - /// - /// A pointer to the AEmitter's flash. Ownership is NOT transferred! - Attachable * GetFlash() const { return m_pFlash; } - - /// - /// Sets the flash for this AEmitter. Ownership IS transferred! - /// - /// The new flash to use. - void SetFlash(Attachable *newFlash); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFlashScale -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the display scale factor of the flash effect. This is purely -// visual. -// Arguments: None. -// Return value: The scale factor of the flash draw. - - float GetFlashScale() const { return m_FlashScale; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFlashScale -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the display scale factor of the flash effect. This is purely -// visual. -// Arguments: The scale factor of the flash draw. -// Return value: None. - - void SetFlashScale(float flashScale = 1.0f) { m_FlashScale = flashScale; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the angle of direction that the emitted particles will be shot at. -// Arguments: A float with the angle in radians. -// Return value: None. - - void SetEmitAngle(const float angle) { m_EmitAngle.SetRadAngle(angle); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetThrottle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the normalized throttle scalar which controls how to affect the -// emission rate as per the emisison rate range. -// Arguments: A float with the normalized throttle scalar. 1.0 means max throttle, -// 0 means normal, -1.0 means least emission rate. -// Return value: None. - - void SetThrottle(float throttle) { m_Throttle = throttle > 1.0f ? 1.0f : (throttle < -1.0f ? -1.0f : throttle); } - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitSpread -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the angle spread of velocity of the emitted MO's to each side of -// angle of emission of this AEmitter. -// Arguments: A float with the spread in r's. PI/2 would mean that MO's fly out to -// one side only, with the m_EmitAngle defining the middle of that half -// circle. -// Return value: None. - - void SetEmitSpread(const float spread) { m_Spread = spread; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitVelMin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the min end of the range the velocity of a particle being emitted -// by this AEmitter can have. -// Arguments: A float with the min vel possible for an emitted particle. -// Return value: None. - - void SetEmitVelMin(const float minVel) { m_MinVelocity = minVel; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitVelMax -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the max end of the range the velocity of a particle being emitted -// by this AEmitter can have. -// Arguments: A float with the max vel possible for an emitted particle. -// Return value: None. - - void SetEmitVelMax(const float maxVel) { m_MaxVelocity = maxVel; } -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TriggerBurst -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Triggers a one-shot burst of emissions in the number that has -// previously been set. The burst will happen during the next Update of -// this AEmitter. -// Arguments: None. -// Return value: None. - - void TriggerBurst() { m_BurstTriggered = true; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CanTriggerBurst -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if it is possible to trigger a one-shot burst of emissions during -// the next Update of this AEmitter. -// Arguments: None. -// Return value: If it is possible to trigger a burst. - - bool CanTriggerBurst() { return m_BurstSpacing <= 0 || m_BurstTimer.IsPastSimMS(m_BurstSpacing); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsSetToBurst -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this AEmitter is set to burst next update or not. -// Arguments: None. -// Return value: Whether a burst is gonna happen or not.. - - bool IsSetToBurst() const { return m_BurstTriggered; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AlarmOnEmit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registers a new AlarmEvent if this emitter has a loudness above zero. -// Arguments: Team that will ignore this AlarmEvent. -// Return value: None. - - void AlarmOnEmit(int Team) const { if (m_LoudnessOnEmit > 0) g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, Team, m_LoudnessOnEmit)); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ResetAllTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resest all the timers used by this. Can be emitters, etc. This is to -// prevent backed up emissions to come out all at once while this has been -// held dormant in an inventory. -// Arguments: None. -// Return value: None. - - void ResetAllTimers() override { Attachable::ResetAllTimers(); m_BurstTimer.Reset(); m_LastEmitTmr.Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - void PostUpdate() override { Attachable::PostUpdate(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBurstDamage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns burst damage of this emitter. -// Arguments: None. -// Return value: Burst damage of emitter. - - float GetBurstDamage() const { return m_BurstDamage * m_EmitterDamageMultiplier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBurstDamage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets burst damage of this emitter. -// Arguments: Burst damage of emitter. -// Return value: None. - - void SetBurstDamage(float newValue) { m_BurstDamage = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitDamage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns emit damage of this emitter. -// Arguments: None. -// Return value: Emit damage of emitter. - - float GetEmitDamage() const { return m_EmitDamage * m_EmitterDamageMultiplier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitDamage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets emit damage of this emitter. -// Arguments: Emit damage of emitter. -// Return value: None. - - void SetEmitDamage(float newValue) { m_EmitDamage = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitterDamageMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns damage multiplier of this emitter. -// Arguments: None. -// Return value: Damage multiplier of emitter. - - float GetEmitterDamageMultiplier() const { return m_EmitterDamageMultiplier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitterDamageMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets damage multiplier of this emitter. -// Arguments: New damage multiplier of emitter -// Return value: None. - - void SetEmitterDamageMultiplier(float newValue) { m_EmitterDamageMultiplier = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this AEmitter's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDamaging -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this emitter deals damage. -// Arguments: None. -// Return value: Returns true if this emitter deals damage. - - bool IsDamaging() { return (m_EmitDamage > 0 || m_BurstDamage > 0) && m_EmitterDamageMultiplier > 0; } - - /// - /// Gets the number of emissions emitted since emission was last enabled. - /// - /// The number of emissions emitted since emission was last enabled. - long GetEmitCount() const { return m_EmitCount; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEmitCountLimit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of emissions left before emitter is disabled. -// Arguments: None. -// Return value: Returns the number of emissions left before emitter is disabled. - - long GetEmitCountLimit() const { return m_EmitCountLimit; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEmitCountLimit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the number of emissions left before emitter is disabled. -// Arguments: New number of emissions left -// Return value: None. - - void SetEmitCountLimit(long newValue) { m_EmitCountLimit = newValue; } - - /// - /// Gets this AEmitter's emission sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this AEmitter's emission sound. - SoundContainer * GetEmissionSound() const { return m_EmissionSound; } - - /// - /// Sets this AEmitter's emission sound. Ownership IS transferred! - /// - /// The new SoundContainer for this AEmitter's emission sound. - void SetEmissionSound(SoundContainer *newSound) { m_EmissionSound = newSound; } - - /// - /// Gets this AEmitter's burst sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this AEmitter's burst sound. - SoundContainer * GetBurstSound() const { return m_BurstSound; } - - /// - /// Sets this AEmitter's burst sound. Ownership IS transferred! - /// - /// The new SoundContainer for this AEmitter's burst sound. - void SetBurstSound(SoundContainer *newSound) { m_BurstSound = newSound; } - - /// - /// Gets this AEmitter's end sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this AEmitter's end sound. - SoundContainer * GetEndSound() const { return m_EndSound; } - - /// - /// Sets this AEmitter's end sound. Ownership IS transferred! - /// - /// The new SoundContainer for this AEmitter's end sound. - void SetEndSound(SoundContainer *newSound) { m_EndSound = newSound; } - - /// - /// Returns whether this emitter just started emitting this frame. - /// - /// Whether this emitter just started emitting this frame. - bool JustStartedEmitting() const { return !m_WasEmitting && m_EmitEnabled; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - - // The list of MO instances that get emitted - std::vector m_EmissionList; - // Sounds - SoundContainer *m_EmissionSound; - SoundContainer *m_BurstSound; - SoundContainer *m_EndSound; - // Whether emitting is currently enabled or not. - bool m_EmitEnabled; - // Whether or not the it was emitting last frame or not. - bool m_WasEmitting; - // The number of emissions emitted since emission was last enabled - long m_EmitCount; - // The max number of emissions to emit per emit being enabled - long m_EmitCountLimit; - float m_NegativeThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is negative. Relative to the absolute throttle value. - float m_PositiveThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is positive. Relative to the absolute throttle value. - float m_Throttle; //!< The normalized throttle which controls the MSPE between 1.0 * m_MSPERange and -1.0 * m_MSPERange. 0 means emit the regular m_PPM amount. - // Whether or not this' emissions ignore hits with itself, even if they are set to hit other MOs. - bool m_EmissionsIgnoreThis; - // The scale factor that will be applied to the regular spread and emission - // velocity to get the the burst particle parameters. - float m_BurstScale; - // Damage dealt to the attached-to parent upon bursting. - float m_BurstDamage; - // Damage multiplier derived from penetrating particle. Affects both burst and emit damage values. - float m_EmitterDamageMultiplier; - // Indicates that a burst is set to happen during the next Update. - bool m_BurstTriggered; - // The shortest possible time between bursts, in ms - float m_BurstSpacing; - // Measures the shortest possible time between bursts - Timer m_BurstTimer; - // The angle of the direction the emitted particles will head in. - // The m_Roataion of this AEmitter will be added to this angle. - Matrix m_EmitAngle; - // Offset of the emission point from this' sprite center, which gets rotated with this - Vector m_EmissionOffset; - // The amount of damage points that this emitter collects when emitting one non-burst particle. - float m_EmitDamage; - // Timer for timing how long ago the last particle was emitted. 0 means no limit. - Timer m_LastEmitTmr; - // Emission flash Attachable - Attachable *m_pFlash; - // Flash display scale - float m_FlashScale; - // How large impulse this emitter generates when bursting - float m_AvgBurstImpulse; - // How large impulse this emitter generates when firing - float m_AvgImpulse; - // How far this is audiable (in screens) when emitting as a jetpack or craft engine - float m_LoudnessOnEmit; - // Whether to only display flash on bursts, and not on any emission frame. - bool m_FlashOnlyOnBurst; - // Whether the burst sound should always play until completion, or whether it stops when this emitter stops emitting - bool m_SustainBurstSound; - // Whether the burst sound follows the emitter - bool m_BurstSoundFollowsEmitter; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AEmitter, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - AEmitter(const AEmitter &reference) = delete; - AEmitter & operator=(const AEmitter &rhs) = delete; - -}; +namespace RTE { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: AEmitter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: An attachable MO that creates and emits particle MO's. + // Parent(s): Attachable. + // Class history: 02/29/2004 AEmitter created. + + class AEmitter : public Attachable { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + friend struct EntityLuaBindings; + + // Concrete allocation and cloning definitions + EntityAllocation(AEmitter); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: AEmitter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a AEmitter object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + AEmitter() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~AEmitter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a AEmitter object before deletion + // from system memory. + // Arguments: None. + + ~AEmitter() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AEmitter to be identical to another, by deep copy. + // Arguments: A reference to the AEmitter to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const AEmitter& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire AEmitter, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + MOSRotating::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEmitting + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this AEmitter is currently enabled and emitting. + // Arguments: None. + // Return value: Whether it's emitting or not. + + bool IsEmitting() const { return m_EmitEnabled; } + + /// + /// Returns whether this emitter was emitting last frame. + /// + /// Whether this emitter was emitting last frame. + bool WasEmitting() const { return m_WasEmitting; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResetEmissionTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reset the timers of all emissions so they will start/stop at the + // correct relative offsets from now. + // Arguments: None. + // Return value: None. + + void ResetEmissionTimers(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableEmission + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this AEmitter to start emitting at the set rate, or to stop. + // Arguments: Whether to enable or disable emission. + // Return value: None. + + void EnableEmission(bool enable = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EstimateImpulse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the forces this emitter applies on any parent. + // Arguments: Whether to calculate a burst update or not. + // Return value: The approximate impulse generated by the emitter. + + float EstimateImpulse(bool burst = false); + + /// + /// Gets the rate at which all of the Emissions of this AEmitter, combined, emit their particles. + /// + /// The combined particles per minute of all Emissions in this AEmitter. + float GetTotalParticlesPerMinute() const; + + /// + /// Gets the number of particles that will be emitted by all the Emissions of this AEmitter combined, in one shot when a burst is triggered. + /// + /// The combined burst size of all Emissions in this AEmitter. + int GetTotalBurstSize() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBurstScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the scale factor that will be applied to the regular spread and + // emission velocity to get the burst particle parameters. + // Arguments: None. + // Return value: The scale factor. + + float GetBurstScale() const { return m_BurstScale; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the angle of direction that the emitted particles will be shot at. + // Arguments: None. + // Return value: A float with the angle in radians. + + float GetEmitAngle() const { return m_EmitAngle.GetRadAngle(); } + + const Matrix& GetEmitAngleMatrix() const { return m_EmitAngle; } + + /// + /// Gets the offset of the emission point from this' sprite center, which gets rotated with this. + /// + /// The emission offset. + Vector GetEmitOffset() const { return m_EmissionOffset; } + + /// + /// Sets the offset of the emission point from this' sprite center, which gets rotated with this. + /// + /// The new emission offset. + void SetEmitOffset(const Vector& newOffset) { m_EmissionOffset = newOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitVector + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A vector in the direction, including the rotation of the emitter, that + // the emitted particles will be shot at. + // Arguments: None. + // Return value: A unit vector. + + Vector GetEmitVector() const { return Vector(1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRecoilVector + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A vector in the opposite direction, including the rotation of the + // emitter, that the emitted particles will be shot at. + // Arguments: None. + // Return value: A unit vector. + + Vector GetRecoilVector() const { return Vector(-1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBurstSpacing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the BurstSpacing for this emitter. + // Arguments: None. + // Return value: The BurstSpacing in ms. + + float GetBurstSpacing() const { return m_BurstSpacing; } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitSpread + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the angle spread of velocity of the emitted MO's to each side of + // the angle of emission of this AEmitter. + // Arguments: None. + // Return value: A float with the spread in r's. PI/2 would mean that MO's fly out to + // one side only, with the m_EmitAngle defining the middle of that half + // circle. + + float GetEmitSpread() const { return m_Spread; } + + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitVelMin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the min end of the range the velocity of a particle being emitted + // by this AEmitter can have. + // Arguments: None. + // Return value: A float with the min vel possible for an emitted particle. + + float GetEmitVelMin() const { return m_MinVelocity; } + + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitVelMax + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the max end of the range the velocity of a particle being emitted + // by this AEmitter can have. + // Arguments: None. + // Return value: A float with the max vel possible for an emitted particle. + + float GetEmitVelMax() const { return m_MaxVelocity; } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetThrottle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the normalized throttle scalar which controls how to affect the + // emission rate as per the emisison rate range. Depricated for Lua, use + // the Throttle property instead. + // Arguments: None. + // Return value: A float with the normalized throttle scalar. 1.0 means max throttle, + // 0 means normal, -1.0 means least emission rate. + + float GetThrottle() const { return m_Throttle; } + + /// + /// Gets the adjusted throttle multiplier that is factored into the emission rate of this AEmitter. + /// + /// The throttle strength as a multiplier. + float GetThrottleFactor() const { return LERP(-1.0f, 1.0f, m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, m_Throttle); } + + /// + /// Gets the throttle value that will achieve a given throttle factor that is factored into the emission rate of this AEmitter. + /// + /// The throttle value that will achieve the given throttle factor. + float GetThrottleForThrottleFactor(float throttleFactor) const { return LERP(m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, -1.0f, 1.0f, throttleFactor); } + + /// + /// Returns a scaled throttle value that represents a linear increase of force. + /// Because of (bad) reasons, throttle is in the range -1.0F to 1.0F, where -1.0F is "minimum force" and 1.0F is "maximum force". + /// 0.0F is "whoever the fuck knows?" force. As such, multiplying throttle by 2 does not mean twice the force emitted, instead it means "whoever the fuck knows?" additional force emitted. + /// All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. All work and no play makes Jack a dull boy. + /// ...this helper function lets us apply a scale to throttle and get a sensible result. + /// + /// The throttle value to be considered. + /// The multiplier to scale by, in terms of absolute force emitted. + /// Adjusted throttle value scaled by the multiplier value. + float GetScaledThrottle(float throttle, float multiplier) const; + + /// + /// Gets the negative throttle multiplier of this AEmitter. + /// + /// The negative throttle multiplier of this AEmitter. + float GetNegativeThrottleMultiplier() const { return m_NegativeThrottleMultiplier; } + + /// + /// Gets the positive throttle multiplier of this AEmitter. + /// + /// The positive throttle multiplier of this AEmitter. + float GetPositiveThrottleMultiplier() const { return m_PositiveThrottleMultiplier; } + + /// + /// Sets the negative throttle multiplier of this AEmitter. + /// + /// The new throttle multiplier of this AEmitter. + void SetNegativeThrottleMultiplier(float newValue) { m_NegativeThrottleMultiplier = newValue; } + + /// + /// Sets the positive throttle multiplier of this AEmitter. + /// + /// The new throttle multiplier of this AEmitter. + void SetPositiveThrottleMultiplier(float newValue) { m_PositiveThrottleMultiplier = newValue; } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitRate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the rate at which this AEmitter emits its particles. + // Arguments: A float with the rate in #/min. + // Return value: None. + + void SetEmitRate(const float rate) { m_PPM = rate; } + + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the number of particles that will be emitted in one shot upon + // a triggered burst of this AEmitter. + // Arguments: The number of emitted particles a burst should have. 0 means burst + // are disabled. + // Return value: None. + + void SetBurstCount(const int count) { m_BurstSize = count; } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the scale factor that will be applied to the regular spread and + // emission velocity to get the burst particle parameters. + // Arguments: The scale factor. + // Return value: None. + + void SetBurstScale(const float scale) { m_BurstScale = scale; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstSpacing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the BurstSpacing for this emitter. + // Arguments: The BurstSpacing in ms. + // Return value: None. + + void SetBurstSpacing(const float spacing) { m_BurstSpacing = spacing; } + + /// + /// Gets the flash of this AEmitter. + /// + /// A pointer to the AEmitter's flash. Ownership is NOT transferred! + Attachable* GetFlash() const { return m_pFlash; } + + /// + /// Sets the flash for this AEmitter. Ownership IS transferred! + /// + /// The new flash to use. + void SetFlash(Attachable* newFlash); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFlashScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the display scale factor of the flash effect. This is purely + // visual. + // Arguments: None. + // Return value: The scale factor of the flash draw. + + float GetFlashScale() const { return m_FlashScale; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFlashScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the display scale factor of the flash effect. This is purely + // visual. + // Arguments: The scale factor of the flash draw. + // Return value: None. + + void SetFlashScale(float flashScale = 1.0f) { m_FlashScale = flashScale; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the angle of direction that the emitted particles will be shot at. + // Arguments: A float with the angle in radians. + // Return value: None. + + void SetEmitAngle(const float angle) { m_EmitAngle.SetRadAngle(angle); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetThrottle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the normalized throttle scalar which controls how to affect the + // emission rate as per the emisison rate range. + // Arguments: A float with the normalized throttle scalar. 1.0 means max throttle, + // 0 means normal, -1.0 means least emission rate. + // Return value: None. + + void SetThrottle(float throttle) { m_Throttle = throttle > 1.0f ? 1.0f : (throttle < -1.0f ? -1.0f : throttle); } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitSpread + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the angle spread of velocity of the emitted MO's to each side of + // angle of emission of this AEmitter. + // Arguments: A float with the spread in r's. PI/2 would mean that MO's fly out to + // one side only, with the m_EmitAngle defining the middle of that half + // circle. + // Return value: None. + + void SetEmitSpread(const float spread) { m_Spread = spread; } + + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitVelMin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the min end of the range the velocity of a particle being emitted + // by this AEmitter can have. + // Arguments: A float with the min vel possible for an emitted particle. + // Return value: None. + + void SetEmitVelMin(const float minVel) { m_MinVelocity = minVel; } + + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitVelMax + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the max end of the range the velocity of a particle being emitted + // by this AEmitter can have. + // Arguments: A float with the max vel possible for an emitted particle. + // Return value: None. + + void SetEmitVelMax(const float maxVel) { m_MaxVelocity = maxVel; } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TriggerBurst + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Triggers a one-shot burst of emissions in the number that has + // previously been set. The burst will happen during the next Update of + // this AEmitter. + // Arguments: None. + // Return value: None. + + void TriggerBurst() { m_BurstTriggered = true; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CanTriggerBurst + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if it is possible to trigger a one-shot burst of emissions during + // the next Update of this AEmitter. + // Arguments: None. + // Return value: If it is possible to trigger a burst. + + bool CanTriggerBurst() { return m_BurstSpacing <= 0 || m_BurstTimer.IsPastSimMS(m_BurstSpacing); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsSetToBurst + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this AEmitter is set to burst next update or not. + // Arguments: None. + // Return value: Whether a burst is gonna happen or not.. + + bool IsSetToBurst() const { return m_BurstTriggered; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AlarmOnEmit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers a new AlarmEvent if this emitter has a loudness above zero. + // Arguments: Team that will ignore this AlarmEvent. + // Return value: None. + + void AlarmOnEmit(int Team) const { + if (m_LoudnessOnEmit > 0) + g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, Team, m_LoudnessOnEmit)); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. + // Arguments: None. + // Return value: None. + + void ResetAllTimers() override { + Attachable::ResetAllTimers(); + m_BurstTimer.Reset(); + m_LastEmitTmr.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + void PostUpdate() override { Attachable::PostUpdate(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBurstDamage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns burst damage of this emitter. + // Arguments: None. + // Return value: Burst damage of emitter. + + float GetBurstDamage() const { return m_BurstDamage * m_EmitterDamageMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstDamage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets burst damage of this emitter. + // Arguments: Burst damage of emitter. + // Return value: None. + + void SetBurstDamage(float newValue) { m_BurstDamage = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitDamage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns emit damage of this emitter. + // Arguments: None. + // Return value: Emit damage of emitter. + + float GetEmitDamage() const { return m_EmitDamage * m_EmitterDamageMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitDamage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets emit damage of this emitter. + // Arguments: Emit damage of emitter. + // Return value: None. + + void SetEmitDamage(float newValue) { m_EmitDamage = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitterDamageMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns damage multiplier of this emitter. + // Arguments: None. + // Return value: Damage multiplier of emitter. + + float GetEmitterDamageMultiplier() const { return m_EmitterDamageMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitterDamageMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets damage multiplier of this emitter. + // Arguments: New damage multiplier of emitter + // Return value: None. + + void SetEmitterDamageMultiplier(float newValue) { m_EmitterDamageMultiplier = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this AEmitter's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDamaging + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this emitter deals damage. + // Arguments: None. + // Return value: Returns true if this emitter deals damage. + + bool IsDamaging() { return (m_EmitDamage > 0 || m_BurstDamage > 0) && m_EmitterDamageMultiplier > 0; } + + /// + /// Gets the number of emissions emitted since emission was last enabled. + /// + /// The number of emissions emitted since emission was last enabled. + long GetEmitCount() const { return m_EmitCount; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitCountLimit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of emissions left before emitter is disabled. + // Arguments: None. + // Return value: Returns the number of emissions left before emitter is disabled. + + long GetEmitCountLimit() const { return m_EmitCountLimit; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitCountLimit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the number of emissions left before emitter is disabled. + // Arguments: New number of emissions left + // Return value: None. + + void SetEmitCountLimit(long newValue) { m_EmitCountLimit = newValue; } + + /// + /// Gets this AEmitter's emission sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this AEmitter's emission sound. + SoundContainer* GetEmissionSound() const { return m_EmissionSound; } + + /// + /// Sets this AEmitter's emission sound. Ownership IS transferred! + /// + /// The new SoundContainer for this AEmitter's emission sound. + void SetEmissionSound(SoundContainer* newSound) { m_EmissionSound = newSound; } + + /// + /// Gets this AEmitter's burst sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this AEmitter's burst sound. + SoundContainer* GetBurstSound() const { return m_BurstSound; } + + /// + /// Sets this AEmitter's burst sound. Ownership IS transferred! + /// + /// The new SoundContainer for this AEmitter's burst sound. + void SetBurstSound(SoundContainer* newSound) { m_BurstSound = newSound; } + + /// + /// Gets this AEmitter's end sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this AEmitter's end sound. + SoundContainer* GetEndSound() const { return m_EndSound; } + + /// + /// Sets this AEmitter's end sound. Ownership IS transferred! + /// + /// The new SoundContainer for this AEmitter's end sound. + void SetEndSound(SoundContainer* newSound) { m_EndSound = newSound; } + + /// + /// Returns whether this emitter just started emitting this frame. + /// + /// Whether this emitter just started emitting this frame. + bool JustStartedEmitting() const { return !m_WasEmitting && m_EmitEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + + // The list of MO instances that get emitted + std::vector m_EmissionList; + // Sounds + SoundContainer* m_EmissionSound; + SoundContainer* m_BurstSound; + SoundContainer* m_EndSound; + // Whether emitting is currently enabled or not. + bool m_EmitEnabled; + // Whether or not the it was emitting last frame or not. + bool m_WasEmitting; + // The number of emissions emitted since emission was last enabled + long m_EmitCount; + // The max number of emissions to emit per emit being enabled + long m_EmitCountLimit; + float m_NegativeThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is negative. Relative to the absolute throttle value. + float m_PositiveThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is positive. Relative to the absolute throttle value. + float m_Throttle; //!< The normalized throttle which controls the MSPE between 1.0 * m_MSPERange and -1.0 * m_MSPERange. 0 means emit the regular m_PPM amount. + // Whether or not this' emissions ignore hits with itself, even if they are set to hit other MOs. + bool m_EmissionsIgnoreThis; + // The scale factor that will be applied to the regular spread and emission + // velocity to get the the burst particle parameters. + float m_BurstScale; + // Damage dealt to the attached-to parent upon bursting. + float m_BurstDamage; + // Damage multiplier derived from penetrating particle. Affects both burst and emit damage values. + float m_EmitterDamageMultiplier; + // Indicates that a burst is set to happen during the next Update. + bool m_BurstTriggered; + // The shortest possible time between bursts, in ms + float m_BurstSpacing; + // Measures the shortest possible time between bursts + Timer m_BurstTimer; + // The angle of the direction the emitted particles will head in. + // The m_Roataion of this AEmitter will be added to this angle. + Matrix m_EmitAngle; + // Offset of the emission point from this' sprite center, which gets rotated with this + Vector m_EmissionOffset; + // The amount of damage points that this emitter collects when emitting one non-burst particle. + float m_EmitDamage; + // Timer for timing how long ago the last particle was emitted. 0 means no limit. + Timer m_LastEmitTmr; + // Emission flash Attachable + Attachable* m_pFlash; + // Flash display scale + float m_FlashScale; + // How large impulse this emitter generates when bursting + float m_AvgBurstImpulse; + // How large impulse this emitter generates when firing + float m_AvgImpulse; + // How far this is audiable (in screens) when emitting as a jetpack or craft engine + float m_LoudnessOnEmit; + // Whether to only display flash on bursts, and not on any emission frame. + bool m_FlashOnlyOnBurst; + // Whether the burst sound should always play until completion, or whether it stops when this emitter stops emitting + bool m_SustainBurstSound; + // Whether the burst sound follows the emitter + bool m_BurstSoundFollowsEmitter; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AEmitter, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + AEmitter(const AEmitter& reference) = delete; + AEmitter& operator=(const AEmitter& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index 8dcb6b7d7..8ce1510a2 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -36,2008 +35,2098 @@ namespace RTE { -ConcreteClassInfo(AHuman, Actor, 20); + ConcreteClassInfo(AHuman, Actor, 20); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AHuman, effectively + // resetting the members of this abstraction level only. + + void AHuman::Clear() { + m_pHead = 0; + m_LookToAimRatio = 0.7F; + m_pJetpack = nullptr; + m_pFGArm = 0; + m_pBGArm = 0; + m_pFGLeg = 0; + m_pBGLeg = 0; + m_pFGHandGroup = 0; + m_pBGHandGroup = 0; + m_pFGFootGroup = 0; + m_BackupFGFootGroup = nullptr; + m_pBGFootGroup = 0; + m_BackupBGFootGroup = nullptr; + m_StrideSound = nullptr; + m_ArmsState = WEAPON_READY; + m_MoveState = STAND; + m_ProneState = NOTPRONE; + m_ProneTimer.Reset(); + m_MaxWalkPathCrouchShift = 6.0F; + m_MaxCrouchRotation = c_QuarterPI * 1.25F; + m_CrouchAmountOverride = -1.0F; + for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { + m_Paths[FGROUND][i].Reset(); + m_Paths[BGROUND][i].Reset(); + m_Paths[FGROUND][i].Terminate(); + m_Paths[BGROUND][i].Terminate(); + m_RotAngleTargets[i] = 0.0F; + } + m_Aiming = false; + m_ArmClimbing[FGROUND] = false; + m_ArmClimbing[BGROUND] = false; + m_StrideFrame = false; + m_StrideStart = false; + m_CanActivateBGItem = false; + m_TriggerPulled = false; + m_WaitingToReloadOffhand = false; + m_ThrowTmr.Reset(); + m_ThrowPrepTime = 1000; + m_SharpAimRevertTimer.Reset(); + m_FGArmFlailScalar = 0.0F; + m_BGArmFlailScalar = 0.7F; + m_EquipHUDTimer.Reset(); + m_WalkAngle.fill(Matrix()); + m_WalkPathOffset.Reset(); + m_ArmSwingRate = 1.0F; + m_DeviceArmSwayRate = 0.5F; + + m_DeviceState = SCANNING; + m_SweepState = NOSWEEP; + m_DigState = NOTDIGGING; + m_JumpState = NOTJUMPING; + m_JumpTarget.Reset(); + m_JumpingRight = true; + m_Crawling = false; + m_DigTunnelEndPos.Reset(); + m_SweepCenterAimAngle = 0; + m_SweepRange = c_EighthPI; + m_DigTarget.Reset(); + m_FireTimer.Reset(); + m_SweepTimer.Reset(); + m_PatrolTimer.Reset(); + m_JumpTimer.Reset(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AHuman object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AHuman, effectively -// resetting the members of this abstraction level only. - -void AHuman::Clear() -{ - m_pHead = 0; - m_LookToAimRatio = 0.7F; - m_pJetpack = nullptr; - m_pFGArm = 0; - m_pBGArm = 0; - m_pFGLeg = 0; - m_pBGLeg = 0; - m_pFGHandGroup = 0; - m_pBGHandGroup = 0; - m_pFGFootGroup = 0; - m_BackupFGFootGroup = nullptr; - m_pBGFootGroup = 0; - m_BackupBGFootGroup = nullptr; - m_StrideSound = nullptr; - m_ArmsState = WEAPON_READY; - m_MoveState = STAND; - m_ProneState = NOTPRONE; - m_ProneTimer.Reset(); - m_MaxWalkPathCrouchShift = 6.0F; - m_MaxCrouchRotation = c_QuarterPI * 1.25F; - m_CrouchAmountOverride = -1.0F; - for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { - m_Paths[FGROUND][i].Reset(); - m_Paths[BGROUND][i].Reset(); - m_Paths[FGROUND][i].Terminate(); - m_Paths[BGROUND][i].Terminate(); - m_RotAngleTargets[i] = 0.0F; - } - m_Aiming = false; - m_ArmClimbing[FGROUND] = false; - m_ArmClimbing[BGROUND] = false; - m_StrideFrame = false; - m_StrideStart = false; - m_CanActivateBGItem = false; - m_TriggerPulled = false; - m_WaitingToReloadOffhand = false; - m_ThrowTmr.Reset(); - m_ThrowPrepTime = 1000; - m_SharpAimRevertTimer.Reset(); - m_FGArmFlailScalar = 0.0F; - m_BGArmFlailScalar = 0.7F; - m_EquipHUDTimer.Reset(); - m_WalkAngle.fill(Matrix()); - m_WalkPathOffset.Reset(); - m_ArmSwingRate = 1.0F; - m_DeviceArmSwayRate = 0.5F; - - m_DeviceState = SCANNING; - m_SweepState = NOSWEEP; - m_DigState = NOTDIGGING; - m_JumpState = NOTJUMPING; - m_JumpTarget.Reset(); - m_JumpingRight = true; - m_Crawling = false; - m_DigTunnelEndPos.Reset(); - m_SweepCenterAimAngle = 0; - m_SweepRange = c_EighthPI; - m_DigTarget.Reset(); - m_FireTimer.Reset(); - m_SweepTimer.Reset(); - m_PatrolTimer.Reset(); - m_JumpTimer.Reset(); -} + int AHuman::Create() { + if (Actor::Create() < 0) { + return -1; + } + if (m_AIMode == Actor::AIMODE_NONE) { + m_AIMode = Actor::AIMODE_BRAINHUNT; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AHuman object ready for use. + // Cheat to make sure the FG Arm is always at the end of the Attachables list so it draws last. + if (m_pFGArm) { + m_Attachables.erase(std::find(m_Attachables.begin(), m_Attachables.end(), m_pFGArm)); + m_Attachables.push_back(m_pFGArm); + } -int AHuman::Create() -{ - if (Actor::Create() < 0) { - return -1; - } + // Make the limb paths for the background limbs + for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { + // If BG path is not initalized, then copy the FG one to it + if (!m_Paths[BGROUND][i].IsInitialized()) { + m_Paths[BGROUND][i].Destroy(); + m_Paths[BGROUND][i].Create(m_Paths[FGROUND][i]); + } + } - if (m_AIMode == Actor::AIMODE_NONE) { - m_AIMode = Actor::AIMODE_BRAINHUNT; - } + // If empty-handed, equip first thing in inventory + if (m_pFGArm && m_pFGArm->IsAttached() && !m_pFGArm->GetHeldDevice()) { + m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory(nullptr, true))); + m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); + } - // Cheat to make sure the FG Arm is always at the end of the Attachables list so it draws last. - if (m_pFGArm) { - m_Attachables.erase(std::find(m_Attachables.begin(), m_Attachables.end(), m_pFGArm)); - m_Attachables.push_back(m_pFGArm); - } + // All AHumans by default avoid hitting each other ont he same team + m_IgnoresTeamHits = true; - // Make the limb paths for the background limbs - for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) - { - // If BG path is not initalized, then copy the FG one to it - if (!m_Paths[BGROUND][i].IsInitialized()) - { - m_Paths[BGROUND][i].Destroy(); - m_Paths[BGROUND][i].Create(m_Paths[FGROUND][i]); - } - } + return 0; + } - // If empty-handed, equip first thing in inventory - if (m_pFGArm && m_pFGArm->IsAttached() && !m_pFGArm->GetHeldDevice()) { - m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory(nullptr, true))); - m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AHuman to be identical to another, by deep copy. - // All AHumans by default avoid hitting each other ont he same team - m_IgnoresTeamHits = true; + int AHuman::Create(const AHuman& reference) { + if (reference.m_pBGArm) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pBGArm->GetUniqueID()); + } + if (reference.m_pBGLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pBGLeg->GetUniqueID()); + } + if (reference.m_pJetpack) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pJetpack->GetUniqueID()); + } + if (reference.m_pHead) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pHead->GetUniqueID()); + } + if (reference.m_pFGLeg) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFGLeg->GetUniqueID()); + } + if (reference.m_pFGArm) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFGArm->GetUniqueID()); + } - return 0; -} + Actor::Create(reference); + // Note - hardcoded attachable copying is organized based on desired draw order here. + if (reference.m_pBGArm) { + SetBGArm(dynamic_cast(reference.m_pBGArm->Clone())); + } + if (reference.m_pBGLeg) { + SetBGLeg(dynamic_cast(reference.m_pBGLeg->Clone())); + } + if (reference.m_pJetpack) { + SetJetpack(dynamic_cast(reference.m_pJetpack->Clone())); + } + if (reference.m_pHead) { + SetHead(dynamic_cast(reference.m_pHead->Clone())); + } + if (reference.m_pFGLeg) { + SetFGLeg(dynamic_cast(reference.m_pFGLeg->Clone())); + } + if (reference.m_pFGArm) { + SetFGArm(dynamic_cast(reference.m_pFGArm->Clone())); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AHuman to be identical to another, by deep copy. - -int AHuman::Create(const AHuman &reference) { - if (reference.m_pBGArm) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pBGArm->GetUniqueID()); } - if (reference.m_pBGLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pBGLeg->GetUniqueID()); } - if (reference.m_pJetpack) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pJetpack->GetUniqueID()); } - if (reference.m_pHead) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pHead->GetUniqueID()); } - if (reference.m_pFGLeg) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFGLeg->GetUniqueID()); } - if (reference.m_pFGArm) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFGArm->GetUniqueID()); } - - Actor::Create(reference); - - //Note - hardcoded attachable copying is organized based on desired draw order here. - if (reference.m_pBGArm) { SetBGArm(dynamic_cast(reference.m_pBGArm->Clone())); } - if (reference.m_pBGLeg) { SetBGLeg(dynamic_cast(reference.m_pBGLeg->Clone())); } - if (reference.m_pJetpack) { SetJetpack(dynamic_cast(reference.m_pJetpack->Clone())); } - if (reference.m_pHead) { SetHead(dynamic_cast(reference.m_pHead->Clone())); } - if (reference.m_pFGLeg) { SetFGLeg(dynamic_cast(reference.m_pFGLeg->Clone())); } - if (reference.m_pFGArm) { SetFGArm(dynamic_cast(reference.m_pFGArm->Clone())); } - - m_LookToAimRatio = reference.m_LookToAimRatio; - - m_ThrowPrepTime = reference.m_ThrowPrepTime; - m_WaitingToReloadOffhand = reference.m_WaitingToReloadOffhand; - m_FGArmFlailScalar = reference.m_FGArmFlailScalar; - m_BGArmFlailScalar = reference.m_BGArmFlailScalar; - m_ArmSwingRate = reference.m_ArmSwingRate; - m_DeviceArmSwayRate = reference.m_DeviceArmSwayRate; - - m_pFGHandGroup = dynamic_cast(reference.m_pFGHandGroup->Clone()); - m_pFGHandGroup->SetOwner(this); - m_pBGHandGroup = dynamic_cast(reference.m_pBGHandGroup->Clone()); - m_pBGHandGroup->SetOwner(this); - - AtomGroup *atomGroupToUseAsFootGroupFG = reference.m_pFGFootGroup ? dynamic_cast(reference.m_pFGFootGroup->Clone()) : m_pFGLeg->GetFootGroupFromFootAtomGroup(); - RTEAssert(atomGroupToUseAsFootGroupFG, "Failed to fallback to using FGFoot AtomGroup as FGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a FGFootGroup or FGLeg Foot attachable!"); - - AtomGroup *atomGroupToUseAsFootGroupBG = reference.m_pBGFootGroup ? dynamic_cast(reference.m_pBGFootGroup->Clone()) : m_pBGLeg->GetFootGroupFromFootAtomGroup();; - RTEAssert(atomGroupToUseAsFootGroupBG, "Failed to fallback to using BGFoot AtomGroup as BGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a BGFootGroup or BGLeg Foot attachable!"); - - m_pFGFootGroup = atomGroupToUseAsFootGroupFG; - m_pFGFootGroup->SetOwner(this); - m_BackupFGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupFG->Clone()); - m_BackupFGFootGroup->RemoveAllAtoms(); - m_BackupFGFootGroup->SetOwner(this); - m_BackupFGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupFG->GetLimbPos()); - m_pBGFootGroup = atomGroupToUseAsFootGroupBG; - m_pBGFootGroup->SetOwner(this); - m_BackupBGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupBG->Clone()); - m_BackupBGFootGroup->RemoveAllAtoms(); - m_BackupBGFootGroup->SetOwner(this); - m_BackupBGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupBG->GetLimbPos()); - - m_MaxWalkPathCrouchShift = reference.m_MaxWalkPathCrouchShift; - m_MaxCrouchRotation = reference.m_MaxCrouchRotation; - - if (reference.m_StrideSound) { m_StrideSound = dynamic_cast(reference.m_StrideSound->Clone()); } - - m_ArmsState = reference.m_ArmsState; - m_MoveState = reference.m_MoveState; - m_ProneState = reference.m_ProneState; - - for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { - m_Paths[FGROUND][i].Create(reference.m_Paths[FGROUND][i]); - m_Paths[BGROUND][i].Create(reference.m_Paths[BGROUND][i]); - m_RotAngleTargets[i] = reference.m_RotAngleTargets[i]; - } - - m_DeviceState = reference.m_DeviceState; - m_SweepState = reference.m_SweepState; - m_DigState = reference.m_DigState; - m_JumpState = reference.m_JumpState; - m_JumpTarget = reference.m_JumpTarget; - m_JumpingRight = reference.m_JumpingRight; - m_Crawling = reference.m_Crawling; - m_DigTunnelEndPos = reference.m_DigTunnelEndPos; - m_SweepCenterAimAngle = reference.m_SweepCenterAimAngle; - m_SweepRange = reference.m_SweepRange; - - return 0; -} + m_LookToAimRatio = reference.m_LookToAimRatio; + + m_ThrowPrepTime = reference.m_ThrowPrepTime; + m_WaitingToReloadOffhand = reference.m_WaitingToReloadOffhand; + m_FGArmFlailScalar = reference.m_FGArmFlailScalar; + m_BGArmFlailScalar = reference.m_BGArmFlailScalar; + m_ArmSwingRate = reference.m_ArmSwingRate; + m_DeviceArmSwayRate = reference.m_DeviceArmSwayRate; + + m_pFGHandGroup = dynamic_cast(reference.m_pFGHandGroup->Clone()); + m_pFGHandGroup->SetOwner(this); + m_pBGHandGroup = dynamic_cast(reference.m_pBGHandGroup->Clone()); + m_pBGHandGroup->SetOwner(this); + + AtomGroup* atomGroupToUseAsFootGroupFG = reference.m_pFGFootGroup ? dynamic_cast(reference.m_pFGFootGroup->Clone()) : m_pFGLeg->GetFootGroupFromFootAtomGroup(); + RTEAssert(atomGroupToUseAsFootGroupFG, "Failed to fallback to using FGFoot AtomGroup as FGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a FGFootGroup or FGLeg Foot attachable!"); + + AtomGroup* atomGroupToUseAsFootGroupBG = reference.m_pBGFootGroup ? dynamic_cast(reference.m_pBGFootGroup->Clone()) : m_pBGLeg->GetFootGroupFromFootAtomGroup(); + ; + RTEAssert(atomGroupToUseAsFootGroupBG, "Failed to fallback to using BGFoot AtomGroup as BGFootGroup in preset " + this->GetModuleAndPresetName() + "!\nPlease define a BGFootGroup or BGLeg Foot attachable!"); + + m_pFGFootGroup = atomGroupToUseAsFootGroupFG; + m_pFGFootGroup->SetOwner(this); + m_BackupFGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupFG->Clone()); + m_BackupFGFootGroup->RemoveAllAtoms(); + m_BackupFGFootGroup->SetOwner(this); + m_BackupFGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupFG->GetLimbPos()); + m_pBGFootGroup = atomGroupToUseAsFootGroupBG; + m_pBGFootGroup->SetOwner(this); + m_BackupBGFootGroup = dynamic_cast(atomGroupToUseAsFootGroupBG->Clone()); + m_BackupBGFootGroup->RemoveAllAtoms(); + m_BackupBGFootGroup->SetOwner(this); + m_BackupBGFootGroup->SetLimbPos(atomGroupToUseAsFootGroupBG->GetLimbPos()); + + m_MaxWalkPathCrouchShift = reference.m_MaxWalkPathCrouchShift; + m_MaxCrouchRotation = reference.m_MaxCrouchRotation; + + if (reference.m_StrideSound) { + m_StrideSound = dynamic_cast(reference.m_StrideSound->Clone()); + } + m_ArmsState = reference.m_ArmsState; + m_MoveState = reference.m_MoveState; + m_ProneState = reference.m_ProneState; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int AHuman::ReadProperty(const std::string_view &propName, Reader &reader) { - StartPropertyList(return Actor::ReadProperty(propName, reader)); - - MatchProperty("ThrowPrepTime", { reader >> m_ThrowPrepTime; }); - MatchProperty("Head", { SetHead(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("LookToAimRatio", { reader >> m_LookToAimRatio; }); - MatchProperty("Jetpack", { SetJetpack(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("FGArmFlailScalar", { reader >> m_FGArmFlailScalar; }); - MatchProperty("BGArmFlailScalar", { reader >> m_BGArmFlailScalar; }); - MatchProperty("ArmSwingRate", { reader >> m_ArmSwingRate; }); - MatchProperty("DeviceArmSwayRate", { reader >> m_DeviceArmSwayRate; }); - MatchProperty("FGArm", { SetFGArm(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("BGArm", { SetBGArm(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("FGLeg", { SetFGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("BGLeg", { SetBGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("HandGroup", { - delete m_pFGHandGroup; - delete m_pBGHandGroup; - m_pFGHandGroup = new AtomGroup(); - m_pBGHandGroup = new AtomGroup(); - reader >> m_pFGHandGroup; - m_pBGHandGroup->Create(*m_pFGHandGroup); - m_pFGHandGroup->SetOwner(this); - m_pBGHandGroup->SetOwner(this); - }); - MatchProperty("FGFootGroup", { - delete m_pFGFootGroup; - m_pFGFootGroup = new AtomGroup(); - reader >> m_pFGFootGroup; - m_pFGFootGroup->SetOwner(this); - m_BackupFGFootGroup = new AtomGroup(*m_pFGFootGroup); - m_BackupFGFootGroup->RemoveAllAtoms(); - }); - MatchProperty("BGFootGroup", { - delete m_pBGFootGroup; - m_pBGFootGroup = new AtomGroup(); - reader >> m_pBGFootGroup; - m_pBGFootGroup->SetOwner(this); - m_BackupBGFootGroup = new AtomGroup(*m_pBGFootGroup); - m_BackupBGFootGroup->RemoveAllAtoms(); - }); - MatchProperty("MaxWalkPathCrouchShift", { reader >> m_MaxWalkPathCrouchShift; }); - MatchProperty("MaxCrouchRotation", { reader >> m_MaxCrouchRotation; }); - MatchProperty("StrideSound", { - m_StrideSound = new SoundContainer; - reader >> m_StrideSound; - }); - MatchProperty("StandLimbPath", { reader >> m_Paths[FGROUND][STAND]; }); - MatchProperty("StandLimbPathBG", { reader >> m_Paths[BGROUND][STAND]; }); - MatchProperty("WalkLimbPath", { reader >> m_Paths[FGROUND][WALK]; }); - MatchProperty("CrouchLimbPath", { reader >> m_Paths[FGROUND][CROUCH]; }); - MatchProperty("CrouchLimbPathBG", { reader >> m_Paths[BGROUND][CROUCH]; }); - MatchProperty("CrawlLimbPath", { reader >> m_Paths[FGROUND][CRAWL]; }); - MatchProperty("ArmCrawlLimbPath", { reader >> m_Paths[FGROUND][ARMCRAWL]; }); - MatchProperty("ClimbLimbPath", { reader >> m_Paths[FGROUND][CLIMB]; }); - MatchProperty("JumpLimbPath", { reader >> m_Paths[FGROUND][JUMP]; }); - MatchProperty("DislodgeLimbPath", { reader >> m_Paths[FGROUND][DISLODGE]; }); - MatchProperty("StandRotAngleTarget", { reader >> m_RotAngleTargets[STAND]; }); - MatchProperty("WalkRotAngleTarget", { reader >> m_RotAngleTargets[WALK]; }); - MatchProperty("CrouchRotAngleTarget", { reader >> m_RotAngleTargets[CROUCH]; }); - MatchProperty("JumpRotAngleTarget", { reader >> m_RotAngleTargets[JUMP]; }); - - - EndPropertyList; -} + for (int i = 0; i < MOVEMENTSTATECOUNT; ++i) { + m_Paths[FGROUND][i].Create(reference.m_Paths[FGROUND][i]); + m_Paths[BGROUND][i].Create(reference.m_Paths[BGROUND][i]); + m_RotAngleTargets[i] = reference.m_RotAngleTargets[i]; + } + m_DeviceState = reference.m_DeviceState; + m_SweepState = reference.m_SweepState; + m_DigState = reference.m_DigState; + m_JumpState = reference.m_JumpState; + m_JumpTarget = reference.m_JumpTarget; + m_JumpingRight = reference.m_JumpingRight; + m_Crawling = reference.m_Crawling; + m_DigTunnelEndPos = reference.m_DigTunnelEndPos; + m_SweepCenterAimAngle = reference.m_SweepCenterAimAngle; + m_SweepRange = reference.m_SweepRange; + + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this AHuman with a Writer for -// later recreation with Create(Reader &reader); - -int AHuman::Save(Writer &writer) const -{ - Actor::Save(writer); - - writer.NewProperty("ThrowPrepTime"); - writer << m_ThrowPrepTime; - writer.NewProperty("Head"); - writer << m_pHead; - writer.NewProperty("LookToAimRatio"); - writer << m_LookToAimRatio; - writer.NewProperty("Jetpack"); - writer << m_pJetpack; - writer.NewProperty("FGArmFlailScalar"); - writer << m_FGArmFlailScalar; - writer.NewProperty("BGArmFlailScalar"); - writer << m_BGArmFlailScalar; - writer.NewProperty("ArmSwingRate"); - writer << m_ArmSwingRate; - writer.NewPropertyWithValue("DeviceArmSwayRate", m_DeviceArmSwayRate); - writer.NewProperty("FGArm"); - writer << m_pFGArm; - writer.NewProperty("BGArm"); - writer << m_pBGArm; - writer.NewProperty("FGLeg"); - writer << m_pFGLeg; - writer.NewProperty("BGLeg"); - writer << m_pBGLeg; - writer.NewProperty("HandGroup"); - writer << m_pFGHandGroup; - writer.NewProperty("FGFootGroup"); - writer << m_pFGFootGroup; - writer.NewProperty("BGFootGroup"); - writer << m_pBGFootGroup; - writer.NewProperty("MaxWalkPathCrouchShift"); - writer << m_MaxWalkPathCrouchShift; - writer.NewProperty("MaxCrouchRotation"); - writer << m_MaxCrouchRotation; - writer.NewProperty("StrideSound"); - writer << m_StrideSound; - - writer.NewProperty("StandLimbPath"); - writer << m_Paths[FGROUND][STAND]; - writer.NewProperty("StandLimbPathBG"); - writer << m_Paths[BGROUND][STAND]; - writer.NewProperty("WalkLimbPath"); - writer << m_Paths[FGROUND][WALK]; - writer.NewProperty("CrouchLimbPath"); - writer << m_Paths[FGROUND][CROUCH]; - writer.NewProperty("CrawlLimbPath"); - writer << m_Paths[FGROUND][CRAWL]; - writer.NewProperty("ArmCrawlLimbPath"); - writer << m_Paths[FGROUND][ARMCRAWL]; - writer.NewProperty("ClimbLimbPath"); - writer << m_Paths[FGROUND][CLIMB]; - writer.NewProperty("JumpLimbPath"); - writer << m_Paths[FGROUND][JUMP]; - writer.NewProperty("DislodgeLimbPath"); - writer << m_Paths[FGROUND][DISLODGE]; - - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int AHuman::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Actor::ReadProperty(propName, reader)); + + MatchProperty("ThrowPrepTime", { reader >> m_ThrowPrepTime; }); + MatchProperty("Head", { SetHead(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("LookToAimRatio", { reader >> m_LookToAimRatio; }); + MatchProperty("Jetpack", { SetJetpack(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("FGArmFlailScalar", { reader >> m_FGArmFlailScalar; }); + MatchProperty("BGArmFlailScalar", { reader >> m_BGArmFlailScalar; }); + MatchProperty("ArmSwingRate", { reader >> m_ArmSwingRate; }); + MatchProperty("DeviceArmSwayRate", { reader >> m_DeviceArmSwayRate; }); + MatchProperty("FGArm", { SetFGArm(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("BGArm", { SetBGArm(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("FGLeg", { SetFGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("BGLeg", { SetBGLeg(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("HandGroup", { + delete m_pFGHandGroup; + delete m_pBGHandGroup; + m_pFGHandGroup = new AtomGroup(); + m_pBGHandGroup = new AtomGroup(); + reader >> m_pFGHandGroup; + m_pBGHandGroup->Create(*m_pFGHandGroup); + m_pFGHandGroup->SetOwner(this); + m_pBGHandGroup->SetOwner(this); + }); + MatchProperty("FGFootGroup", { + delete m_pFGFootGroup; + m_pFGFootGroup = new AtomGroup(); + reader >> m_pFGFootGroup; + m_pFGFootGroup->SetOwner(this); + m_BackupFGFootGroup = new AtomGroup(*m_pFGFootGroup); + m_BackupFGFootGroup->RemoveAllAtoms(); + }); + MatchProperty("BGFootGroup", { + delete m_pBGFootGroup; + m_pBGFootGroup = new AtomGroup(); + reader >> m_pBGFootGroup; + m_pBGFootGroup->SetOwner(this); + m_BackupBGFootGroup = new AtomGroup(*m_pBGFootGroup); + m_BackupBGFootGroup->RemoveAllAtoms(); + }); + MatchProperty("MaxWalkPathCrouchShift", { reader >> m_MaxWalkPathCrouchShift; }); + MatchProperty("MaxCrouchRotation", { reader >> m_MaxCrouchRotation; }); + MatchProperty("StrideSound", { + m_StrideSound = new SoundContainer; + reader >> m_StrideSound; + }); + MatchProperty("StandLimbPath", { reader >> m_Paths[FGROUND][STAND]; }); + MatchProperty("StandLimbPathBG", { reader >> m_Paths[BGROUND][STAND]; }); + MatchProperty("WalkLimbPath", { reader >> m_Paths[FGROUND][WALK]; }); + MatchProperty("CrouchLimbPath", { reader >> m_Paths[FGROUND][CROUCH]; }); + MatchProperty("CrouchLimbPathBG", { reader >> m_Paths[BGROUND][CROUCH]; }); + MatchProperty("CrawlLimbPath", { reader >> m_Paths[FGROUND][CRAWL]; }); + MatchProperty("ArmCrawlLimbPath", { reader >> m_Paths[FGROUND][ARMCRAWL]; }); + MatchProperty("ClimbLimbPath", { reader >> m_Paths[FGROUND][CLIMB]; }); + MatchProperty("JumpLimbPath", { reader >> m_Paths[FGROUND][JUMP]; }); + MatchProperty("DislodgeLimbPath", { reader >> m_Paths[FGROUND][DISLODGE]; }); + MatchProperty("StandRotAngleTarget", { reader >> m_RotAngleTargets[STAND]; }); + MatchProperty("WalkRotAngleTarget", { reader >> m_RotAngleTargets[WALK]; }); + MatchProperty("CrouchRotAngleTarget", { reader >> m_RotAngleTargets[CROUCH]; }); + MatchProperty("JumpRotAngleTarget", { reader >> m_RotAngleTargets[JUMP]; }); + + EndPropertyList; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this AHuman with a Writer for + // later recreation with Create(Reader &reader); + + int AHuman::Save(Writer& writer) const { + Actor::Save(writer); + + writer.NewProperty("ThrowPrepTime"); + writer << m_ThrowPrepTime; + writer.NewProperty("Head"); + writer << m_pHead; + writer.NewProperty("LookToAimRatio"); + writer << m_LookToAimRatio; + writer.NewProperty("Jetpack"); + writer << m_pJetpack; + writer.NewProperty("FGArmFlailScalar"); + writer << m_FGArmFlailScalar; + writer.NewProperty("BGArmFlailScalar"); + writer << m_BGArmFlailScalar; + writer.NewProperty("ArmSwingRate"); + writer << m_ArmSwingRate; + writer.NewPropertyWithValue("DeviceArmSwayRate", m_DeviceArmSwayRate); + writer.NewProperty("FGArm"); + writer << m_pFGArm; + writer.NewProperty("BGArm"); + writer << m_pBGArm; + writer.NewProperty("FGLeg"); + writer << m_pFGLeg; + writer.NewProperty("BGLeg"); + writer << m_pBGLeg; + writer.NewProperty("HandGroup"); + writer << m_pFGHandGroup; + writer.NewProperty("FGFootGroup"); + writer << m_pFGFootGroup; + writer.NewProperty("BGFootGroup"); + writer << m_pBGFootGroup; + writer.NewProperty("MaxWalkPathCrouchShift"); + writer << m_MaxWalkPathCrouchShift; + writer.NewProperty("MaxCrouchRotation"); + writer << m_MaxCrouchRotation; + writer.NewProperty("StrideSound"); + writer << m_StrideSound; + + writer.NewProperty("StandLimbPath"); + writer << m_Paths[FGROUND][STAND]; + writer.NewProperty("StandLimbPathBG"); + writer << m_Paths[BGROUND][STAND]; + writer.NewProperty("WalkLimbPath"); + writer << m_Paths[FGROUND][WALK]; + writer.NewProperty("CrouchLimbPath"); + writer << m_Paths[FGROUND][CROUCH]; + writer.NewProperty("CrawlLimbPath"); + writer << m_Paths[FGROUND][CRAWL]; + writer.NewProperty("ArmCrawlLimbPath"); + writer << m_Paths[FGROUND][ARMCRAWL]; + writer.NewProperty("ClimbLimbPath"); + writer << m_Paths[FGROUND][CLIMB]; + writer.NewProperty("JumpLimbPath"); + writer << m_Paths[FGROUND][JUMP]; + writer.NewProperty("DislodgeLimbPath"); + writer << m_Paths[FGROUND][DISLODGE]; + + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AHuman object. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AHuman object. -void AHuman::Destroy(bool notInherited) { - delete m_pFGHandGroup; - delete m_pBGHandGroup; - delete m_pFGFootGroup; - delete m_pBGFootGroup; + void AHuman::Destroy(bool notInherited) { + delete m_pFGHandGroup; + delete m_pBGHandGroup; + delete m_pFGFootGroup; + delete m_pBGFootGroup; - delete m_StrideSound; + delete m_StrideSound; - if (!notInherited) { Actor::Destroy(); } - Clear(); -} + if (!notInherited) { + Actor::Destroy(); + } + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this Actor and all its carried + // gold and inventory. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this Actor and all its carried -// gold and inventory. + float AHuman::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const { + float totalValue = Actor::GetTotalValue(nativeModule, foreignMult, nativeMult); -float AHuman::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const -{ - float totalValue = Actor::GetTotalValue(nativeModule, foreignMult, nativeMult); + // If holding something, then add its value, too + if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) + totalValue += m_pFGArm->GetHeldDevice()->GetTotalValue(nativeModule, foreignMult, nativeMult); - // If holding something, then add its value, too - if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) - totalValue += m_pFGArm->GetHeldDevice()->GetTotalValue(nativeModule, foreignMult, nativeMult); + return totalValue; + } - return totalValue; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this carries a specifically named object in its inventory. + // Also looks through the inventories of potential passengers, as applicable. + bool AHuman::HasObject(std::string objectName) const { + bool found = Actor::HasObject(objectName); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this carries a specifically named object in its inventory. -// Also looks through the inventories of potential passengers, as applicable. + // If holding something, then check that too + if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) + found = found || m_pFGArm->GetHeldDevice()->HasObject(objectName); + if (m_pBGArm && m_pBGArm->IsAttached() && m_pBGArm->GetHeldDevice()) + found = found || m_pBGArm->GetHeldDevice()->HasObject(objectName); -bool AHuman::HasObject(std::string objectName) const -{ - bool found = Actor::HasObject(objectName); + return found; + } - // If holding something, then check that too - if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) - found = found || m_pFGArm->GetHeldDevice()->HasObject(objectName); - if (m_pBGArm && m_pBGArm->IsAttached() && m_pBGArm->GetHeldDevice()) - found = found || m_pBGArm->GetHeldDevice()->HasObject(objectName); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObjectInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically grouped object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. - return found; -} + bool AHuman::HasObjectInGroup(std::string groupName) const { + bool found = Actor::HasObjectInGroup(groupName); + // If holding something, then check that too + if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) + found = found || m_pFGArm->GetHeldDevice()->HasObjectInGroup(groupName); + if (m_pBGArm && m_pBGArm->IsAttached() && m_pBGArm->GetHeldDevice()) + found = found || m_pBGArm->GetHeldDevice()->HasObjectInGroup(groupName); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObjectInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically grouped object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. + return found; + } -bool AHuman::HasObjectInGroup(std::string groupName) const -{ - bool found = Actor::HasObjectInGroup(groupName); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetCPUPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' brain, or equivalent. - // If holding something, then check that too - if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) - found = found || m_pFGArm->GetHeldDevice()->HasObjectInGroup(groupName); - if (m_pBGArm && m_pBGArm->IsAttached() && m_pBGArm->GetHeldDevice()) - found = found || m_pBGArm->GetHeldDevice()->HasObjectInGroup(groupName); + Vector AHuman::GetCPUPos() const { + if (m_pHead && m_pHead->IsAttached()) + return m_Pos + ((m_pHead->GetParentOffset().GetXFlipped(m_HFlipped) * m_Rotation) * 1.5); - return found; -} + return m_Pos; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEyePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' eye, or equivalent, where look + // vector starts from. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetCPUPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' brain, or equivalent. + Vector AHuman::GetEyePos() const { + if (m_pHead && m_pHead->IsAttached()) { + return m_Pos + m_pHead->GetParentOffset() * 1.2F; + } -Vector AHuman::GetCPUPos() const -{ - if (m_pHead && m_pHead->IsAttached()) - return m_Pos + ((m_pHead->GetParentOffset().GetXFlipped(m_HFlipped) * m_Rotation) * 1.5); + return m_Pos; + } - return m_Pos; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEyePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' eye, or equivalent, where look -// vector starts from. + void AHuman::SetHead(Attachable* newHead) { + if (m_pHead && m_pHead->IsAttached()) { + RemoveAndDeleteAttachable(m_pHead); + } + if (newHead == nullptr) { + m_pHead = nullptr; + } else { + m_pHead = newHead; + AddAttachable(newHead); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newHead->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + dynamic_cast(parent)->SetHead(attachable); + }}); -Vector AHuman::GetEyePos() const -{ - if (m_pHead && m_pHead->IsAttached()) { - return m_Pos + m_pHead->GetParentOffset() * 1.2F; + if (m_pHead->HasNoSetDamageMultiplier()) { + m_pHead->SetDamageMultiplier(4.0F); + } + if (m_pHead->IsDrawnAfterParent()) { + m_pHead->SetDrawnNormallyByParent(false); + } + m_pHead->SetInheritsRotAngle(false); + } } - return m_Pos; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void AHuman::SetHead(Attachable *newHead) { - if (m_pHead && m_pHead->IsAttached()) { RemoveAndDeleteAttachable(m_pHead); } - if (newHead == nullptr) { - m_pHead = nullptr; - } else { - m_pHead = newHead; - AddAttachable(newHead); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newHead->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - dynamic_cast(parent)->SetHead(attachable); - }}); - - if (m_pHead->HasNoSetDamageMultiplier()) { m_pHead->SetDamageMultiplier(4.0F); } - if (m_pHead->IsDrawnAfterParent()) { m_pHead->SetDrawnNormallyByParent(false); } - m_pHead->SetInheritsRotAngle(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void AHuman::SetJetpack(AEJetpack *newJetpack) { - if (m_pJetpack && m_pJetpack->IsAttached()) { RemoveAndDeleteAttachable(m_pJetpack); } - if (newJetpack == nullptr) { - m_pJetpack = nullptr; - } else { - m_pJetpack = newJetpack; - AddAttachable(newJetpack); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newJetpack->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - AEJetpack *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetJetpack"); - dynamic_cast(parent)->SetJetpack(castedAttachable); - }}); - - if (m_pJetpack->HasNoSetDamageMultiplier()) { m_pJetpack->SetDamageMultiplier(0.0F); } - m_pJetpack->SetApplyTransferredForcesAtOffset(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void AHuman::SetFGArm(Arm *newArm) { - if (m_pFGArm && m_pFGArm->IsAttached()) { RemoveAndDeleteAttachable(m_pFGArm); } - if (newArm == nullptr) { - m_pFGArm = nullptr; - } else { - m_pFGArm = newArm; - AddAttachable(newArm); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newArm->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Arm *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetFGArm"); - dynamic_cast(parent)->SetFGArm(castedAttachable); - }}); - - if (m_pFGArm->HasNoSetDamageMultiplier()) { m_pFGArm->SetDamageMultiplier(1.0F); } - m_pFGArm->SetDrawnAfterParent(true); - m_pFGArm->SetDrawnNormallyByParent(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void AHuman::SetBGArm(Arm *newArm) { - if (m_pBGArm && m_pBGArm->IsAttached()) { RemoveAndDeleteAttachable(m_pBGArm); } - if (newArm == nullptr) { - m_pBGArm = nullptr; - } else { - m_pBGArm = newArm; - AddAttachable(newArm); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newArm->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Arm *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetBGArm"); - dynamic_cast(parent)->SetBGArm(castedAttachable); - }}); - - if (m_pBGArm->HasNoSetDamageMultiplier()) { m_pBGArm->SetDamageMultiplier(1.0F); } - m_pBGArm->SetDrawnAfterParent(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void AHuman::SetFGLeg(Leg *newLeg) { - if (m_pFGLeg && m_pFGLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pFGLeg); } - if (newLeg == nullptr) { - m_pFGLeg = nullptr; - } else { - m_pFGLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetFGLeg"); - dynamic_cast(parent)->SetFGLeg(castedAttachable); - }}); - - if (m_pFGLeg->HasNoSetDamageMultiplier()) { m_pFGLeg->SetDamageMultiplier(1.0F); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void AHuman::SetBGLeg(Leg *newLeg) { - if (m_pBGLeg && m_pBGLeg->IsAttached()) { RemoveAndDeleteAttachable(m_pBGLeg); } - if (newLeg == nullptr) { - m_pBGLeg = nullptr; - } else { - m_pBGLeg = newLeg; - AddAttachable(newLeg); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Leg *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetBGLeg"); - dynamic_cast(parent)->SetBGLeg(castedAttachable); - }}); - - if (m_pBGLeg->HasNoSetDamageMultiplier()) { m_pBGLeg->SetDamageMultiplier(1.0F); } - m_pBGLeg->SetDrawnAfterParent(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -BITMAP * AHuman::GetGraphicalIcon() const { - return m_GraphicalIcon ? m_GraphicalIcon : (m_pHead ? m_pHead->GetSpriteFrame(0) : GetSpriteFrame(0)); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void AHuman::SetJetpack(AEJetpack* newJetpack) { + if (m_pJetpack && m_pJetpack->IsAttached()) { + RemoveAndDeleteAttachable(m_pJetpack); + } + if (newJetpack == nullptr) { + m_pJetpack = nullptr; + } else { + m_pJetpack = newJetpack; + AddAttachable(newJetpack); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. - -bool AHuman::CollideAtPoint(HitData &hd) -{ - return Actor::CollideAtPoint(hd); - -/* - hd.ResImpulse[HITOR].Reset(); - hd.ResImpulse[HITEE].Reset(); - hd.HitRadius[HITEE] = (hd.HitPoint - m_Pos) * c_MPP; - hd.mass[HITEE] = m_Mass; - hd.MomInertia[HITEE] = m_pAtomGroup->GetMomentOfInertia(); - hd.HitVel[HITEE] = m_Vel + hd.HitRadius[HITEE].GetPerpendicular() * m_AngularVel; - hd.VelDiff = hd.HitVel[HITOR] - hd.HitVel[HITEE]; - Vector hitAcc = -hd.VelDiff * (1 + hd.Body[HITOR]->GetMaterial().restitution * GetMaterial().restitution); - - float hittorLever = hd.HitRadius[HITOR].GetPerpendicular().Dot(hd.BitmapNormal); - float hitteeLever = hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.BitmapNormal); - hittorLever *= hittorLever; - hitteeLever *= hitteeLever; - float impulse = hitAcc.Dot(hd.BitmapNormal) / (((1 / hd.mass[HITOR]) + (1 / hd.mass[HITEE])) + - (hittorLever / hd.MomInertia[HITOR]) + (hitteeLever / hd.MomInertia[HITEE])); - - hd.ResImpulse[HITOR] = hd.BitmapNormal * impulse * hd.ImpulseFactor[HITOR]; - hd.ResImpulse[HITEE] = hd.BitmapNormal * -impulse * hd.ImpulseFactor[HITEE]; - - //////////////////////////////////////////////////////////////////////////////// - // If a particle, which does not penetrate, but bounces, do any additional - // effects of that bounce. - if (!ParticlePenetration()) -// TODO: Add blunt trauma effects here!") - ; - } - - m_Vel += hd.ResImpulse[HITEE] / hd.mass[HITEE]; - m_AngularVel += hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.ResImpulse[HITEE]) / - hd.MomInertia[HITEE]; -*/ -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnBounce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// bounces off of something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. + m_HardcodedAttachableUniqueIDsAndSetters.insert({newJetpack->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + AEJetpack* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetJetpack"); + dynamic_cast(parent)->SetJetpack(castedAttachable); + }}); -bool AHuman::OnBounce(const Vector &pos) -{ - return false; -} + if (m_pJetpack->HasNoSetDamageMultiplier()) { + m_pJetpack->SetDamageMultiplier(0.0F); + } + m_pJetpack->SetApplyTransferredForcesAtOffset(false); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnSink -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// sink into something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. - -bool AHuman::OnSink(const Vector &pos) -{ - return false; -} -*/ - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool AHuman::HandlePieCommand(PieSlice::SliceType pieSliceIndex) { - if (pieSliceIndex != PieSlice::SliceType::NoType) { - if (pieSliceIndex == PieSlice::SliceType::Pickup) { - m_Controller.SetState(WEAPON_PICKUP); - } else if (pieSliceIndex == PieSlice::SliceType::Drop) { - m_Controller.SetState(WEAPON_DROP); - } else if (pieSliceIndex == PieSlice::SliceType::Reload) { - m_Controller.SetState(WEAPON_RELOAD); - } else if (pieSliceIndex == PieSlice::SliceType::NextItem) { - m_Controller.SetState(WEAPON_CHANGE_NEXT, true); - } else if (pieSliceIndex == PieSlice::SliceType::PreviousItem) { - m_Controller.SetState(WEAPON_CHANGE_PREV, true); - } else if (pieSliceIndex == PieSlice::SliceType::Sentry) { - m_AIMode = AIMODE_SENTRY; - } else if (pieSliceIndex == PieSlice::SliceType::Patrol) { - m_AIMode = AIMODE_PATROL; - } else if (pieSliceIndex == PieSlice::SliceType::BrainHunt) { - m_AIMode = AIMODE_BRAINHUNT; - ClearAIWaypoints(); - } else if (pieSliceIndex == PieSlice::SliceType::GoTo) { - m_AIMode = AIMODE_GOTO; - ClearAIWaypoints(); - m_UpdateMovePath = true; - } else if (pieSliceIndex == PieSlice::SliceType::GoldDig) { - m_AIMode = AIMODE_GOLDDIG; - } else { - return Actor::HandlePieCommand(pieSliceIndex); - } - } - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void AHuman::SetFGArm(Arm* newArm) { + if (m_pFGArm && m_pFGArm->IsAttached()) { + RemoveAndDeleteAttachable(m_pFGArm); + } + if (newArm == nullptr) { + m_pFGArm = nullptr; + } else { + m_pFGArm = newArm; + AddAttachable(newArm); + m_HardcodedAttachableUniqueIDsAndSetters.insert({newArm->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Arm* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetFGArm"); + dynamic_cast(parent)->SetFGArm(castedAttachable); + }}); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: AddInventoryItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an inventory item to this AHuman. This also puts that item -// directly in the hands of this if they are empty. - -void AHuman::AddInventoryItem(MovableObject *pItemToAdd) { - // If we have nothing in inventory, and nothing in our hands, just grab this first thing added to us. - if (HeldDevice *itemToAddAsHeldDevice = dynamic_cast(pItemToAdd); itemToAddAsHeldDevice && m_Inventory.empty() && m_pFGArm && m_pFGArm->IsAttached() && !m_pFGArm->GetHeldDevice()) { - m_pFGArm->SetHeldDevice(itemToAddAsHeldDevice); - m_pFGArm->SetHandPos(m_HolsterOffset.GetXFlipped(m_HFlipped)); - } else { - Actor::AddInventoryItem(pItemToAdd); + if (m_pFGArm->HasNoSetDamageMultiplier()) { + m_pFGArm->SetDamageMultiplier(1.0F); + } + m_pFGArm->SetDrawnAfterParent(true); + m_pFGArm->SetDrawnNormallyByParent(false); + } } - EquipShieldInBGArm(); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void AHuman::SetBGArm(Arm* newArm) { + if (m_pBGArm && m_pBGArm->IsAttached()) { + RemoveAndDeleteAttachable(m_pBGArm); + } + if (newArm == nullptr) { + m_pBGArm = nullptr; + } else { + m_pBGArm = newArm; + AddAttachable(newArm); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m_HardcodedAttachableUniqueIDsAndSetters.insert({newArm->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Arm* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetBGArm"); + dynamic_cast(parent)->SetBGArm(castedAttachable); + }}); -MovableObject * AHuman::SwapNextInventory(MovableObject *inventoryItemToSwapIn, bool muteSound) { - MovableObject *swappedInventoryItem = Actor::SwapNextInventory(inventoryItemToSwapIn, muteSound); - while (!dynamic_cast(swappedInventoryItem) && !m_Inventory.empty()) { - g_MovableMan.AddMO(swappedInventoryItem); - swappedInventoryItem = Actor::SwapNextInventory(nullptr, muteSound); + if (m_pBGArm->HasNoSetDamageMultiplier()) { + m_pBGArm->SetDamageMultiplier(1.0F); + } + m_pBGArm->SetDrawnAfterParent(false); + } } - return swappedInventoryItem; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void AHuman::SetFGLeg(Leg* newLeg) { + if (m_pFGLeg && m_pFGLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pFGLeg); + } + if (newLeg == nullptr) { + m_pFGLeg = nullptr; + } else { + m_pFGLeg = newLeg; + AddAttachable(newLeg); -MovableObject * AHuman::SwapPrevInventory(MovableObject *inventoryItemToSwapIn) { - MovableObject *swappedInventoryItem = Actor::SwapPrevInventory(inventoryItemToSwapIn); - while (!dynamic_cast(swappedInventoryItem) && !m_Inventory.empty()) { - g_MovableMan.AddMO(swappedInventoryItem); - swappedInventoryItem = Actor::SwapNextInventory(nullptr); - } + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetFGLeg"); + dynamic_cast(parent)->SetFGLeg(castedAttachable); + }}); - return swappedInventoryItem; -} + if (m_pFGLeg->HasNoSetDamageMultiplier()) { + m_pFGLeg->SetDamageMultiplier(1.0F); + } + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void AHuman::SetBGLeg(Leg* newLeg) { + if (m_pBGLeg && m_pBGLeg->IsAttached()) { + RemoveAndDeleteAttachable(m_pBGLeg); + } + if (newLeg == nullptr) { + m_pBGLeg = nullptr; + } else { + m_pBGLeg = newLeg; + AddAttachable(newLeg); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipFirearm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found firearm -// in the inventory. If the held device already is a firearm, or no -// firearm is in inventory, nothing happens. + m_HardcodedAttachableUniqueIDsAndSetters.insert({newLeg->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Leg* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetBGLeg"); + dynamic_cast(parent)->SetBGLeg(castedAttachable); + }}); -bool AHuman::EquipFirearm(bool doEquip) -{ - if (!(m_pFGArm && m_pFGArm->IsAttached())) { - return false; + if (m_pBGLeg->HasNoSetDamageMultiplier()) { + m_pBGLeg->SetDamageMultiplier(1.0F); + } + m_pBGLeg->SetDrawnAfterParent(false); + } } - if (HDFirearm *heldDeviceAsFirearm = dynamic_cast(m_pFGArm->GetHeldDevice()); heldDeviceAsFirearm && heldDeviceAsFirearm->IsWeapon()) { - return true; - } else { - UnequipBGArm(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + BITMAP* AHuman::GetGraphicalIcon() const { + return m_GraphicalIcon ? m_GraphicalIcon : (m_pHead ? m_pHead->GetSpriteFrame(0) : GetSpriteFrame(0)); } - // Go through the inventory looking for the proper device - for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - HDFirearm *pWeapon = dynamic_cast(*itr); - // Found proper device to equip, so make the switch! - if (pWeapon && pWeapon->IsWeapon()) - { - if (doEquip) - { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - - // Put back into the inventory what we had in our hands, if anything - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice()) { - heldDevice->Deactivate(); - AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); - } - - // Now put the device we were looking for and found into the hand - m_pFGArm->SetHeldDevice(pWeapon); - // Move the hand to a poisition so it looks like the new device was drawn from inventory - m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); - - // Equip shield in BG arm if applicable - EquipShieldInBGArm(); - - // Play the device switching sound - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } - } - - return true; - } - } - - return false; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipDeviceInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found device -// of the specified group in the inventory. If the held device already -// is of that group, or no device is in inventory, nothing happens. + bool AHuman::CollideAtPoint(HitData& hd) { + return Actor::CollideAtPoint(hd); -bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) -{ - if (!(m_pFGArm && m_pFGArm->IsAttached())) { - return false; + /* + hd.ResImpulse[HITOR].Reset(); + hd.ResImpulse[HITEE].Reset(); + hd.HitRadius[HITEE] = (hd.HitPoint - m_Pos) * c_MPP; + hd.mass[HITEE] = m_Mass; + hd.MomInertia[HITEE] = m_pAtomGroup->GetMomentOfInertia(); + hd.HitVel[HITEE] = m_Vel + hd.HitRadius[HITEE].GetPerpendicular() * m_AngularVel; + hd.VelDiff = hd.HitVel[HITOR] - hd.HitVel[HITEE]; + Vector hitAcc = -hd.VelDiff * (1 + hd.Body[HITOR]->GetMaterial().restitution * GetMaterial().restitution); + + float hittorLever = hd.HitRadius[HITOR].GetPerpendicular().Dot(hd.BitmapNormal); + float hitteeLever = hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.BitmapNormal); + hittorLever *= hittorLever; + hitteeLever *= hitteeLever; + float impulse = hitAcc.Dot(hd.BitmapNormal) / (((1 / hd.mass[HITOR]) + (1 / hd.mass[HITEE])) + + (hittorLever / hd.MomInertia[HITOR]) + (hitteeLever / hd.MomInertia[HITEE])); + + hd.ResImpulse[HITOR] = hd.BitmapNormal * impulse * hd.ImpulseFactor[HITOR]; + hd.ResImpulse[HITEE] = hd.BitmapNormal * -impulse * hd.ImpulseFactor[HITEE]; + + //////////////////////////////////////////////////////////////////////////////// + // If a particle, which does not penetrate, but bounces, do any additional + // effects of that bounce. + if (!ParticlePenetration()) + // TODO: Add blunt trauma effects here!") + ; + } + + m_Vel += hd.ResImpulse[HITEE] / hd.mass[HITEE]; + m_AngularVel += hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.ResImpulse[HITEE]) / + hd.MomInertia[HITEE]; + */ } - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && heldDevice->IsInGroup(group)) { - return true; - } - - // Go through the inventory looking for the proper device - for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - HeldDevice *pDevice = dynamic_cast(*itr); - // Found proper device to equip, so make the switch! - if (pDevice && pDevice->IsInGroup(group)) - { - if (doEquip) - { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - - // Put back into the inventory what we had in our hands, if anything - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice()) - { - heldDevice->Deactivate(); - MovableObject *previouslyHeldItem = m_pFGArm->RemoveAttachable(heldDevice); - if (previouslyHeldItem) { - // Note - This is a fix to deal with an edge case bug when this method is called by a global script. - // Because the global script runs before everything has finished traveling, the removed item needs to undraw itself from the MO layer, otherwise it can result in ghost collisions and crashes. - if (previouslyHeldItem->GetsHitByMOs()) { -#ifdef DRAW_MOID_LAYER - previouslyHeldItem->Draw(g_SceneMan.GetMOIDBitmap(), Vector(), g_DrawNoMOID, true); -#else - previouslyHeldItem->SetTraveling(true); -#endif - } - AddToInventoryBack(previouslyHeldItem); - } - } + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnBounce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // bounces off of something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. - // Now put the device we were looking for and found into the hand - m_pFGArm->SetHeldDevice(pDevice); - // Move the hand to a poisition so it looks like the new device was drawn from inventory - m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); + bool AHuman::OnBounce(const Vector &pos) + { + return false; + } - // Equip shield in BG arm if applicable - EquipShieldInBGArm(); - // Play the device switching sound - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnSink + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // sink into something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. + + bool AHuman::OnSink(const Vector &pos) + { + return false; + } + */ + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool AHuman::HandlePieCommand(PieSlice::SliceType pieSliceIndex) { + if (pieSliceIndex != PieSlice::SliceType::NoType) { + if (pieSliceIndex == PieSlice::SliceType::Pickup) { + m_Controller.SetState(WEAPON_PICKUP); + } else if (pieSliceIndex == PieSlice::SliceType::Drop) { + m_Controller.SetState(WEAPON_DROP); + } else if (pieSliceIndex == PieSlice::SliceType::Reload) { + m_Controller.SetState(WEAPON_RELOAD); + } else if (pieSliceIndex == PieSlice::SliceType::NextItem) { + m_Controller.SetState(WEAPON_CHANGE_NEXT, true); + } else if (pieSliceIndex == PieSlice::SliceType::PreviousItem) { + m_Controller.SetState(WEAPON_CHANGE_PREV, true); + } else if (pieSliceIndex == PieSlice::SliceType::Sentry) { + m_AIMode = AIMODE_SENTRY; + } else if (pieSliceIndex == PieSlice::SliceType::Patrol) { + m_AIMode = AIMODE_PATROL; + } else if (pieSliceIndex == PieSlice::SliceType::BrainHunt) { + m_AIMode = AIMODE_BRAINHUNT; + ClearAIWaypoints(); + } else if (pieSliceIndex == PieSlice::SliceType::GoTo) { + m_AIMode = AIMODE_GOTO; + ClearAIWaypoints(); + m_UpdateMovePath = true; + } else if (pieSliceIndex == PieSlice::SliceType::GoldDig) { + m_AIMode = AIMODE_GOLDDIG; + } else { + return Actor::HandlePieCommand(pieSliceIndex); } + } + return false; + } - return true; - } - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: AddInventoryItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an inventory item to this AHuman. This also puts that item + // directly in the hands of this if they are empty. + void AHuman::AddInventoryItem(MovableObject* pItemToAdd) { + // If we have nothing in inventory, and nothing in our hands, just grab this first thing added to us. + if (HeldDevice* itemToAddAsHeldDevice = dynamic_cast(pItemToAdd); itemToAddAsHeldDevice && m_Inventory.empty() && m_pFGArm && m_pFGArm->IsAttached() && !m_pFGArm->GetHeldDevice()) { + m_pFGArm->SetHeldDevice(itemToAddAsHeldDevice); + m_pFGArm->SetHandPos(m_HolsterOffset.GetXFlipped(m_HFlipped)); + } else { + Actor::AddInventoryItem(pItemToAdd); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipLoadedFirearmInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first loaded HDFirearm -// of the specified group in the inventory. If no such weapon is in the -// inventory, nothing happens. - -bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGroup, bool doEquip) -{ - if (!(m_pFGArm && m_pFGArm->IsAttached())) { - return false; + EquipShieldInBGArm(); } - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && !heldDevice->NeedsReloading() && heldDevice->IsInGroup(group) && !heldDevice->IsInGroup(excludeGroup)) { - return true; - } - - // Go through the inventory looking for the proper device - for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - HDFirearm *pFirearm = dynamic_cast(*itr); - // Found proper device to equip, so make the switch! - if (pFirearm && !pFirearm->NeedsReloading() && pFirearm->IsInGroup(group) && !pFirearm->IsInGroup(excludeGroup)) - { - if (doEquip) - { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - - // Put back into the inventory what we had in our hands, if anything - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice()) - { - m_pFGArm->GetHeldDevice()->Deactivate(); - AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Now put the device we were looking for and found into the hand - m_pFGArm->SetHeldDevice(pFirearm); - // Move the hand to a poisition so it looks like the new device was drawn from inventory - m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); + MovableObject* AHuman::SwapNextInventory(MovableObject* inventoryItemToSwapIn, bool muteSound) { + MovableObject* swappedInventoryItem = Actor::SwapNextInventory(inventoryItemToSwapIn, muteSound); + while (!dynamic_cast(swappedInventoryItem) && !m_Inventory.empty()) { + g_MovableMan.AddMO(swappedInventoryItem); + swappedInventoryItem = Actor::SwapNextInventory(nullptr, muteSound); + } - // Equip shield in BG arm if applicable - EquipShieldInBGArm(); + return swappedInventoryItem; + } - // Play the device switching sound - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return true; - } - } + MovableObject* AHuman::SwapPrevInventory(MovableObject* inventoryItemToSwapIn) { + MovableObject* swappedInventoryItem = Actor::SwapPrevInventory(inventoryItemToSwapIn); + while (!dynamic_cast(swappedInventoryItem) && !m_Inventory.empty()) { + g_MovableMan.AddMO(swappedInventoryItem); + swappedInventoryItem = Actor::SwapNextInventory(nullptr); + } - return false; -} + return swappedInventoryItem; + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipNamedDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found device -// of with the specified preset name in the inventory. If the held device already -// is of that preset name, or no device is in inventory, nothing happens. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipFirearm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found firearm + // in the inventory. If the held device already is a firearm, or no + // firearm is in inventory, nothing happens. -bool AHuman::EquipNamedDevice(const std::string &moduleName, const std::string &presetName, bool doEquip) -{ - if (!(m_pFGArm && m_pFGArm->IsAttached())) { - return false; - } + bool AHuman::EquipFirearm(bool doEquip) { + if (!(m_pFGArm && m_pFGArm->IsAttached())) { + return false; + } - if (const HeldDevice *heldDevice = m_pFGArm->GetHeldDevice(); - heldDevice && (moduleName.empty() || heldDevice->GetModuleName() == moduleName) && heldDevice->GetPresetName() == presetName) { - return true; - } + if (HDFirearm* heldDeviceAsFirearm = dynamic_cast(m_pFGArm->GetHeldDevice()); heldDeviceAsFirearm && heldDeviceAsFirearm->IsWeapon()) { + return true; + } else { + UnequipBGArm(); + } - // Go through the inventory looking for the proper device - for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - HeldDevice *pDevice = dynamic_cast(*itr); - // Found proper device to equip, so make the switch! - if (pDevice && (moduleName.empty() || pDevice->GetModuleName() == moduleName) && pDevice->GetPresetName() == presetName) - { - if (doEquip) - { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + // Go through the inventory looking for the proper device + for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + HDFirearm* pWeapon = dynamic_cast(*itr); + // Found proper device to equip, so make the switch! + if (pWeapon && pWeapon->IsWeapon()) { + if (doEquip) { + // Erase the inventory entry containing the device we now have switched to + *itr = 0; + m_Inventory.erase(itr); + + // Put back into the inventory what we had in our hands, if anything + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); + } - // Put back into the inventory what we had in our hands, if anything - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice()) - { - heldDevice->Deactivate(); - AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); - } + // Now put the device we were looking for and found into the hand + m_pFGArm->SetHeldDevice(pWeapon); + // Move the hand to a poisition so it looks like the new device was drawn from inventory + m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); - // Now put the device we were looking for and found into the hand - m_pFGArm->SetHeldDevice(pDevice); - // Move the hand to a poisition so it looks like the new device was drawn from inventory - m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); + // Equip shield in BG arm if applicable + EquipShieldInBGArm(); - // Equip shield in BG arm if applicable - EquipShieldInBGArm(); + // Play the device switching sound + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + } - // Play the device switching sound - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } + return true; } + } - return true; - } - } - - return false; -} + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipDeviceInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found device + // of the specified group in the inventory. If the held device already + // is of that group, or no device is in inventory, nothing happens. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipThrowable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found ThrownDevice -// in the inventory. If the held device already is a ThrownDevice, or no -// ThrownDevice is in inventory, nothing happens. + bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { + if (!(m_pFGArm && m_pFGArm->IsAttached())) { + return false; + } -bool AHuman::EquipThrowable(bool doEquip) -{ - if (!(m_pFGArm && m_pFGArm->IsAttached())) { - return false; - } + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && heldDevice->IsInGroup(group)) { + return true; + } - if (dynamic_cast(m_pFGArm->GetHeldDevice())) { - return true; - } - - // Go through the inventory looking for the proper device - for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - ThrownDevice *pThrown = dynamic_cast(*itr); - // Found proper device to equip, so make the switch! -// TODO: see if thrown is weapon or not, don't want to throw key items etc - if (pThrown)// && pThrown->IsWeapon()) - { - if (doEquip) - { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - - // Put back into the inventory what we had in our hands, if anything - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice()) - { - heldDevice->Deactivate(); - AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); - } - - // Now put the device we were looking for and found into the hand - m_pFGArm->SetHeldDevice(pThrown); - // Move the hand to a poisition so it looks like the new device was drawn from inventory - m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); - - // Equip shield in BG arm as applicable - EquipShieldInBGArm(); - - // Play the device switching sound - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } - } - - return true; - } - } - - return false; -} + // Go through the inventory looking for the proper device + for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + HeldDevice* pDevice = dynamic_cast(*itr); + // Found proper device to equip, so make the switch! + if (pDevice && pDevice->IsInGroup(group)) { + if (doEquip) { + // Erase the inventory entry containing the device we now have switched to + *itr = 0; + m_Inventory.erase(itr); + + // Put back into the inventory what we had in our hands, if anything + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + MovableObject* previouslyHeldItem = m_pFGArm->RemoveAttachable(heldDevice); + if (previouslyHeldItem) { + // Note - This is a fix to deal with an edge case bug when this method is called by a global script. + // Because the global script runs before everything has finished traveling, the removed item needs to undraw itself from the MO layer, otherwise it can result in ghost collisions and crashes. + if (previouslyHeldItem->GetsHitByMOs()) { +#ifdef DRAW_MOID_LAYER + previouslyHeldItem->Draw(g_SceneMan.GetMOIDBitmap(), Vector(), g_DrawNoMOID, true); +#else + previouslyHeldItem->SetTraveling(true); +#endif + } + AddToInventoryBack(previouslyHeldItem); + } + } -////////////////////////////////////////////////////////////////////////////////////////// + // Now put the device we were looking for and found into the hand + m_pFGArm->SetHeldDevice(pDevice); + // Move the hand to a poisition so it looks like the new device was drawn from inventory + m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); -bool AHuman::EquipDiggingTool(bool doEquip) { - if (!(m_pFGArm && m_pFGArm->IsAttached())) { - return false; - } + // Equip shield in BG arm if applicable + EquipShieldInBGArm(); - const HDFirearm *strongestDigger = nullptr; - float strongestDiggerDigStrength = 0; - bool strongestDiggerIsHeld = false; - if (const HDFirearm *heldDeviceAsFirearm = dynamic_cast(m_pFGArm->GetHeldDevice()); heldDeviceAsFirearm && heldDeviceAsFirearm->IsInGroup("Tools - Diggers")) { - strongestDigger = heldDeviceAsFirearm; - strongestDiggerDigStrength = heldDeviceAsFirearm->EstimateDigStrength(); - strongestDiggerIsHeld = true; - } + // Play the device switching sound + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + } - if (doEquip || !strongestDigger) { - for (MovableObject *inventoryItem : m_Inventory) { - if (const HDFirearm *inventoryItemAsFirearm = dynamic_cast(inventoryItem); inventoryItemAsFirearm && inventoryItemAsFirearm->IsInGroup("Tools - Diggers") && inventoryItemAsFirearm->EstimateDigStrength() > strongestDiggerDigStrength) { - strongestDigger = inventoryItemAsFirearm; - strongestDiggerDigStrength = inventoryItemAsFirearm->EstimateDigStrength(); - strongestDiggerIsHeld = false; + return true; } } - } - if (doEquip && strongestDigger && !strongestDiggerIsHeld) { - EquipNamedDevice(strongestDigger->GetModuleName(), strongestDigger->GetPresetName(), true); + return false; } - return strongestDigger != nullptr; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -float AHuman::EstimateDigStrength() const { - float maxPenetration = Actor::EstimateDigStrength(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipLoadedFirearmInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first loaded HDFirearm + // of the specified group in the inventory. If no such weapon is in the + // inventory, nothing happens. - if (!(m_pFGArm && m_pFGArm->IsAttached())) { - return maxPenetration; - } + bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGroup, bool doEquip) { + if (!(m_pFGArm && m_pFGArm->IsAttached())) { + return false; + } - if (const HDFirearm *heldDeviceAsHDFirearm = dynamic_cast(m_pFGArm->GetHeldDevice()); heldDeviceAsHDFirearm && heldDeviceAsHDFirearm->IsInGroup("Tools - Diggers")) { - maxPenetration = std::max(heldDeviceAsHDFirearm->EstimateDigStrength(), maxPenetration); - } + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && !heldDevice->NeedsReloading() && heldDevice->IsInGroup(group) && !heldDevice->IsInGroup(excludeGroup)) { + return true; + } - for (const MovableObject *inventoryItem : m_Inventory) { - if (const HDFirearm *inventoryItemAsFirearm = dynamic_cast(inventoryItem); inventoryItemAsFirearm && inventoryItemAsFirearm->IsInGroup("Tools - Diggers")) { - maxPenetration = std::max(inventoryItemAsFirearm->EstimateDigStrength(), maxPenetration); - } - } + // Go through the inventory looking for the proper device + for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + HDFirearm* pFirearm = dynamic_cast(*itr); + // Found proper device to equip, so make the switch! + if (pFirearm && !pFirearm->NeedsReloading() && pFirearm->IsInGroup(group) && !pFirearm->IsInGroup(excludeGroup)) { + if (doEquip) { + // Erase the inventory entry containing the device we now have switched to + *itr = 0; + m_Inventory.erase(itr); + + // Put back into the inventory what we had in our hands, if anything + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { + m_pFGArm->GetHeldDevice()->Deactivate(); + AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); + } - return maxPenetration; -} + // Now put the device we were looking for and found into the hand + m_pFGArm->SetHeldDevice(pFirearm); + // Move the hand to a poisition so it looks like the new device was drawn from inventory + m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); -////////////////////////////////////////////////////////////////////////////////////////// + // Equip shield in BG arm if applicable + EquipShieldInBGArm(); + // Play the device switching sound + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipShield -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found shield -// in the inventory. If the held device already is a shield, or no -// shield is in inventory, nothing happens. + return true; + } + } -bool AHuman::EquipShield() -{ - if (!(m_pFGArm && m_pFGArm->IsAttached())) { return false; } - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && heldDevice->IsShield()) { - return true; - } - - // Go through the inventory looking for the proper device - for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - HeldDevice *pShield = dynamic_cast(*itr); - // Found proper device to equip, so make the switch! - if (pShield && pShield->IsShield()) - { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipNamedDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found device + // of with the specified preset name in the inventory. If the held device already + // is of that preset name, or no device is in inventory, nothing happens. - // Put back into the inventory what we had in our hands, if anything - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice()) - { - heldDevice->Deactivate(); - AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); - } - - // Now put the device we were looking for and found into the hand - m_pFGArm->SetHeldDevice(pShield); - // Move the hand to a poisition so it looks like the new device was drawn from inventory - m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); + bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string& presetName, bool doEquip) { + if (!(m_pFGArm && m_pFGArm->IsAttached())) { + return false; + } - // Equip shield in BG arm is applicable - EquipShieldInBGArm(); + if (const HeldDevice* heldDevice = m_pFGArm->GetHeldDevice(); + heldDevice && (moduleName.empty() || heldDevice->GetModuleName() == moduleName) && heldDevice->GetPresetName() == presetName) { + return true; + } - // Play the device switching sound - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } + // Go through the inventory looking for the proper device + for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + HeldDevice* pDevice = dynamic_cast(*itr); + // Found proper device to equip, so make the switch! + if (pDevice && (moduleName.empty() || pDevice->GetModuleName() == moduleName) && pDevice->GetPresetName() == presetName) { + if (doEquip) { + // Erase the inventory entry containing the device we now have switched to + *itr = 0; + m_Inventory.erase(itr); + + // Put back into the inventory what we had in our hands, if anything + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); + } - return true; - } - } + // Now put the device we were looking for and found into the hand + m_pFGArm->SetHeldDevice(pDevice); + // Move the hand to a poisition so it looks like the new device was drawn from inventory + m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); - return false; -} + // Equip shield in BG arm if applicable + EquipShieldInBGArm(); + // Play the device switching sound + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipShieldInBGArm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tries to equip the first shield in inventory to the background arm; -// this only works if nothing is held at all, or the FG arm holds a -// one-handed device, or we're in inventory mode. + return true; + } + } -bool AHuman::EquipShieldInBGArm() -{ - if (!(m_pBGArm && m_pBGArm->IsAttached())) { return false; } - if (HeldDevice *heldDevice = m_pBGArm->GetHeldDevice(); heldDevice && (heldDevice->IsShield() || heldDevice->IsDualWieldable())) { - // If we're holding a shield, but aren't supposed to, because we need to support the FG hand's two-handed device, then let go of the shield and put it back in inventory. - if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice() && !m_pFGArm->GetHeldDevice()->IsOneHanded()) { - m_pBGArm->GetHeldDevice()->Deactivate(); - AddToInventoryBack(m_pBGArm->RemoveAttachable(heldDevice)); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipThrowable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found ThrownDevice + // in the inventory. If the held device already is a ThrownDevice, or no + // ThrownDevice is in inventory, nothing happens. + + bool AHuman::EquipThrowable(bool doEquip) { + if (!(m_pFGArm && m_pFGArm->IsAttached())) { return false; } - return true; - } - - // Only equip if the BG hand isn't occupied with supporting a two handed device - if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice() && !m_pFGArm->GetHeldDevice()->IsOneHanded()) { - return false; - } - - // Go through the inventory looking for the proper device - for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - HeldDevice *pShield = dynamic_cast(*itr); - // Found proper device to equip, so make the switch! - if (pShield && (pShield->IsShield() || pShield->IsDualWieldable())) - { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - - // Put back into the inventory what we had in our hands, if anything - if (HeldDevice *heldDevice = m_pBGArm->GetHeldDevice()) - { - heldDevice->Deactivate(); - AddToInventoryBack(m_pBGArm->RemoveAttachable(heldDevice)); - } - - // Now put the device we were looking for and found into the hand - m_pBGArm->SetHeldDevice(pShield); - // Move the hand to a poisition so it looks like the new device was drawn from inventory - m_pBGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); - - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } - - return true; - } - } - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool AHuman::UnequipFGArm() { - if (m_pFGArm) { - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice()) { - heldDevice->Deactivate(); - AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); - m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + if (dynamic_cast(m_pFGArm->GetHeldDevice())) { return true; } - } - return false; -} -////////////////////////////////////////////////////////////////////////////////////////// + // Go through the inventory looking for the proper device + for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + ThrownDevice* pThrown = dynamic_cast(*itr); + // Found proper device to equip, so make the switch! + // TODO: see if thrown is weapon or not, don't want to throw key items etc + if (pThrown) // && pThrown->IsWeapon()) + { + if (doEquip) { + // Erase the inventory entry containing the device we now have switched to + *itr = 0; + m_Inventory.erase(itr); + + // Put back into the inventory what we had in our hands, if anything + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); + } -bool AHuman::UnequipBGArm() { - if (m_pBGArm) { - if (HeldDevice *heldDevice = m_pBGArm->GetHeldDevice()) { - heldDevice->Deactivate(); - AddToInventoryFront(m_pBGArm->RemoveAttachable(heldDevice)); - m_pBGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); - return true; - } - } - return false; -} + // Now put the device we were looking for and found into the hand + m_pFGArm->SetHeldDevice(pThrown); + // Move the hand to a poisition so it looks like the new device was drawn from inventory + m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); -////////////////////////////////////////////////////////////////////////////////////////// + // Equip shield in BG arm as applicable + EquipShieldInBGArm(); -float AHuman::GetEquippedMass() const { - float equippedMass = 0; - if (MovableObject *fgDevice = GetEquippedItem()) { - equippedMass += fgDevice->GetMass(); - } - if (MovableObject *bgDevice = GetEquippedBGItem()) { - equippedMass += bgDevice->GetMass(); - } - return equippedMass; -} + // Play the device switching sound + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmIsReady -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held device's current mag is empty on -// ammo or not. + return true; + } + } -bool AHuman::FirearmIsReady() const -{ - // Check if the currently held device is already the desired type - if (m_pFGArm && m_pFGArm->IsAttached()) - { - const HDFirearm *pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); - if (pWeapon && pWeapon->GetRoundInMagCount() != 0) - return true; - } + return false; + } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + bool AHuman::EquipDiggingTool(bool doEquip) { + if (!(m_pFGArm && m_pFGArm->IsAttached())) { + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: ThrowableIsReady -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held ThrownDevice's is ready to go. + const HDFirearm* strongestDigger = nullptr; + float strongestDiggerDigStrength = 0; + bool strongestDiggerIsHeld = false; + if (const HDFirearm* heldDeviceAsFirearm = dynamic_cast(m_pFGArm->GetHeldDevice()); heldDeviceAsFirearm && heldDeviceAsFirearm->IsInGroup("Tools - Diggers")) { + strongestDigger = heldDeviceAsFirearm; + strongestDiggerDigStrength = heldDeviceAsFirearm->EstimateDigStrength(); + strongestDiggerIsHeld = true; + } -bool AHuman::ThrowableIsReady() const -{ - // Check if the currently held thrown device is already the desired type - if (m_pFGArm && m_pFGArm->IsAttached()) - { - const ThrownDevice *pThrown = dynamic_cast(m_pFGArm->GetHeldDevice()); - if (pThrown)// && pThrown->blah() > 0) - return true; - } + if (doEquip || !strongestDigger) { + for (MovableObject* inventoryItem: m_Inventory) { + if (const HDFirearm* inventoryItemAsFirearm = dynamic_cast(inventoryItem); inventoryItemAsFirearm && inventoryItemAsFirearm->IsInGroup("Tools - Diggers") && inventoryItemAsFirearm->EstimateDigStrength() > strongestDiggerDigStrength) { + strongestDigger = inventoryItemAsFirearm; + strongestDiggerDigStrength = inventoryItemAsFirearm->EstimateDigStrength(); + strongestDiggerIsHeld = false; + } + } + } - return false; -} + if (doEquip && strongestDigger && !strongestDiggerIsHeld) { + EquipNamedDevice(strongestDigger->GetModuleName(), strongestDigger->GetPresetName(), true); + } + return strongestDigger != nullptr; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmIsEmpty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is out of ammo. + ////////////////////////////////////////////////////////////////////////////////////////// -bool AHuman::FirearmIsEmpty() const -{ - if (m_pFGArm && m_pFGArm->IsAttached()) - { - const HDFirearm *pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); - if (pWeapon && pWeapon->GetRoundInMagCount() == 0) - return true; - } + float AHuman::EstimateDigStrength() const { + float maxPenetration = Actor::EstimateDigStrength(); - return false; -} + if (!(m_pFGArm && m_pFGArm->IsAttached())) { + return maxPenetration; + } + if (const HDFirearm* heldDeviceAsHDFirearm = dynamic_cast(m_pFGArm->GetHeldDevice()); heldDeviceAsHDFirearm && heldDeviceAsHDFirearm->IsInGroup("Tools - Diggers")) { + maxPenetration = std::max(heldDeviceAsHDFirearm->EstimateDigStrength(), maxPenetration); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmNeedsReload -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is almost out of ammo. + for (const MovableObject* inventoryItem: m_Inventory) { + if (const HDFirearm* inventoryItemAsFirearm = dynamic_cast(inventoryItem); inventoryItemAsFirearm && inventoryItemAsFirearm->IsInGroup("Tools - Diggers")) { + maxPenetration = std::max(inventoryItemAsFirearm->EstimateDigStrength(), maxPenetration); + } + } -bool AHuman::FirearmNeedsReload() const { - if (const HDFirearm *fgWeapon = dynamic_cast(GetEquippedItem()); fgWeapon && fgWeapon->NeedsReloading()) { - return true; - } - if (const HDFirearm *bgWeapon = dynamic_cast(GetEquippedBGItem()); bgWeapon && bgWeapon->NeedsReloading()) { - return true; + return maxPenetration; } - return false; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// -bool AHuman::FirearmsAreReloading(bool onlyIfAllFirearmsAreReloading) const { - int reloadingFirearmCount = 0; - int totalFirearmCount = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipShield + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found shield + // in the inventory. If the held device already is a shield, or no + // shield is in inventory, nothing happens. - if (const HDFirearm *fgWeapon = dynamic_cast(GetEquippedItem())) { - totalFirearmCount++; - if (fgWeapon->IsReloading()) { - reloadingFirearmCount++; + bool AHuman::EquipShield() { + if (!(m_pFGArm && m_pFGArm->IsAttached())) { + return false; } - } - if (reloadingFirearmCount > 0 && !onlyIfAllFirearmsAreReloading) { - return true; - } - if (const HDFirearm *bgWeapon = dynamic_cast(GetEquippedBGItem())) { - totalFirearmCount++; - if (bgWeapon->IsReloading()) { - reloadingFirearmCount++; + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && heldDevice->IsShield()) { + return true; } - } - return onlyIfAllFirearmsAreReloading ? reloadingFirearmCount == totalFirearmCount : reloadingFirearmCount > 0; -} + // Go through the inventory looking for the proper device + for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + HeldDevice* pShield = dynamic_cast(*itr); + // Found proper device to equip, so make the switch! + if (pShield && pShield->IsShield()) { + // Erase the inventory entry containing the device we now have switched to + *itr = 0; + m_Inventory.erase(itr); + + // Put back into the inventory what we had in our hands, if anything + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Now put the device we were looking for and found into the hand + m_pFGArm->SetHeldDevice(pShield); + // Move the hand to a poisition so it looks like the new device was drawn from inventory + m_pFGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmIsSemiAuto -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is semi or full auto. + // Equip shield in BG arm is applicable + EquipShieldInBGArm(); -bool AHuman::FirearmIsSemiAuto() const -{ - if (m_pFGArm && m_pFGArm->IsAttached()) - { - const HDFirearm *pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); - return pWeapon && !pWeapon->IsFullAuto(); - } - return false; -} + // Play the device switching sound + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + return true; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: ReloadFirearm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the currently held firearm, if any. -// Arguments: None. -// Return value: None. + return false; + } -void AHuman::ReloadFirearms(bool onlyReloadEmptyFirearms) { - for (Arm *arm : { m_pFGArm, m_pBGArm }) { - if (arm) { - HDFirearm *heldFirearm = dynamic_cast(arm->GetHeldDevice()); - if (!heldFirearm) { - continue; - } - bool heldFirearmCanReload = heldFirearm->IsReloadable() && !heldFirearm->IsFull() && !heldFirearm->IsReloading() && (!onlyReloadEmptyFirearms || heldFirearm->IsEmpty()); - if (!heldFirearmCanReload) { - continue; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipShieldInBGArm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tries to equip the first shield in inventory to the background arm; + // this only works if nothing is held at all, or the FG arm holds a + // one-handed device, or we're in inventory mode. + + bool AHuman::EquipShieldInBGArm() { + if (!(m_pBGArm && m_pBGArm->IsAttached())) { + return false; + } + + if (HeldDevice* heldDevice = m_pBGArm->GetHeldDevice(); heldDevice && (heldDevice->IsShield() || heldDevice->IsDualWieldable())) { + // If we're holding a shield, but aren't supposed to, because we need to support the FG hand's two-handed device, then let go of the shield and put it back in inventory. + if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice() && !m_pFGArm->GetHeldDevice()->IsOneHanded()) { + m_pBGArm->GetHeldDevice()->Deactivate(); + AddToInventoryBack(m_pBGArm->RemoveAttachable(heldDevice)); + return false; } + return true; + } - Arm *otherArm = arm == m_pFGArm ? m_pBGArm : m_pFGArm; - HDFirearm *otherHeldFirearm = otherArm ? dynamic_cast(otherArm->GetHeldDevice()) : nullptr; + // Only equip if the BG hand isn't occupied with supporting a two handed device + if (m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice() && !m_pFGArm->GetHeldDevice()->IsOneHanded()) { + return false; + } - bool reloadHeldFirearm = false; - if (otherHeldFirearm && otherHeldFirearm->IsReloadable()) { - if (heldFirearm->IsDualReloadable() && otherHeldFirearm->IsDualReloadable()) { - reloadHeldFirearm = true; - } else if (!otherHeldFirearm->IsReloading()) { - reloadHeldFirearm = true; - if (arm == m_pFGArm) { - m_WaitingToReloadOffhand = true; - } + // Go through the inventory looking for the proper device + for (std::deque::iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + HeldDevice* pShield = dynamic_cast(*itr); + // Found proper device to equip, so make the switch! + if (pShield && (pShield->IsShield() || pShield->IsDualWieldable())) { + // Erase the inventory entry containing the device we now have switched to + *itr = 0; + m_Inventory.erase(itr); + + // Put back into the inventory what we had in our hands, if anything + if (HeldDevice* heldDevice = m_pBGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + AddToInventoryBack(m_pBGArm->RemoveAttachable(heldDevice)); } - } else { - reloadHeldFirearm = true; - } - if (reloadHeldFirearm) { - heldFirearm->Reload(); - if (m_DeviceSwitchSound) { - m_DeviceSwitchSound->Play(m_Pos); + // Now put the device we were looking for and found into the hand + m_pBGArm->SetHeldDevice(pShield); + // Move the hand to a poisition so it looks like the new device was drawn from inventory + m_pBGArm->SetHandPos(m_Pos + m_HolsterOffset.GetXFlipped(m_HFlipped)); + + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); } - bool otherArmIsAvailable = otherArm && !otherArm->GetHeldDevice(); + return true; + } + } - // If using the support offset, other code in arm etc will handle where we should target - otherArmIsAvailable = otherArmIsAvailable && !heldFirearm->GetUseSupportOffsetWhileReloading(); + return false; + } - if (otherArmIsAvailable) { - float delayAtTarget = std::max(static_cast(heldFirearm->GetReloadTime() - 200), 0.0F); - otherArm->AddHandTarget("Magazine Pos", heldFirearm->GetMagazinePos()); - if (!m_ReloadOffset.IsZero()) { - otherArm->AddHandTarget("Reload Offset", m_Pos + RotateOffset(m_ReloadOffset), delayAtTarget); - } else { - otherArm->AddHandTarget("Holster Offset", m_Pos + RotateOffset(m_HolsterOffset), delayAtTarget); - } - } + ////////////////////////////////////////////////////////////////////////////////////////// + + bool AHuman::UnequipFGArm() { + if (m_pFGArm) { + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); + m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + return true; } } + return false; } -} + ////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmActivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the currently held device's delay between pulling the trigger -// and activating. + bool AHuman::UnequipBGArm() { + if (m_pBGArm) { + if (HeldDevice* heldDevice = m_pBGArm->GetHeldDevice()) { + heldDevice->Deactivate(); + AddToInventoryFront(m_pBGArm->RemoveAttachable(heldDevice)); + m_pBGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + return true; + } + } + return false; + } -int AHuman::FirearmActivationDelay() const -{ - // Check if the currently held device is already the desired type - if (m_pFGArm && m_pFGArm->IsAttached()) - { - const HDFirearm *pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); - if (pWeapon) - return pWeapon->GetActivationDelay(); - } + ////////////////////////////////////////////////////////////////////////////////////////// - return 0; -} + float AHuman::GetEquippedMass() const { + float equippedMass = 0; + if (MovableObject* fgDevice = GetEquippedItem()) { + equippedMass += fgDevice->GetMass(); + } + if (MovableObject* bgDevice = GetEquippedBGItem()) { + equippedMass += bgDevice->GetMass(); + } + return equippedMass; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmIsReady + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held device's current mag is empty on + // ammo or not. + + bool AHuman::FirearmIsReady() const { + // Check if the currently held device is already the desired type + if (m_pFGArm && m_pFGArm->IsAttached()) { + const HDFirearm* pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); + if (pWeapon && pWeapon->GetRoundInMagCount() != 0) + return true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsWithinRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a point on the scene is within range of the currently -// used device and aiming status, if applicable. + return false; + } -bool AHuman::IsWithinRange(Vector &point) const -{ - if (m_SharpAimMaxedOut) - return true; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: ThrowableIsReady + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held ThrownDevice's is ready to go. + + bool AHuman::ThrowableIsReady() const { + // Check if the currently held thrown device is already the desired type + if (m_pFGArm && m_pFGArm->IsAttached()) { + const ThrownDevice* pThrown = dynamic_cast(m_pFGArm->GetHeldDevice()); + if (pThrown) // && pThrown->blah() > 0) + return true; + } - Vector diff = g_SceneMan.ShortestDistance(m_Pos, point, false); - float sqrDistance = diff.GetSqrMagnitude(); + return false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmIsEmpty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is out of ammo. - // Really close! - if (sqrDistance <= (m_CharHeight * m_CharHeight)) { - return true; + bool AHuman::FirearmIsEmpty() const { + if (m_pFGArm && m_pFGArm->IsAttached()) { + const HDFirearm* pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); + if (pWeapon && pWeapon->GetRoundInMagCount() == 0) + return true; + } + + return false; } - float range = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmNeedsReload + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is almost out of ammo. - if (FirearmIsReady()) - { - // Start with the default aim distance - range = m_AimDistance; + bool AHuman::FirearmNeedsReload() const { + if (const HDFirearm* fgWeapon = dynamic_cast(GetEquippedItem()); fgWeapon && fgWeapon->NeedsReloading()) { + return true; + } + if (const HDFirearm* bgWeapon = dynamic_cast(GetEquippedBGItem()); bgWeapon && bgWeapon->NeedsReloading()) { + return true; + } + return false; + } - // Add the sharp range of the equipped weapon - if (m_pFGArm && m_pFGArm->IsAttached()) - range += m_pFGArm->GetHeldDevice()->GetSharpLength() + 150; - } - else if (ThrowableIsReady()) - { -// TODO: make proper throw range calc based on the throwable's mass etc - range += m_CharHeight * 4; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return sqrDistance <= (range * range); -} + bool AHuman::FirearmsAreReloading(bool onlyIfAllFirearmsAreReloading) const { + int reloadingFirearmCount = 0; + int totalFirearmCount = 0; + if (const HDFirearm* fgWeapon = dynamic_cast(GetEquippedItem())) { + totalFirearmCount++; + if (fgWeapon->IsReloading()) { + reloadingFirearmCount++; + } + } + if (reloadingFirearmCount > 0 && !onlyIfAllFirearmsAreReloading) { + return true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Look -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an unseen-revealing ray in the direction of where this is facing. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. - -bool AHuman::Look(float FOVSpread, float range) -{ - if (!g_SceneMan.AnythingUnseen(m_Team) || m_CanRevealUnseen == false) - return false; - - // Set the length of the look vector - float aimDistance = m_AimDistance + range; - Vector aimPos = m_Pos; - - // If aiming down the barrel, look through that - if (m_Controller.IsState(AIM_SHARP) && m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) - { - aimPos = m_pFGArm->GetHeldDevice()->GetPos(); - aimDistance += m_pFGArm->GetHeldDevice()->GetSharpLength(); - } - // If just looking, use the eyes on the head instead - else if (m_pHead && m_pHead->IsAttached()) - { - aimPos = GetEyePos(); - } - - // Create the vector to trace along - Vector lookVector(aimDistance, 0); - // Set the rotation to the actual aiming angle - Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); - aimMatrix.SetXFlipped(m_HFlipped); - lookVector *= aimMatrix; - // Add the spread - lookVector.DegRotate(FOVSpread * RandomNormalNum()); - - // TODO: generate an alarm event if we spot an enemy actor? - - Vector ignored; - // Cast the seeing ray, adjusting the skip to match the resolution of the unseen map - return g_SceneMan.CastSeeRay(m_Team, aimPos, lookVector, ignored, 25, (int)g_SceneMan.GetUnseenResolution(m_Team).GetSmallest() / 2); -} + if (const HDFirearm* bgWeapon = dynamic_cast(GetEquippedBGItem())) { + totalFirearmCount++; + if (bgWeapon->IsReloading()) { + reloadingFirearmCount++; + } + } + return onlyIfAllFirearmsAreReloading ? reloadingFirearmCount == totalFirearmCount : reloadingFirearmCount > 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: LookForGold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts a material detecting ray in the direction of where this is facing. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool AHuman::LookForGold(float FOVSpread, float range, Vector &foundLocation) const -{ - Vector ray(m_HFlipped ? -range : range, 0); - ray.DegRotate(FOVSpread * RandomNormalNum()); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmIsSemiAuto + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is semi or full auto. - return g_SceneMan.CastMaterialRay(m_Pos, ray, g_MaterialGold, foundLocation, 4); -} + bool AHuman::FirearmIsSemiAuto() const { + if (m_pFGArm && m_pFGArm->IsAttached()) { + const HDFirearm* pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); + return pWeapon && !pWeapon->IsFullAuto(); + } + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: ReloadFirearm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the currently held firearm, if any. + // Arguments: None. + // Return value: None. + + void AHuman::ReloadFirearms(bool onlyReloadEmptyFirearms) { + for (Arm* arm: {m_pFGArm, m_pBGArm}) { + if (arm) { + HDFirearm* heldFirearm = dynamic_cast(arm->GetHeldDevice()); + if (!heldFirearm) { + continue; + } + bool heldFirearmCanReload = heldFirearm->IsReloadable() && !heldFirearm->IsFull() && !heldFirearm->IsReloading() && (!onlyReloadEmptyFirearms || heldFirearm->IsEmpty()); + if (!heldFirearmCanReload) { + continue; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: LookForMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an MO detecting ray in the direction of where the head is looking -// at the time. Factors including head rotation, sharp aim mode, and -// other variables determine how this ray is cast. - -MovableObject * AHuman::LookForMOs(float FOVSpread, unsigned char ignoreMaterial, bool ignoreAllTerrain) -{ - MovableObject *pSeenMO = 0; - Vector aimPos = m_Pos; - float aimDistance = m_AimDistance + g_FrameMan.GetPlayerScreenWidth() * 0.51; // Set the length of the look vector - - // If aiming down the barrel, look through that - if (m_Controller.IsState(AIM_SHARP) && m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) - { - aimPos = m_pFGArm->GetHeldDevice()->GetPos(); - aimDistance += m_pFGArm->GetHeldDevice()->GetSharpLength(); - } - // If just looking, use the eyes on the head instead - else if (m_pHead && m_pHead->IsAttached()) - { - aimPos = GetEyePos(); - } - - // Create the vector to trace along - Vector lookVector(aimDistance, 0); - // Set the rotation to the actual aiming angle - Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); - aimMatrix.SetXFlipped(m_HFlipped); - lookVector *= aimMatrix; - // Add the spread - lookVector.DegRotate(FOVSpread * RandomNormalNum()); - - MOID seenMOID = g_SceneMan.CastMORay(aimPos, lookVector, m_MOID, IgnoresWhichTeam(), ignoreMaterial, ignoreAllTerrain, 5); - pSeenMO = g_MovableMan.GetMOFromID(seenMOID); - if (pSeenMO) - return pSeenMO->GetRootParent(); - - return pSeenMO; -} + Arm* otherArm = arm == m_pFGArm ? m_pBGArm : m_pFGArm; + HDFirearm* otherHeldFirearm = otherArm ? dynamic_cast(otherArm->GetHeldDevice()) : nullptr; + + bool reloadHeldFirearm = false; + if (otherHeldFirearm && otherHeldFirearm->IsReloadable()) { + if (heldFirearm->IsDualReloadable() && otherHeldFirearm->IsDualReloadable()) { + reloadHeldFirearm = true; + } else if (!otherHeldFirearm->IsReloading()) { + reloadHeldFirearm = true; + if (arm == m_pFGArm) { + m_WaitingToReloadOffhand = true; + } + } + } else { + reloadHeldFirearm = true; + } + if (reloadHeldFirearm) { + heldFirearm->Reload(); + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ResetAllTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resest all the timers used by this. Can be emitters, etc. This is to -// prevent backed up emissions to come out all at once while this has been -// held dormant in an inventory. + bool otherArmIsAvailable = otherArm && !otherArm->GetHeldDevice(); -void AHuman::ResetAllTimers() -{ - Actor::ResetAllTimers(); + // If using the support offset, other code in arm etc will handle where we should target + otherArmIsAvailable = otherArmIsAvailable && !heldFirearm->GetUseSupportOffsetWhileReloading(); - if (m_pFGArm && m_pFGArm->GetHeldDevice()) { - m_pFGArm->GetHeldDevice()->ResetAllTimers(); - } -} + if (otherArmIsAvailable) { + float delayAtTarget = std::max(static_cast(heldFirearm->GetReloadTime() - 200), 0.0F); + otherArm->AddHandTarget("Magazine Pos", heldFirearm->GetMagazinePos()); + if (!m_ReloadOffset.IsZero()) { + otherArm->AddHandTarget("Reload Offset", m_Pos + RotateOffset(m_ReloadOffset), delayAtTarget); + } else { + otherArm->AddHandTarget("Holster Offset", m_Pos + RotateOffset(m_HolsterOffset), delayAtTarget); + } + } + } + } + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmActivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the currently held device's delay between pulling the trigger + // and activating. + + int AHuman::FirearmActivationDelay() const { + // Check if the currently held device is already the desired type + if (m_pFGArm && m_pFGArm->IsAttached()) { + const HDFirearm* pWeapon = dynamic_cast(m_pFGArm->GetHeldDevice()); + if (pWeapon) + return pWeapon->GetActivationDelay(); + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsWithinRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a point on the scene is within range of the currently + // used device and aiming status, if applicable. -void AHuman::OnNewMovePath() -{ - Actor::OnNewMovePath(); - - // Process the new path we now have, if any - if (!m_MovePath.empty()) - { - // Smash all airborne waypoints down to just above the ground, except for when it makes the path intersect terrain or it is the final destination - std::list::iterator finalItr = m_MovePath.end(); - finalItr--; - Vector smashedPoint; - Vector previousPoint = *(m_MovePath.begin()); - std::list::iterator nextItr = m_MovePath.begin(); - for (std::list::iterator lItr = m_MovePath.begin(); lItr != finalItr; ++lItr) - { - nextItr++; - smashedPoint = g_SceneMan.MovePointToGround((*lItr), m_CharHeight*0.2, 7); - - // Only smash if the new location doesn't cause the path to intersect hard terrain ahead or behind of it - // Try three times to halve the height to see if that won't intersect - for (int i = 0; i < 3; i++) - { - Vector notUsed; - if (!g_SceneMan.CastStrengthRay(previousPoint, smashedPoint - previousPoint, 5, notUsed, 3, g_MaterialDoor) && - nextItr != m_MovePath.end() && !g_SceneMan.CastStrengthRay(smashedPoint, (*nextItr) - smashedPoint, 5, notUsed, 3, g_MaterialDoor)) - { - (*lItr) = smashedPoint; - break; - } - else - smashedPoint.m_Y -= ((smashedPoint.m_Y - (*lItr).m_Y) / 2); - } - - previousPoint = (*lItr); - } - } -} + bool AHuman::IsWithinRange(Vector& point) const { + if (m_SharpAimMaxedOut) + return true; -////////////////////////////////////////////////////////////////////////////////////////// + Vector diff = g_SceneMan.ShortestDistance(m_Pos, point, false); + float sqrDistance = diff.GetSqrMagnitude(); -void AHuman::UpdateWalkAngle(AHuman::Layer whichLayer) { - if (m_Controller.IsState(BODY_JUMP)) { - m_WalkAngle[whichLayer] = Matrix(c_QuarterPI * GetFlipFactor()); - } else { - float rayLength = 15.0F; - Vector hipPos = m_Pos; - if (whichLayer == AHuman::Layer::FGROUND && m_pFGLeg) { - rayLength += m_pFGLeg->GetMaxLength(); - hipPos += RotateOffset(m_pFGLeg->GetParentOffset()); - } else if (m_pBGLeg) { - rayLength += m_pBGLeg->GetMaxLength(); - hipPos += RotateOffset(m_pBGLeg->GetParentOffset()); - } - - // Cast a ray down from the left and right of us, to determine our angle of ascent - //TODO Don't use a magic number here, calculate something based on stride length and maybe footgroup width. - Vector hitPosLeft = hipPos + Vector(-10.0F, 0.0F); - Vector hitPosRight = hipPos + Vector(10.0F, 0.0F); - g_SceneMan.CastStrengthRay(hitPosLeft, Vector(0.0F, rayLength), 10.0F, hitPosLeft, 0, g_MaterialGrass); - g_SceneMan.CastStrengthRay(hitPosRight, Vector(0.0F, rayLength), 10.0F, hitPosRight, 0, g_MaterialGrass); - - // Clamp the max angle, so we don't end up trying to walk at a 80 degree angle up sheer walls - const float maxAngleDegrees = 40.0F; - float terrainRotationDegs = std::clamp((hitPosRight - hitPosLeft).GetAbsDegAngle(), -maxAngleDegrees, maxAngleDegrees); - - Matrix walkAngle; - walkAngle.SetDegAngle(terrainRotationDegs); - m_WalkAngle[whichLayer] = walkAngle; - } -} + // Really close! + if (sqrDistance <= (m_CharHeight * m_CharHeight)) { + return true; + } -////////////////////////////////////////////////////////////////////////////////////////// + float range = 0; -void AHuman::UpdateCrouching() { - if (!m_Controller.IsState(BODY_JUMP) && m_pHead) { - float desiredWalkPathYOffset = 0.0F; - if (m_CrouchAmountOverride == -1.0F) { - // Cast a ray above our head to either side to determine whether we need to crouch - float desiredCrouchHeadRoom = std::floor(m_pHead->GetRadius() + 2.0f); - float toPredicted = std::floor(m_Vel.m_X * m_pHead->GetRadius()); // Check where we'll be a second from now - Vector hitPosStart = (m_pHead->GetPos() + Vector(0.0F, m_SpriteRadius * 0.5F)).Floor(); - Vector hitPosPredictedStart = (m_pHead->GetPos() + Vector(toPredicted, m_SpriteRadius * 0.5F)).Floor(); - Vector hitPos, hitPosPredicted; - g_SceneMan.CastStrengthRay(hitPosStart, Vector(0.0F, -desiredCrouchHeadRoom + m_SpriteRadius * -0.5F), 1.0F, hitPos, 0, g_MaterialGrass); - g_SceneMan.CastStrengthRay(hitPosPredictedStart, Vector(0.0F, -desiredCrouchHeadRoom + m_SpriteRadius * -0.5F), 1.0F, hitPosPredicted, 0, g_MaterialGrass); + if (FirearmIsReady()) { + // Start with the default aim distance + range = m_AimDistance; - // Don't do it if we're already hitting, we're probably in a weird spot - if (hitPosStart.m_Y - hitPos.m_Y <= 2.0F) { - hitPos.m_Y = 0.0F; - } + // Add the sharp range of the equipped weapon + if (m_pFGArm && m_pFGArm->IsAttached()) + range += m_pFGArm->GetHeldDevice()->GetSharpLength() + 150; + } else if (ThrowableIsReady()) { + // TODO: make proper throw range calc based on the throwable's mass etc + range += m_CharHeight * 4; + } - if (hitPosPredictedStart.m_Y - hitPosPredicted.m_Y <= 2.0F) { - hitPosPredicted.m_Y = 0.0F; - } + return sqrDistance <= (range * range); + } - float headroom = m_pHead->GetPos().m_Y - std::max(hitPos.m_Y, hitPosPredicted.m_Y); - desiredWalkPathYOffset = desiredCrouchHeadRoom - headroom; - } else { - desiredWalkPathYOffset = m_CrouchAmountOverride * m_MaxWalkPathCrouchShift; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Look + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an unseen-revealing ray in the direction of where this is facing. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + + bool AHuman::Look(float FOVSpread, float range) { + if (!g_SceneMan.AnythingUnseen(m_Team) || m_CanRevealUnseen == false) + return false; + + // Set the length of the look vector + float aimDistance = m_AimDistance + range; + Vector aimPos = m_Pos; + + // If aiming down the barrel, look through that + if (m_Controller.IsState(AIM_SHARP) && m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) { + aimPos = m_pFGArm->GetHeldDevice()->GetPos(); + aimDistance += m_pFGArm->GetHeldDevice()->GetSharpLength(); + } + // If just looking, use the eyes on the head instead + else if (m_pHead && m_pHead->IsAttached()) { + aimPos = GetEyePos(); } - float finalWalkPathYOffset = std::clamp(LERP(0.0F, 1.0F, -m_WalkPathOffset.m_Y, desiredWalkPathYOffset, 0.3F), 0.0F, m_MaxWalkPathCrouchShift); - m_WalkPathOffset.m_Y = -finalWalkPathYOffset; + // Create the vector to trace along + Vector lookVector(aimDistance, 0); + // Set the rotation to the actual aiming angle + Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); + aimMatrix.SetXFlipped(m_HFlipped); + lookVector *= aimMatrix; + // Add the spread + lookVector.DegRotate(FOVSpread * RandomNormalNum()); - // If crouching, move at reduced speed - const float crouchSpeedMultiplier = 0.5F; - float travelSpeedMultiplier = LERP(0.0F, m_MaxWalkPathCrouchShift, 1.0F, crouchSpeedMultiplier, -m_WalkPathOffset.m_Y); - m_Paths[FGROUND][WALK].SetTravelSpeedMultiplier(travelSpeedMultiplier); - m_Paths[BGROUND][WALK].SetTravelSpeedMultiplier(travelSpeedMultiplier); + // TODO: generate an alarm event if we spot an enemy actor? - // Adjust our X offset to try to keep our legs under our centre-of-mass - const float ratioBetweenBodyAndHeadToAimFor = 0.15F; - float predictedPosition = ((m_pHead->GetPos().m_X - m_Pos.m_X) * ratioBetweenBodyAndHeadToAimFor) + m_Vel.m_X; - m_WalkPathOffset.m_X = predictedPosition; - } else { - m_WalkPathOffset.Reset(); + Vector ignored; + // Cast the seeing ray, adjusting the skip to match the resolution of the unseen map + return g_SceneMan.CastSeeRay(m_Team, aimPos, lookVector, ignored, 25, (int)g_SceneMan.GetUnseenResolution(m_Team).GetSmallest() / 2); } -} -////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: LookForGold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts a material detecting ray in the direction of where this is facing. -void AHuman::PreControllerUpdate() -{ - ZoneScoped; + bool AHuman::LookForGold(float FOVSpread, float range, Vector& foundLocation) const { + Vector ray(m_HFlipped ? -range : range, 0); + ray.DegRotate(FOVSpread * RandomNormalNum()); - Actor::PreControllerUpdate(); + return g_SceneMan.CastMaterialRay(m_Pos, ray, g_MaterialGold, foundLocation, 4); + } - float deltaTime = g_TimerMan.GetDeltaTimeSecs(); - float rot = m_Rotation.GetRadAngle(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: LookForMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an MO detecting ray in the direction of where the head is looking + // at the time. Factors including head rotation, sharp aim mode, and + // other variables determine how this ray is cast. + + MovableObject* AHuman::LookForMOs(float FOVSpread, unsigned char ignoreMaterial, bool ignoreAllTerrain) { + MovableObject* pSeenMO = 0; + Vector aimPos = m_Pos; + float aimDistance = m_AimDistance + g_FrameMan.GetPlayerScreenWidth() * 0.51; // Set the length of the look vector + + // If aiming down the barrel, look through that + if (m_Controller.IsState(AIM_SHARP) && m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->GetHeldDevice()) { + aimPos = m_pFGArm->GetHeldDevice()->GetPos(); + aimDistance += m_pFGArm->GetHeldDevice()->GetSharpLength(); + } + // If just looking, use the eyes on the head instead + else if (m_pHead && m_pHead->IsAttached()) { + aimPos = GetEyePos(); + } - Vector analogAim = m_Controller.GetAnalogAim(); - const float analogDeadzone = 0.1F; + // Create the vector to trace along + Vector lookVector(aimDistance, 0); + // Set the rotation to the actual aiming angle + Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); + aimMatrix.SetXFlipped(m_HFlipped); + lookVector *= aimMatrix; + // Add the spread + lookVector.DegRotate(FOVSpread * RandomNormalNum()); + + MOID seenMOID = g_SceneMan.CastMORay(aimPos, lookVector, m_MOID, IgnoresWhichTeam(), ignoreMaterial, ignoreAllTerrain, 5); + pSeenMO = g_MovableMan.GetMOFromID(seenMOID); + if (pSeenMO) + return pSeenMO->GetRootParent(); + + return pSeenMO; + } - m_Paths[FGROUND][m_MoveState].SetHFlip(m_HFlipped); - m_Paths[BGROUND][m_MoveState].SetHFlip(m_HFlipped); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. - if (m_pJetpack && m_pJetpack->IsAttached()) { - m_pJetpack->UpdateBurstState(*this); + void AHuman::ResetAllTimers() { + Actor::ResetAllTimers(); - if (m_Controller.IsState(BODY_JUMP) && !m_pJetpack->IsOutOfFuel() && m_Status != INACTIVE) { - m_Paths[FGROUND][JUMP].Restart(); - m_Paths[BGROUND][JUMP].Restart(); - } + if (m_pFGArm && m_pFGArm->GetHeldDevice()) { + m_pFGArm->GetHeldDevice()->ResetAllTimers(); + } } - //////////////////////////////////// - // Movement direction - - const float movementThreshold = 1.0F; - bool isStill = (m_Vel + m_PrevVel).MagnitudeIsLessThan(movementThreshold); - bool isSharpAiming = m_Controller.IsState(AIM_SHARP); - - // If the pie menu is on, try to preserve whatever move state we had before it going into effect. - // This is only done for digital input, where the user needs to use the keyboard to choose pie slices. - // For analog input, this doesn't matter - the mouse or aiming analog stick controls the pie menu. - bool keepOldState = m_Controller.IsKeyboardOnlyControlled() && m_Controller.IsState(PIE_MENU_ACTIVE); - - if (!keepOldState) { - bool crouching = m_Controller.IsState(BODY_CROUCH); - if ((m_Controller.IsState(MOVE_RIGHT) || m_Controller.IsState(MOVE_LEFT) || m_MoveState == JUMP) && m_Status != INACTIVE) { - for (int i = WALK; i < MOVEMENTSTATECOUNT; ++i) { - m_Paths[FGROUND][i].SetHFlip(m_HFlipped); - m_Paths[BGROUND][i].SetHFlip(m_HFlipped); - } - // Only if not jumping, OR if jumping, and apparently stuck on something - then help out with the limbs. - if (m_MoveState != JUMP || isStill) { - // Restart the stride if we're just starting to walk or crawl. - if ((m_MoveState != WALK && !crouching) || (m_MoveState != CRAWL && crouching)) { - m_StrideStart = true; - MoveOutOfTerrain(g_MaterialGrass); - } - - m_MoveState = crouching ? CRAWL : WALK; - - // Engage prone state, this makes the body's rotational spring pull it horizontal instead of upright. - if (m_MoveState == CRAWL && m_ProneState == NOTPRONE) { - m_ProneState = GOPRONE; - m_ProneTimer.Reset(); - } - - m_Paths[FGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); - m_Paths[BGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); - } - - // Walk backwards if the aiming is already focused in the opposite direction of travel. - // Note that we check against zero here rather than the deadzone, because using the deadzone makes jetpacking mouse players unable to fly one way and aim the other. - if (!analogAim.IsZero() || isSharpAiming) { - m_Paths[FGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); - m_Paths[BGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); - } else if ((m_Controller.IsState(MOVE_RIGHT) && m_HFlipped) || (m_Controller.IsState(MOVE_LEFT) && !m_HFlipped)) { - m_HFlipped = !m_HFlipped; - m_CheckTerrIntersection = true; - if (m_ProneState == NOTPRONE) { MoveOutOfTerrain(g_MaterialGrass); } - - for (int i = WALK; i < MOVEMENTSTATECOUNT; ++i) { - m_Paths[FGROUND][i].SetHFlip(m_HFlipped); - m_Paths[BGROUND][i].SetHFlip(m_HFlipped); - m_Paths[FGROUND][i].Terminate(); - m_Paths[BGROUND][i].Terminate(); - } - m_StrideStart = true; - // Stop the going prone spring. - if (m_ProneState == GOPRONE) { m_ProneState = PRONE; } - } - } else { - m_ArmClimbing[FGROUND] = false; - m_ArmClimbing[BGROUND] = false; - if (crouching) { - // Don't go back to crouching if we're already prone, the player has to let go of the crouch button first. If already laying down, just stay put. - m_MoveState = m_ProneState == NOTPRONE ? CROUCH : NOMOVE; - } else { - m_MoveState = STAND; - } - } - // Disengage the prone state as soon as crouch is released. - if (!crouching && m_ProneState != NOTPRONE) { - EquipShieldInBGArm(); - m_ProneState = NOTPRONE; + ////////////////////////////////////////////////////////////////////////////////////////// + + void AHuman::OnNewMovePath() { + Actor::OnNewMovePath(); + + // Process the new path we now have, if any + if (!m_MovePath.empty()) { + // Smash all airborne waypoints down to just above the ground, except for when it makes the path intersect terrain or it is the final destination + std::list::iterator finalItr = m_MovePath.end(); + finalItr--; + Vector smashedPoint; + Vector previousPoint = *(m_MovePath.begin()); + std::list::iterator nextItr = m_MovePath.begin(); + for (std::list::iterator lItr = m_MovePath.begin(); lItr != finalItr; ++lItr) { + nextItr++; + smashedPoint = g_SceneMan.MovePointToGround((*lItr), m_CharHeight * 0.2, 7); + + // Only smash if the new location doesn't cause the path to intersect hard terrain ahead or behind of it + // Try three times to halve the height to see if that won't intersect + for (int i = 0; i < 3; i++) { + Vector notUsed; + if (!g_SceneMan.CastStrengthRay(previousPoint, smashedPoint - previousPoint, 5, notUsed, 3, g_MaterialDoor) && + nextItr != m_MovePath.end() && !g_SceneMan.CastStrengthRay(smashedPoint, (*nextItr) - smashedPoint, 5, notUsed, 3, g_MaterialDoor)) { + (*lItr) = smashedPoint; + break; + } else + smashedPoint.m_Y -= ((smashedPoint.m_Y - (*lItr).m_Y) / 2); + } + + previousPoint = (*lItr); + } } - } + } - //////////////////////////////////// - // Standard Reloading + ////////////////////////////////////////////////////////////////////////////////////////// - for (const Arm *arm : { m_pFGArm, m_pBGArm }) { - if (arm) { - if (HDFirearm *heldFirearm = dynamic_cast(arm->GetHeldDevice())) { - Arm *otherArm = arm == m_pFGArm ? m_pBGArm : m_pFGArm; - bool otherArmIsAvailable = otherArm && !otherArm->GetHeldDevice(); - if (otherArmIsAvailable && heldFirearm->DoneReloading()) { otherArm->SetHandPos(heldFirearm->GetMagazinePos()); }; - heldFirearm->SetSupportAvailable(otherArmIsAvailable); + void AHuman::UpdateWalkAngle(AHuman::Layer whichLayer) { + if (m_Controller.IsState(BODY_JUMP)) { + m_WalkAngle[whichLayer] = Matrix(c_QuarterPI * GetFlipFactor()); + } else { + float rayLength = 15.0F; + Vector hipPos = m_Pos; + if (whichLayer == AHuman::Layer::FGROUND && m_pFGLeg) { + rayLength += m_pFGLeg->GetMaxLength(); + hipPos += RotateOffset(m_pFGLeg->GetParentOffset()); + } else if (m_pBGLeg) { + rayLength += m_pBGLeg->GetMaxLength(); + hipPos += RotateOffset(m_pBGLeg->GetParentOffset()); } + + // Cast a ray down from the left and right of us, to determine our angle of ascent + // TODO Don't use a magic number here, calculate something based on stride length and maybe footgroup width. + Vector hitPosLeft = hipPos + Vector(-10.0F, 0.0F); + Vector hitPosRight = hipPos + Vector(10.0F, 0.0F); + g_SceneMan.CastStrengthRay(hitPosLeft, Vector(0.0F, rayLength), 10.0F, hitPosLeft, 0, g_MaterialGrass); + g_SceneMan.CastStrengthRay(hitPosRight, Vector(0.0F, rayLength), 10.0F, hitPosRight, 0, g_MaterialGrass); + + // Clamp the max angle, so we don't end up trying to walk at a 80 degree angle up sheer walls + const float maxAngleDegrees = 40.0F; + float terrainRotationDegs = std::clamp((hitPosRight - hitPosLeft).GetAbsDegAngle(), -maxAngleDegrees, maxAngleDegrees); + + Matrix walkAngle; + walkAngle.SetDegAngle(terrainRotationDegs); + m_WalkAngle[whichLayer] = walkAngle; } } - if (m_Controller.IsState(ControlState::WEAPON_RELOAD)) { - ReloadFirearms(); - } - if (m_WaitingToReloadOffhand) { - if (HeldDevice *equippedItem = GetEquippedItem(); equippedItem && !equippedItem->IsReloading()) { - ReloadFirearms(); - m_WaitingToReloadOffhand = false; + + ////////////////////////////////////////////////////////////////////////////////////////// + + void AHuman::UpdateCrouching() { + if (!m_Controller.IsState(BODY_JUMP) && m_pHead) { + float desiredWalkPathYOffset = 0.0F; + if (m_CrouchAmountOverride == -1.0F) { + // Cast a ray above our head to either side to determine whether we need to crouch + float desiredCrouchHeadRoom = std::floor(m_pHead->GetRadius() + 2.0f); + float toPredicted = std::floor(m_Vel.m_X * m_pHead->GetRadius()); // Check where we'll be a second from now + Vector hitPosStart = (m_pHead->GetPos() + Vector(0.0F, m_SpriteRadius * 0.5F)).Floor(); + Vector hitPosPredictedStart = (m_pHead->GetPos() + Vector(toPredicted, m_SpriteRadius * 0.5F)).Floor(); + Vector hitPos, hitPosPredicted; + g_SceneMan.CastStrengthRay(hitPosStart, Vector(0.0F, -desiredCrouchHeadRoom + m_SpriteRadius * -0.5F), 1.0F, hitPos, 0, g_MaterialGrass); + g_SceneMan.CastStrengthRay(hitPosPredictedStart, Vector(0.0F, -desiredCrouchHeadRoom + m_SpriteRadius * -0.5F), 1.0F, hitPosPredicted, 0, g_MaterialGrass); + + // Don't do it if we're already hitting, we're probably in a weird spot + if (hitPosStart.m_Y - hitPos.m_Y <= 2.0F) { + hitPos.m_Y = 0.0F; + } + + if (hitPosPredictedStart.m_Y - hitPosPredicted.m_Y <= 2.0F) { + hitPosPredicted.m_Y = 0.0F; + } + + float headroom = m_pHead->GetPos().m_Y - std::max(hitPos.m_Y, hitPosPredicted.m_Y); + desiredWalkPathYOffset = desiredCrouchHeadRoom - headroom; + } else { + desiredWalkPathYOffset = m_CrouchAmountOverride * m_MaxWalkPathCrouchShift; + } + + float finalWalkPathYOffset = std::clamp(LERP(0.0F, 1.0F, -m_WalkPathOffset.m_Y, desiredWalkPathYOffset, 0.3F), 0.0F, m_MaxWalkPathCrouchShift); + m_WalkPathOffset.m_Y = -finalWalkPathYOffset; + + // If crouching, move at reduced speed + const float crouchSpeedMultiplier = 0.5F; + float travelSpeedMultiplier = LERP(0.0F, m_MaxWalkPathCrouchShift, 1.0F, crouchSpeedMultiplier, -m_WalkPathOffset.m_Y); + m_Paths[FGROUND][WALK].SetTravelSpeedMultiplier(travelSpeedMultiplier); + m_Paths[BGROUND][WALK].SetTravelSpeedMultiplier(travelSpeedMultiplier); + + // Adjust our X offset to try to keep our legs under our centre-of-mass + const float ratioBetweenBodyAndHeadToAimFor = 0.15F; + float predictedPosition = ((m_pHead->GetPos().m_X - m_Pos.m_X) * ratioBetweenBodyAndHeadToAimFor) + m_Vel.m_X; + m_WalkPathOffset.m_X = predictedPosition; + } else { + m_WalkPathOffset.Reset(); } } - //////////////////////////////////// - // Change held MovableObjects - - if (m_pFGArm && m_Status != INACTIVE) { - bool changeNext = m_Controller.IsState(WEAPON_CHANGE_NEXT); - bool changePrev = m_Controller.IsState(WEAPON_CHANGE_PREV); - if (changeNext || changePrev) { - if (changeNext && changePrev) { - UnequipArms(); - } else if (!m_Inventory.empty() || UnequipBGArm()) { - if (HDFirearm *firearm = dynamic_cast(m_pFGArm->GetHeldDevice())) { - firearm->StopActivationSound(); + ////////////////////////////////////////////////////////////////////////////////////////// + + void AHuman::PreControllerUpdate() { + ZoneScoped; + + Actor::PreControllerUpdate(); + + float deltaTime = g_TimerMan.GetDeltaTimeSecs(); + float rot = m_Rotation.GetRadAngle(); + + Vector analogAim = m_Controller.GetAnalogAim(); + const float analogDeadzone = 0.1F; + + m_Paths[FGROUND][m_MoveState].SetHFlip(m_HFlipped); + m_Paths[BGROUND][m_MoveState].SetHFlip(m_HFlipped); + + if (m_pJetpack && m_pJetpack->IsAttached()) { + m_pJetpack->UpdateBurstState(*this); + + if (m_Controller.IsState(BODY_JUMP) && !m_pJetpack->IsOutOfFuel() && m_Status != INACTIVE) { + m_Paths[FGROUND][JUMP].Restart(); + m_Paths[BGROUND][JUMP].Restart(); + } + } + + //////////////////////////////////// + // Movement direction + + const float movementThreshold = 1.0F; + bool isStill = (m_Vel + m_PrevVel).MagnitudeIsLessThan(movementThreshold); + bool isSharpAiming = m_Controller.IsState(AIM_SHARP); + + // If the pie menu is on, try to preserve whatever move state we had before it going into effect. + // This is only done for digital input, where the user needs to use the keyboard to choose pie slices. + // For analog input, this doesn't matter - the mouse or aiming analog stick controls the pie menu. + bool keepOldState = m_Controller.IsKeyboardOnlyControlled() && m_Controller.IsState(PIE_MENU_ACTIVE); + + if (!keepOldState) { + bool crouching = m_Controller.IsState(BODY_CROUCH); + if ((m_Controller.IsState(MOVE_RIGHT) || m_Controller.IsState(MOVE_LEFT) || m_MoveState == JUMP) && m_Status != INACTIVE) { + for (int i = WALK; i < MOVEMENTSTATECOUNT; ++i) { + m_Paths[FGROUND][i].SetHFlip(m_HFlipped); + m_Paths[BGROUND][i].SetHFlip(m_HFlipped); + } + // Only if not jumping, OR if jumping, and apparently stuck on something - then help out with the limbs. + if (m_MoveState != JUMP || isStill) { + // Restart the stride if we're just starting to walk or crawl. + if ((m_MoveState != WALK && !crouching) || (m_MoveState != CRAWL && crouching)) { + m_StrideStart = true; + MoveOutOfTerrain(g_MaterialGrass); + } + + m_MoveState = crouching ? CRAWL : WALK; + + // Engage prone state, this makes the body's rotational spring pull it horizontal instead of upright. + if (m_MoveState == CRAWL && m_ProneState == NOTPRONE) { + m_ProneState = GOPRONE; + m_ProneTimer.Reset(); + } + + m_Paths[FGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); + m_Paths[BGROUND][m_MoveState].SetSpeed(m_Controller.IsState(MOVE_FAST) ? FAST : NORMAL); + } + + // Walk backwards if the aiming is already focused in the opposite direction of travel. + // Note that we check against zero here rather than the deadzone, because using the deadzone makes jetpacking mouse players unable to fly one way and aim the other. + if (!analogAim.IsZero() || isSharpAiming) { + m_Paths[FGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); + m_Paths[BGROUND][m_MoveState].SetHFlip(m_Controller.IsState(MOVE_LEFT)); + } else if ((m_Controller.IsState(MOVE_RIGHT) && m_HFlipped) || (m_Controller.IsState(MOVE_LEFT) && !m_HFlipped)) { + m_HFlipped = !m_HFlipped; + m_CheckTerrIntersection = true; + if (m_ProneState == NOTPRONE) { + MoveOutOfTerrain(g_MaterialGrass); + } + + for (int i = WALK; i < MOVEMENTSTATECOUNT; ++i) { + m_Paths[FGROUND][i].SetHFlip(m_HFlipped); + m_Paths[BGROUND][i].SetHFlip(m_HFlipped); + m_Paths[FGROUND][i].Terminate(); + m_Paths[BGROUND][i].Terminate(); + } + m_StrideStart = true; + // Stop the going prone spring. + if (m_ProneState == GOPRONE) { + m_ProneState = PRONE; + } } - if (changeNext) { - m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory(m_pFGArm->RemoveAttachable(m_pFGArm->GetHeldDevice())))); + } else { + m_ArmClimbing[FGROUND] = false; + m_ArmClimbing[BGROUND] = false; + if (crouching) { + // Don't go back to crouching if we're already prone, the player has to let go of the crouch button first. If already laying down, just stay put. + m_MoveState = m_ProneState == NOTPRONE ? CROUCH : NOMOVE; } else { - m_pFGArm->SetHeldDevice(dynamic_cast(SwapPrevInventory(m_pFGArm->RemoveAttachable(m_pFGArm->GetHeldDevice())))); + m_MoveState = STAND; } + } + // Disengage the prone state as soon as crouch is released. + if (!crouching && m_ProneState != NOTPRONE) { EquipShieldInBGArm(); - m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + m_ProneState = NOTPRONE; } - m_EquipHUDTimer.Reset(); - m_SharpAimProgress = 0; - // Reload empty firearms when we swap to them, for convenience. - ReloadFirearms(true); } - } - //////////////////////////////////// - // Aiming - - if (m_Controller.IsState(AIM_UP) && m_Status != INACTIVE) { - // Set the timer to a base number so we don't get a sluggish feeling at start. - if (m_AimState != AIMUP) { m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); } - m_AimState = AIMUP; - m_AimAngle += isSharpAiming ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); - if (m_AimAngle > m_AimRange) { m_AimAngle = m_AimRange; } - - } else if (m_Controller.IsState(AIM_DOWN) && m_Status != INACTIVE) { - // Set the timer to a base number so we don't get a sluggish feeling at start. - if (m_AimState != AIMDOWN) {m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); } - m_AimState = AIMDOWN; - m_AimAngle -= isSharpAiming ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); - if (m_AimAngle < -m_AimRange) { m_AimAngle = -m_AimRange; } - - } else if (analogAim.MagnitudeIsGreaterThan(analogDeadzone) && m_Status != INACTIVE) { - // Hack to avoid the GetAbsRadAngle from mangling an aim angle straight down. - if (analogAim.m_X == 0) { analogAim.m_X += 0.01F * GetFlipFactor(); } - m_AimAngle = analogAim.GetAbsRadAngle(); - - if ((analogAim.m_X > 0 && m_HFlipped) || (analogAim.m_X < 0 && !m_HFlipped)) { - m_HFlipped = !m_HFlipped; - m_CheckTerrIntersection = true; - if (m_ProneState == NOTPRONE) { MoveOutOfTerrain(g_MaterialGrass); } - for (int i = STAND; i < CLIMB; ++i) { - m_Paths[FGROUND][i].SetHFlip(m_HFlipped); - m_Paths[BGROUND][i].SetHFlip(m_HFlipped); - m_Paths[FGROUND][i].Terminate(); - m_Paths[BGROUND][i].Terminate(); - } - m_StrideStart = true; - // Stop the going prone spring. - if (m_ProneState == GOPRONE) { m_ProneState = PRONE; } - } - // Correct angle based on flip. - m_AimAngle = FacingAngle(m_AimAngle); - // Clamp so it's within the range. - Clamp(m_AimAngle, m_AimRange, -m_AimRange); - } else { - m_AimState = AIMSTILL; - } - float adjustedAimAngle = m_AimAngle * GetFlipFactor(); + //////////////////////////////////// + // Standard Reloading + + for (const Arm* arm: {m_pFGArm, m_pBGArm}) { + if (arm) { + if (HDFirearm* heldFirearm = dynamic_cast(arm->GetHeldDevice())) { + Arm* otherArm = arm == m_pFGArm ? m_pBGArm : m_pFGArm; + bool otherArmIsAvailable = otherArm && !otherArm->GetHeldDevice(); + if (otherArmIsAvailable && heldFirearm->DoneReloading()) { + otherArm->SetHandPos(heldFirearm->GetMagazinePos()); + }; + heldFirearm->SetSupportAvailable(otherArmIsAvailable); + } + } + } + if (m_Controller.IsState(ControlState::WEAPON_RELOAD)) { + ReloadFirearms(); + } + if (m_WaitingToReloadOffhand) { + if (HeldDevice* equippedItem = GetEquippedItem(); equippedItem && !equippedItem->IsReloading()) { + ReloadFirearms(); + m_WaitingToReloadOffhand = false; + } + } + + //////////////////////////////////// + // Change held MovableObjects + + if (m_pFGArm && m_Status != INACTIVE) { + bool changeNext = m_Controller.IsState(WEAPON_CHANGE_NEXT); + bool changePrev = m_Controller.IsState(WEAPON_CHANGE_PREV); + if (changeNext || changePrev) { + if (changeNext && changePrev) { + UnequipArms(); + } else if (!m_Inventory.empty() || UnequipBGArm()) { + if (HDFirearm* firearm = dynamic_cast(m_pFGArm->GetHeldDevice())) { + firearm->StopActivationSound(); + } + if (changeNext) { + m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory(m_pFGArm->RemoveAttachable(m_pFGArm->GetHeldDevice())))); + } else { + m_pFGArm->SetHeldDevice(dynamic_cast(SwapPrevInventory(m_pFGArm->RemoveAttachable(m_pFGArm->GetHeldDevice())))); + } + EquipShieldInBGArm(); + m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + } + m_EquipHUDTimer.Reset(); + m_SharpAimProgress = 0; + // Reload empty firearms when we swap to them, for convenience. + ReloadFirearms(true); + } + } + + //////////////////////////////////// + // Aiming - ////////////////////////////// - // Sharp aim calculation + if (m_Controller.IsState(AIM_UP) && m_Status != INACTIVE) { + // Set the timer to a base number so we don't get a sluggish feeling at start. + if (m_AimState != AIMUP) { + m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); + } + m_AimState = AIMUP; + m_AimAngle += isSharpAiming ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); + if (m_AimAngle > m_AimRange) { + m_AimAngle = m_AimRange; + } -// TODO: make the delay data driven by both the actor and the device! - // - if (isSharpAiming && m_Status == STABLE && (m_MoveState == STAND || m_MoveState == CROUCH || m_MoveState == NOMOVE || m_MoveState == WALK) && m_Vel.MagnitudeIsLessThan(5.0F) && GetEquippedItem()) { - float aimMag = analogAim.GetMagnitude(); + } else if (m_Controller.IsState(AIM_DOWN) && m_Status != INACTIVE) { + // Set the timer to a base number so we don't get a sluggish feeling at start. + if (m_AimState != AIMDOWN) { + m_AimTmr.SetElapsedSimTimeMS(m_AimState == AIMSTILL ? 150 : 300); + } + m_AimState = AIMDOWN; + m_AimAngle -= isSharpAiming ? std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00005F, 0.05F) : std::min(static_cast(m_AimTmr.GetElapsedSimTimeMS()) * 0.00015F, 0.15F) * m_Controller.GetDigitalAimSpeed(); + if (m_AimAngle < -m_AimRange) { + m_AimAngle = -m_AimRange; + } - // If aim sharp is being done digitally, then translate to full analog aim mag - if (aimMag < 0.1F) { aimMag = 1.0F; } - if (m_MoveState == WALK) { aimMag *= 0.3F; } + } else if (analogAim.MagnitudeIsGreaterThan(analogDeadzone) && m_Status != INACTIVE) { + // Hack to avoid the GetAbsRadAngle from mangling an aim angle straight down. + if (analogAim.m_X == 0) { + analogAim.m_X += 0.01F * GetFlipFactor(); + } + m_AimAngle = analogAim.GetAbsRadAngle(); - if (m_SharpAimTimer.IsPastSimMS(m_SharpAimDelay)) { - // Only go slower outward - if (m_SharpAimProgress < aimMag) { - m_SharpAimProgress += (aimMag - m_SharpAimProgress) * 0.035F; - } else { - m_SharpAimProgress = aimMag; + if ((analogAim.m_X > 0 && m_HFlipped) || (analogAim.m_X < 0 && !m_HFlipped)) { + m_HFlipped = !m_HFlipped; + m_CheckTerrIntersection = true; + if (m_ProneState == NOTPRONE) { + MoveOutOfTerrain(g_MaterialGrass); + } + for (int i = STAND; i < CLIMB; ++i) { + m_Paths[FGROUND][i].SetHFlip(m_HFlipped); + m_Paths[BGROUND][i].SetHFlip(m_HFlipped); + m_Paths[FGROUND][i].Terminate(); + m_Paths[BGROUND][i].Terminate(); + } + m_StrideStart = true; + // Stop the going prone spring. + if (m_ProneState == GOPRONE) { + m_ProneState = PRONE; + } } - m_SharpAimRevertTimer.Reset(); + // Correct angle based on flip. + m_AimAngle = FacingAngle(m_AimAngle); + // Clamp so it's within the range. + Clamp(m_AimAngle, m_AimRange, -m_AimRange); } else { - m_SharpAimProgress *= 0.95F; - m_SharpAimRevertTimer.SetElapsedSimTimeMS(m_SharpAimDelay - m_SharpAimTimer.GetElapsedSimTimeMS()); + m_AimState = AIMSTILL; } - } else { - m_SharpAimProgress = std::max(m_SharpAimProgress * 0.95F - 0.1F, 0.0F); - if (m_SharpAimRevertTimer.IsPastSimMS(m_SharpAimDelay)) { - m_SharpAimTimer.Reset(); + float adjustedAimAngle = m_AimAngle * GetFlipFactor(); + + ////////////////////////////// + // Sharp aim calculation + + // TODO: make the delay data driven by both the actor and the device! + // + if (isSharpAiming && m_Status == STABLE && (m_MoveState == STAND || m_MoveState == CROUCH || m_MoveState == NOMOVE || m_MoveState == WALK) && m_Vel.MagnitudeIsLessThan(5.0F) && GetEquippedItem()) { + float aimMag = analogAim.GetMagnitude(); + + // If aim sharp is being done digitally, then translate to full analog aim mag + if (aimMag < 0.1F) { + aimMag = 1.0F; + } + if (m_MoveState == WALK) { + aimMag *= 0.3F; + } + + if (m_SharpAimTimer.IsPastSimMS(m_SharpAimDelay)) { + // Only go slower outward + if (m_SharpAimProgress < aimMag) { + m_SharpAimProgress += (aimMag - m_SharpAimProgress) * 0.035F; + } else { + m_SharpAimProgress = aimMag; + } + m_SharpAimRevertTimer.Reset(); + } else { + m_SharpAimProgress *= 0.95F; + m_SharpAimRevertTimer.SetElapsedSimTimeMS(m_SharpAimDelay - m_SharpAimTimer.GetElapsedSimTimeMS()); + } } else { - m_SharpAimTimer.SetElapsedSimTimeMS(m_SharpAimDelay - m_SharpAimRevertTimer.GetElapsedSimTimeMS()); + m_SharpAimProgress = std::max(m_SharpAimProgress * 0.95F - 0.1F, 0.0F); + if (m_SharpAimRevertTimer.IsPastSimMS(m_SharpAimDelay)) { + m_SharpAimTimer.Reset(); + } else { + m_SharpAimTimer.SetElapsedSimTimeMS(m_SharpAimDelay - m_SharpAimRevertTimer.GetElapsedSimTimeMS()); + } } - } - //////////////////////////////////// - // Handle firing/activating/throwing HeldDevices and ThrownDevices. - // Also deal with certain reload cases and setting sharp aim progress for HeldDevices. + //////////////////////////////////// + // Handle firing/activating/throwing HeldDevices and ThrownDevices. + // Also deal with certain reload cases and setting sharp aim progress for HeldDevices. - ThrownDevice *thrownDevice = nullptr; - if (HeldDevice *device = GetEquippedItem(); device && m_Status != INACTIVE) { - if (!dynamic_cast(device)) { - device->SetSharpAim(m_SharpAimProgress); + ThrownDevice* thrownDevice = nullptr; + if (HeldDevice* device = GetEquippedItem(); device && m_Status != INACTIVE) { + if (!dynamic_cast(device)) { + device->SetSharpAim(m_SharpAimProgress); - if (HDFirearm *deviceAsFirearm = dynamic_cast(device)) { - if (m_Controller.IsState(WEAPON_FIRE)) { - if (!m_CanActivateBGItem) { - if (deviceAsFirearm->IsFullAuto()) { - deviceAsFirearm->Activate(); - m_CanActivateBGItem = deviceAsFirearm->FiredOnce() && deviceAsFirearm->HalfwayToNextRound(); - } else if (!m_TriggerPulled) { - deviceAsFirearm->Activate(); - if (deviceAsFirearm->FiredOnce()) { - m_CanActivateBGItem = true; - m_TriggerPulled = true; - } else { - m_CanActivateBGItem = !deviceAsFirearm->CanFire(); + if (HDFirearm* deviceAsFirearm = dynamic_cast(device)) { + if (m_Controller.IsState(WEAPON_FIRE)) { + if (!m_CanActivateBGItem) { + if (deviceAsFirearm->IsFullAuto()) { + deviceAsFirearm->Activate(); + m_CanActivateBGItem = deviceAsFirearm->FiredOnce() && deviceAsFirearm->HalfwayToNextRound(); + } else if (!m_TriggerPulled) { + deviceAsFirearm->Activate(); + if (deviceAsFirearm->FiredOnce()) { + m_CanActivateBGItem = true; + m_TriggerPulled = true; + } else { + m_CanActivateBGItem = !deviceAsFirearm->CanFire(); + } } } + } else { + deviceAsFirearm->Deactivate(); + m_TriggerPulled = false; + } + } else { + m_CanActivateBGItem = true; + if (m_Controller.IsState(WEAPON_FIRE)) { + device->Activate(); + if (device->IsEmpty()) { + ReloadFirearms(true); + } + } else { + device->Deactivate(); + } + } + // If reloading 2 guns one-at-a-time, the automatic reload when firing empty won't trigger, so this makes sure it happens automatically. + if (device->IsEmpty()) { + ReloadFirearms(true); + } + + if (device->IsReloading()) { + m_CanActivateBGItem = true; + m_SharpAimTimer.Reset(); + m_SharpAimProgress = 0; + device->SetSharpAim(m_SharpAimProgress); + } + } else { + m_CanActivateBGItem = true; + if (thrownDevice = dynamic_cast(device)) { + thrownDevice->SetSharpAim(isSharpAiming ? 1.0F : 0); + if (m_Controller.IsState(WEAPON_FIRE)) { + if (m_ArmsState != THROWING_PREP) { + m_ThrowTmr.Reset(); + if (!thrownDevice->ActivatesWhenReleased()) { + thrownDevice->Activate(); + } + } + float throwProgress = GetThrowProgress(); + m_ArmsState = THROWING_PREP; + m_pFGArm->SetHandPos(m_pFGArm->GetJointPos() + (thrownDevice->GetStartThrowOffset().GetXFlipped(m_HFlipped) * throwProgress + thrownDevice->GetStanceOffset() * (1.0F - throwProgress)).RadRotate(adjustedAimAngle)); + } else if (m_ArmsState == THROWING_PREP) { + m_ArmsState = THROWING_RELEASE; + m_pFGArm->SetHandPos(m_pFGArm->GetJointPos() + thrownDevice->GetEndThrowOffset().RadRotate(adjustedAimAngle).GetXFlipped(m_HFlipped)); + + float maxThrowVel = thrownDevice->GetCalculatedMaxThrowVelIncludingArmThrowStrength(); + if (MovableObject* pMO = m_pFGArm->RemoveAttachable(thrownDevice)) { + pMO->SetPos(m_pFGArm->GetJointPos() + Vector(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F).RadRotate(adjustedAimAngle)); + float minThrowVel = thrownDevice->GetMinThrowVel(); + if (minThrowVel == 0) { + minThrowVel = maxThrowVel * 0.2F; + } + + Vector tossVec(minThrowVel + (maxThrowVel - minThrowVel) * GetThrowProgress(), 0.5F * RandomNormalNum()); + pMO->SetVel(m_Vel * 0.5F + tossVec.RadRotate(m_AimAngle).GetXFlipped(m_HFlipped)); + pMO->SetAngularVel(m_AngularVel + RandomNum(-5.0F, 2.5F) * GetFlipFactor()); + pMO->SetRotAngle(adjustedAimAngle); + + if (HeldDevice* moAsHeldDevice = dynamic_cast(pMO)) { + moAsHeldDevice->SetTeam(m_Team); + moAsHeldDevice->SetIgnoresTeamHits(true); + g_MovableMan.AddItem(moAsHeldDevice); + } + pMO = 0; + } + if (thrownDevice->ActivatesWhenReleased()) { + thrownDevice->Activate(); + } + m_ThrowTmr.Reset(); + } + } else if (m_ArmsState == THROWING_RELEASE && m_ThrowTmr.GetElapsedSimTimeMS() > 100) { + m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory())); + m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + EquipShieldInBGArm(); + m_ArmsState = WEAPON_READY; + } else if (m_ArmsState == THROWING_RELEASE) { + m_pFGArm->AddHandTarget("Adjusted Aim Angle", m_Pos + Vector(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F).RadRotate(adjustedAimAngle)); + } + } + } else if (m_ArmsState == THROWING_RELEASE && m_ThrowTmr.GetElapsedSimTimeMS() > 100) { + if (m_pFGArm) { + m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory())); + m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + } + EquipShieldInBGArm(); + m_ArmsState = WEAPON_READY; + } else if (m_ArmsState == THROWING_RELEASE && m_pFGArm) { + m_pFGArm->AddHandTarget("Adjusted Aim Angle", m_Pos + Vector(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F).RadRotate(adjustedAimAngle)); + } else { + m_CanActivateBGItem = true; + } + + if (HeldDevice* device = GetEquippedBGItem(); device && m_Status != INACTIVE) { + if (HDFirearm* deviceAsFirearm = dynamic_cast(device)) { + if (m_Controller.IsState(WEAPON_FIRE)) { + if (m_CanActivateBGItem && (!m_TriggerPulled || (deviceAsFirearm->IsFullAuto() && deviceAsFirearm->HalfwayToNextRound()))) { + deviceAsFirearm->Activate(); + if (deviceAsFirearm->FiredOnce()) { + m_CanActivateBGItem = false; + m_TriggerPulled = true; + } else { + m_CanActivateBGItem = deviceAsFirearm->CanFire(); + } } } else { deviceAsFirearm->Deactivate(); m_TriggerPulled = false; } } else { - m_CanActivateBGItem = true; + m_CanActivateBGItem = false; if (m_Controller.IsState(WEAPON_FIRE)) { device->Activate(); - if (device->IsEmpty()) { - ReloadFirearms(true); - } } else { device->Deactivate(); } @@ -2046,1129 +2135,1075 @@ void AHuman::PreControllerUpdate() if (device->IsEmpty()) { ReloadFirearms(true); } + device->SetSharpAim(m_SharpAimProgress); if (device->IsReloading()) { - m_CanActivateBGItem = true; + m_CanActivateBGItem = false; m_SharpAimTimer.Reset(); m_SharpAimProgress = 0; device->SetSharpAim(m_SharpAimProgress); } } else { - m_CanActivateBGItem = true; - if (thrownDevice = dynamic_cast(device)) { - thrownDevice->SetSharpAim(isSharpAiming ? 1.0F : 0); - if (m_Controller.IsState(WEAPON_FIRE)) { - if (m_ArmsState != THROWING_PREP) { - m_ThrowTmr.Reset(); - if (!thrownDevice->ActivatesWhenReleased()) { thrownDevice->Activate(); } - } - float throwProgress = GetThrowProgress(); - m_ArmsState = THROWING_PREP; - m_pFGArm->SetHandPos(m_pFGArm->GetJointPos() + (thrownDevice->GetStartThrowOffset().GetXFlipped(m_HFlipped) * throwProgress + thrownDevice->GetStanceOffset() * (1.0F - throwProgress)).RadRotate(adjustedAimAngle)); - } else if (m_ArmsState == THROWING_PREP) { - m_ArmsState = THROWING_RELEASE; - m_pFGArm->SetHandPos(m_pFGArm->GetJointPos() + thrownDevice->GetEndThrowOffset().RadRotate(adjustedAimAngle).GetXFlipped(m_HFlipped)); - - float maxThrowVel = thrownDevice->GetCalculatedMaxThrowVelIncludingArmThrowStrength(); - if (MovableObject *pMO = m_pFGArm->RemoveAttachable(thrownDevice)) { - pMO->SetPos(m_pFGArm->GetJointPos() + Vector(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F).RadRotate(adjustedAimAngle)); - float minThrowVel = thrownDevice->GetMinThrowVel(); - if (minThrowVel == 0) { minThrowVel = maxThrowVel * 0.2F; } - - Vector tossVec(minThrowVel + (maxThrowVel - minThrowVel) * GetThrowProgress(), 0.5F * RandomNormalNum()); - pMO->SetVel(m_Vel * 0.5F + tossVec.RadRotate(m_AimAngle).GetXFlipped(m_HFlipped)); - pMO->SetAngularVel(m_AngularVel + RandomNum(-5.0F, 2.5F) * GetFlipFactor()); - pMO->SetRotAngle(adjustedAimAngle); - - if (HeldDevice *moAsHeldDevice = dynamic_cast(pMO)) { - moAsHeldDevice->SetTeam(m_Team); - moAsHeldDevice->SetIgnoresTeamHits(true); - g_MovableMan.AddItem(moAsHeldDevice); + m_CanActivateBGItem = false; + } + + if (m_ArmsState == THROWING_PREP && !thrownDevice) { + m_ArmsState = WEAPON_READY; + } + + // m_aSprite->SetAngle((m_AimAngle / 180) * 3.141592654); + // m_aSprite->SetScale(2.0); + + //////////////////////////////////////// + // Item dropping logic + + if (m_Controller.IsState(WEAPON_DROP) && m_Status != INACTIVE) { + Arm* dropperArm = nullptr; + for (Arm* arm: {m_pFGArm, m_pBGArm}) { + if (arm && arm->GetHeldDevice()) { + HeldDevice* heldDevice = arm->GetHeldDevice(); + arm->RemoveAttachable(heldDevice, true, false); + if (dropperArm) { + if (heldDevice) { + dropperArm->SetHeldDevice(heldDevice); + arm->SetHandPos(dropperArm->GetPos()); } - pMO = 0; + } else { + heldDevice->SetPos(arm->GetJointPos() + Vector(arm->GetMaxLength() * GetFlipFactor(), 0).RadRotate(adjustedAimAngle)); + Vector tossVec(1.0F + std::sqrt(std::abs(arm->GetThrowStrength()) / std::sqrt(std::abs(heldDevice->GetMass()) + 1.0F)), RandomNormalNum()); + heldDevice->SetVel(heldDevice->GetVel() * 0.5F + tossVec.RadRotate(m_AimAngle).GetXFlipped(m_HFlipped)); + heldDevice->SetAngularVel(heldDevice->GetAngularVel() + m_AngularVel * 0.5F + 3.0F * RandomNormalNum()); + + arm->SetHandPos(heldDevice->GetPos()); } - if (thrownDevice->ActivatesWhenReleased()) { thrownDevice->Activate(); } - m_ThrowTmr.Reset(); + dropperArm = arm; + } else if (dropperArm && !m_Inventory.empty()) { + dropperArm->SetHeldDevice(dynamic_cast(SwapNextInventory())); + dropperArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + } + } + if (!dropperArm && !m_Inventory.empty() && !m_pFGArm) { + DropAllInventory(); + if (m_pBGArm) { + m_pBGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); } - } else if (m_ArmsState == THROWING_RELEASE && m_ThrowTmr.GetElapsedSimTimeMS() > 100) { - m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory())); - m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); - EquipShieldInBGArm(); - m_ArmsState = WEAPON_READY; - } else if (m_ArmsState == THROWING_RELEASE) { - m_pFGArm->AddHandTarget("Adjusted Aim Angle", m_Pos + Vector(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F).RadRotate(adjustedAimAngle)); } + EquipShieldInBGArm(); + m_SharpAimProgress = 0; + m_EquipHUDTimer.Reset(); } - } else if (m_ArmsState == THROWING_RELEASE && m_ThrowTmr.GetElapsedSimTimeMS() > 100) { - if (m_pFGArm) { - m_pFGArm->SetHeldDevice(dynamic_cast(SwapNextInventory())); - m_pFGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + + //////////////////////////////////////// + // Item pickup logic + + float reach = m_SpriteRadius; + Vector reachPoint = m_Pos; + + // Try to detect a new item + if ((m_pFGArm || m_pBGArm) && m_Status == STABLE) { + reach += m_pFGArm ? m_pFGArm->GetMaxLength() : m_pBGArm->GetMaxLength(); + reachPoint = m_pFGArm ? m_pFGArm->GetJointPos() : m_pBGArm->GetJointPos(); + + MOID itemMOID = g_SceneMan.CastMORay(reachPoint, Vector(reach * RandomNum(0.5F, 1.0F) * GetFlipFactor(), 0).RadRotate(m_pItemInReach ? adjustedAimAngle : RandomNum(-(c_HalfPI + c_EighthPI), m_AimAngle * 0.75F + c_EighthPI) * GetFlipFactor()), m_MOID, m_Team, g_MaterialGrass, true, 3); + + if (MovableObject* foundMO = g_MovableMan.GetMOFromID(itemMOID)) { + if (HeldDevice* foundDevice = dynamic_cast(foundMO->GetRootParent())) { + m_pItemInReach = (m_pFGArm || foundDevice->IsOneHanded()) ? foundDevice : nullptr; + } + } } - EquipShieldInBGArm(); - m_ArmsState = WEAPON_READY; - } else if (m_ArmsState == THROWING_RELEASE && m_pFGArm) { - m_pFGArm->AddHandTarget("Adjusted Aim Angle", m_Pos + Vector(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F).RadRotate(adjustedAimAngle)); - } else { - m_CanActivateBGItem = true; - } - if (HeldDevice *device = GetEquippedBGItem(); device && m_Status != INACTIVE) { - if (HDFirearm *deviceAsFirearm = dynamic_cast(device)) { - if (m_Controller.IsState(WEAPON_FIRE)) { - if (m_CanActivateBGItem && (!m_TriggerPulled || (deviceAsFirearm->IsFullAuto() && deviceAsFirearm->HalfwayToNextRound()))) { - deviceAsFirearm->Activate(); - if (deviceAsFirearm->FiredOnce()) { - m_CanActivateBGItem = false; - m_TriggerPulled = true; - } else { - m_CanActivateBGItem = deviceAsFirearm->CanFire(); + // Item currently set to be within reach has expired or is now out of range + if (m_pItemInReach && (!m_pItemInReach->IsPickupableBy(this) || !g_MovableMan.IsDevice(m_pItemInReach) || g_SceneMan.ShortestDistance(reachPoint, m_pItemInReach->GetPos(), g_SceneMan.SceneWrapsX()).MagnitudeIsGreaterThan(reach + m_pItemInReach->GetRadius()))) { + m_pItemInReach = nullptr; + } + + if (m_pItemInReach && (m_pFGArm || m_pBGArm) && m_Controller.IsState(WEAPON_PICKUP) && m_Status != INACTIVE && g_MovableMan.RemoveMO(m_pItemInReach)) { + Arm* armToUse = m_pFGArm ? m_pFGArm : m_pBGArm; + Attachable* pMO = armToUse->RemoveAttachable(armToUse->GetHeldDevice()); + AddToInventoryBack(pMO); + armToUse->SetHandPos(m_pItemInReach->GetJointPos()); + armToUse->SetHeldDevice(m_pItemInReach); + m_pItemInReach = nullptr; + + if (armToUse != m_pBGArm) { + EquipShieldInBGArm(); + } + m_SharpAimProgress = 0; + if (m_DeviceSwitchSound) { + m_DeviceSwitchSound->Play(m_Pos); + } + + m_EquipHUDTimer.Reset(); + } + + /////////////////////////////////////////////////// + // Travel the limb AtomGroup:s + + m_StrideFrame = false; + + UpdateCrouching(); + + if (m_Status == STABLE && !m_LimbPushForcesAndCollisionsDisabled && m_MoveState != NOMOVE) { + // This exists to support disabling foot collisions if the limbpath has that flag set. + if ((m_pFGFootGroup->GetAtomCount() == 0 && m_BackupFGFootGroup->GetAtomCount() > 0) != m_Paths[FGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { + m_BackupFGFootGroup->SetLimbPos(m_pFGFootGroup->GetLimbPos()); + std::swap(m_pFGFootGroup, m_BackupFGFootGroup); + } + if ((m_pBGFootGroup->GetAtomCount() == 0 && m_BackupBGFootGroup->GetAtomCount() > 0) != m_Paths[BGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { + m_BackupBGFootGroup->SetLimbPos(m_pBGFootGroup->GetLimbPos()); + std::swap(m_pBGFootGroup, m_BackupBGFootGroup); + } + + if (m_pFGLeg) { + UpdateWalkAngle(FGROUND); + } + if (m_pBGLeg) { + UpdateWalkAngle(BGROUND); + } + + // WALKING, OR WE ARE JETPACKING AND STUCK + if (m_MoveState == WALK || (m_MoveState == JUMP && isStill)) { + m_Paths[FGROUND][STAND].Terminate(); + m_Paths[BGROUND][STAND].Terminate(); + + // float FGLegProg = MAX(m_Paths[FGROUND][WALK].GetRegularProgress(), m_Paths[FGROUND][WALK].GetTotalTimeProgress()); + // float BGLegProg = MAX(m_Paths[BGROUND][WALK].GetRegularProgress(), m_Paths[BGROUND][WALK].GetTotalTimeProgress()); + float FGLegProg = m_Paths[FGROUND][WALK].GetRegularProgress(); + float BGLegProg = m_Paths[BGROUND][WALK].GetRegularProgress(); + + bool restarted = false; + + // Make sure we are starting a stride if we're basically stopped. + if (isStill) { + m_StrideStart = true; + } + + if (m_pFGLeg && (!m_pBGLeg || !(m_Paths[FGROUND][WALK].PathEnded() && BGLegProg < 0.5F) || m_StrideStart)) { + // Reset the stride timer if the path is about to restart. + if (m_Paths[FGROUND][WALK].PathEnded() || m_Paths[FGROUND][WALK].PathIsAtStart()) { + m_StrideTimer.Reset(); + } + Vector jointPos = m_Pos + RotateOffset(m_pFGLeg->GetParentOffset()); + m_ArmClimbing[BGROUND] = !m_pFGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[FGROUND], m_Paths[FGROUND][WALK], deltaTime, &restarted, false, Vector(0.0F, m_Paths[FGROUND][WALK].GetLowestY()), m_WalkPathOffset); + } else { + m_ArmClimbing[BGROUND] = false; + } + if (m_pBGLeg && (!m_pFGLeg || !(m_Paths[BGROUND][WALK].PathEnded() && FGLegProg < 0.5F))) { + m_StrideStart = false; + // Reset the stride timer if the path is about to restart. + if (m_Paths[BGROUND][WALK].PathEnded() || m_Paths[BGROUND][WALK].PathIsAtStart()) { + m_StrideTimer.Reset(); + } + Vector jointPos = m_Pos + RotateOffset(m_pBGLeg->GetParentOffset()); + m_ArmClimbing[FGROUND] = !m_pBGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[BGROUND], m_Paths[BGROUND][WALK], deltaTime, &restarted, false, Vector(0.0F, m_Paths[BGROUND][WALK].GetLowestY()), m_WalkPathOffset); + } else { + if (m_pBGLeg) { + m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pBGLeg->GetMass(), deltaTime); + } + m_ArmClimbing[FGROUND] = false; + } + bool climbing = m_ArmClimbing[FGROUND] || m_ArmClimbing[BGROUND]; + + if (m_StrideSound) { + m_StrideSound->SetPosition(m_Pos); + if (m_StrideSound->GetLoopSetting() < 0) { + if (!m_StrideSound->IsBeingPlayed()) { + m_StrideSound->Play(); + } + } else if (restarted && !climbing) { + m_StrideSound->Play(); + } + } + if (restarted) { + if (climbing) { + m_WalkAngle[FGROUND] = Matrix(); + m_WalkAngle[BGROUND] = Matrix(); + } else { + m_StrideFrame = true; + RunScriptedFunctionInAppropriateScripts("OnStride"); + } + } + + //////////////////////////////////////// + // Arm Climbing if the leg paths failed to find clear spot to restart + + // float FGArmProg = MAX(m_Paths[FGROUND][CLIMB].GetRegularProgress(), m_Paths[FGROUND][CLIMB].GetTotalTimeProgress()); + // float BGArmProg = MAX(m_Paths[BGROUND][CLIMB].GetRegularProgress(), m_Paths[BGROUND][CLIMB].GetTotalTimeProgress()); + float FGArmProg = m_Paths[FGROUND][CLIMB].GetRegularProgress(); + float BGArmProg = m_Paths[BGROUND][CLIMB].GetRegularProgress(); + + // TODO: Figure out what this comment means, and then rephrase it better! + // Slightly negative BGArmProg makes sense because any progress on the starting segments are reported as negative, + // and there's many starting segments on properly formed climbing paths + if (climbing) { + if (m_pFGArm && !m_pFGArm->GetHeldDevice() && !(m_Paths[FGROUND][CLIMB].PathEnded() && BGArmProg > 0.1F)) { // < 0.5F + m_ArmClimbing[FGROUND] = true; + m_Paths[FGROUND][WALK].Terminate(); + m_StrideStart = true; + // Reset the stride timer if the path is about to restart. + if (m_Paths[FGROUND][CLIMB].PathEnded() || m_Paths[FGROUND][CLIMB].PathIsAtStart()) { + m_StrideTimer.Reset(); + } + m_pFGHandGroup->PushAsLimb(m_Pos + Vector(0, m_pFGArm->GetParentOffset().m_Y).RadRotate(-rot), m_Vel, Matrix(), m_Paths[FGROUND][CLIMB], deltaTime, 0, false); + } else { + m_ArmClimbing[FGROUND] = false; + m_Paths[FGROUND][CLIMB].Terminate(); + } + if (m_pBGArm) { + m_ArmClimbing[BGROUND] = true; + m_Paths[BGROUND][WALK].Terminate(); + m_StrideStart = true; + // Reset the stride timer if the path is about to restart. + if (m_Paths[BGROUND][CLIMB].PathEnded() || m_Paths[BGROUND][CLIMB].PathIsAtStart()) { + m_StrideTimer.Reset(); + } + m_pBGHandGroup->PushAsLimb(m_Pos + Vector(0, m_pBGArm->GetParentOffset().m_Y).RadRotate(-rot), m_Vel, Matrix(), m_Paths[BGROUND][CLIMB], deltaTime, 0, false); + } else { + m_ArmClimbing[BGROUND] = false; + m_Paths[BGROUND][CLIMB].Terminate(); + } + } + + // Restart the climbing stroke if the current one seems to be taking too long with no movement. + if (climbing && isStill && m_StrideTimer.IsPastSimMS(static_cast(m_Paths[BGROUND][CLIMB].GetTotalPathTime() * 0.5F))) { + m_StrideStart = true; + m_Paths[FGROUND][CLIMB].Terminate(); + m_Paths[BGROUND][CLIMB].Terminate(); + } else if (m_StrideTimer.IsPastSimMS(static_cast(m_Paths[FGROUND][WALK].GetTotalPathTime() * 1.1F))) { + // Reset the walking stride if it's taking longer than it should. + m_StrideStart = true; + m_Paths[FGROUND][WALK].Terminate(); + m_Paths[BGROUND][WALK].Terminate(); + } + } else if (m_MoveState == CRAWL) { + // Start crawling only once we are fully prone. + if (m_ProneState == PRONE) { + + float FGLegProg = m_Paths[FGROUND][CRAWL].GetRegularProgress(); + float BGLegProg = m_Paths[BGROUND][CRAWL].GetRegularProgress(); + + if (m_pFGLeg && (!m_pBGLeg || (!(m_Paths[FGROUND][CRAWL].PathEnded() && BGLegProg < 0.5F) || m_StrideStart))) { + if (m_Paths[FGROUND][CRAWL].PathEnded() || m_Paths[FGROUND][CRAWL].PathIsAtStart()) { + m_StrideTimer.Reset(); + } + m_pFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pFGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[FGROUND][CRAWL], deltaTime); + } else { + m_Paths[FGROUND][CRAWL].Terminate(); + } + if (m_pBGLeg && (!m_pFGLeg || !(m_Paths[BGROUND][CRAWL].PathEnded() && FGLegProg < 0.5F))) { + m_StrideStart = false; + if (m_Paths[BGROUND][CRAWL].PathEnded() || m_Paths[BGROUND][CRAWL].PathIsAtStart()) { + m_StrideTimer.Reset(); + } + m_pBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pBGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[BGROUND][CRAWL], deltaTime); + } else { + m_Paths[BGROUND][CRAWL].Terminate(); + } + if (m_pBGArm) { + m_ArmClimbing[BGROUND] = true; + m_pBGHandGroup->PushAsLimb(m_Pos + RotateOffset(Vector(0, m_pBGArm->GetParentOffset().m_Y)), m_Vel, m_Rotation, m_Paths[BGROUND][ARMCRAWL], deltaTime); + } + if (m_pFGArm && !m_pFGArm->GetHeldDevice() && !(m_Paths[FGROUND][ARMCRAWL].PathEnded() && m_Paths[BGROUND][ARMCRAWL].GetRegularProgress() < 0.5F)) { + m_ArmClimbing[FGROUND] = true; + m_pFGHandGroup->PushAsLimb(m_Pos + RotateOffset(Vector(0, m_pFGArm->GetParentOffset().m_Y)), m_Vel, m_Rotation, m_Paths[FGROUND][ARMCRAWL], deltaTime); + } + // Restart the stride if the current one seems to be taking too long. + if (m_StrideTimer.IsPastSimMS(m_Paths[FGROUND][CRAWL].GetTotalPathTime())) { + m_StrideStart = true; + m_Paths[FGROUND][CRAWL].Terminate(); + m_Paths[BGROUND][CRAWL].Terminate(); + } + } else { + if (m_pFGLeg) { + m_pFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGLeg->GetParentOffset()), m_pFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pFGLeg->GetMass(), deltaTime); + } + + if (m_pBGLeg) { + m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pBGLeg->GetMass(), deltaTime); + } + } + } else if (m_pFGLeg || m_pBGLeg) { + if (m_MoveState == JUMP) { + // TODO: Utilize jump paths in an intuitive way! + if (m_pFGLeg) { + m_pFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGLeg->GetParentOffset()), m_pFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pFGLeg->GetMass(), deltaTime); + } + + if (m_pBGLeg) { + m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pBGLeg->GetMass(), deltaTime); + } + } else { + m_Paths[FGROUND][JUMP].Terminate(); + m_Paths[BGROUND][JUMP].Terminate(); + if (m_MoveState == CROUCH) { + m_Paths[FGROUND][WALK].Terminate(); + m_Paths[BGROUND][WALK].Terminate(); + m_Paths[FGROUND][CRAWL].Terminate(); + m_Paths[BGROUND][CRAWL].Terminate(); + + if (m_pFGLeg) { + m_pFGFootGroup->PushAsLimb(m_Pos.GetFloored() + m_pFGLeg->GetParentOffset().GetXFlipped(m_HFlipped), m_Vel, Matrix(), m_Paths[FGROUND][CROUCH], deltaTime); + } + + if (m_pBGLeg) { + m_pBGFootGroup->PushAsLimb(m_Pos.GetFloored() + m_pBGLeg->GetParentOffset().GetXFlipped(m_HFlipped), m_Vel, Matrix(), m_Paths[BGROUND][CROUCH], deltaTime); + } + + } else { + m_Paths[FGROUND][WALK].Terminate(); + m_Paths[BGROUND][WALK].Terminate(); + m_Paths[FGROUND][CRAWL].Terminate(); + m_Paths[BGROUND][CRAWL].Terminate(); + m_Paths[FGROUND][ARMCRAWL].Terminate(); + m_Paths[BGROUND][ARMCRAWL].Terminate(); + + if (m_pFGLeg) { + Vector jointPos = m_Pos.GetFloored() + m_pFGLeg->GetParentOffset().GetXFlipped(m_HFlipped); + m_pFGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[FGROUND], m_Paths[FGROUND][STAND], deltaTime, nullptr, !m_pBGLeg, Vector(0.0F, m_Paths[FGROUND][STAND].GetLowestY()), m_WalkPathOffset); + } + + if (m_pBGLeg) { + Vector jointPos = m_Pos.GetFloored() + m_pBGLeg->GetParentOffset().GetXFlipped(m_HFlipped); + m_pBGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[BGROUND], m_Paths[BGROUND][STAND], deltaTime, nullptr, !m_pFGLeg, Vector(0.0F, m_Paths[FGROUND][STAND].GetLowestY()), m_WalkPathOffset); + } } } - } else { - deviceAsFirearm->Deactivate(); - m_TriggerPulled = false; } } else { - m_CanActivateBGItem = false; - if (m_Controller.IsState(WEAPON_FIRE)) { - device->Activate(); - } else { - device->Deactivate(); + // Not stable/standing, so make sure the end of limbs are moving around limply in a ragdoll fashion. + // TODO: Make the limb atom groups fly around and react to terrain, without getting stuck etc. + if (m_pFGArm) { + m_pFGHandGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGArm->GetParentOffset()), m_pFGArm->GetMaxLength(), m_PrevVel * m_pFGArm->GetJointStiffness(), m_AngularVel, m_pFGArm->GetMass(), deltaTime); } - } - // If reloading 2 guns one-at-a-time, the automatic reload when firing empty won't trigger, so this makes sure it happens automatically. - if (device->IsEmpty()) { - ReloadFirearms(true); - } - device->SetSharpAim(m_SharpAimProgress); - - if (device->IsReloading()) { - m_CanActivateBGItem = false; - m_SharpAimTimer.Reset(); - m_SharpAimProgress = 0; - device->SetSharpAim(m_SharpAimProgress); - } - } else { - m_CanActivateBGItem = false; - } - if (m_ArmsState == THROWING_PREP && !thrownDevice) { - m_ArmsState = WEAPON_READY; - } + if (m_pBGArm) { + m_pBGHandGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGArm->GetParentOffset()), m_pBGArm->GetMaxLength(), m_PrevVel * m_pBGArm->GetJointStiffness(), m_AngularVel, m_pBGArm->GetMass(), deltaTime); + } -// m_aSprite->SetAngle((m_AimAngle / 180) * 3.141592654); -// m_aSprite->SetScale(2.0); - - //////////////////////////////////////// - // Item dropping logic - - if (m_Controller.IsState(WEAPON_DROP) && m_Status != INACTIVE) { - Arm *dropperArm = nullptr; - for (Arm *arm : { m_pFGArm, m_pBGArm }) { - if (arm && arm->GetHeldDevice()) { - HeldDevice *heldDevice = arm->GetHeldDevice(); - arm->RemoveAttachable(heldDevice, true, false); - if (dropperArm) { - if (heldDevice) { - dropperArm->SetHeldDevice(heldDevice); - arm->SetHandPos(dropperArm->GetPos()); - } - } else { - heldDevice->SetPos(arm->GetJointPos() + Vector(arm->GetMaxLength() * GetFlipFactor(), 0).RadRotate(adjustedAimAngle)); - Vector tossVec(1.0F + std::sqrt(std::abs(arm->GetThrowStrength()) / std::sqrt(std::abs(heldDevice->GetMass()) + 1.0F)), RandomNormalNum()); - heldDevice->SetVel(heldDevice->GetVel() * 0.5F + tossVec.RadRotate(m_AimAngle).GetXFlipped(m_HFlipped)); - heldDevice->SetAngularVel(heldDevice->GetAngularVel() + m_AngularVel * 0.5F + 3.0F * RandomNormalNum()); + if (m_pFGLeg) { + m_pFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGLeg->GetParentOffset()), m_pFGLeg->GetMaxLength(), m_PrevVel * m_pFGLeg->GetJointStiffness(), m_AngularVel, m_pFGLeg->GetMass(), deltaTime); + } - arm->SetHandPos(heldDevice->GetPos()); - } - dropperArm = arm; - } else if (dropperArm && !m_Inventory.empty()) { - dropperArm->SetHeldDevice(dynamic_cast(SwapNextInventory())); - dropperArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); + if (m_pBGLeg) { + m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel * m_pBGLeg->GetJointStiffness(), m_AngularVel, m_pBGLeg->GetMass(), deltaTime); } } - if (!dropperArm && !m_Inventory.empty() && !m_pFGArm) { - DropAllInventory(); - if (m_pBGArm) { - m_pBGArm->SetHandPos(m_Pos + RotateOffset(m_HolsterOffset)); - } + if (m_MoveState != WALK && m_StrideSound && m_StrideSound->GetLoopSetting() < 0) { + m_StrideSound->Stop(); } - EquipShieldInBGArm(); - m_SharpAimProgress = 0; - m_EquipHUDTimer.Reset(); - } - //////////////////////////////////////// - // Item pickup logic + ///////////////////////////////// + // Manage Attachables - float reach = m_SpriteRadius; - Vector reachPoint = m_Pos; - - // Try to detect a new item - if ((m_pFGArm || m_pBGArm) && m_Status == STABLE) { - reach += m_pFGArm ? m_pFGArm->GetMaxLength() : m_pBGArm->GetMaxLength(); - reachPoint = m_pFGArm ? m_pFGArm->GetJointPos() : m_pBGArm->GetJointPos(); - - MOID itemMOID = g_SceneMan.CastMORay(reachPoint, Vector(reach * RandomNum(0.5F, 1.0F) * GetFlipFactor(), 0).RadRotate(m_pItemInReach ? adjustedAimAngle : RandomNum(-(c_HalfPI + c_EighthPI), m_AimAngle * 0.75F + c_EighthPI) * GetFlipFactor()), m_MOID, m_Team, g_MaterialGrass, true, 3); - - if (MovableObject *foundMO = g_MovableMan.GetMOFromID(itemMOID)) { - if (HeldDevice *foundDevice = dynamic_cast(foundMO->GetRootParent())) { - m_pItemInReach = (m_pFGArm || foundDevice->IsOneHanded()) ? foundDevice : nullptr; + if (m_pHead) { + float toRotate = 0; + // Only rotate the head to match the aim angle if body is stable and upright + if (m_Status == STABLE && std::abs(rot) < (c_HalfPI + c_QuarterPI)) { + toRotate = m_pHead->GetRotMatrix().GetRadAngleTo((adjustedAimAngle)*m_LookToAimRatio + rot * (0.9F - m_LookToAimRatio)) * 0.15F; + } else { + // Rotate the head loosely along with the body if upside down, unstable or dying. + toRotate = m_pHead->GetRotMatrix().GetRadAngleTo(rot) * m_pHead->GetJointStiffness() * c_QuarterPI; } + m_pHead->SetRotAngle(m_pHead->GetRotAngle() + toRotate); } - } - - // Item currently set to be within reach has expired or is now out of range - if (m_pItemInReach && (!m_pItemInReach->IsPickupableBy(this) || !g_MovableMan.IsDevice(m_pItemInReach) || g_SceneMan.ShortestDistance(reachPoint, m_pItemInReach->GetPos(), g_SceneMan.SceneWrapsX()).MagnitudeIsGreaterThan(reach + m_pItemInReach->GetRadius()))) { - m_pItemInReach = nullptr; - } - if (m_pItemInReach && (m_pFGArm || m_pBGArm) && m_Controller.IsState(WEAPON_PICKUP) && m_Status != INACTIVE && g_MovableMan.RemoveMO(m_pItemInReach)) { - Arm *armToUse = m_pFGArm ? m_pFGArm : m_pBGArm; - Attachable *pMO = armToUse->RemoveAttachable(armToUse->GetHeldDevice()); - AddToInventoryBack(pMO); - armToUse->SetHandPos(m_pItemInReach->GetJointPos()); - armToUse->SetHeldDevice(m_pItemInReach); - m_pItemInReach = nullptr; + if (m_pFGLeg) { + m_pFGLeg->EnableIdle(m_ProneState == NOTPRONE && m_Status != UNSTABLE); + m_pFGLeg->SetTargetPosition(m_pFGFootGroup->GetLimbPos(m_HFlipped)); + } - if (armToUse != m_pBGArm) { - EquipShieldInBGArm(); + if (m_pBGLeg) { + m_pBGLeg->EnableIdle(m_ProneState == NOTPRONE && m_Status != UNSTABLE); + m_pBGLeg->SetTargetPosition(m_pBGFootGroup->GetLimbPos(m_HFlipped)); } - m_SharpAimProgress = 0; - if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } - m_EquipHUDTimer.Reset(); - } - - /////////////////////////////////////////////////// - // Travel the limb AtomGroup:s - - m_StrideFrame = false; - - UpdateCrouching(); - - if (m_Status == STABLE && !m_LimbPushForcesAndCollisionsDisabled && m_MoveState != NOMOVE) - { - // This exists to support disabling foot collisions if the limbpath has that flag set. - if ((m_pFGFootGroup->GetAtomCount() == 0 && m_BackupFGFootGroup->GetAtomCount() > 0) != m_Paths[FGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { - m_BackupFGFootGroup->SetLimbPos(m_pFGFootGroup->GetLimbPos()); - std::swap(m_pFGFootGroup, m_BackupFGFootGroup); - } - if ((m_pBGFootGroup->GetAtomCount() == 0 && m_BackupBGFootGroup->GetAtomCount() > 0) != m_Paths[BGROUND][m_MoveState].FootCollisionsShouldBeDisabled()) { - m_BackupBGFootGroup->SetLimbPos(m_pBGFootGroup->GetLimbPos()); - std::swap(m_pBGFootGroup, m_BackupBGFootGroup); - } - - if (m_pFGLeg) { UpdateWalkAngle(FGROUND); } - if (m_pBGLeg) { UpdateWalkAngle(BGROUND); } - - // WALKING, OR WE ARE JETPACKING AND STUCK - if (m_MoveState == WALK || (m_MoveState == JUMP && isStill)) { - m_Paths[FGROUND][STAND].Terminate(); - m_Paths[BGROUND][STAND].Terminate(); - -// float FGLegProg = MAX(m_Paths[FGROUND][WALK].GetRegularProgress(), m_Paths[FGROUND][WALK].GetTotalTimeProgress()); -// float BGLegProg = MAX(m_Paths[BGROUND][WALK].GetRegularProgress(), m_Paths[BGROUND][WALK].GetTotalTimeProgress()); - float FGLegProg = m_Paths[FGROUND][WALK].GetRegularProgress(); - float BGLegProg = m_Paths[BGROUND][WALK].GetRegularProgress(); - - bool restarted = false; - - // Make sure we are starting a stride if we're basically stopped. - if (isStill) { m_StrideStart = true; } - - if (m_pFGLeg && (!m_pBGLeg || !(m_Paths[FGROUND][WALK].PathEnded() && BGLegProg < 0.5F) || m_StrideStart)) { - // Reset the stride timer if the path is about to restart. - if (m_Paths[FGROUND][WALK].PathEnded() || m_Paths[FGROUND][WALK].PathIsAtStart()) { m_StrideTimer.Reset(); } - Vector jointPos = m_Pos + RotateOffset(m_pFGLeg->GetParentOffset()); - m_ArmClimbing[BGROUND] = !m_pFGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[FGROUND], m_Paths[FGROUND][WALK], deltaTime, &restarted, false, Vector(0.0F, m_Paths[FGROUND][WALK].GetLowestY()), m_WalkPathOffset); - } else { - m_ArmClimbing[BGROUND] = false; - } - if (m_pBGLeg && (!m_pFGLeg || !(m_Paths[BGROUND][WALK].PathEnded() && FGLegProg < 0.5F))) { - m_StrideStart = false; - // Reset the stride timer if the path is about to restart. - if (m_Paths[BGROUND][WALK].PathEnded() || m_Paths[BGROUND][WALK].PathIsAtStart()) { m_StrideTimer.Reset(); } - Vector jointPos = m_Pos + RotateOffset(m_pBGLeg->GetParentOffset()); - m_ArmClimbing[FGROUND] = !m_pBGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[BGROUND], m_Paths[BGROUND][WALK], deltaTime, &restarted, false, Vector(0.0F, m_Paths[BGROUND][WALK].GetLowestY()), m_WalkPathOffset); - } else { - if (m_pBGLeg) { m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pBGLeg->GetMass(), deltaTime); } - m_ArmClimbing[FGROUND] = false; - } - bool climbing = m_ArmClimbing[FGROUND] || m_ArmClimbing[BGROUND]; + // FG Arm rotating and climbing + if (m_pFGArm) { + float affectingBodyAngle = m_Status < INACTIVE ? m_FGArmFlailScalar : 1.0F; + if (affectingBodyAngle != 0 && m_SharpAimDelay != 0) { + float aimScalar = std::min(static_cast(m_SharpAimTimer.GetElapsedSimTimeMS()) / static_cast(m_SharpAimDelay), 1.0F); + float revertScalar = std::min(static_cast(m_SharpAimRevertTimer.GetElapsedSimTimeMS()) / static_cast(m_SharpAimDelay), 1.0F); + aimScalar = (aimScalar > revertScalar) ? aimScalar : 1.0F - revertScalar; - if (m_StrideSound) { - m_StrideSound->SetPosition(m_Pos); - if (m_StrideSound->GetLoopSetting() < 0) { - if (!m_StrideSound->IsBeingPlayed()) { m_StrideSound->Play(); } - } else if (restarted && !climbing) { - m_StrideSound->Play(); - } - } - if (restarted) { - if (climbing) { - m_WalkAngle[FGROUND] = Matrix(); - m_WalkAngle[BGROUND] = Matrix(); - } else { - m_StrideFrame = true; - RunScriptedFunctionInAppropriateScripts("OnStride"); - } + affectingBodyAngle *= std::abs(std::sin(rot)) * rot * (1.0F - aimScalar); } + m_pFGArm->SetRotAngle(affectingBodyAngle + adjustedAimAngle); - //////////////////////////////////////// - // Arm Climbing if the leg paths failed to find clear spot to restart - -// float FGArmProg = MAX(m_Paths[FGROUND][CLIMB].GetRegularProgress(), m_Paths[FGROUND][CLIMB].GetTotalTimeProgress()); -// float BGArmProg = MAX(m_Paths[BGROUND][CLIMB].GetRegularProgress(), m_Paths[BGROUND][CLIMB].GetTotalTimeProgress()); - float FGArmProg = m_Paths[FGROUND][CLIMB].GetRegularProgress(); - float BGArmProg = m_Paths[BGROUND][CLIMB].GetRegularProgress(); - - // TODO: Figure out what this comment means, and then rephrase it better! - // Slightly negative BGArmProg makes sense because any progress on the starting segments are reported as negative, - // and there's many starting segments on properly formed climbing paths - if (climbing) { - if (m_pFGArm && !m_pFGArm->GetHeldDevice() && !(m_Paths[FGROUND][CLIMB].PathEnded() && BGArmProg > 0.1F)) { // < 0.5F - m_ArmClimbing[FGROUND] = true; - m_Paths[FGROUND][WALK].Terminate(); - m_StrideStart = true; - // Reset the stride timer if the path is about to restart. - if (m_Paths[FGROUND][CLIMB].PathEnded() || m_Paths[FGROUND][CLIMB].PathIsAtStart()) { m_StrideTimer.Reset(); } - m_pFGHandGroup->PushAsLimb(m_Pos + Vector(0, m_pFGArm->GetParentOffset().m_Y).RadRotate(-rot), m_Vel, Matrix(), m_Paths[FGROUND][CLIMB], deltaTime, 0, false); - } else { - m_ArmClimbing[FGROUND] = false; - m_Paths[FGROUND][CLIMB].Terminate(); - } - if (m_pBGArm) { - m_ArmClimbing[BGROUND] = true; - m_Paths[BGROUND][WALK].Terminate(); - m_StrideStart = true; - // Reset the stride timer if the path is about to restart. - if (m_Paths[BGROUND][CLIMB].PathEnded() || m_Paths[BGROUND][CLIMB].PathIsAtStart()) { m_StrideTimer.Reset(); } - m_pBGHandGroup->PushAsLimb(m_Pos + Vector(0, m_pBGArm->GetParentOffset().m_Y).RadRotate(-rot), m_Vel, Matrix(), m_Paths[BGROUND][CLIMB], deltaTime, 0, false); - } else { - m_ArmClimbing[BGROUND] = false; - m_Paths[BGROUND][CLIMB].Terminate(); + if (m_Status == STABLE) { + if (m_ArmClimbing[FGROUND]) { + m_pFGArm->AddHandTarget("Hand AtomGroup Limb Pos", m_pFGHandGroup->GetLimbPos(m_HFlipped)); } + } else if (!m_pFGArm->GetHeldDevice()) { + m_pFGArm->ClearHandTargets(); + m_pFGArm->AddHandTarget("Arm Flail", m_pFGHandGroup->GetLimbPos(m_HFlipped)); } + } - // Restart the climbing stroke if the current one seems to be taking too long with no movement. - if (climbing && isStill && m_StrideTimer.IsPastSimMS(static_cast(m_Paths[BGROUND][CLIMB].GetTotalPathTime() * 0.5F))) { - m_StrideStart = true; - m_Paths[FGROUND][CLIMB].Terminate(); - m_Paths[BGROUND][CLIMB].Terminate(); - } else if (m_StrideTimer.IsPastSimMS(static_cast(m_Paths[FGROUND][WALK].GetTotalPathTime() * 1.1F))) { - // Reset the walking stride if it's taking longer than it should. - m_StrideStart = true; - m_Paths[FGROUND][WALK].Terminate(); - m_Paths[BGROUND][WALK].Terminate(); - } - } else if (m_MoveState == CRAWL) { - // Start crawling only once we are fully prone. - if (m_ProneState == PRONE) { - - float FGLegProg = m_Paths[FGROUND][CRAWL].GetRegularProgress(); - float BGLegProg = m_Paths[BGROUND][CRAWL].GetRegularProgress(); - - if (m_pFGLeg && (!m_pBGLeg || (!(m_Paths[FGROUND][CRAWL].PathEnded() && BGLegProg < 0.5F) || m_StrideStart))) { - if (m_Paths[FGROUND][CRAWL].PathEnded() || m_Paths[FGROUND][CRAWL].PathIsAtStart()) { m_StrideTimer.Reset(); } - m_pFGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pFGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[FGROUND][CRAWL], deltaTime); - } else { - m_Paths[FGROUND][CRAWL].Terminate(); - } - if (m_pBGLeg && (!m_pFGLeg || !(m_Paths[BGROUND][CRAWL].PathEnded() && FGLegProg < 0.5F))) { - m_StrideStart = false; - if (m_Paths[BGROUND][CRAWL].PathEnded() || m_Paths[BGROUND][CRAWL].PathIsAtStart()) { m_StrideTimer.Reset(); } - m_pBGFootGroup->PushAsLimb(m_Pos + RotateOffset(m_pBGLeg->GetParentOffset()), m_Vel, m_Rotation, m_Paths[BGROUND][CRAWL], deltaTime); + // BG Arm rotating, climbing, throw animations, supporting fg weapon + if (m_pBGArm) { + float affectingBodyAngle = m_Status < INACTIVE ? m_BGArmFlailScalar : 1.0F; + m_pBGArm->SetRotAngle(std::abs(std::sin(rot)) * rot * affectingBodyAngle + adjustedAimAngle); + + if (m_Status == STABLE) { + if (m_ArmClimbing[BGROUND]) { + // Can't climb or crawl with the shield + if (m_MoveState != CRAWL || m_ProneState == PRONE) { + UnequipBGArm(); + } + m_pBGArm->AddHandTarget("Hand AtomGroup Limb Pos", m_pBGHandGroup->GetLimbPos(m_HFlipped)); } else { - m_Paths[BGROUND][CRAWL].Terminate(); - } - if (m_pBGArm) { - m_ArmClimbing[BGROUND] = true; - m_pBGHandGroup->PushAsLimb(m_Pos + RotateOffset(Vector(0, m_pBGArm->GetParentOffset().m_Y)), m_Vel, m_Rotation, m_Paths[BGROUND][ARMCRAWL], deltaTime); - } - if (m_pFGArm && !m_pFGArm->GetHeldDevice() && !(m_Paths[FGROUND][ARMCRAWL].PathEnded() && m_Paths[BGROUND][ARMCRAWL].GetRegularProgress() < 0.5F)) { - m_ArmClimbing[FGROUND] = true; - m_pFGHandGroup->PushAsLimb(m_Pos + RotateOffset(Vector(0, m_pFGArm->GetParentOffset().m_Y)), m_Vel, m_Rotation, m_Paths[FGROUND][ARMCRAWL], deltaTime); - } - // Restart the stride if the current one seems to be taking too long. - if (m_StrideTimer.IsPastSimMS(m_Paths[FGROUND][CRAWL].GetTotalPathTime())) { - m_StrideStart = true; - m_Paths[FGROUND][CRAWL].Terminate(); - m_Paths[BGROUND][CRAWL].Terminate(); + HeldDevice* heldDevice = GetEquippedItem(); + ThrownDevice* thrownDevice = dynamic_cast(heldDevice); + if (thrownDevice && (m_ArmsState == THROWING_PREP || isSharpAiming)) { + m_pBGArm->AddHandTarget("End Throw Offset", m_pBGArm->GetJointPos() + thrownDevice->GetEndThrowOffset().GetXFlipped(m_HFlipped).RadRotate(adjustedAimAngle)); + } else if (heldDevice) { + if (HeldDevice* bgDevice = GetEquippedBGItem(); bgDevice && !heldDevice->IsOneHanded()) { + UnequipBGArm(); + } else if (!bgDevice && !heldDevice->IsReloading() && heldDevice->IsSupportable()) { + m_pBGArm->SetHeldDeviceThisArmIsTryingToSupport(heldDevice); + + if (!m_pBGArm->HasAnyHandTargets() && m_pBGArm->GetHandHasReachedCurrentTarget()) { + heldDevice->SetSupported(true); + m_pBGArm->SetRecoil(heldDevice->GetRecoilForce(), heldDevice->GetRecoilOffset(), heldDevice->IsRecoiled()); + } else { + // BGArm did not reach to support the device. Count device as supported anyway, if crouching or prone. + heldDevice->SetSupported(m_MoveState == CROUCH || m_ProneState == PRONE); + m_pBGArm->SetRecoil(Vector(), Vector(), false); + } + } + } } } else { - if (m_pFGLeg) { m_pFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGLeg->GetParentOffset()), m_pFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pFGLeg->GetMass(), deltaTime); } - - if (m_pBGLeg) { m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pBGLeg->GetMass(), deltaTime); } + m_pBGArm->ClearHandTargets(); + m_pBGArm->AddHandTarget("Arm Flail", m_pBGHandGroup->GetLimbPos(m_HFlipped)); } - } else if (m_pFGLeg || m_pBGLeg) { - if (m_MoveState == JUMP) { - // TODO: Utilize jump paths in an intuitive way! - if (m_pFGLeg) { m_pFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGLeg->GetParentOffset()), m_pFGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pFGLeg->GetMass(), deltaTime); } - - if (m_pBGLeg) { m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel, m_AngularVel, m_pBGLeg->GetMass(), deltaTime); } - } else { - m_Paths[FGROUND][JUMP].Terminate(); - m_Paths[BGROUND][JUMP].Terminate(); - if (m_MoveState == CROUCH) { - m_Paths[FGROUND][WALK].Terminate(); - m_Paths[BGROUND][WALK].Terminate(); - m_Paths[FGROUND][CRAWL].Terminate(); - m_Paths[BGROUND][CRAWL].Terminate(); - - if (m_pFGLeg) { m_pFGFootGroup->PushAsLimb(m_Pos.GetFloored() + m_pFGLeg->GetParentOffset().GetXFlipped(m_HFlipped), m_Vel, Matrix(), m_Paths[FGROUND][CROUCH], deltaTime); } - - if (m_pBGLeg) { m_pBGFootGroup->PushAsLimb(m_Pos.GetFloored() + m_pBGLeg->GetParentOffset().GetXFlipped(m_HFlipped), m_Vel, Matrix(), m_Paths[BGROUND][CROUCH], deltaTime); } + } else if (HeldDevice* heldDevice = GetEquippedItem()) { + heldDevice->SetSupported(false); + } + // Make sure the bg arm doesn't think it's supporting something when it isn't. + if (m_pBGArm && (!m_pFGArm || !m_pFGArm->GetHeldDevice() || m_pBGArm->GetHeldDevice())) { + m_pBGArm->SetHeldDeviceThisArmIsTryingToSupport(nullptr); + } - } else { - m_Paths[FGROUND][WALK].Terminate(); - m_Paths[BGROUND][WALK].Terminate(); - m_Paths[FGROUND][CRAWL].Terminate(); - m_Paths[BGROUND][CRAWL].Terminate(); - m_Paths[FGROUND][ARMCRAWL].Terminate(); - m_Paths[BGROUND][ARMCRAWL].Terminate(); + ///////////////////////////////// + // Arm swinging or device swaying walking animations - if (m_pFGLeg) { - Vector jointPos = m_Pos.GetFloored() + m_pFGLeg->GetParentOffset().GetXFlipped(m_HFlipped); - m_pFGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[FGROUND], m_Paths[FGROUND][STAND], deltaTime, nullptr, !m_pBGLeg, Vector(0.0F, m_Paths[FGROUND][STAND].GetLowestY()), m_WalkPathOffset); + if (m_MoveState != MovementState::STAND && (m_ArmSwingRate != 0 || m_DeviceArmSwayRate != 0)) { + for (Arm* arm: {m_pFGArm, m_pBGArm}) { + if (arm && !arm->GetHeldDeviceThisArmIsTryingToSupport()) { + Leg* legToSwingWith = arm == m_pFGArm ? m_pBGLeg : m_pFGLeg; + Leg* otherLeg = legToSwingWith == m_pBGLeg ? m_pFGLeg : m_pBGLeg; + if (!legToSwingWith || m_MoveState == JUMP || m_MoveState == CROUCH) { + std::swap(legToSwingWith, otherLeg); } - if (m_pBGLeg) { - Vector jointPos = m_Pos.GetFloored() + m_pBGLeg->GetParentOffset().GetXFlipped(m_HFlipped); - m_pBGFootGroup->PushAsLimb(jointPos, m_Vel, m_WalkAngle[BGROUND], m_Paths[BGROUND][STAND], deltaTime, nullptr, !m_pFGLeg, Vector(0.0F, m_Paths[FGROUND][STAND].GetLowestY()), m_WalkPathOffset); + if (legToSwingWith) { + float armMovementRateToUse = m_ArmSwingRate; + if (HeldDevice* heldDevice = arm->GetHeldDevice()) { + armMovementRateToUse = m_DeviceArmSwayRate * (1.0F - m_SharpAimProgress) * std::sin(std::abs(heldDevice->GetStanceOffset().GetAbsRadAngle())); + } + float angleToSwingTo = std::sin(legToSwingWith->GetRotAngle() + (c_HalfPI * GetFlipFactor())); + arm->SetHandIdleRotation(angleToSwingTo * armMovementRateToUse); } } } } - } else { - // Not stable/standing, so make sure the end of limbs are moving around limply in a ragdoll fashion. - // TODO: Make the limb atom groups fly around and react to terrain, without getting stuck etc. - if (m_pFGArm) { m_pFGHandGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGArm->GetParentOffset()), m_pFGArm->GetMaxLength(), m_PrevVel * m_pFGArm->GetJointStiffness(), m_AngularVel, m_pFGArm->GetMass(), deltaTime); } + } - if (m_pBGArm) { m_pBGHandGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGArm->GetParentOffset()), m_pBGArm->GetMaxLength(), m_PrevVel * m_pBGArm->GetJointStiffness(), m_AngularVel, m_pBGArm->GetMass(), deltaTime); } + ////////////////////////////////////////////////////////////////////////////////////////// - if (m_pFGLeg) { m_pFGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pFGLeg->GetParentOffset()), m_pFGLeg->GetMaxLength(), m_PrevVel * m_pFGLeg->GetJointStiffness(), m_AngularVel, m_pFGLeg->GetMass(), deltaTime); } + void AHuman::Update() { + ZoneScoped; - if (m_pBGLeg) { m_pBGFootGroup->FlailAsLimb(m_Pos, RotateOffset(m_pBGLeg->GetParentOffset()), m_pBGLeg->GetMaxLength(), m_PrevVel * m_pBGLeg->GetJointStiffness(), m_AngularVel, m_pBGLeg->GetMass(), deltaTime); } - } - if (m_MoveState != WALK && m_StrideSound && m_StrideSound->GetLoopSetting() < 0) { - m_StrideSound->Stop(); - } - - ///////////////////////////////// - // Manage Attachables - - if (m_pHead) { - float toRotate = 0; - // Only rotate the head to match the aim angle if body is stable and upright - if (m_Status == STABLE && std::abs(rot) < (c_HalfPI + c_QuarterPI)) { - toRotate = m_pHead->GetRotMatrix().GetRadAngleTo((adjustedAimAngle) * m_LookToAimRatio + rot * (0.9F - m_LookToAimRatio)) * 0.15F; - } else { - // Rotate the head loosely along with the body if upside down, unstable or dying. - toRotate = m_pHead->GetRotMatrix().GetRadAngleTo(rot) * m_pHead->GetJointStiffness() * c_QuarterPI; - } - m_pHead->SetRotAngle(m_pHead->GetRotAngle() + toRotate); - } + float rot = m_Rotation.GetRadAngle(); // eugh, for backwards compat to be the same behaviour as with multithreaded AI - if (m_pFGLeg) { - m_pFGLeg->EnableIdle(m_ProneState == NOTPRONE && m_Status != UNSTABLE); - m_pFGLeg->SetTargetPosition(m_pFGFootGroup->GetLimbPos(m_HFlipped)); - } - - if (m_pBGLeg) { - m_pBGLeg->EnableIdle(m_ProneState == NOTPRONE && m_Status != UNSTABLE); - m_pBGLeg->SetTargetPosition(m_pBGFootGroup->GetLimbPos(m_HFlipped)); - } - - // FG Arm rotating and climbing - if (m_pFGArm) { - float affectingBodyAngle = m_Status < INACTIVE ? m_FGArmFlailScalar : 1.0F; - if (affectingBodyAngle != 0 && m_SharpAimDelay != 0) { - float aimScalar = std::min(static_cast(m_SharpAimTimer.GetElapsedSimTimeMS()) / static_cast(m_SharpAimDelay), 1.0F); - float revertScalar = std::min(static_cast(m_SharpAimRevertTimer.GetElapsedSimTimeMS()) / static_cast(m_SharpAimDelay), 1.0F); - aimScalar = (aimScalar > revertScalar) ? aimScalar : 1.0F - revertScalar; - - affectingBodyAngle *= std::abs(std::sin(rot)) * rot * (1.0F - aimScalar); - } - m_pFGArm->SetRotAngle(affectingBodyAngle + adjustedAimAngle); - - if (m_Status == STABLE) { - if (m_ArmClimbing[FGROUND]) { - m_pFGArm->AddHandTarget("Hand AtomGroup Limb Pos", m_pFGHandGroup->GetLimbPos(m_HFlipped)); - } - } else if (!m_pFGArm->GetHeldDevice()) { - m_pFGArm->ClearHandTargets(); - m_pFGArm->AddHandTarget("Arm Flail", m_pFGHandGroup->GetLimbPos(m_HFlipped)); - } - } - - // BG Arm rotating, climbing, throw animations, supporting fg weapon - if (m_pBGArm) { - float affectingBodyAngle = m_Status < INACTIVE ? m_BGArmFlailScalar : 1.0F; - m_pBGArm->SetRotAngle(std::abs(std::sin(rot)) * rot * affectingBodyAngle + adjustedAimAngle); - - if (m_Status == STABLE) { - if (m_ArmClimbing[BGROUND]) { - // Can't climb or crawl with the shield - if (m_MoveState != CRAWL || m_ProneState == PRONE) { - UnequipBGArm(); - } - m_pBGArm->AddHandTarget("Hand AtomGroup Limb Pos", m_pBGHandGroup->GetLimbPos(m_HFlipped)); - } else { - HeldDevice *heldDevice = GetEquippedItem(); - ThrownDevice *thrownDevice = dynamic_cast(heldDevice); - if (thrownDevice && (m_ArmsState == THROWING_PREP || isSharpAiming)) { - m_pBGArm->AddHandTarget("End Throw Offset", m_pBGArm->GetJointPos() + thrownDevice->GetEndThrowOffset().GetXFlipped(m_HFlipped).RadRotate(adjustedAimAngle)); - } else if (heldDevice) { - if (HeldDevice *bgDevice = GetEquippedBGItem(); bgDevice && !heldDevice->IsOneHanded()) { - UnequipBGArm(); - } else if (!bgDevice && !heldDevice->IsReloading() && heldDevice->IsSupportable()) { - m_pBGArm->SetHeldDeviceThisArmIsTryingToSupport(heldDevice); + Actor::Update(); - if (!m_pBGArm->HasAnyHandTargets() && m_pBGArm->GetHandHasReachedCurrentTarget()) { - heldDevice->SetSupported(true); - m_pBGArm->SetRecoil(heldDevice->GetRecoilForce(), heldDevice->GetRecoilOffset(), heldDevice->IsRecoiled()); - } else { - // BGArm did not reach to support the device. Count device as supported anyway, if crouching or prone. - heldDevice->SetSupported(m_MoveState == CROUCH || m_ProneState == PRONE); - m_pBGArm->SetRecoil(Vector(), Vector(), false); + //////////////////////////////////// + // Update viewpoint + + // Set viewpoint based on how we are aiming etc. + Vector aimSight(m_AimDistance, 0); + Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); + aimMatrix.SetXFlipped(m_HFlipped); + // Reset this each frame + m_SharpAimMaxedOut = false; + + if (HeldDevice* heldDevice = GetEquippedItem()) { + float maxLength = heldDevice->GetSharpLength(); + if (maxLength == 0) { + m_SharpAimProgress = 0; + m_SharpAimMaxedOut = true; + } else if (m_MoveState == WALK) { + maxLength *= 0.7F; + } + // Use a non-terrain check ray to cap the magnitude, so we can't see into objects etc + if (m_SharpAimProgress > 0) { + // TODO: make an uniform function to get the total GripStrength of an AHuman? + float totalGripStrength = m_pFGArm->GetGripStrength(); + if (m_pBGArm) { + if (m_pBGArm->GetHeldDevice()) { + HeldDevice* heldBGDevice = m_pBGArm->GetHeldDevice(); + if (heldBGDevice->IsRecoiled()) { + m_SharpAimProgress *= 1.0F - std::min(heldBGDevice->GetRecoilForce().GetMagnitude() / std::max(m_pBGArm->GetGripStrength() * heldBGDevice->GetGripStrengthMultiplier(), 1.0F), 1.0F); } + } else if (heldDevice->GetSupported()) { + totalGripStrength += m_pBGArm->GetGripStrength(); } } - } - } else { - m_pBGArm->ClearHandTargets(); - m_pBGArm->AddHandTarget("Arm Flail", m_pBGHandGroup->GetLimbPos(m_HFlipped)); - } - } else if (HeldDevice *heldDevice = GetEquippedItem()) { - heldDevice->SetSupported(false); - } - // Make sure the bg arm doesn't think it's supporting something when it isn't. - if (m_pBGArm && (!m_pFGArm || !m_pFGArm->GetHeldDevice() || m_pBGArm->GetHeldDevice())) { - m_pBGArm->SetHeldDeviceThisArmIsTryingToSupport(nullptr); - } - - ///////////////////////////////// - // Arm swinging or device swaying walking animations - - if (m_MoveState != MovementState::STAND && (m_ArmSwingRate != 0 || m_DeviceArmSwayRate != 0)) { - for (Arm *arm : { m_pFGArm, m_pBGArm }) { - if (arm && !arm->GetHeldDeviceThisArmIsTryingToSupport()) { - Leg *legToSwingWith = arm == m_pFGArm ? m_pBGLeg : m_pFGLeg; - Leg *otherLeg = legToSwingWith == m_pBGLeg ? m_pFGLeg : m_pBGLeg; - if (!legToSwingWith || m_MoveState == JUMP || m_MoveState == CROUCH) { - std::swap(legToSwingWith, otherLeg); + if (heldDevice->IsRecoiled()) { + m_SharpAimProgress *= 1.0F - std::min(heldDevice->GetRecoilForce().GetMagnitude() / std::max(totalGripStrength * heldDevice->GetGripStrengthMultiplier(), 1.0F), 1.0F); } - - if (legToSwingWith) { - float armMovementRateToUse = m_ArmSwingRate; - if (HeldDevice *heldDevice = arm->GetHeldDevice()) { - armMovementRateToUse = m_DeviceArmSwayRate * (1.0F - m_SharpAimProgress) * std::sin(std::abs(heldDevice->GetStanceOffset().GetAbsRadAngle())); - } - float angleToSwingTo = std::sin(legToSwingWith->GetRotAngle() + (c_HalfPI * GetFlipFactor())); - arm->SetHandIdleRotation(angleToSwingTo * armMovementRateToUse); + Vector notUsed; + Vector sharpAimVector(maxLength, 0); + sharpAimVector *= aimMatrix; + + // See how far along the sharp aim vector there is opaque air + float result = g_SceneMan.CastObstacleRay(heldDevice->GetMuzzlePos(), sharpAimVector, notUsed, notUsed, GetRootID(), IgnoresWhichTeam(), g_MaterialAir, 5); + // If we didn't find anything but air before the sharpdistance, then don't alter the sharp distance + if (result >= 0 && result < (maxLength * m_SharpAimProgress)) { + m_SharpAimProgress = result / maxLength; + m_SharpAimMaxedOut = true; } } + if (m_SharpAimProgress > 0.9F) { + m_SharpAimMaxedOut = true; + } + aimSight.m_X += maxLength * m_SharpAimProgress; } - } -} -////////////////////////////////////////////////////////////////////////////////////////// + // Rotate the aiming spot vector and add it to the view point + aimSight *= aimMatrix; + m_ViewPoint = m_Pos.GetFloored() + aimSight; -void AHuman::Update() -{ - ZoneScoped; + // Add velocity also so the viewpoint moves ahead at high speeds + if (m_Vel.MagnitudeIsGreaterThan(10.0F)) { + m_ViewPoint += m_Vel * std::sqrt(m_Vel.GetMagnitude() * 0.1F); + } - float rot = m_Rotation.GetRadAngle(); // eugh, for backwards compat to be the same behaviour as with multithreaded AI + //////////////////////////////////////// + // Balance stuff - Actor::Update(); + // Eliminate full rotations + while (std::abs(rot) > c_TwoPI) { + rot -= rot > 0 ? c_TwoPI : -c_TwoPI; + } + // Eliminate rotations over half a turn + if (std::abs(rot) > c_PI) { + rot = (rot > 0 ? -c_PI : c_PI) + (rot - (rot > 0 ? c_PI : -c_PI)); + // If we're upside down, we're unstable damnit + if (m_Status == STABLE) { + m_Status = UNSTABLE; + } + m_StableRecoverTimer.Reset(); + } - //////////////////////////////////// - // Update viewpoint + // Rotational balancing spring calc + if (m_Status == STABLE) { - // Set viewpoint based on how we are aiming etc. - Vector aimSight(m_AimDistance, 0); - Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); - aimMatrix.SetXFlipped(m_HFlipped); - // Reset this each frame - m_SharpAimMaxedOut = false; + // If we're supposed to be laying down on the ground, make the spring pull the body that way until we reach that angle + if (m_ProneState != NOTPRONE) { + float rotTarget = m_HFlipped ? c_HalfPI : -c_HalfPI; + float rotDiff = rotTarget - rot; - if (HeldDevice *heldDevice = GetEquippedItem()) { - float maxLength = heldDevice->GetSharpLength(); - if (maxLength == 0) { - m_SharpAimProgress = 0; - m_SharpAimMaxedOut = true; - } else if (m_MoveState == WALK) { - maxLength *= 0.7F; - } - // Use a non-terrain check ray to cap the magnitude, so we can't see into objects etc - if (m_SharpAimProgress > 0) { - // TODO: make an uniform function to get the total GripStrength of an AHuman? - float totalGripStrength = m_pFGArm->GetGripStrength(); - if (m_pBGArm) { - if (m_pBGArm->GetHeldDevice()) { - HeldDevice *heldBGDevice = m_pBGArm->GetHeldDevice(); - if (heldBGDevice->IsRecoiled()) { - m_SharpAimProgress *= 1.0F - std::min(heldBGDevice->GetRecoilForce().GetMagnitude() / std::max(m_pBGArm->GetGripStrength() * heldBGDevice->GetGripStrengthMultiplier(), 1.0F), 1.0F); + if (m_ProneState == GOPRONE) { + if (!m_ProneTimer.IsPastSimMS(333)) { + if (std::abs(rotDiff) > 0.1F && std::abs(rotDiff) < c_PI) { + m_AngularVel += rotDiff * 0.4F; + m_Vel.m_X += (m_HFlipped ? -std::abs(rotDiff) : std::abs(rotDiff)) / std::max(m_Vel.GetMagnitude(), 4.0F); + } + } else { + // Done going down, now stay down without spring. + m_AngularVel *= 0.5F; + m_ProneState = PRONE; } - } else if (heldDevice->GetSupported()) { - totalGripStrength += m_pBGArm->GetGripStrength(); - } - } - if (heldDevice->IsRecoiled()) { - m_SharpAimProgress *= 1.0F - std::min(heldDevice->GetRecoilForce().GetMagnitude() / std::max(totalGripStrength * heldDevice->GetGripStrengthMultiplier(), 1.0F), 1.0F); - } - Vector notUsed; - Vector sharpAimVector(maxLength, 0); - sharpAimVector *= aimMatrix; - - // See how far along the sharp aim vector there is opaque air - float result = g_SceneMan.CastObstacleRay(heldDevice->GetMuzzlePos(), sharpAimVector, notUsed, notUsed, GetRootID(), IgnoresWhichTeam(), g_MaterialAir, 5); - // If we didn't find anything but air before the sharpdistance, then don't alter the sharp distance - if (result >= 0 && result < (maxLength * m_SharpAimProgress)) - { - m_SharpAimProgress = result / maxLength; - m_SharpAimMaxedOut = true; - } - } - if (m_SharpAimProgress > 0.9F) { m_SharpAimMaxedOut = true; } - aimSight.m_X += maxLength * m_SharpAimProgress; - } - - // Rotate the aiming spot vector and add it to the view point - aimSight *= aimMatrix; - m_ViewPoint = m_Pos.GetFloored() + aimSight; - - // Add velocity also so the viewpoint moves ahead at high speeds - if (m_Vel.MagnitudeIsGreaterThan(10.0F)) { m_ViewPoint += m_Vel * std::sqrt(m_Vel.GetMagnitude() * 0.1F); } - - //////////////////////////////////////// - // Balance stuff - - // Eliminate full rotations - while (std::abs(rot) > c_TwoPI) { - rot -= rot > 0 ? c_TwoPI : -c_TwoPI; - } - // Eliminate rotations over half a turn - if (std::abs(rot) > c_PI) { - rot = (rot > 0 ? -c_PI : c_PI) + (rot - (rot > 0 ? c_PI : -c_PI)); - // If we're upside down, we're unstable damnit - if (m_Status == STABLE) { m_Status = UNSTABLE; } - m_StableRecoverTimer.Reset(); - } - - // Rotational balancing spring calc - if (m_Status == STABLE) { - - // If we're supposed to be laying down on the ground, make the spring pull the body that way until we reach that angle - if (m_ProneState != NOTPRONE) - { - float rotTarget = m_HFlipped ? c_HalfPI : -c_HalfPI; - float rotDiff = rotTarget - rot; - - if (m_ProneState == GOPRONE) { - if (!m_ProneTimer.IsPastSimMS(333)) { - if (std::abs(rotDiff) > 0.1F && std::abs(rotDiff) < c_PI) { - m_AngularVel += rotDiff * 0.4F; - m_Vel.m_X += (m_HFlipped ? -std::abs(rotDiff) : std::abs(rotDiff)) / std::max(m_Vel.GetMagnitude(), 4.0F); + } else if (m_ProneState == PRONE) { + // If down, try to keep flat against the ground. + if (std::abs(rotDiff) > c_SixteenthPI && std::abs(rotDiff) < c_HalfPI) { + m_AngularVel += rotDiff * 0.65F; + } else if (std::abs(m_AngularVel) > 0.3F) { + m_AngularVel *= 0.85F; } - } else { - // Done going down, now stay down without spring. - m_AngularVel *= 0.5F; - m_ProneState = PRONE; - } - } else if (m_ProneState == PRONE) { - // If down, try to keep flat against the ground. - if (std::abs(rotDiff) > c_SixteenthPI && std::abs(rotDiff) < c_HalfPI) { - m_AngularVel += rotDiff * 0.65F; - } else if (std::abs(m_AngularVel) > 0.3F) { - m_AngularVel *= 0.85F; } + } else { + // Upright body posture + float rotTarget = (GetRotAngleTarget(m_MoveState) * (m_AimAngle > 0 ? 1.0F - (m_AimAngle / c_HalfPI) : 1.0F) * GetFlipFactor()); + + // Lean forwards when crouching + float crouchAngleAdjust = m_HFlipped ? m_MaxCrouchRotation : -m_MaxCrouchRotation; + rotTarget += LERP(0.0F, m_MaxWalkPathCrouchShift, 0.0F, crouchAngleAdjust, m_WalkPathOffset.m_Y * -1.0F); + + float rotDiff = rot - rotTarget; + m_AngularVel = m_AngularVel * (0.98F - 0.06F * (m_Health / m_MaxHealth)) - (rotDiff * 0.5F); + } + } else if (m_Status == UNSTABLE) { + float rotTarget = 0; + // If traveling at speed, always start falling forward. + if (std::abs(m_Vel.m_X) > 1.0F) { + rotTarget = m_HFlipped ? c_HalfPI : -c_HalfPI; + } else { + // Otherwise, go whichever way we're already rotated. + rotTarget = rot > 0 ? c_HalfPI : -c_HalfPI; + } + + float rotDiff = rotTarget - rot; + if (std::abs(rotDiff) > 0.1F && std::abs(rotDiff) < c_PI) { + m_AngularVel += rotDiff * 0.05F; + } + } else if (m_Status == DYING) { + float rotTarget = m_Vel.m_X - (rot + m_AngularVel) > 0 ? -c_HalfPI : c_HalfPI; + float rotDiff = rotTarget - rot; + if (!m_DeathTmr.IsPastSimMS(125) && std::abs(rotDiff) > 0.1F && std::abs(rotDiff) < c_PI) { + // TODO: finetune this for situations like low gravity! + float velScalar = 0.5F; //* (g_SceneMan.GetGlobalAcc().GetY() * m_GlobalAccScalar) / c_PPM; + m_AngularVel += rotDiff * velScalar; + m_Vel.m_X += (rotTarget > 0 ? -std::abs(rotDiff) : std::abs(rotDiff)) * velScalar * 0.5F; + } else { + m_Status = DEAD; } - } else { - // Upright body posture - float rotTarget = (GetRotAngleTarget(m_MoveState) * (m_AimAngle > 0 ? 1.0F - (m_AimAngle / c_HalfPI) : 1.0F) * GetFlipFactor()); - - // Lean forwards when crouching - float crouchAngleAdjust = m_HFlipped ? m_MaxCrouchRotation : -m_MaxCrouchRotation; - rotTarget += LERP(0.0F, m_MaxWalkPathCrouchShift, 0.0F, crouchAngleAdjust, m_WalkPathOffset.m_Y * -1.0F); - - float rotDiff = rot - rotTarget; - m_AngularVel = m_AngularVel * (0.98F - 0.06F * (m_Health / m_MaxHealth)) - (rotDiff * 0.5F); - } - } - else if (m_Status == UNSTABLE) { - float rotTarget = 0; - // If traveling at speed, always start falling forward. - if (std::abs(m_Vel.m_X) > 1.0F) { - rotTarget = m_HFlipped ? c_HalfPI : -c_HalfPI; - } else { - // Otherwise, go whichever way we're already rotated. - rotTarget = rot > 0 ? c_HalfPI : -c_HalfPI; - } - - float rotDiff = rotTarget - rot; - if (std::abs(rotDiff) > 0.1F && std::abs(rotDiff) < c_PI) { - m_AngularVel += rotDiff * 0.05F; - } - } else if (m_Status == DYING) { - float rotTarget = m_Vel.m_X - (rot + m_AngularVel) > 0 ? -c_HalfPI : c_HalfPI; - float rotDiff = rotTarget - rot; - if (!m_DeathTmr.IsPastSimMS(125) && std::abs(rotDiff) > 0.1F && std::abs(rotDiff) < c_PI) { - // TODO: finetune this for situations like low gravity! - float velScalar = 0.5F; //* (g_SceneMan.GetGlobalAcc().GetY() * m_GlobalAccScalar) / c_PPM; - m_AngularVel += rotDiff * velScalar; - m_Vel.m_X += (rotTarget > 0 ? -std::abs(rotDiff) : std::abs(rotDiff)) * velScalar * 0.5F; - } else { - m_Status = DEAD; } - } - m_Rotation.SetRadAngle(rot); + m_Rotation.SetRadAngle(rot); - /////////////////////////////////////////////////// - // Death detection and handling + /////////////////////////////////////////////////// + // Death detection and handling - if (!m_pHead && m_Status != DYING && m_Status != DEAD) { - m_Health -= m_MaxHealth + 1.0F; - } else if (!m_pFGArm && !m_pBGArm && !m_pFGLeg && !m_pBGLeg && m_Status != DYING && m_Status != DEAD) { - m_Health -= 0.1F; - } + if (!m_pHead && m_Status != DYING && m_Status != DEAD) { + m_Health -= m_MaxHealth + 1.0F; + } else if (!m_pFGArm && !m_pBGArm && !m_pFGLeg && !m_pBGLeg && m_Status != DYING && m_Status != DEAD) { + m_Health -= 0.1F; + } - if (m_Status == DYING) { - if (m_pFGArm) { m_pFGArm->RemoveAttachable(m_pFGArm->GetHeldDevice(), true, false); } - if (m_pBGArm) { m_pBGArm->RemoveAttachable(m_pBGArm->GetHeldDevice(), true, false); } - } + if (m_Status == DYING) { + if (m_pFGArm) { + m_pFGArm->RemoveAttachable(m_pFGArm->GetHeldDevice(), true, false); + } + if (m_pBGArm) { + m_pBGArm->RemoveAttachable(m_pBGArm->GetHeldDevice(), true, false); + } + } - ///////////////////////////////////////// - // Misc. + ///////////////////////////////////////// + // Misc. -// m_DeepCheck = true/*m_Status == DEAD*/; -} + // m_DeepCheck = true/*m_Status == DEAD*/; + } + ////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// + void AHuman::DrawThrowingReticle(BITMAP* targetBitmap, const Vector& targetPos, float progressScalar) const { + const int pointCount = 9; + Vector points[pointCount]; -void AHuman::DrawThrowingReticle(BITMAP *targetBitmap, const Vector &targetPos, float progressScalar) const { - const int pointCount = 9; - Vector points[pointCount]; + for (int index = 0; index < pointCount; index++) { + points[index].SetXY(static_cast(index * 4), 0.0F); + } + Vector outOffset(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F); + float adjustedAimAngle = m_AimAngle * GetFlipFactor(); - for (int index = 0; index < pointCount; index++) { - points[index].SetXY(static_cast(index * 4), 0.0F); - } - Vector outOffset(m_pFGArm->GetMaxLength() * GetFlipFactor(), -m_pFGArm->GetMaxLength() * 0.5F); - float adjustedAimAngle = m_AimAngle * GetFlipFactor(); + acquire_bitmap(targetBitmap); - acquire_bitmap(targetBitmap); + for (int i = 0; i < pointCount * progressScalar; ++i) { + points[i].FlipX(m_HFlipped); + points[i] += outOffset; + points[i].RadRotate(adjustedAimAngle); + points[i] += m_pFGArm->GetJointPos(); - for (int i = 0; i < pointCount * progressScalar; ++i) { - points[i].FlipX(m_HFlipped); - points[i] += outOffset; - points[i].RadRotate(adjustedAimAngle); - points[i] += m_pFGArm->GetJointPos(); + g_PostProcessMan.RegisterGlowDotEffect(points[i], YellowDot, RandomNum(63, 127)); + putpixel(targetBitmap, points[i].GetFloorIntX() - targetPos.GetFloorIntX(), points[i].GetFloorIntY() - targetPos.GetFloorIntY(), g_YellowGlowColor); + } - g_PostProcessMan.RegisterGlowDotEffect(points[i], YellowDot, RandomNum(63, 127)); - putpixel(targetBitmap, points[i].GetFloorIntX() - targetPos.GetFloorIntX(), points[i].GetFloorIntY() - targetPos.GetFloorIntY(), g_YellowGlowColor); + release_bitmap(targetBitmap); } - release_bitmap(targetBitmap); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this AHuman's current graphical representation to a -// BITMAP of choice. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this AHuman's current graphical representation to a + // BITMAP of choice. -void AHuman::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { - Actor::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + void AHuman::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + Actor::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - DrawMode realMode = (mode == g_DrawColor && !m_FlashWhiteTimer.IsPastRealTimeLimit()) ? g_DrawWhite : mode; - // Note: For some reason the ordering of the attachables list can get messed up. The most important thing here is that the FGArm is on top of everything else. - if (m_pHead && m_pHead->IsDrawnAfterParent()) { m_pHead->Draw(pTargetBitmap, targetPos, realMode, onlyPhysical); } - if (m_pFGArm) { m_pFGArm->Draw(pTargetBitmap, targetPos, realMode, onlyPhysical); } - - // Draw background Arm's hand after the HeldDevice of FGArm is drawn if the FGArm is holding a weapon. - if (m_pFGArm && m_pBGArm && !onlyPhysical && mode == g_DrawColor && m_pBGArm->GetHandHasReachedCurrentTarget() && !GetEquippedBGItem()) { - if (HeldDevice *heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && !dynamic_cast(heldDevice) && !heldDevice->IsReloading() && !heldDevice->IsShield()) { - m_pBGArm->DrawHand(pTargetBitmap, targetPos, realMode); + DrawMode realMode = (mode == g_DrawColor && !m_FlashWhiteTimer.IsPastRealTimeLimit()) ? g_DrawWhite : mode; + // Note: For some reason the ordering of the attachables list can get messed up. The most important thing here is that the FGArm is on top of everything else. + if (m_pHead && m_pHead->IsDrawnAfterParent()) { + m_pHead->Draw(pTargetBitmap, targetPos, realMode, onlyPhysical); + } + if (m_pFGArm) { + m_pFGArm->Draw(pTargetBitmap, targetPos, realMode, onlyPhysical); } - } - if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawHandAndFootGroupVisualizations()) { - m_pFGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - m_pBGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); - m_pFGHandGroup->Draw(pTargetBitmap, targetPos, true, 13); - m_pBGHandGroup->Draw(pTargetBitmap, targetPos, true, 13); - } + // Draw background Arm's hand after the HeldDevice of FGArm is drawn if the FGArm is holding a weapon. + if (m_pFGArm && m_pBGArm && !onlyPhysical && mode == g_DrawColor && m_pBGArm->GetHandHasReachedCurrentTarget() && !GetEquippedBGItem()) { + if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice(); heldDevice && !dynamic_cast(heldDevice) && !heldDevice->IsReloading() && !heldDevice->IsShield()) { + m_pBGArm->DrawHand(pTargetBitmap, targetPos, realMode); + } + } - if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawLimbPathVisualizations()) { - m_Paths[m_HFlipped][WALK].Draw(pTargetBitmap, targetPos, 122); - m_Paths[m_HFlipped][CRAWL].Draw(pTargetBitmap, targetPos, 122); - m_Paths[m_HFlipped][ARMCRAWL].Draw(pTargetBitmap, targetPos, 13); - m_Paths[m_HFlipped][CLIMB].Draw(pTargetBitmap, targetPos, 165); - } -} + if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawHandAndFootGroupVisualizations()) { + m_pFGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + m_pBGFootGroup->Draw(pTargetBitmap, targetPos, true, 13); + m_pFGHandGroup->Draw(pTargetBitmap, targetPos, true, 13); + m_pBGHandGroup->Draw(pTargetBitmap, targetPos, true, 13); + } + if (mode == g_DrawColor && !onlyPhysical && g_SettingsMan.DrawLimbPathVisualizations()) { + m_Paths[m_HFlipped][WALK].Draw(pTargetBitmap, targetPos, 122); + m_Paths[m_HFlipped][CRAWL].Draw(pTargetBitmap, targetPos, 122); + m_Paths[m_HFlipped][ARMCRAWL].Draw(pTargetBitmap, targetPos, 13); + m_Paths[m_HFlipped][CLIMB].Draw(pTargetBitmap, targetPos, 165); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. -void AHuman::DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) { - m_HUDStack = -m_CharHeight / 2; + void AHuman::DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { + m_HUDStack = -m_CharHeight / 2; - // Only do HUD if on a team - if (m_Team < 0) - return; + // Only do HUD if on a team + if (m_Team < 0) + return; - // Only draw if the team viewing this is on the same team OR has seen the space where this is located. - int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); - if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { - return; - } + // Only draw if the team viewing this is on the same team OR has seen the space where this is located. + int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); + if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { + return; + } - Actor::DrawHUD(pTargetBitmap, targetPos, whichScreen); + Actor::DrawHUD(pTargetBitmap, targetPos, whichScreen); - if (!m_HUDVisible) { - return; - } + if (!m_HUDVisible) { + return; + } #ifdef DEBUG_BUILD - // Limbpath debug drawing - m_Paths[FGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); - m_Paths[FGROUND][CRAWL].Draw(pTargetBitmap, targetPos, 122); - m_Paths[FGROUND][ARMCRAWL].Draw(pTargetBitmap, targetPos, 13); - m_Paths[FGROUND][CLIMB].Draw(pTargetBitmap, targetPos, 98); - - m_Paths[BGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); - m_Paths[BGROUND][CRAWL].Draw(pTargetBitmap, targetPos, 122); - m_Paths[BGROUND][ARMCRAWL].Draw(pTargetBitmap, targetPos, 13); - m_Paths[BGROUND][CLIMB].Draw(pTargetBitmap, targetPos, 98); - - // Draw the AI paths - std::list::iterator last = m_MovePath.begin(); - Vector waypoint, lastPoint, lineVec; - for (std::list::iterator lItr = m_MovePath.begin(); lItr != m_MovePath.end(); ++lItr) - { - lastPoint = (*last) - targetPos; - waypoint = lastPoint + g_SceneMan.ShortestDistance(lastPoint, (*lItr) - targetPos); - line(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, waypoint.m_X, waypoint.m_Y, g_RedColor); - last = lItr; - } - waypoint = m_MoveTarget - targetPos; - circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 3, g_RedColor); - lastPoint = m_PrevPathTarget - targetPos; - circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); - lastPoint = m_DigTunnelEndPos - targetPos; - circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); - // Radius + // Limbpath debug drawing + m_Paths[FGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); + m_Paths[FGROUND][CRAWL].Draw(pTargetBitmap, targetPos, 122); + m_Paths[FGROUND][ARMCRAWL].Draw(pTargetBitmap, targetPos, 13); + m_Paths[FGROUND][CLIMB].Draw(pTargetBitmap, targetPos, 98); + + m_Paths[BGROUND][WALK].Draw(pTargetBitmap, targetPos, 122); + m_Paths[BGROUND][CRAWL].Draw(pTargetBitmap, targetPos, 122); + m_Paths[BGROUND][ARMCRAWL].Draw(pTargetBitmap, targetPos, 13); + m_Paths[BGROUND][CLIMB].Draw(pTargetBitmap, targetPos, 98); + + // Draw the AI paths + std::list::iterator last = m_MovePath.begin(); + Vector waypoint, lastPoint, lineVec; + for (std::list::iterator lItr = m_MovePath.begin(); lItr != m_MovePath.end(); ++lItr) { + lastPoint = (*last) - targetPos; + waypoint = lastPoint + g_SceneMan.ShortestDistance(lastPoint, (*lItr) - targetPos); + line(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, waypoint.m_X, waypoint.m_Y, g_RedColor); + last = lItr; + } + waypoint = m_MoveTarget - targetPos; + circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 3, g_RedColor); + lastPoint = m_PrevPathTarget - targetPos; + circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); + lastPoint = m_DigTunnelEndPos - targetPos; + circlefill(pTargetBitmap, lastPoint.m_X, lastPoint.m_Y, 2, g_YellowGlowColor); + // Radius // waypoint = m_Pos - targetPos; // circle(pTargetBitmap, waypoint.m_X, waypoint.m_Y, m_MoveProximityLimit, g_RedColor); #endif - // Player AI drawing - - if (m_pFGArm && m_pFGArm->GetHeldDevice()) { - // Draw the aiming dots for the currently held device. - if (m_ArmsState == THROWING_PREP) { - DrawThrowingReticle(pTargetBitmap, targetPos, GetThrowProgress()); - } else if (m_Controller.IsState(AIM_SHARP) || (m_Controller.IsPlayerControlled() && !m_Controller.IsState(PIE_MENU_ACTIVE))) { - m_pFGArm->GetHeldDevice()->DrawHUD(pTargetBitmap, targetPos, whichScreen, m_Controller.IsState(AIM_SHARP) && m_Controller.IsPlayerControlled()); - } - } - - ////////////////////////////////////// - // Draw stat info HUD - char str[64]; - - GUIFont *pSymbolFont = g_FrameMan.GetLargeFont(); - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); + // Player AI drawing - // Only show extra HUD if this guy is controlled by the same player that this screen belongs to - if (m_Controller.IsPlayerControlled() && g_ActivityMan.GetActivity()->ScreenOfPlayer(m_Controller.GetPlayer()) == whichScreen && pSmallFont && pSymbolFont) - { - AllegroBitmap allegroBitmap(pTargetBitmap); - /* - // Device aiming reticle - if (m_Controller.IsState(AIM_SHARP) && - m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->HoldsHeldDevice()) - m_pFGArm->GetHeldDevice()->DrawHUD(pTargetBitmap, targetPos, whichScreen);*/ - - Vector drawPos = m_Pos - targetPos; - - // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam - if (!targetPos.IsZero()) - { - // Spans vertical scene seam - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) - { - if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) - drawPos.m_X -= sceneWidth; - else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) - drawPos.m_X += sceneWidth; - } - // Spans horizontal scene seam - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) - { - if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) - drawPos.m_Y -= sceneHeight; - else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) - drawPos.m_Y += sceneHeight; + if (m_pFGArm && m_pFGArm->GetHeldDevice()) { + // Draw the aiming dots for the currently held device. + if (m_ArmsState == THROWING_PREP) { + DrawThrowingReticle(pTargetBitmap, targetPos, GetThrowProgress()); + } else if (m_Controller.IsState(AIM_SHARP) || (m_Controller.IsPlayerControlled() && !m_Controller.IsState(PIE_MENU_ACTIVE))) { + m_pFGArm->GetHeldDevice()->DrawHUD(pTargetBitmap, targetPos, whichScreen, m_Controller.IsState(AIM_SHARP) && m_Controller.IsPlayerControlled()); } } - if (m_pFGArm || m_pBGArm) { - // Held-related GUI stuff - HDFirearm* fgHeldFirearm = dynamic_cast(GetEquippedItem()); - HDFirearm* bgHeldFirearm = dynamic_cast(GetEquippedBGItem()); - - if (fgHeldFirearm || bgHeldFirearm) { - str[0] = -56; - str[1] = 0; + ////////////////////////////////////// + // Draw stat info HUD + char str[64]; + + GUIFont* pSymbolFont = g_FrameMan.GetLargeFont(); + GUIFont* pSmallFont = g_FrameMan.GetSmallFont(); + + // Only show extra HUD if this guy is controlled by the same player that this screen belongs to + if (m_Controller.IsPlayerControlled() && g_ActivityMan.GetActivity()->ScreenOfPlayer(m_Controller.GetPlayer()) == whichScreen && pSmallFont && pSymbolFont) { + AllegroBitmap allegroBitmap(pTargetBitmap); + /* + // Device aiming reticle + if (m_Controller.IsState(AIM_SHARP) && + m_pFGArm && m_pFGArm->IsAttached() && m_pFGArm->HoldsHeldDevice()) + m_pFGArm->GetHeldDevice()->DrawHUD(pTargetBitmap, targetPos, whichScreen);*/ + + Vector drawPos = m_Pos - targetPos; + + // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam + if (!targetPos.IsZero()) { + // Spans vertical scene seam + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) + drawPos.m_X -= sceneWidth; + else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) + drawPos.m_X += sceneWidth; + } + // Spans horizontal scene seam + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) + drawPos.m_Y -= sceneHeight; + else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) + drawPos.m_Y += sceneHeight; + } + } - std::string fgWeaponString = "EMPTY"; - if (fgHeldFirearm) { - if (fgHeldFirearm->IsReloading()) { - fgWeaponString = "Reloading"; - int barColorIndex = 77; - if (!fgHeldFirearm->GetSupportAvailable()) { - float reloadMultiplier = fgHeldFirearm->GetOneHandedReloadTimeMultiplier(); - if (reloadMultiplier != 1.0F) { - // Add a hand icon next to the ammo icon when reloading without supporting hand. - str[0] = -37; str[1] = -49; str[2] = -56; str[3] = 0; - if (reloadMultiplier > 1.0F) { - if (m_IconBlinkTimer.AlternateSim(250)) { barColorIndex = 13; } - } - else { - barColorIndex = 133; + if (m_pFGArm || m_pBGArm) { + // Held-related GUI stuff + HDFirearm* fgHeldFirearm = dynamic_cast(GetEquippedItem()); + HDFirearm* bgHeldFirearm = dynamic_cast(GetEquippedBGItem()); + + if (fgHeldFirearm || bgHeldFirearm) { + str[0] = -56; + str[1] = 0; + + std::string fgWeaponString = "EMPTY"; + if (fgHeldFirearm) { + if (fgHeldFirearm->IsReloading()) { + fgWeaponString = "Reloading"; + int barColorIndex = 77; + if (!fgHeldFirearm->GetSupportAvailable()) { + float reloadMultiplier = fgHeldFirearm->GetOneHandedReloadTimeMultiplier(); + if (reloadMultiplier != 1.0F) { + // Add a hand icon next to the ammo icon when reloading without supporting hand. + str[0] = -37; + str[1] = -49; + str[2] = -56; + str[3] = 0; + if (reloadMultiplier > 1.0F) { + if (m_IconBlinkTimer.AlternateSim(250)) { + barColorIndex = 13; + } + } else { + barColorIndex = 133; + } } } + rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 13, drawPos.GetFloorIntX() + 29, drawPos.GetFloorIntY() + m_HUDStack + 14, 245); + rectfill(pTargetBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 12, drawPos.GetFloorIntX() + static_cast(28.0F * fgHeldFirearm->GetReloadProgress() + 0.5F), drawPos.GetFloorIntY() + m_HUDStack + 13, barColorIndex); + } else { + fgWeaponString = fgHeldFirearm->GetRoundInMagCount() < 0 ? "Infinite" : std::to_string(fgHeldFirearm->GetRoundInMagCount()); } - rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 13, drawPos.GetFloorIntX() + 29, drawPos.GetFloorIntY() + m_HUDStack + 14, 245); - rectfill(pTargetBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 12, drawPos.GetFloorIntX() + static_cast(28.0F * fgHeldFirearm->GetReloadProgress() + 0.5F), drawPos.GetFloorIntY() + m_HUDStack + 13, barColorIndex); - } - else { - fgWeaponString = fgHeldFirearm->GetRoundInMagCount() < 0 ? "Infinite" : std::to_string(fgHeldFirearm->GetRoundInMagCount()); } - } - std::string bgWeaponString; - if (bgHeldFirearm) { - if (bgHeldFirearm->IsReloading()) { - bgWeaponString = "Reloading"; - int barColorIndex = 77; - if (!bgHeldFirearm->GetSupportAvailable()) { - float reloadMultiplier = bgHeldFirearm->GetOneHandedReloadTimeMultiplier(); - if (reloadMultiplier != 1.0F) { - // Add a hand icon next to the ammo icon when reloading without supporting hand. - str[0] = -37; str[1] = -49; str[2] = -56; str[3] = 0; - if (reloadMultiplier > 1.0F) { - if (m_IconBlinkTimer.AlternateSim(250)) { barColorIndex = 13; } - } - else { - barColorIndex = 133; + std::string bgWeaponString; + if (bgHeldFirearm) { + if (bgHeldFirearm->IsReloading()) { + bgWeaponString = "Reloading"; + int barColorIndex = 77; + if (!bgHeldFirearm->GetSupportAvailable()) { + float reloadMultiplier = bgHeldFirearm->GetOneHandedReloadTimeMultiplier(); + if (reloadMultiplier != 1.0F) { + // Add a hand icon next to the ammo icon when reloading without supporting hand. + str[0] = -37; + str[1] = -49; + str[2] = -56; + str[3] = 0; + if (reloadMultiplier > 1.0F) { + if (m_IconBlinkTimer.AlternateSim(250)) { + barColorIndex = 13; + } + } else { + barColorIndex = 133; + } } } + int totalTextWidth = pSmallFont->CalculateWidth(fgWeaponString) + 6; + rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, drawPos.GetFloorIntX() + 29 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 14, 245); + rectfill(pTargetBitmap, drawPos.GetFloorIntX() + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 12, drawPos.GetFloorIntX() + static_cast(28.0F * bgHeldFirearm->GetReloadProgress() + 0.5F) + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, barColorIndex); + } else { + bgWeaponString = bgHeldFirearm->GetRoundInMagCount() < 0 ? "Infinite" : std::to_string(bgHeldFirearm->GetRoundInMagCount()); } - int totalTextWidth = pSmallFont->CalculateWidth(fgWeaponString) + 6; - rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, drawPos.GetFloorIntX() + 29 + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 14, 245); - rectfill(pTargetBitmap, drawPos.GetFloorIntX() + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 12, drawPos.GetFloorIntX() + static_cast(28.0F * bgHeldFirearm->GetReloadProgress() + 0.5F) + totalTextWidth, drawPos.GetFloorIntY() + m_HUDStack + 13, barColorIndex); - } - else { - bgWeaponString = bgHeldFirearm->GetRoundInMagCount() < 0 ? "Infinite" : std::to_string(bgHeldFirearm->GetRoundInMagCount()); } - } - pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - pSymbolFont->CalculateWidth(str) - 3, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Left); - std::snprintf(str, sizeof(str), bgHeldFirearm ? "%s | %s" : "%s", fgWeaponString.c_str(), bgWeaponString.c_str()); - pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 3, str, GUIFont::Left); - - m_HUDStack -= 9; - } - if (m_Controller.IsState(PIE_MENU_ACTIVE) || !m_EquipHUDTimer.IsPastRealMS(700)) { - HeldDevice* fgEquippedItem = GetEquippedItem(); - HeldDevice* bgEquippedItem = GetEquippedBGItem(); - std::string equippedItemsString = (fgEquippedItem ? fgEquippedItem->GetPresetName() : "EMPTY") + (bgEquippedItem ? " | " + bgEquippedItem->GetPresetName() : ""); - pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 3, equippedItemsString, GUIFont::Centre); - m_HUDStack -= 9; - } - } - else - { - std::snprintf(str, sizeof(str), "NO ARM!"); - pSmallFont->DrawAligned(&allegroBitmap, drawPos.m_X + 2, drawPos.m_Y + m_HUDStack + 3, str, GUIFont::Centre); - m_HUDStack -= 9; - } + pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - pSymbolFont->CalculateWidth(str) - 3, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Left); + std::snprintf(str, sizeof(str), bgHeldFirearm ? "%s | %s" : "%s", fgWeaponString.c_str(), bgWeaponString.c_str()); + pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 3, str, GUIFont::Left); - if (m_pJetpack && m_Status != INACTIVE && !m_Controller.IsState(PIE_MENU_ACTIVE) && (m_Controller.IsState(BODY_JUMP) || !m_pJetpack->IsFullyFueled())) { - if (m_pJetpack->GetJetTimeLeft() < 100.0F) { - str[0] = m_IconBlinkTimer.AlternateSim(100) ? -26 : -25; - } - else if (m_pJetpack->IsEmitting()) { - float acceleration = m_pJetpack->EstimateImpulse(false) / std::max(GetMass(), 0.1F); - if (acceleration > 0.41F) { - str[0] = acceleration > 0.47F ? -31 : -30; + m_HUDStack -= 9; } - else { - str[0] = acceleration > 0.35F ? -29 : -28; - if (m_IconBlinkTimer.AlternateSim(200)) { str[0] = -27; } + if (m_Controller.IsState(PIE_MENU_ACTIVE) || !m_EquipHUDTimer.IsPastRealMS(700)) { + HeldDevice* fgEquippedItem = GetEquippedItem(); + HeldDevice* bgEquippedItem = GetEquippedBGItem(); + std::string equippedItemsString = (fgEquippedItem ? fgEquippedItem->GetPresetName() : "EMPTY") + (bgEquippedItem ? " | " + bgEquippedItem->GetPresetName() : ""); + pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 3, equippedItemsString, GUIFont::Centre); + m_HUDStack -= 9; } + } else { + std::snprintf(str, sizeof(str), "NO ARM!"); + pSmallFont->DrawAligned(&allegroBitmap, drawPos.m_X + 2, drawPos.m_Y + m_HUDStack + 3, str, GUIFont::Centre); + m_HUDStack -= 9; } - else { - str[0] = -27; - } - str[1] = 0; - pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 7, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Centre); - rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 7, drawPos.GetFloorIntX() + 15, drawPos.GetFloorIntY() + m_HUDStack + 8, 245); - if (m_pJetpack->GetJetTimeTotal() > 0) { - float jetTimeRatio = m_pJetpack->GetJetTimeRatio(); - int gaugeColor; - if (jetTimeRatio > 0.75F) { - gaugeColor = 149; - } - else if (jetTimeRatio > 0.5F) { - gaugeColor = 133; - } - else if (jetTimeRatio > 0.375F) { - gaugeColor = 77; - } - else if (jetTimeRatio > 0.25F) { - gaugeColor = 48; + if (m_pJetpack && m_Status != INACTIVE && !m_Controller.IsState(PIE_MENU_ACTIVE) && (m_Controller.IsState(BODY_JUMP) || !m_pJetpack->IsFullyFueled())) { + if (m_pJetpack->GetJetTimeLeft() < 100.0F) { + str[0] = m_IconBlinkTimer.AlternateSim(100) ? -26 : -25; + } else if (m_pJetpack->IsEmitting()) { + float acceleration = m_pJetpack->EstimateImpulse(false) / std::max(GetMass(), 0.1F); + if (acceleration > 0.41F) { + str[0] = acceleration > 0.47F ? -31 : -30; + } else { + str[0] = acceleration > 0.35F ? -29 : -28; + if (m_IconBlinkTimer.AlternateSim(200)) { + str[0] = -27; + } + } + } else { + str[0] = -27; } - else { - gaugeColor = 13; + str[1] = 0; + pSymbolFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX() - 7, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Centre); + + rectfill(pTargetBitmap, drawPos.GetFloorIntX() + 1, drawPos.GetFloorIntY() + m_HUDStack + 7, drawPos.GetFloorIntX() + 15, drawPos.GetFloorIntY() + m_HUDStack + 8, 245); + if (m_pJetpack->GetJetTimeTotal() > 0) { + float jetTimeRatio = m_pJetpack->GetJetTimeRatio(); + int gaugeColor; + if (jetTimeRatio > 0.75F) { + gaugeColor = 149; + } else if (jetTimeRatio > 0.5F) { + gaugeColor = 133; + } else if (jetTimeRatio > 0.375F) { + gaugeColor = 77; + } else if (jetTimeRatio > 0.25F) { + gaugeColor = 48; + } else { + gaugeColor = 13; + } + rectfill(pTargetBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 6, drawPos.GetFloorIntX() + static_cast(15.0F * jetTimeRatio), drawPos.GetFloorIntY() + m_HUDStack + 7, gaugeColor); } - rectfill(pTargetBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 6, drawPos.GetFloorIntX() + static_cast(15.0F * jetTimeRatio), drawPos.GetFloorIntY() + m_HUDStack + 7, gaugeColor); + m_HUDStack -= 9; } - m_HUDStack -= 9; - } - // Pickup GUI - if (!m_Controller.IsState(PIE_MENU_ACTIVE) && m_pItemInReach) { - std::snprintf(str, sizeof(str), " %c %s", -49, m_pItemInReach->GetPresetName().c_str()); - pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 3, str, GUIFont::Centre); - m_HUDStack -= 9; + // Pickup GUI + if (!m_Controller.IsState(PIE_MENU_ACTIVE) && m_pItemInReach) { + std::snprintf(str, sizeof(str), " %c %s", -49, m_pItemInReach->GetPresetName().c_str()); + pSmallFont->DrawAligned(&allegroBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 3, str, GUIFont::Centre); + m_HUDStack -= 9; + } } } -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get walking limb path speed for the specified preset. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get walking limb path speed for the specified preset. -float AHuman::GetLimbPathSpeed(int speedPreset) const -{ - return m_Paths[FGROUND][WALK].GetSpeed(speedPreset); -} + float AHuman::GetLimbPathSpeed(int speedPreset) const { + return m_Paths[FGROUND][WALK].GetSpeed(speedPreset); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Set walking limb path speed for the specified preset. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Set walking limb path speed for the specified preset. -void AHuman::SetLimbPathSpeed(int speedPreset, float speed) -{ - m_Paths[FGROUND][WALK].OverrideSpeed(speedPreset, speed); - m_Paths[BGROUND][WALK].OverrideSpeed(speedPreset, speed); -} + void AHuman::SetLimbPathSpeed(int speedPreset, float speed) { + m_Paths[FGROUND][WALK].OverrideSpeed(speedPreset, speed); + m_Paths[BGROUND][WALK].OverrideSpeed(speedPreset, speed); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the force that a limb traveling walking LimbPath can push against -// stuff in the scene with. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the force that a limb traveling walking LimbPath can push against + // stuff in the scene with. -float AHuman::GetLimbPathPushForce() const -{ - return m_Paths[FGROUND][WALK].GetDefaultPushForce(); -} + float AHuman::GetLimbPathPushForce() const { + return m_Paths[FGROUND][WALK].GetDefaultPushForce(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the default force that a limb traveling walking LimbPath can push against -// stuff in the scene with. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the default force that a limb traveling walking LimbPath can push against + // stuff in the scene with. -void AHuman::SetLimbPathPushForce(float force) -{ - m_Paths[FGROUND][WALK].OverridePushForce(force); - m_Paths[BGROUND][WALK].OverridePushForce(force); -} + void AHuman::SetLimbPathPushForce(float force) { + m_Paths[FGROUND][WALK].OverridePushForce(force); + m_Paths[BGROUND][WALK].OverridePushForce(force); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int AHuman::WhilePieMenuOpenListener(const PieMenu *pieMenu) { - int result = Actor::WhilePieMenuOpenListener(pieMenu); + int AHuman::WhilePieMenuOpenListener(const PieMenu* pieMenu) { + int result = Actor::WhilePieMenuOpenListener(pieMenu); - for (PieSlice *pieSlice : GetPieMenu()->GetPieSlices()) { - switch (pieSlice->GetType()) { - case PieSlice::SliceType::Pickup: - case PieSlice::SliceType::Reload: - pieSlice->SetType(m_pItemInReach ? PieSlice::SliceType::Pickup : PieSlice::SliceType::Reload); - pieSlice->SetIcon(dynamic_cast(g_PresetMan.GetEntityPreset("Icon", m_pItemInReach ? "Pick Up" : "Refresh")->Clone())); + for (PieSlice* pieSlice: GetPieMenu()->GetPieSlices()) { + switch (pieSlice->GetType()) { + case PieSlice::SliceType::Pickup: + case PieSlice::SliceType::Reload: + pieSlice->SetType(m_pItemInReach ? PieSlice::SliceType::Pickup : PieSlice::SliceType::Reload); + pieSlice->SetIcon(dynamic_cast(g_PresetMan.GetEntityPreset("Icon", m_pItemInReach ? "Pick Up" : "Refresh")->Clone())); - if (pieSlice->GetType() == PieSlice::SliceType::Pickup) { - if (m_pFGArm || (m_pBGArm && m_pItemInReach->IsOneHanded())) { + if (pieSlice->GetType() == PieSlice::SliceType::Pickup) { + if (m_pFGArm || (m_pBGArm && m_pItemInReach->IsOneHanded())) { + pieSlice->SetEnabled(m_Status != INACTIVE); + pieSlice->SetDescription("Pick Up " + m_pItemInReach->GetPresetName()); + } else { + pieSlice->SetEnabled(false); + pieSlice->SetDescription("No Arm"); + } + } else { + const HeldDevice* fgHeldDevice = dynamic_cast(GetEquippedItem()); + const HeldDevice* bgHeldDevice = dynamic_cast(GetEquippedBGItem()); + if (fgHeldDevice || bgHeldDevice) { + pieSlice->SetEnabled(m_Status != INACTIVE && ((fgHeldDevice && !fgHeldDevice->IsFull()) || (bgHeldDevice && !bgHeldDevice->IsFull()))); + pieSlice->SetDescription("Reload"); + } else { + pieSlice->SetEnabled(false); + pieSlice->SetDescription(m_pFGArm ? "Not Holding Anything" : "No Arm"); + } + } + break; + case PieSlice::SliceType::NextItem: + if (!IsInventoryEmpty() && m_pFGArm) { pieSlice->SetEnabled(m_Status != INACTIVE); - pieSlice->SetDescription("Pick Up " + m_pItemInReach->GetPresetName()); + pieSlice->SetDescription("Next Item"); } else { pieSlice->SetEnabled(false); - pieSlice->SetDescription("No Arm"); + pieSlice->SetDescription(m_pFGArm ? "Not Holding Anything" : "No Arm"); } - } else { - const HeldDevice *fgHeldDevice = dynamic_cast(GetEquippedItem()); - const HeldDevice *bgHeldDevice = dynamic_cast(GetEquippedBGItem()); - if (fgHeldDevice || bgHeldDevice) { - pieSlice->SetEnabled(m_Status != INACTIVE && ((fgHeldDevice && !fgHeldDevice->IsFull()) || (bgHeldDevice && !bgHeldDevice->IsFull()))); - pieSlice->SetDescription("Reload"); + break; + case PieSlice::SliceType::PreviousItem: + if (!IsInventoryEmpty() && m_pFGArm) { + pieSlice->SetEnabled(m_Status != INACTIVE); + pieSlice->SetDescription("Prev Item"); } else { pieSlice->SetEnabled(false); pieSlice->SetDescription(m_pFGArm ? "Not Holding Anything" : "No Arm"); } - } - break; - case PieSlice::SliceType::NextItem: - if (!IsInventoryEmpty() && m_pFGArm) { - pieSlice->SetEnabled(m_Status != INACTIVE); - pieSlice->SetDescription("Next Item"); - } else { - pieSlice->SetEnabled(false); - pieSlice->SetDescription(m_pFGArm ? "Not Holding Anything" : "No Arm"); - } - break; - case PieSlice::SliceType::PreviousItem: - if (!IsInventoryEmpty() && m_pFGArm) { - pieSlice->SetEnabled(m_Status != INACTIVE); - pieSlice->SetDescription("Prev Item"); - } else { - pieSlice->SetEnabled(false); - pieSlice->SetDescription(m_pFGArm ? "Not Holding Anything" : "No Arm"); - } - break; - case PieSlice::SliceType::Drop: - if (const MovableObject *equippedFGItem = GetEquippedItem()) { - pieSlice->SetEnabled(m_Status != INACTIVE); - pieSlice->SetDescription("Drop " + equippedFGItem->GetPresetName()); - } else if (const MovableObject *equippedBGItem = GetEquippedBGItem()) { - pieSlice->SetDescription("Drop " + equippedBGItem->GetPresetName()); - pieSlice->SetEnabled(m_Status != INACTIVE); - } else if (!IsInventoryEmpty() && !m_pFGArm) { - pieSlice->SetEnabled(m_Status != INACTIVE); - pieSlice->SetDescription("Drop Inventory"); - } else { - pieSlice->SetEnabled(false); - pieSlice->SetDescription((m_pFGArm || m_pBGArm) ? "Not Holding Anything" : "No Arm"); - } - break; + break; + case PieSlice::SliceType::Drop: + if (const MovableObject* equippedFGItem = GetEquippedItem()) { + pieSlice->SetEnabled(m_Status != INACTIVE); + pieSlice->SetDescription("Drop " + equippedFGItem->GetPresetName()); + } else if (const MovableObject* equippedBGItem = GetEquippedBGItem()) { + pieSlice->SetDescription("Drop " + equippedBGItem->GetPresetName()); + pieSlice->SetEnabled(m_Status != INACTIVE); + } else if (!IsInventoryEmpty() && !m_pFGArm) { + pieSlice->SetEnabled(m_Status != INACTIVE); + pieSlice->SetDescription("Drop Inventory"); + } else { + pieSlice->SetEnabled(false); + pieSlice->SetDescription((m_pFGArm || m_pBGArm) ? "Not Holding Anything" : "No Arm"); + } + break; + } } + return result; } - return result; -} - } // namespace RTE diff --git a/Source/Entities/AHuman.h b/Source/Entities/AHuman.h index 22306412e..9af2ebf22 100644 --- a/Source/Entities/AHuman.h +++ b/Source/Entities/AHuman.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -21,1104 +20,1059 @@ struct BITMAP; -namespace RTE -{ - -class AEJetpack; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: AHuman -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A humanoid actor. -// Parent(s): Actor. -// Class history: 05/24/2001 AHuman created. - -class AHuman : public Actor { - friend struct EntityLuaBindings; - - -enum UpperBodyState -{ - WEAPON_READY = 0, - AIMING_SHARP, - HOLSTERING_BACK, - HOLSTERING_BELT, - DEHOLSTERING_BACK, - DEHOLSTERING_BELT, - THROWING_PREP, - THROWING_RELEASE -}; - -enum ProneState -{ - NOTPRONE = 0, - GOPRONE, - PRONE, - PRONESTATECOUNT -}; - -enum Layer -{ - FGROUND = 0, - BGROUND -}; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(AHuman); -AddScriptFunctionNames(Actor, "OnStride"); -SerializableOverrideMethods; -ClassInfoGetters; -DefaultPieMenuNameGetter("Default Human Pie Menu"); - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: AHuman -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a AHuman object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - AHuman() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~AHuman -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a AHuman object before deletion -// from system memory. -// Arguments: None. - - ~AHuman() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AHuman object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a AHuman to be identical to another, by deep copy. -// Arguments: A reference to the AHuman to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const AHuman &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire AHuman, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Actor::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this Actor and all its carried -// gold and inventory. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// Return value: The current value of this Actor and all his carried assets. - - float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically named object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The Preset name of the object to look for. -// Return value: Whetehr the object was found carried by this. - - bool HasObject(std::string objectName) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObjectInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically grouped object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The name of the group to look for. -// Return value: Whetehr the object in the group was found carried by this. - - bool HasObjectInGroup(std::string groupName) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetCPUPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' brain, or equivalent. -// Arguments: None. -// Return value: A Vector with the absolute position of this' brain. - - Vector GetCPUPos() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEyePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' eye, or equivalent, where look -// vector starts from. -// Arguments: None. -// Return value: A Vector with the absolute position of this' eye or view point. - - Vector GetEyePos() const override; - - - /// - /// Gets the head of this AHuman. - /// - /// A pointer to the head of this AHuman. Ownership is NOT transferred. - Attachable * GetHead() const { return m_pHead; } - - /// - /// Sets the head for this AHuman. - /// - /// The new head to use. - void SetHead(Attachable *newHead); - - /// - /// Gets the jetpack of this AHuman. - /// - /// A pointer to the jetpack of this AHuman. Ownership is NOT transferred. - AEJetpack * GetJetpack() const { return m_pJetpack; } - - /// - /// Sets the jetpack for this AHuman. - /// - /// The new jetpack to use. - void SetJetpack(AEJetpack *newJetpack); - - /// - /// Gets the foreground Arm of this AHuman. - /// - /// A pointer to the foreground Arm of this AHuman. Ownership is NOT transferred. - Arm * GetFGArm() const { return m_pFGArm; } - - /// - /// Sets the foreground Arm for this AHuman. - /// - /// The new Arm to use. - void SetFGArm(Arm *newArm); - - /// - /// Gets the background arm of this AHuman. - /// - /// A pointer to the background arm of this AHuman. Ownership is NOT transferred. - Arm * GetBGArm() const { return m_pBGArm; } - - /// - /// Sets the background Arm for this AHuman. - /// - /// The new Arm to use. - void SetBGArm(Arm *newArm); - - /// - /// Gets the foreground Leg of this AHuman. - /// - /// A pointer to the foreground Leg of this AHuman. Ownership is NOT transferred. - Leg * GetFGLeg() const { return m_pFGLeg; } - - /// - /// Sets the foreground Leg for this AHuman. - /// - /// The new Leg to use. - void SetFGLeg(Leg *newLeg); - - /// - /// Gets the background Leg of this AHuman. - /// - /// A pointer to the background Leg of this AHuman. Ownership is NOT transferred. - Leg * GetBGLeg() const { return m_pBGLeg; } - - /// - /// Sets the background Leg for this AHuman. - /// - /// The new Leg to use. - void SetBGLeg(Leg *newLeg); - - /// - /// Gets the foot Attachable of this AHuman's foreground Leg. - /// - /// A pointer to the foot Attachable of this AHuman's foreground Leg. Ownership is NOT transferred! - Attachable * GetFGFoot() const { return m_pFGLeg ? m_pFGLeg->GetFoot() : nullptr; } - - /// - /// Sets the foot Attachable of this AHuman's foreground Leg. - /// - /// The new foot for this AHuman's foreground Leg to use. - void SetFGFoot(Attachable *newFoot) { if (m_pFGLeg && m_pFGLeg->IsAttached()) { m_pFGLeg->SetFoot(newFoot); } } - - /// - /// Gets the foot Attachable of this AHuman's background Leg. - /// - /// A pointer to the foot Attachable of this AHuman's background Leg. Ownership is NOT transferred! - Attachable * GetBGFoot() const { return m_pBGLeg ? m_pBGLeg->GetFoot() : nullptr; } - - /// - /// Sets the foot Attachable of this AHuman's background Leg. - /// - /// The new foot for this AHuman's background Leg to use. - void SetBGFoot(Attachable *newFoot) { if (m_pBGLeg && m_pBGLeg->IsAttached()) { m_pBGLeg->SetFoot(newFoot); } } - - /// Gets this AHuman's UpperBodyState. - /// - /// This AHuman's UpperBodyState. - UpperBodyState GetUpperBodyState() const { return m_ArmsState; } - - /// - /// Sets this AHuman's UpperBodyState to the new state. - /// - /// This AHuman's new UpperBodyState. - void SetUpperBodyState(UpperBodyState newUpperBodyState) { m_ArmsState = newUpperBodyState; } - - /// Gets this AHuman's ProneState. - /// - /// This AHuman's ProneState. - ProneState GetProneState() const { return m_ProneState; } - - /// - /// Sets this AHuman's ProneState to the new state. - /// - /// This AHuman's new ProneState. - void SetProneState(ProneState newProneState) { m_ProneState = newProneState; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. -// Arguments: Reference to the HitData struct which describes the collision. This -// will be modified to represent the results of the collision. -// Return value: Whether the collision has been deemed valid. If false, then disregard -// any impulses in the Hitdata. - - bool CollideAtPoint(HitData &hitData) override; - - /// - /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. - /// - /// The SliceType of the PieSlice being handled. - /// Whether or not the activated PieSlice SliceType was able to be handled. - bool HandlePieCommand(PieSlice::SliceType pieSliceType) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: AddInventoryItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an inventory item to this AHuman. This also puts that item -// directly in the hands of this if they are empty. -// Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! -// Return value: None. - - void AddInventoryItem(MovableObject *pItemToAdd) override; - - /// - /// Swaps the next MovableObject carried by this AHuman and puts one not currently carried into the back of the inventory of this. - /// For safety reasons, this will dump any non-HeldDevice inventory items it finds into MovableMan, ensuring the returned item is a HeldDevice (but not casted to one, for overload purposes). - /// - /// A pointer to the external MovableObject to swap in. Ownership IS transferred. - /// Whether or not to mute the sound on this event. - /// The next HeldDevice in this AHuman's inventory, if there are any. - MovableObject * SwapNextInventory(MovableObject *inventoryItemToSwapIn = nullptr, bool muteSound = false) override; - - /// - /// Swaps the previous MovableObject carried by this AHuman and puts one not currently carried into the back of the inventory of this. - /// For safety reasons, this will dump any non-HeldDevice inventory items it finds into MovableMan, ensuring the returned item is a HeldDevice (but not casted to one, for overload purposes). - /// - /// A pointer to the external MovableObject to swap in. Ownership IS transferred. - /// The previous HeldDevice in this AHuman's inventory, if there are any. - MovableObject * SwapPrevInventory(MovableObject *inventoryItemToSwapIn = nullptr) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipFirearm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found firearm -// in the inventory. If the held device already is a firearm, or no -// firearm is in inventory, nothing happens. -// Arguments: Whether to actually equip any matching item found in the inventory, -// or just report that it's there or not. -// Return value: Whether a firearm was successfully switched to, or already held. - - bool EquipFirearm(bool doEquip = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipDeviceInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found device -// of the specified group in the inventory. If the held device already -// is of that group, or no device is in inventory, nothing happens. -// Arguments: The group the device must belong to. -// Whether to actually equip any matching item found in the inventory, -// or just report that it's there or not. -// Return value: Whether a firearm was successfully switched to, or already held. - - bool EquipDeviceInGroup(std::string group, bool doEquip = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipLoadedFirearmInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first loaded HDFirearm -// of the specified group in the inventory. If no such weapon is in the -// inventory, nothing happens. -// Arguments: The group the HDFirearm must belong to. "Any" for all groups. -// The group the HDFirearm must *not* belong to. "None" for no group. -// Whether to actually equip any matching item found in the inventory, -// or just report that it's there or not. -// Return value: Whether a firearm was successfully switched to, or already held. - - bool EquipLoadedFirearmInGroup(std::string group, std::string exludeGroup, bool doEquip = true); - - /// - /// Switches the equipped HeldDevice (if any) to the first found device with the specified preset name in the inventory. - /// If the equipped HeldDevice is of that module and preset name, nothing happens. - /// - /// The preset name of the HeldDevice to equip. - /// Whether to actually equip any matching item found in the inventory, or just report whether or not it's there. - /// Whether a matching HeldDevice was successfully found/switched -o, or already held. - bool EquipNamedDevice(const std::string &presetName, bool doEquip) { return EquipNamedDevice("", presetName, doEquip); } - - /// - /// Switches the equipped HeldDevice (if any) to the first found device with the specified module and preset name in the inventory. - /// If the equipped HeldDevice is of that module and preset name, nothing happens. - /// - /// The module name of the HeldDevice to equip. - /// The preset name of the HeldDevice to equip. - /// Whether to actually equip any matching item found in the inventory, or just report whether or not it's there. - /// Whether a matching HeldDevice was successfully found/switched -o, or already held. - bool EquipNamedDevice(const std::string &moduleName, const std::string &presetName, bool doEquip); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipThrowable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found ThrownDevice -// in the inventory. If the held device already is a ThrownDevice, or no -// ThrownDevice is in inventory, nothing happens. -// Arguments: Whether to actually equip any matching item found in the inventory, -// or just report that it's there or not. -// Return value: Whether a ThrownDevice was successfully switched to, or already held. - - bool EquipThrowable(bool doEquip = true); - - /// - /// Switches the currently held device (if any) to the strongest digging tool in the inventory. - /// - /// Whether to actually equip the strongest digging tool, or just report whether a digging tool was found. - /// Whether or not the strongest digging tool was successfully equipped. - bool EquipDiggingTool(bool doEquip = true); - - /// - /// Estimates what material strength any digger this AHuman is carrying can penetrate. - /// - /// The maximum material strength this AHuman's digger can penetrate, or a default dig strength if they don't have a digger. - float EstimateDigStrength() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipShield -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches the currently held device (if any) to the first found shield -// in the inventory. If the held device already is a shield, or no -// shield is in inventory, nothing happens. -// Arguments: None. -// Return value: Whether a shield was successfully switched to, or already held. - - bool EquipShield(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipShieldInBGArm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tries to equip the first shield in inventory to the background arm; -// this only works if nothing is held at all, or the FG arm holds a -// one-handed device, or we're in inventory mode. -// Arguments: None. -// Return value: Whether a shield was successfully equipped in the background arm. - - bool EquipShieldInBGArm(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: EquipDualWieldableInBGArm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tries to equip the first dual-wieldable in inventory to the background arm; -// this only works if nothing is held at all, or the FG arm holds a -// one-handed device, or we're in inventory mode. -// Arguments: None. -// Return value: Whether a shield was successfully equipped in the background arm. - -// bool EquipDualWieldableInBGArm(); - - /// - /// Gets the throw chargeup progress of this AHuman. - /// - /// The throw chargeup progress, as a scalar from 0 to 1. - float GetThrowProgress() const { return m_ThrowPrepTime > 0 ? static_cast(std::min(m_ThrowTmr.GetElapsedSimTimeMS() / static_cast(m_ThrowPrepTime), 1.0)) : 1.0F; } - - /// - /// Unequips whatever is in the FG arm and puts it into the inventory. - /// - /// Whether there was anything to unequip. - bool UnequipFGArm(); - - /// - /// Unequips whatever is in the BG arm and puts it into the inventory. - /// - /// Whether there was anything to unequip. - bool UnequipBGArm(); - - /// - /// Unequips whatever is in either of the arms and puts them into the inventory. - /// - void UnequipArms() { UnequipBGArm(); UnequipFGArm(); } - - /// - /// Gets the FG Arm's HeldDevice. Ownership is NOT transferred. - /// - /// The FG Arm's HeldDevice. - HeldDevice * GetEquippedItem() const { return m_pFGArm ? m_pFGArm->GetHeldDevice() : nullptr; } - - /// - /// Gets the BG Arm's HeldDevice. Ownership is NOT transferred. - /// - /// The BG Arm's HeldDevice. - HeldDevice * GetEquippedBGItem() const { return m_pBGArm ? m_pBGArm->GetHeldDevice() : nullptr; } - - /// - /// Gets the total mass of this AHuman's currently equipped devices. - /// - /// The mass of this AHuman's equipped devices. - float GetEquippedMass() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: FirearmIsReady -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is ready for use, and has -// ammo etc. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) is ready for use. - - bool FirearmIsReady() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ThrowableIsReady -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held ThrownDevice's is ready to go. -// Arguments: None. -// Return value: Whether a currently held ThrownDevice (if any) is ready for use. - - bool ThrowableIsReady() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmIsEmpty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is out of ammo. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) is out of ammo. - - bool FirearmIsEmpty() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmNeedsReload -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether any currently held HDFirearms are almost out of ammo. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) has less than half of ammo left. - - bool FirearmNeedsReload() const; - - /// - /// Indicates whether currently held HDFirearms are reloading. If the parameter is true, it will only return true if all firearms are reloading, otherwise it will return whether any firearm is reloading. - /// - /// Whether or not currently held HDFirearms are reloading. - bool FirearmsAreReloading(bool onlyIfAllFirearmsAreReloading) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmIsSemiAuto -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the currently held HDFirearm's is semi or full auto. -// Arguments: None. -// Return value: Whether a currently HDFirearm (if any) is a semi auto device. - - bool FirearmIsSemiAuto() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FirearmActivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the currently held device's delay between pulling the trigger -// and activating. -// Arguments: None. -// Return value: Delay in ms or zero if not a HDFirearm. - - int FirearmActivationDelay() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReloadFirearm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reloads the currently held firearm, if any. Will only reload the BG Firearm if the FG one is full already, to support reloading guns one at a time. -// Arguments: Whether or not to only reload empty fireams. -// Return value: None. - - void ReloadFirearms(bool onlyReloadEmptyFirearms = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsWithinRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a point on the scene is within close range of the currently -// used device and aiming status, if applicable. -// Arguments: A Vector with the aboslute coordinates of a point to check. -// Return value: Whether the point is within close range of this. - - bool IsWithinRange(Vector &point) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Look -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an unseen-revealing ray in the direction of where this is facing. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. -// The range, in pixels, beyond the actors sharp aim that the ray will have. -// Return value: Whether any unseen pixels were revealed by this look. - - bool Look(float FOVSpread, float range) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LookForGold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts a material detecting ray in the direction of where this is facing. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. -// The range, in pixels, that the ray will have. -// A Vector which will be filled with the absolute coordinates of any -// found gold. It will be unaltered if false is returned. -// Return value: Whether gold was spotted by this ray cast. If so, foundLocation -// has been filled out with the absolute location of the gold. - - bool LookForGold(float FOVSpread, float range, Vector &foundLocation) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LookForMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an MO detecting ray in the direction of where the head is looking -// at the time. Factors including head rotation, sharp aim mode, and -// other variables determine how this ray is cast. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. -// A specific material ID to ignore (see through) -// Whether to ignore all terrain or not (true means 'x-ray vision'). -// Return value: A pointer to the MO seen while looking. - - MovableObject * LookForMOs(float FOVSpread = 45, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false); - - - /// - /// Gets the GUI representation of this AHuman, only defaulting to its Head or body if no GraphicalIcon has been defined. - /// - /// The graphical representation of this AHuman as a BITMAP. - BITMAP * GetGraphicalIcon() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ResetAllTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resest all the timers used by this. Can be emitters, etc. This is to -// prevent backed up emissions to come out all at once while this has been -// held dormant in an inventory. -// Arguments: None. -// Return value: None. - - void ResetAllTimers() override; - - /// - /// Detects slopes in terrain and updates the walk path rotation for the corresponding Layer accordingly. - /// - /// The Layer in question. - void UpdateWalkAngle(AHuman::Layer whichLayer); - - /// - /// Detects overhead ceilings and crouches for them. - /// - void UpdateCrouching(); - - /// - /// Gets the walk path rotation for the specified Layer. - /// - /// The Layer in question. - /// The walk angle in radians. - float GetWalkAngle(AHuman::Layer whichLayer) const { return m_WalkAngle[whichLayer].GetRadAngle(); } - - /// - /// Sets the walk path rotation for the specified Layer. - /// - /// The Layer in question. - /// The angle to set. - void SetWalkAngle(AHuman::Layer whichLayer, float angle) { m_WalkAngle[whichLayer] = Matrix(angle); } - - /// - /// Gets whether this AHuman has just taken a stride this frame. - /// - /// Whether this AHuman has taken a stride this frame or not. - bool StrideFrame() const { return m_StrideFrame; } - - /// - /// Gets whether this AHuman is currently attempting to climb something, using arms. - /// - /// Whether this AHuman is currently climbing or not. - bool IsClimbing() const { return m_ArmClimbing[FGROUND] || m_ArmClimbing[BGROUND]; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreControllerUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void PreControllerUpdate() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this AHuman's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// Which player's screen this is being drawn to. May affect what HUD elements -// get drawn etc. -// Return value: None. - - void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; - - - /// - /// Gets the LimbPath corresponding to the passed in Layer and MovementState values. - /// - /// Whether to get foreground or background LimbPath. - /// Which movement state to get the LimbPath for. - /// The LimbPath corresponding to the passed in Layer and MovementState values. - LimbPath * GetLimbPath(Layer layer, MovementState movementState) { return &m_Paths[layer][movementState]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get walking limb path speed for the specified preset. -// Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST -// Return value: Limb path speed for the specified preset in m/s. - - float GetLimbPathSpeed(int speedPreset) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLimbPathSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Set walking limb path speed for the specified preset. -// Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST. New speed value in m/s. -// Return value: None. - - void SetLimbPathSpeed(int speedPreset, float speed); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the default force that a limb traveling walking LimbPath can push against -// stuff in the scene with. -// Arguments: None. -// Return value: The default set force maximum, in kg * m/s^2. - - float GetLimbPathPushForce() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLimbPathPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the default force that a limb traveling walking LimbPath can push against -// stuff in the scene with. -// Arguments: The default set force maximum, in kg * m/s^2. -// Return value: None - - void SetLimbPathPushForce(float force); - - /// - /// Gets the target rot angle for the given MovementState. - /// - /// The MovementState to get the rot angle target for. - /// The target rot angle for the given MovementState. - float GetRotAngleTarget(MovementState movementState) { return m_RotAngleTargets[movementState]; } - - /// - /// Sets the target rot angle for the given MovementState. - /// - /// The MovementState to get the rot angle target for. - /// The new rot angle target to use. - void SetRotAngleTarget(MovementState movementState, float newRotAngleTarget) { m_RotAngleTargets[movementState] = newRotAngleTarget; } - - /// - /// Gets the duration it takes this AHuman to fully charge a throw. - /// - /// The duration it takes to fully charge a throw in MS. - long GetThrowPrepTime() const { return m_ThrowPrepTime; } - - /// - /// Sets the duration it takes this AHuman to fully charge a throw. - /// - /// New duration to fully charge a throw in MS. - void SetThrowPrepTime(long newPrepTime) { m_ThrowPrepTime = newPrepTime; } - - /// - /// Gets the rate at which this AHuman's Arms will swing with Leg movement, if they're not holding or supporting a HeldDevice. - /// - /// The arm swing rate of this AHuman. - float GetArmSwingRate() const { return m_ArmSwingRate; } - - /// - /// Sets the rate at which this AHuman's Arms will swing with Leg movement, if they're not holding or supporting a HeldDevice. - /// - /// The new arm swing rate for this AHuman. - void SetArmSwingRate(float newValue) { m_ArmSwingRate = newValue; } - - /// - /// Gets the rate at which this AHuman's Arms will sway with Leg movement, if they're holding or supporting a HeldDevice. - /// - /// The device arm sway rate of this AHuman. - float GetDeviceArmSwayRate() const { return m_DeviceArmSwayRate; } - - /// - /// Sets the rate at which this AHuman's Arms will sway with Leg movement, if they're holding or supporting a HeldDevice. - /// - /// The new device arm sway rate for this AHuman. - void SetDeviceArmSwayRate(float newValue) { m_DeviceArmSwayRate = newValue; } - - /// - /// Gets this AHuman's max walkpath adjustment upwards to crouch below low ceilings. - /// - /// This AHuman's max walkpath adjustment. - float GetMaxWalkPathCrouchShift() const { return m_MaxWalkPathCrouchShift; } - - /// - /// Sets this AHuman's max walkpath adjustment upwards to crouch below low ceilings. - /// - /// The new value for this AHuman's max walkpath adjustment. - void SetMaxWalkPathCrouchShift(float newValue) { m_MaxWalkPathCrouchShift = newValue; } - - /// - /// Gets this AHuman's max crouch rotation to duck below low ceilings. - /// - /// This AHuman's max crouch rotation adjustment. - float GetMaxCrouchRotation() const { return m_MaxCrouchRotation; } - - /// - /// Sets this AHuman's max crouch rotation to duck below low ceilings. - /// - /// The new value for this AHuman's max crouch rotation adjustment. - void SetMaxCrouchRotation(float newValue) { m_MaxCrouchRotation = newValue; } - - /// - /// Gets this AHuman's current crouch amount. 0.0 == fully standing, 1.0 == fully crouched. - /// - /// This AHuman's current crouch amount. - float GetCrouchAmount() const { return (m_WalkPathOffset.m_Y * -1.0F) / m_MaxWalkPathCrouchShift; } - - /// - /// Gets this AHuman's current crouch amount override. 0.0 == fully standing, 1.0 == fully crouched, -1 == no override. - /// - /// This AHuman's current crouch amount override. - float GetCrouchAmountOverride() const { return m_CrouchAmountOverride; } - - /// - /// Sets this AHuman's current crouch amount override. - /// - /// The new value for this AHuman's current crouch amount override. - void SetCrouchAmountOverride(float newValue) { m_CrouchAmountOverride = newValue; } - - /// - /// Gets this AHuman's stride sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this AHuman's stride sound. - SoundContainer * GetStrideSound() const { return m_StrideSound; } - - /// - /// Sets this AHuman's stride sound. Ownership IS transferred! - /// - /// The new SoundContainer for this AHuman's stride sound. - void SetStrideSound(SoundContainer *newSound) { m_StrideSound = newSound; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Function that is called when we get a new movepath. - /// This processes and cleans up the movepath. - /// - void OnNewMovePath() override; - - /// - /// Draws an aiming aid in front of this AHuman for throwing. - /// - /// A pointer to a BITMAP to draw on. - /// The absolute position of the target bitmap's upper left corner in the Scene. - /// A normalized scalar that determines the magnitude of the reticle, to indicate force in the throw. - void DrawThrowingReticle(BITMAP *targetBitmap, const Vector &targetPos = Vector(), float progressScalar = 1.0F) const; - - - // Member variables - static Entity::ClassInfo m_sClass; - // Articulated head. - Attachable *m_pHead; - // Ratio at which the head's rotation follows the aim angle - float m_LookToAimRatio; - // Foreground arm. - Arm *m_pFGArm; - // Background arm. - Arm *m_pBGArm; - // Foreground leg. - Leg *m_pFGLeg; - // Background leg. - Leg *m_pBGLeg; - // Limb AtomGroups. - AtomGroup *m_pFGHandGroup; - AtomGroup *m_pBGHandGroup; - AtomGroup *m_pFGFootGroup; - AtomGroup *m_BackupFGFootGroup; - AtomGroup *m_pBGFootGroup; - AtomGroup *m_BackupBGFootGroup; - // The sound of the actor taking a step (think robot servo) - SoundContainer *m_StrideSound; - // Jetpack booster. - AEJetpack *m_pJetpack; - bool m_CanActivateBGItem; //!< A flag for whether or not the BG item is waiting to be activated separately. Used for dual-wielding. TODO: Should this be able to be toggled off per actor, device, or controller? - bool m_TriggerPulled; //!< Internal flag for whether this AHuman is currently holding down the trigger of a HDFirearm. Used for dual-wielding. - bool m_WaitingToReloadOffhand; //!< A flag for whether or not the offhand HeldDevice is waiting to be reloaded. - // Blink timer - Timer m_IconBlinkTimer; - // Current upper body state. - UpperBodyState m_ArmsState; - // Current movement state. - MovementState m_MoveState; - // Whether the guy is currently lying down on the ground, rotational spring pulling him that way - // This is engaged if the player first crouches (still upright spring), and then presses left/right - // It is disengaged as soon as the crouch button/direction is released - ProneState m_ProneState; - // Timer for the going prone procedural animation - Timer m_ProneTimer; - // The maximum amount our walkpath can be shifted upwards to crouch and avoid ceilings above us - float m_MaxWalkPathCrouchShift; - // The maximum amount we will duck our head down to avoid obstacles above us. - float m_MaxCrouchRotation; - // The script-set forced crouching amount. 0.0 == fully standing, 1.0 == fully crouched, -1 == no override. - float m_CrouchAmountOverride; - // Limb paths for different movement states. - // [0] is for the foreground limbs, and [1] is for BG. - LimbPath m_Paths[2][MOVEMENTSTATECOUNT]; - std::array m_RotAngleTargets; //!< An array of rot angle targets for different movement states. - // Whether was aiming during the last frame too. - bool m_Aiming; - // Whether the BG Arm is helping with locomotion or not. - bool m_ArmClimbing[2]; - // Whether a stride was taken this frame or not. - bool m_StrideFrame = false; - // Controls the start of leg synch. - bool m_StrideStart; - // Times the stride to see if it is taking too long and needs restart - Timer m_StrideTimer; - // For timing throws - Timer m_ThrowTmr; - // The duration it takes this AHuman to fully charge a throw. - long m_ThrowPrepTime; - Timer m_SharpAimRevertTimer; //!< For timing the transition from sharp aim back to regular aim. - float m_FGArmFlailScalar; //!< The rate at which this AHuman's FG Arm follows the the bodily rotation. Best to keep this at 0 so it doesn't complicate aiming. - float m_BGArmFlailScalar; //!< The rate at which this AHuman's BG Arm follows the the bodily rotation. Set to a negative value for a "counterweight" effect. - Timer m_EquipHUDTimer; //!< Timer for showing the name of any newly equipped Device. - std::array m_WalkAngle; //!< An array of rot angle targets for different movement states. - Vector m_WalkPathOffset; - float m_ArmSwingRate; //!< Controls the rate at which this AHuman's Arms follow the movement of its Legs while they're not holding device(s). - float m_DeviceArmSwayRate; //!< Controls the rate at which this AHuman's Arms follow the movement of its Legs while they're holding device(s). One-handed devices sway half as much as two-handed ones. Defaults to three quarters of Arm swing rate. - - //////////////// - // AI States - - enum DeviceHandlingState - { - STILL = 0, - POINTING, - SCANNING, - AIMING, - FIRING, - THROWING, - DIGGING - }; - - enum SweepState - { - NOSWEEP = 0, - SWEEPINGUP, - SWEEPUPPAUSE, - SWEEPINGDOWN, - SWEEPDOWNPAUSE - }; - - enum DigState - { - NOTDIGGING = 0, - PREDIG, - STARTDIG, - TUNNELING, - FINISHINGDIG, - PAUSEDIGGER - }; - - enum JumpState - { - NOTJUMPING = 0, - FORWARDJUMP, - PREUPJUMP, - UPJUMP, - APEXJUMP, - LANDJUMP - }; - - // What the AI is doing with its held devices - DeviceHandlingState m_DeviceState; - // What we are doing with a device sweeping - SweepState m_SweepState; - // The current digging state - DigState m_DigState; - // The current jumping state - JumpState m_JumpState; - // Jumping target, overshoot this and the jump is completed - Vector m_JumpTarget; - // Jumping left or right - bool m_JumpingRight; - // AI is crawling - bool m_Crawling; - // The position of the end of the current tunnel being dug. When it is reached, digging can stop. - Vector m_DigTunnelEndPos; - // The center angle (in rads) for the sweeping motion done duing scannign and digging - float m_SweepCenterAimAngle; - // The range to each direction of the center that the sweeping motion will be done in - float m_SweepRange; - // The absolute coordinates of the last detected gold deposits - Vector m_DigTarget; - // Timer for how long to be shooting at a seen enemy target - Timer m_FireTimer; - // Timer for how long to be shooting at a seen enemy target - Timer m_SweepTimer; - // Timer for how long to be patrolling in a direction - Timer m_PatrolTimer; - // Timer for how long to be firing the jetpack in a direction - Timer m_JumpTimer; +namespace RTE { + + class AEJetpack; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: AHuman + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A humanoid actor. + // Parent(s): Actor. + // Class history: 05/24/2001 AHuman created. + + class AHuman : public Actor { + friend struct EntityLuaBindings; + + enum UpperBodyState { + WEAPON_READY = 0, + AIMING_SHARP, + HOLSTERING_BACK, + HOLSTERING_BELT, + DEHOLSTERING_BACK, + DEHOLSTERING_BELT, + THROWING_PREP, + THROWING_RELEASE + }; + + enum ProneState { + NOTPRONE = 0, + GOPRONE, + PRONE, + PRONESTATECOUNT + }; + + enum Layer { + FGROUND = 0, + BGROUND + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(AHuman); + AddScriptFunctionNames(Actor, "OnStride"); + SerializableOverrideMethods; + ClassInfoGetters; + DefaultPieMenuNameGetter("Default Human Pie Menu"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: AHuman + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a AHuman object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + AHuman() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~AHuman + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a AHuman object before deletion + // from system memory. + // Arguments: None. + + ~AHuman() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AHuman object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a AHuman to be identical to another, by deep copy. + // Arguments: A reference to the AHuman to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const AHuman& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire AHuman, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Actor::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this Actor and all its carried + // gold and inventory. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // Return value: The current value of this Actor and all his carried assets. + + float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically named object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The Preset name of the object to look for. + // Return value: Whetehr the object was found carried by this. + + bool HasObject(std::string objectName) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObjectInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically grouped object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The name of the group to look for. + // Return value: Whetehr the object in the group was found carried by this. + + bool HasObjectInGroup(std::string groupName) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetCPUPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' brain, or equivalent. + // Arguments: None. + // Return value: A Vector with the absolute position of this' brain. + + Vector GetCPUPos() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEyePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' eye, or equivalent, where look + // vector starts from. + // Arguments: None. + // Return value: A Vector with the absolute position of this' eye or view point. + + Vector GetEyePos() const override; + + /// + /// Gets the head of this AHuman. + /// + /// A pointer to the head of this AHuman. Ownership is NOT transferred. + Attachable* GetHead() const { return m_pHead; } + + /// + /// Sets the head for this AHuman. + /// + /// The new head to use. + void SetHead(Attachable* newHead); + + /// + /// Gets the jetpack of this AHuman. + /// + /// A pointer to the jetpack of this AHuman. Ownership is NOT transferred. + AEJetpack* GetJetpack() const { return m_pJetpack; } + + /// + /// Sets the jetpack for this AHuman. + /// + /// The new jetpack to use. + void SetJetpack(AEJetpack* newJetpack); + + /// + /// Gets the foreground Arm of this AHuman. + /// + /// A pointer to the foreground Arm of this AHuman. Ownership is NOT transferred. + Arm* GetFGArm() const { return m_pFGArm; } + + /// + /// Sets the foreground Arm for this AHuman. + /// + /// The new Arm to use. + void SetFGArm(Arm* newArm); + + /// + /// Gets the background arm of this AHuman. + /// + /// A pointer to the background arm of this AHuman. Ownership is NOT transferred. + Arm* GetBGArm() const { return m_pBGArm; } + + /// + /// Sets the background Arm for this AHuman. + /// + /// The new Arm to use. + void SetBGArm(Arm* newArm); + + /// + /// Gets the foreground Leg of this AHuman. + /// + /// A pointer to the foreground Leg of this AHuman. Ownership is NOT transferred. + Leg* GetFGLeg() const { return m_pFGLeg; } + + /// + /// Sets the foreground Leg for this AHuman. + /// + /// The new Leg to use. + void SetFGLeg(Leg* newLeg); + + /// + /// Gets the background Leg of this AHuman. + /// + /// A pointer to the background Leg of this AHuman. Ownership is NOT transferred. + Leg* GetBGLeg() const { return m_pBGLeg; } + + /// + /// Sets the background Leg for this AHuman. + /// + /// The new Leg to use. + void SetBGLeg(Leg* newLeg); + + /// + /// Gets the foot Attachable of this AHuman's foreground Leg. + /// + /// A pointer to the foot Attachable of this AHuman's foreground Leg. Ownership is NOT transferred! + Attachable* GetFGFoot() const { return m_pFGLeg ? m_pFGLeg->GetFoot() : nullptr; } + + /// + /// Sets the foot Attachable of this AHuman's foreground Leg. + /// + /// The new foot for this AHuman's foreground Leg to use. + void SetFGFoot(Attachable* newFoot) { + if (m_pFGLeg && m_pFGLeg->IsAttached()) { + m_pFGLeg->SetFoot(newFoot); + } + } + + /// + /// Gets the foot Attachable of this AHuman's background Leg. + /// + /// A pointer to the foot Attachable of this AHuman's background Leg. Ownership is NOT transferred! + Attachable* GetBGFoot() const { return m_pBGLeg ? m_pBGLeg->GetFoot() : nullptr; } + + /// + /// Sets the foot Attachable of this AHuman's background Leg. + /// + /// The new foot for this AHuman's background Leg to use. + void SetBGFoot(Attachable* newFoot) { + if (m_pBGLeg && m_pBGLeg->IsAttached()) { + m_pBGLeg->SetFoot(newFoot); + } + } + + /// Gets this AHuman's UpperBodyState. + /// + /// This AHuman's UpperBodyState. + UpperBodyState GetUpperBodyState() const { return m_ArmsState; } + + /// + /// Sets this AHuman's UpperBodyState to the new state. + /// + /// This AHuman's new UpperBodyState. + void SetUpperBodyState(UpperBodyState newUpperBodyState) { m_ArmsState = newUpperBodyState; } + + /// Gets this AHuman's ProneState. + /// + /// This AHuman's ProneState. + ProneState GetProneState() const { return m_ProneState; } + + /// + /// Sets this AHuman's ProneState to the new state. + /// + /// This AHuman's new ProneState. + void SetProneState(ProneState newProneState) { m_ProneState = newProneState; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + // Arguments: Reference to the HitData struct which describes the collision. This + // will be modified to represent the results of the collision. + // Return value: Whether the collision has been deemed valid. If false, then disregard + // any impulses in the Hitdata. + + bool CollideAtPoint(HitData& hitData) override; + + /// + /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. + /// + /// The SliceType of the PieSlice being handled. + /// Whether or not the activated PieSlice SliceType was able to be handled. + bool HandlePieCommand(PieSlice::SliceType pieSliceType) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: AddInventoryItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an inventory item to this AHuman. This also puts that item + // directly in the hands of this if they are empty. + // Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! + // Return value: None. + + void AddInventoryItem(MovableObject* pItemToAdd) override; + + /// + /// Swaps the next MovableObject carried by this AHuman and puts one not currently carried into the back of the inventory of this. + /// For safety reasons, this will dump any non-HeldDevice inventory items it finds into MovableMan, ensuring the returned item is a HeldDevice (but not casted to one, for overload purposes). + /// + /// A pointer to the external MovableObject to swap in. Ownership IS transferred. + /// Whether or not to mute the sound on this event. + /// The next HeldDevice in this AHuman's inventory, if there are any. + MovableObject* SwapNextInventory(MovableObject* inventoryItemToSwapIn = nullptr, bool muteSound = false) override; + + /// + /// Swaps the previous MovableObject carried by this AHuman and puts one not currently carried into the back of the inventory of this. + /// For safety reasons, this will dump any non-HeldDevice inventory items it finds into MovableMan, ensuring the returned item is a HeldDevice (but not casted to one, for overload purposes). + /// + /// A pointer to the external MovableObject to swap in. Ownership IS transferred. + /// The previous HeldDevice in this AHuman's inventory, if there are any. + MovableObject* SwapPrevInventory(MovableObject* inventoryItemToSwapIn = nullptr) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipFirearm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found firearm + // in the inventory. If the held device already is a firearm, or no + // firearm is in inventory, nothing happens. + // Arguments: Whether to actually equip any matching item found in the inventory, + // or just report that it's there or not. + // Return value: Whether a firearm was successfully switched to, or already held. + + bool EquipFirearm(bool doEquip = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipDeviceInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found device + // of the specified group in the inventory. If the held device already + // is of that group, or no device is in inventory, nothing happens. + // Arguments: The group the device must belong to. + // Whether to actually equip any matching item found in the inventory, + // or just report that it's there or not. + // Return value: Whether a firearm was successfully switched to, or already held. + + bool EquipDeviceInGroup(std::string group, bool doEquip = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipLoadedFirearmInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first loaded HDFirearm + // of the specified group in the inventory. If no such weapon is in the + // inventory, nothing happens. + // Arguments: The group the HDFirearm must belong to. "Any" for all groups. + // The group the HDFirearm must *not* belong to. "None" for no group. + // Whether to actually equip any matching item found in the inventory, + // or just report that it's there or not. + // Return value: Whether a firearm was successfully switched to, or already held. + + bool EquipLoadedFirearmInGroup(std::string group, std::string exludeGroup, bool doEquip = true); + + /// + /// Switches the equipped HeldDevice (if any) to the first found device with the specified preset name in the inventory. + /// If the equipped HeldDevice is of that module and preset name, nothing happens. + /// + /// The preset name of the HeldDevice to equip. + /// Whether to actually equip any matching item found in the inventory, or just report whether or not it's there. + /// Whether a matching HeldDevice was successfully found/switched -o, or already held. + bool EquipNamedDevice(const std::string& presetName, bool doEquip) { return EquipNamedDevice("", presetName, doEquip); } + + /// + /// Switches the equipped HeldDevice (if any) to the first found device with the specified module and preset name in the inventory. + /// If the equipped HeldDevice is of that module and preset name, nothing happens. + /// + /// The module name of the HeldDevice to equip. + /// The preset name of the HeldDevice to equip. + /// Whether to actually equip any matching item found in the inventory, or just report whether or not it's there. + /// Whether a matching HeldDevice was successfully found/switched -o, or already held. + bool EquipNamedDevice(const std::string& moduleName, const std::string& presetName, bool doEquip); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipThrowable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found ThrownDevice + // in the inventory. If the held device already is a ThrownDevice, or no + // ThrownDevice is in inventory, nothing happens. + // Arguments: Whether to actually equip any matching item found in the inventory, + // or just report that it's there or not. + // Return value: Whether a ThrownDevice was successfully switched to, or already held. + + bool EquipThrowable(bool doEquip = true); + + /// + /// Switches the currently held device (if any) to the strongest digging tool in the inventory. + /// + /// Whether to actually equip the strongest digging tool, or just report whether a digging tool was found. + /// Whether or not the strongest digging tool was successfully equipped. + bool EquipDiggingTool(bool doEquip = true); + + /// + /// Estimates what material strength any digger this AHuman is carrying can penetrate. + /// + /// The maximum material strength this AHuman's digger can penetrate, or a default dig strength if they don't have a digger. + float EstimateDigStrength() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipShield + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches the currently held device (if any) to the first found shield + // in the inventory. If the held device already is a shield, or no + // shield is in inventory, nothing happens. + // Arguments: None. + // Return value: Whether a shield was successfully switched to, or already held. + + bool EquipShield(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipShieldInBGArm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tries to equip the first shield in inventory to the background arm; + // this only works if nothing is held at all, or the FG arm holds a + // one-handed device, or we're in inventory mode. + // Arguments: None. + // Return value: Whether a shield was successfully equipped in the background arm. + + bool EquipShieldInBGArm(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: EquipDualWieldableInBGArm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tries to equip the first dual-wieldable in inventory to the background arm; + // this only works if nothing is held at all, or the FG arm holds a + // one-handed device, or we're in inventory mode. + // Arguments: None. + // Return value: Whether a shield was successfully equipped in the background arm. + + // bool EquipDualWieldableInBGArm(); + + /// + /// Gets the throw chargeup progress of this AHuman. + /// + /// The throw chargeup progress, as a scalar from 0 to 1. + float GetThrowProgress() const { return m_ThrowPrepTime > 0 ? static_cast(std::min(m_ThrowTmr.GetElapsedSimTimeMS() / static_cast(m_ThrowPrepTime), 1.0)) : 1.0F; } + + /// + /// Unequips whatever is in the FG arm and puts it into the inventory. + /// + /// Whether there was anything to unequip. + bool UnequipFGArm(); + + /// + /// Unequips whatever is in the BG arm and puts it into the inventory. + /// + /// Whether there was anything to unequip. + bool UnequipBGArm(); + + /// + /// Unequips whatever is in either of the arms and puts them into the inventory. + /// + void UnequipArms() { + UnequipBGArm(); + UnequipFGArm(); + } + + /// + /// Gets the FG Arm's HeldDevice. Ownership is NOT transferred. + /// + /// The FG Arm's HeldDevice. + HeldDevice* GetEquippedItem() const { return m_pFGArm ? m_pFGArm->GetHeldDevice() : nullptr; } + + /// + /// Gets the BG Arm's HeldDevice. Ownership is NOT transferred. + /// + /// The BG Arm's HeldDevice. + HeldDevice* GetEquippedBGItem() const { return m_pBGArm ? m_pBGArm->GetHeldDevice() : nullptr; } + + /// + /// Gets the total mass of this AHuman's currently equipped devices. + /// + /// The mass of this AHuman's equipped devices. + float GetEquippedMass() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: FirearmIsReady + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is ready for use, and has + // ammo etc. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) is ready for use. + + bool FirearmIsReady() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ThrowableIsReady + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held ThrownDevice's is ready to go. + // Arguments: None. + // Return value: Whether a currently held ThrownDevice (if any) is ready for use. + + bool ThrowableIsReady() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmIsEmpty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is out of ammo. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) is out of ammo. + + bool FirearmIsEmpty() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmNeedsReload + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether any currently held HDFirearms are almost out of ammo. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) has less than half of ammo left. + + bool FirearmNeedsReload() const; + + /// + /// Indicates whether currently held HDFirearms are reloading. If the parameter is true, it will only return true if all firearms are reloading, otherwise it will return whether any firearm is reloading. + /// + /// Whether or not currently held HDFirearms are reloading. + bool FirearmsAreReloading(bool onlyIfAllFirearmsAreReloading) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmIsSemiAuto + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the currently held HDFirearm's is semi or full auto. + // Arguments: None. + // Return value: Whether a currently HDFirearm (if any) is a semi auto device. + + bool FirearmIsSemiAuto() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FirearmActivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the currently held device's delay between pulling the trigger + // and activating. + // Arguments: None. + // Return value: Delay in ms or zero if not a HDFirearm. + + int FirearmActivationDelay() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReloadFirearm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reloads the currently held firearm, if any. Will only reload the BG Firearm if the FG one is full already, to support reloading guns one at a time. + // Arguments: Whether or not to only reload empty fireams. + // Return value: None. + + void ReloadFirearms(bool onlyReloadEmptyFirearms = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsWithinRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a point on the scene is within close range of the currently + // used device and aiming status, if applicable. + // Arguments: A Vector with the aboslute coordinates of a point to check. + // Return value: Whether the point is within close range of this. + + bool IsWithinRange(Vector& point) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Look + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an unseen-revealing ray in the direction of where this is facing. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + // The range, in pixels, beyond the actors sharp aim that the ray will have. + // Return value: Whether any unseen pixels were revealed by this look. + + bool Look(float FOVSpread, float range) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LookForGold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts a material detecting ray in the direction of where this is facing. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + // The range, in pixels, that the ray will have. + // A Vector which will be filled with the absolute coordinates of any + // found gold. It will be unaltered if false is returned. + // Return value: Whether gold was spotted by this ray cast. If so, foundLocation + // has been filled out with the absolute location of the gold. + + bool LookForGold(float FOVSpread, float range, Vector& foundLocation) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LookForMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an MO detecting ray in the direction of where the head is looking + // at the time. Factors including head rotation, sharp aim mode, and + // other variables determine how this ray is cast. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + // A specific material ID to ignore (see through) + // Whether to ignore all terrain or not (true means 'x-ray vision'). + // Return value: A pointer to the MO seen while looking. + + MovableObject* LookForMOs(float FOVSpread = 45, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false); + + /// + /// Gets the GUI representation of this AHuman, only defaulting to its Head or body if no GraphicalIcon has been defined. + /// + /// The graphical representation of this AHuman as a BITMAP. + BITMAP* GetGraphicalIcon() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. + // Arguments: None. + // Return value: None. + + void ResetAllTimers() override; + + /// + /// Detects slopes in terrain and updates the walk path rotation for the corresponding Layer accordingly. + /// + /// The Layer in question. + void UpdateWalkAngle(AHuman::Layer whichLayer); + + /// + /// Detects overhead ceilings and crouches for them. + /// + void UpdateCrouching(); + + /// + /// Gets the walk path rotation for the specified Layer. + /// + /// The Layer in question. + /// The walk angle in radians. + float GetWalkAngle(AHuman::Layer whichLayer) const { return m_WalkAngle[whichLayer].GetRadAngle(); } + + /// + /// Sets the walk path rotation for the specified Layer. + /// + /// The Layer in question. + /// The angle to set. + void SetWalkAngle(AHuman::Layer whichLayer, float angle) { m_WalkAngle[whichLayer] = Matrix(angle); } + + /// + /// Gets whether this AHuman has just taken a stride this frame. + /// + /// Whether this AHuman has taken a stride this frame or not. + bool StrideFrame() const { return m_StrideFrame; } + + /// + /// Gets whether this AHuman is currently attempting to climb something, using arms. + /// + /// Whether this AHuman is currently climbing or not. + bool IsClimbing() const { return m_ArmClimbing[FGROUND] || m_ArmClimbing[BGROUND]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreControllerUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void PreControllerUpdate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this AHuman's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // Which player's screen this is being drawn to. May affect what HUD elements + // get drawn etc. + // Return value: None. + + void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + + /// + /// Gets the LimbPath corresponding to the passed in Layer and MovementState values. + /// + /// Whether to get foreground or background LimbPath. + /// Which movement state to get the LimbPath for. + /// The LimbPath corresponding to the passed in Layer and MovementState values. + LimbPath* GetLimbPath(Layer layer, MovementState movementState) { return &m_Paths[layer][movementState]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get walking limb path speed for the specified preset. + // Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST + // Return value: Limb path speed for the specified preset in m/s. + + float GetLimbPathSpeed(int speedPreset) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLimbPathSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Set walking limb path speed for the specified preset. + // Arguments: Speed preset to set 0 = LimbPath::SLOW, 1 = Limbpath::NORMAL, 2 = LimbPath::FAST. New speed value in m/s. + // Return value: None. + + void SetLimbPathSpeed(int speedPreset, float speed); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the default force that a limb traveling walking LimbPath can push against + // stuff in the scene with. + // Arguments: None. + // Return value: The default set force maximum, in kg * m/s^2. + + float GetLimbPathPushForce() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLimbPathPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the default force that a limb traveling walking LimbPath can push against + // stuff in the scene with. + // Arguments: The default set force maximum, in kg * m/s^2. + // Return value: None + + void SetLimbPathPushForce(float force); + + /// + /// Gets the target rot angle for the given MovementState. + /// + /// The MovementState to get the rot angle target for. + /// The target rot angle for the given MovementState. + float GetRotAngleTarget(MovementState movementState) { return m_RotAngleTargets[movementState]; } + + /// + /// Sets the target rot angle for the given MovementState. + /// + /// The MovementState to get the rot angle target for. + /// The new rot angle target to use. + void SetRotAngleTarget(MovementState movementState, float newRotAngleTarget) { m_RotAngleTargets[movementState] = newRotAngleTarget; } + + /// + /// Gets the duration it takes this AHuman to fully charge a throw. + /// + /// The duration it takes to fully charge a throw in MS. + long GetThrowPrepTime() const { return m_ThrowPrepTime; } + + /// + /// Sets the duration it takes this AHuman to fully charge a throw. + /// + /// New duration to fully charge a throw in MS. + void SetThrowPrepTime(long newPrepTime) { m_ThrowPrepTime = newPrepTime; } + + /// + /// Gets the rate at which this AHuman's Arms will swing with Leg movement, if they're not holding or supporting a HeldDevice. + /// + /// The arm swing rate of this AHuman. + float GetArmSwingRate() const { return m_ArmSwingRate; } + + /// + /// Sets the rate at which this AHuman's Arms will swing with Leg movement, if they're not holding or supporting a HeldDevice. + /// + /// The new arm swing rate for this AHuman. + void SetArmSwingRate(float newValue) { m_ArmSwingRate = newValue; } + + /// + /// Gets the rate at which this AHuman's Arms will sway with Leg movement, if they're holding or supporting a HeldDevice. + /// + /// The device arm sway rate of this AHuman. + float GetDeviceArmSwayRate() const { return m_DeviceArmSwayRate; } + + /// + /// Sets the rate at which this AHuman's Arms will sway with Leg movement, if they're holding or supporting a HeldDevice. + /// + /// The new device arm sway rate for this AHuman. + void SetDeviceArmSwayRate(float newValue) { m_DeviceArmSwayRate = newValue; } + + /// + /// Gets this AHuman's max walkpath adjustment upwards to crouch below low ceilings. + /// + /// This AHuman's max walkpath adjustment. + float GetMaxWalkPathCrouchShift() const { return m_MaxWalkPathCrouchShift; } + + /// + /// Sets this AHuman's max walkpath adjustment upwards to crouch below low ceilings. + /// + /// The new value for this AHuman's max walkpath adjustment. + void SetMaxWalkPathCrouchShift(float newValue) { m_MaxWalkPathCrouchShift = newValue; } + + /// + /// Gets this AHuman's max crouch rotation to duck below low ceilings. + /// + /// This AHuman's max crouch rotation adjustment. + float GetMaxCrouchRotation() const { return m_MaxCrouchRotation; } + + /// + /// Sets this AHuman's max crouch rotation to duck below low ceilings. + /// + /// The new value for this AHuman's max crouch rotation adjustment. + void SetMaxCrouchRotation(float newValue) { m_MaxCrouchRotation = newValue; } + + /// + /// Gets this AHuman's current crouch amount. 0.0 == fully standing, 1.0 == fully crouched. + /// + /// This AHuman's current crouch amount. + float GetCrouchAmount() const { return (m_WalkPathOffset.m_Y * -1.0F) / m_MaxWalkPathCrouchShift; } + + /// + /// Gets this AHuman's current crouch amount override. 0.0 == fully standing, 1.0 == fully crouched, -1 == no override. + /// + /// This AHuman's current crouch amount override. + float GetCrouchAmountOverride() const { return m_CrouchAmountOverride; } + + /// + /// Sets this AHuman's current crouch amount override. + /// + /// The new value for this AHuman's current crouch amount override. + void SetCrouchAmountOverride(float newValue) { m_CrouchAmountOverride = newValue; } + + /// + /// Gets this AHuman's stride sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this AHuman's stride sound. + SoundContainer* GetStrideSound() const { return m_StrideSound; } + + /// + /// Sets this AHuman's stride sound. Ownership IS transferred! + /// + /// The new SoundContainer for this AHuman's stride sound. + void SetStrideSound(SoundContainer* newSound) { m_StrideSound = newSound; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Function that is called when we get a new movepath. + /// This processes and cleans up the movepath. + /// + void OnNewMovePath() override; + + /// + /// Draws an aiming aid in front of this AHuman for throwing. + /// + /// A pointer to a BITMAP to draw on. + /// The absolute position of the target bitmap's upper left corner in the Scene. + /// A normalized scalar that determines the magnitude of the reticle, to indicate force in the throw. + void DrawThrowingReticle(BITMAP* targetBitmap, const Vector& targetPos = Vector(), float progressScalar = 1.0F) const; + + // Member variables + static Entity::ClassInfo m_sClass; + // Articulated head. + Attachable* m_pHead; + // Ratio at which the head's rotation follows the aim angle + float m_LookToAimRatio; + // Foreground arm. + Arm* m_pFGArm; + // Background arm. + Arm* m_pBGArm; + // Foreground leg. + Leg* m_pFGLeg; + // Background leg. + Leg* m_pBGLeg; + // Limb AtomGroups. + AtomGroup* m_pFGHandGroup; + AtomGroup* m_pBGHandGroup; + AtomGroup* m_pFGFootGroup; + AtomGroup* m_BackupFGFootGroup; + AtomGroup* m_pBGFootGroup; + AtomGroup* m_BackupBGFootGroup; + // The sound of the actor taking a step (think robot servo) + SoundContainer* m_StrideSound; + // Jetpack booster. + AEJetpack* m_pJetpack; + bool m_CanActivateBGItem; //!< A flag for whether or not the BG item is waiting to be activated separately. Used for dual-wielding. TODO: Should this be able to be toggled off per actor, device, or controller? + bool m_TriggerPulled; //!< Internal flag for whether this AHuman is currently holding down the trigger of a HDFirearm. Used for dual-wielding. + bool m_WaitingToReloadOffhand; //!< A flag for whether or not the offhand HeldDevice is waiting to be reloaded. + // Blink timer + Timer m_IconBlinkTimer; + // Current upper body state. + UpperBodyState m_ArmsState; + // Current movement state. + MovementState m_MoveState; + // Whether the guy is currently lying down on the ground, rotational spring pulling him that way + // This is engaged if the player first crouches (still upright spring), and then presses left/right + // It is disengaged as soon as the crouch button/direction is released + ProneState m_ProneState; + // Timer for the going prone procedural animation + Timer m_ProneTimer; + // The maximum amount our walkpath can be shifted upwards to crouch and avoid ceilings above us + float m_MaxWalkPathCrouchShift; + // The maximum amount we will duck our head down to avoid obstacles above us. + float m_MaxCrouchRotation; + // The script-set forced crouching amount. 0.0 == fully standing, 1.0 == fully crouched, -1 == no override. + float m_CrouchAmountOverride; + // Limb paths for different movement states. + // [0] is for the foreground limbs, and [1] is for BG. + LimbPath m_Paths[2][MOVEMENTSTATECOUNT]; + std::array m_RotAngleTargets; //!< An array of rot angle targets for different movement states. + // Whether was aiming during the last frame too. + bool m_Aiming; + // Whether the BG Arm is helping with locomotion or not. + bool m_ArmClimbing[2]; + // Whether a stride was taken this frame or not. + bool m_StrideFrame = false; + // Controls the start of leg synch. + bool m_StrideStart; + // Times the stride to see if it is taking too long and needs restart + Timer m_StrideTimer; + // For timing throws + Timer m_ThrowTmr; + // The duration it takes this AHuman to fully charge a throw. + long m_ThrowPrepTime; + Timer m_SharpAimRevertTimer; //!< For timing the transition from sharp aim back to regular aim. + float m_FGArmFlailScalar; //!< The rate at which this AHuman's FG Arm follows the the bodily rotation. Best to keep this at 0 so it doesn't complicate aiming. + float m_BGArmFlailScalar; //!< The rate at which this AHuman's BG Arm follows the the bodily rotation. Set to a negative value for a "counterweight" effect. + Timer m_EquipHUDTimer; //!< Timer for showing the name of any newly equipped Device. + std::array m_WalkAngle; //!< An array of rot angle targets for different movement states. + Vector m_WalkPathOffset; + float m_ArmSwingRate; //!< Controls the rate at which this AHuman's Arms follow the movement of its Legs while they're not holding device(s). + float m_DeviceArmSwayRate; //!< Controls the rate at which this AHuman's Arms follow the movement of its Legs while they're holding device(s). One-handed devices sway half as much as two-handed ones. Defaults to three quarters of Arm swing rate. + + //////////////// + // AI States + + enum DeviceHandlingState { + STILL = 0, + POINTING, + SCANNING, + AIMING, + FIRING, + THROWING, + DIGGING + }; + + enum SweepState { + NOSWEEP = 0, + SWEEPINGUP, + SWEEPUPPAUSE, + SWEEPINGDOWN, + SWEEPDOWNPAUSE + }; + + enum DigState { + NOTDIGGING = 0, + PREDIG, + STARTDIG, + TUNNELING, + FINISHINGDIG, + PAUSEDIGGER + }; + + enum JumpState { + NOTJUMPING = 0, + FORWARDJUMP, + PREUPJUMP, + UPJUMP, + APEXJUMP, + LANDJUMP + }; + + // What the AI is doing with its held devices + DeviceHandlingState m_DeviceState; + // What we are doing with a device sweeping + SweepState m_SweepState; + // The current digging state + DigState m_DigState; + // The current jumping state + JumpState m_JumpState; + // Jumping target, overshoot this and the jump is completed + Vector m_JumpTarget; + // Jumping left or right + bool m_JumpingRight; + // AI is crawling + bool m_Crawling; + // The position of the end of the current tunnel being dug. When it is reached, digging can stop. + Vector m_DigTunnelEndPos; + // The center angle (in rads) for the sweeping motion done duing scannign and digging + float m_SweepCenterAimAngle; + // The range to each direction of the center that the sweeping motion will be done in + float m_SweepRange; + // The absolute coordinates of the last detected gold deposits + Vector m_DigTarget; + // Timer for how long to be shooting at a seen enemy target + Timer m_FireTimer; + // Timer for how long to be shooting at a seen enemy target + Timer m_SweepTimer; + // Timer for how long to be patrolling in a direction + Timer m_PatrolTimer; + // Timer for how long to be firing the jetpack in a direction + Timer m_JumpTimer; #pragma region Event Handling - /// - /// Event listener to be run while this AHuman's PieMenu is opened. - /// - /// The PieMenu this event listener needs to listen to. This will always be this' m_PieMenu and only exists for std::bind. - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int WhilePieMenuOpenListener(const PieMenu *pieMenu) override; + /// + /// Event listener to be run while this AHuman's PieMenu is opened. + /// + /// The PieMenu this event listener needs to listen to. This will always be this' m_PieMenu and only exists for std::bind. + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + int WhilePieMenuOpenListener(const PieMenu* pieMenu) override; #pragma endregion + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AHuman, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AHuman, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. - // Disallow the use of some implicit methods. - AHuman(const AHuman &reference) = delete; - AHuman & operator=(const AHuman &rhs) = delete; + void Clear(); -}; + // Disallow the use of some implicit methods. + AHuman(const AHuman& reference) = delete; + AHuman& operator=(const AHuman& rhs) = delete; + }; } // namespace RTE diff --git a/Source/Entities/Activity.cpp b/Source/Entities/Activity.cpp index 795ea6353..4166e47a3 100644 --- a/Source/Entities/Activity.cpp +++ b/Source/Entities/Activity.cpp @@ -22,9 +22,9 @@ namespace RTE { AbstractClassInfo(Activity, Entity); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void Activity::Clear() { + void Activity::Clear() { m_ActivityState = ActivityState::NotStarted; m_Paused = false; m_AllowsUserSaving = false; @@ -70,7 +70,7 @@ void Activity::Clear() { m_SavedValues.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::Create() { if (Entity::Create() < 0) { @@ -78,15 +78,14 @@ void Activity::Clear() { } for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { std::string teamNum = std::to_string(team + 1); - m_TeamIcons[team] = *dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Team " + teamNum + " Default")); - + m_TeamIcons[team] = *dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Team " + teamNum + " Default")); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Activity::Create(const Activity &reference) { + int Activity::Create(const Activity& reference) { Entity::Create(reference); m_ActivityState = reference.m_ActivityState; @@ -121,7 +120,9 @@ void Activity::Clear() { m_TeamFunds[team] = reference.m_TeamFunds[team]; m_FundsChanged[team] = reference.m_FundsChanged[team]; m_TeamNames[team] = reference.m_TeamNames[team]; - if (reference.m_TeamIcons[team].GetFrameCount() > 0) { m_TeamIcons[team] = reference.m_TeamIcons[team]; } + if (reference.m_TeamIcons[team].GetFrameCount() > 0) { + m_TeamIcons[team] = reference.m_TeamIcons[team]; + } m_TeamDeaths[team] = reference.m_TeamDeaths[team]; m_TeamAISkillLevels[team] = reference.m_TeamAISkillLevels[team]; } @@ -131,11 +132,11 @@ void Activity::Clear() { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Activity::ReadProperty(const std::string_view &propName, Reader &reader) { + int Activity::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("Description", { reader >> m_Description; }); MatchProperty("SceneName", { reader >> m_SceneName; }); MatchProperty("MaxPlayerSupport", { reader >> m_MaxPlayerSupport; }); @@ -154,7 +155,9 @@ void Activity::Clear() { if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { m_Team[playerTeam] = team; m_IsActive[playerTeam] = true; - if (!m_TeamActive[team]) { m_TeamCount++; } + if (!m_TeamActive[team]) { + m_TeamCount++; + } m_TeamActive[team] = true; } else { m_IsActive[playerTeam] = false; @@ -162,7 +165,7 @@ void Activity::Clear() { break; } } - }); + }); MatchForwards("Player1IsHuman") MatchForwards("Player2IsHuman") MatchForwards("Player3IsHuman") MatchProperty("Player4IsHuman", { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { std::string playerNum = std::to_string(player + 1); @@ -171,18 +174,20 @@ void Activity::Clear() { break; } } - }); + }); MatchForwards("Team1Name") MatchForwards("Team2Name") MatchForwards("Team3Name") MatchProperty("Team4Name", { for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { std::string teamNum = std::to_string(team + 1); if (propName == "Team" + teamNum + "Name") { reader >> m_TeamNames[team]; - if (!m_TeamActive[team]) { m_TeamCount++; } + if (!m_TeamActive[team]) { + m_TeamCount++; + } m_TeamActive[team] = true; break; } } - }); + }); MatchForwards("Team1Icon") MatchForwards("Team2Icon") MatchForwards("Team3Icon") MatchProperty("Team4Icon", { for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { std::string teamNum = std::to_string(team + 1); @@ -191,7 +196,7 @@ void Activity::Clear() { break; } } - }); + }); MatchForwards("Team1Funds") MatchForwards("Team2Funds") MatchForwards("Team3Funds") MatchProperty("Team4Funds", { for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; team++) { std::string teamNum = std::to_string(team + 1); @@ -200,7 +205,7 @@ void Activity::Clear() { break; } } - }); + }); MatchForwards("TeamFundsShareOfPlayer1") MatchForwards("TeamFundsShareOfPlayer2") MatchForwards("TeamFundsShareOfPlayer3") MatchProperty("TeamFundsShareOfPlayer4", { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { std::string playerNum = std::to_string(player + 1); @@ -209,7 +214,7 @@ void Activity::Clear() { break; } } - }); + }); MatchForwards("FundsContributionOfPlayer1") MatchForwards("FundsContributionOfPlayer2") MatchForwards("FundsContributionOfPlayer3") MatchProperty("FundsContributionOfPlayer4", { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { std::string playerNum = std::to_string(player + 1); @@ -224,9 +229,9 @@ void Activity::Clear() { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Activity::Save(Writer &writer) const { + int Activity::Save(Writer& writer) const { Entity::Save(writer); writer.NewProperty("Description"); @@ -283,7 +288,7 @@ void Activity::Clear() { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::Start() { // Reseed the RNG for determinism @@ -330,9 +335,9 @@ void Activity::Clear() { } g_CameraMan.ResetAllScreenShake(); - //TODO currently this sets brains to players arbitrarily. We should save information on which brain is for which player in the scene so we can set them properly! + // TODO currently this sets brains to players arbitrarily. We should save information on which brain is for which player in the scene so we can set them properly! if (m_IsActive[player]) { - if (Actor *brain = g_MovableMan.GetUnassignedBrain(GetTeamOfPlayer(player))) { + if (Actor* brain = g_MovableMan.GetUnassignedBrain(GetTeamOfPlayer(player))) { SetPlayerBrain(brain, player); } } @@ -341,7 +346,7 @@ void Activity::Clear() { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Activity::End() { g_AudioMan.FinishIngameLoopingSounds(); @@ -352,7 +357,7 @@ void Activity::Clear() { m_ActivityState = ActivityState::Over; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Activity::SetupPlayers() { m_TeamCount = 0; @@ -365,7 +370,9 @@ void Activity::Clear() { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { if (m_IsActive[player]) { m_PlayerCount++; - if (!m_TeamActive[m_Team[player]]) { m_TeamCount++; } + if (!m_TeamActive[m_Team[player]]) { + m_TeamCount++; + } m_TeamActive[m_Team[player]] = true; } @@ -373,14 +380,16 @@ void Activity::Clear() { int screenIndex = -1; if (m_IsActive[player] && m_IsHuman[player]) { for (int playerToCheck = Players::PlayerOne; playerToCheck < Players::MaxPlayerCount && playerToCheck <= player; ++playerToCheck) { - if (m_IsActive[playerToCheck] && m_IsHuman[playerToCheck]) { screenIndex++; } + if (m_IsActive[playerToCheck] && m_IsHuman[playerToCheck]) { + screenIndex++; + } } } m_PlayerScreen[player] = screenIndex; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Activity::DeactivatePlayer(int playerToDeactivate) { if (playerToDeactivate < Players::PlayerOne || playerToDeactivate >= Players::MaxPlayerCount || !m_IsActive[playerToDeactivate] || !m_TeamActive[m_Team[playerToDeactivate]]) { @@ -406,9 +415,9 @@ void Activity::Clear() { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Activity::AddPlayer(int playerToAdd, bool isHuman, int team, float funds, const Icon *teamIcon) { + int Activity::AddPlayer(int playerToAdd, bool isHuman, int team, float funds, const Icon* teamIcon) { if (playerToAdd < Players::PlayerOne || playerToAdd >= Players::MaxPlayerCount || team < Teams::TeamOne || team >= Teams::MaxTeamCount) { return m_PlayerCount; } @@ -421,15 +430,21 @@ void Activity::Clear() { float newRatio = 1.0F + (funds / totalFunds); for (int teamPlayer = Players::PlayerOne; teamPlayer < Players::MaxPlayerCount; ++teamPlayer) { - if (m_IsActive[teamPlayer] && m_Team[teamPlayer] == team) { m_TeamFundsShare[teamPlayer] /= newRatio; } + if (m_IsActive[teamPlayer] && m_Team[teamPlayer] == team) { + m_TeamFundsShare[teamPlayer] /= newRatio; + } } m_TeamFundsShare[playerToAdd] = funds / totalFunds; } m_TeamActive[team] = true; - if (teamIcon) { SetTeamIcon(team, *teamIcon); } + if (teamIcon) { + SetTeamIcon(team, *teamIcon); + } - if (!m_IsActive[playerToAdd]) { m_PlayerCount++; } + if (!m_IsActive[playerToAdd]) { + m_PlayerCount++; + } m_IsActive[playerToAdd] = true; m_IsHuman[playerToAdd] = isHuman; @@ -440,7 +455,7 @@ void Activity::Clear() { return m_PlayerCount; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Activity::ClearPlayers(bool resetFunds) { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { @@ -455,23 +470,27 @@ void Activity::Clear() { for (int team = Teams::TeamOne; team < Teams::MaxTeamCount; ++team) { m_TeamActive[team] = false; - if (resetFunds) { m_TeamFunds[team] = 0; } + if (resetFunds) { + m_TeamFunds[team] = 0; + } } m_PlayerCount = m_TeamCount = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::GetHumanCount() const { int humans = 0; for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - if (m_IsActive[player] && m_IsHuman[player]) { humans++; } + if (m_IsActive[player] && m_IsHuman[player]) { + humans++; + } } return humans; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Activity::SetTeamOfPlayer(int player, int team) { if (team < Teams::TeamOne || team >= Teams::MaxTeamCount || player < Players::PlayerOne || player >= Players::MaxPlayerCount) { @@ -483,7 +502,7 @@ void Activity::Clear() { m_IsActive[player] = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::PlayerOfScreen(int screen) const { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { @@ -494,7 +513,7 @@ void Activity::Clear() { return Players::NoPlayer; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Activity::GetTeamName(int whichTeam) const { if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { @@ -503,7 +522,7 @@ void Activity::Clear() { return ""; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Activity::IsHumanTeam(int whichTeam) const { if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { @@ -516,17 +535,19 @@ void Activity::Clear() { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::PlayersInTeamCount(int team) const { int count = 0; for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - if (m_IsActive[player] && m_Team[player] == team) { count++; } + if (m_IsActive[player] && m_Team[player] == team) { + count++; + } } return count; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Activity::ChangeTeamFunds(float howMuch, int whichTeam) { if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { @@ -534,13 +555,15 @@ void Activity::Clear() { m_FundsChanged[whichTeam] = true; if (IsHumanTeam(whichTeam)) { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { - if (m_Team[player] == whichTeam) { g_GUISound.FundsChangedSound()->Play(player); } + if (m_Team[player] == whichTeam) { + g_GUISound.FundsChangedSound()->Play(player); + } } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Activity::TeamFundsChanged(int whichTeam) { if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { @@ -551,7 +574,7 @@ void Activity::Clear() { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Activity::UpdatePlayerFundsContribution(int player, float newFunds) { if (player < Players::PlayerOne || player >= Players::MaxPlayerCount || !m_IsActive[player] || !m_TeamActive[m_Team[player]]) { @@ -567,17 +590,21 @@ void Activity::Clear() { // Tally up all the funds of all players on this guy's team for (int playerOnTeam = Players::PlayerOne; playerOnTeam < Players::MaxPlayerCount; ++playerOnTeam) { - if (m_IsActive[playerOnTeam] && m_Team[playerOnTeam] == m_Team[player]) { m_TeamFunds[m_Team[player]] += m_FundsContribution[playerOnTeam]; } + if (m_IsActive[playerOnTeam] && m_Team[playerOnTeam] == m_Team[player]) { + m_TeamFunds[m_Team[player]] += m_FundsContribution[playerOnTeam]; + } } // Now that we have the updated total, update the shares of all team players for (int playerOnTeam = Players::PlayerOne; playerOnTeam < Players::MaxPlayerCount; ++playerOnTeam) { - if (m_IsActive[playerOnTeam] && m_Team[playerOnTeam] == m_Team[player]) { m_TeamFundsShare[playerOnTeam] = m_FundsContribution[playerOnTeam] / m_TeamFunds[m_Team[player]]; } + if (m_IsActive[playerOnTeam] && m_Team[playerOnTeam] == m_Team[player]) { + m_TeamFundsShare[playerOnTeam] = m_FundsContribution[playerOnTeam] / m_TeamFunds[m_Team[player]]; + } } } return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Activity::GetPlayerFundsShare(int player) const { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { @@ -586,17 +613,19 @@ void Activity::Clear() { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Activity::SetPlayerBrain(Actor *newBrain, int player) { + void Activity::SetPlayerBrain(Actor* newBrain, int player) { if ((player >= Players::PlayerOne || player < Players::MaxPlayerCount) && newBrain) { - if (newBrain->GetTeam() != m_Team[player]) { newBrain->SetTeam(m_Team[player]); } + if (newBrain->GetTeam() != m_Team[player]) { + newBrain->SetTeam(m_Team[player]); + } m_HadBrain[player] = true; } m_Brain[player] = newBrain; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Activity::AnyBrainWasEvacuated() const { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { @@ -607,9 +636,9 @@ void Activity::Clear() { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Activity::IsAssignedBrain(Actor *actor) const { + bool Activity::IsAssignedBrain(Actor* actor) const { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { if (actor == m_Brain[player]) { return true; @@ -618,9 +647,9 @@ void Activity::Clear() { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Activity::IsBrainOfWhichPlayer(Actor *actor) const { + int Activity::IsBrainOfWhichPlayer(Actor* actor) const { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { if (actor == m_Brain[player]) { return player; @@ -629,9 +658,9 @@ void Activity::Clear() { return Players::NoPlayer; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Activity::IsOtherPlayerBrain(Actor *actor, int player) const { + bool Activity::IsOtherPlayerBrain(Actor* actor, int player) const { for (int playerToCheck = Players::PlayerOne; playerToCheck < Players::MaxPlayerCount; ++playerToCheck) { if (m_IsActive[playerToCheck] && playerToCheck != player && actor == m_Brain[playerToCheck]) { return true; @@ -640,7 +669,7 @@ void Activity::Clear() { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Activity::GetDifficultyString(int difficulty) { if (difficulty <= DifficultySetting::CakeDifficulty) { @@ -658,7 +687,7 @@ void Activity::Clear() { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Activity::GetAISkillString(int skill) { if (skill < AISkillSetting::InferiorSkill) { @@ -672,7 +701,7 @@ void Activity::Clear() { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::GetTeamAISkill(int team) const { if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { @@ -691,14 +720,14 @@ void Activity::Clear() { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Activity::ReassignSquadLeader(const int player, const int team) { if (m_ControlledActor[player]->GetAIMode() == Actor::AIMODE_SQUAD) { MOID leaderID = m_ControlledActor[player]->GetAIMOWaypointID(); if (leaderID != g_NoMOID) { - Actor *actor = g_MovableMan.GetNextTeamActor(team, m_ControlledActor[player]); + Actor* actor = g_MovableMan.GetNextTeamActor(team, m_ControlledActor[player]); do { // Set the controlled actor as new leader if actor follow the old leader, and not player controlled and not brain @@ -715,8 +744,10 @@ void Activity::Clear() { if (m_ControlledActor[player]->GetAIMode() == Actor::AIMODE_GOTO) { // Copy the old leaders move orders if (actor->GetAIMOWaypointID() != g_NoMOID) { - const MovableObject *targetMO = g_MovableMan.GetMOFromID(actor->GetAIMOWaypointID()); - if (targetMO) { m_ControlledActor[player]->AddAIMOWaypoint(targetMO); } + const MovableObject* targetMO = g_MovableMan.GetMOFromID(actor->GetAIMOWaypointID()); + if (targetMO) { + m_ControlledActor[player]->AddAIMOWaypoint(targetMO); + } } else if ((actor->GetLastAIWaypoint() - actor->GetPos()).GetLargest() > 1) { m_ControlledActor[player]->AddAISceneWaypoint(actor->GetLastAIWaypoint()); } @@ -733,9 +764,9 @@ void Activity::Clear() { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Activity::SwitchToActor(Actor *actor, int player, int team) { + bool Activity::SwitchToActor(Actor* actor, int player, int team) { if (team < Teams::TeamOne || team >= Teams::MaxTeamCount || player < Players::PlayerOne || player >= Players::MaxPlayerCount || !m_IsHuman[player]) { return false; } @@ -747,7 +778,7 @@ void Activity::Clear() { return false; } - Actor *preSwitchActor = (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) ? m_ControlledActor[player] : nullptr; + Actor* preSwitchActor = (m_ControlledActor[player] && g_MovableMan.IsActor(m_ControlledActor[player])) ? m_ControlledActor[player] : nullptr; if (preSwitchActor && preSwitchActor->GetController()->GetPlayer() == player) { preSwitchActor->SetControllerMode(Controller::CIM_AI); preSwitchActor->GetController()->SetDisabled(false); @@ -760,7 +791,7 @@ void Activity::Clear() { m_ControlledActor[player]->SetControllerMode(Controller::CIM_PLAYER, player); m_ControlledActor[player]->GetController()->SetDisabled(false); - SoundContainer *actorSwitchSoundToPlay = (m_ControlledActor[player] == m_Brain[player]) ? g_GUISound.BrainSwitchSound() : g_GUISound.ActorSwitchSound(); + SoundContainer* actorSwitchSoundToPlay = (m_ControlledActor[player] == m_Brain[player]) ? g_GUISound.BrainSwitchSound() : g_GUISound.ActorSwitchSound(); actorSwitchSoundToPlay->Play(player); // If out of frame from the POV of the preswitch actor, play the camera travel noise @@ -775,11 +806,11 @@ void Activity::Clear() { return true; } -////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// void Activity::LoseControlOfActor(int player) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { - if (Actor *actor = m_ControlledActor[player]; actor && g_MovableMan.IsActor(actor)) { + if (Actor* actor = m_ControlledActor[player]; actor && g_MovableMan.IsActor(actor)) { actor->SetControllerMode(Controller::CIM_AI); actor->GetController()->SetDisabled(false); } @@ -789,9 +820,9 @@ void Activity::Clear() { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Activity::HandleCraftEnteringOrbit(ACraft *orbitedCraft) { + void Activity::HandleCraftEnteringOrbit(ACraft* orbitedCraft) { if (!orbitedCraft) { return; } @@ -805,7 +836,7 @@ void Activity::Clear() { if (g_MetaMan.GameInProgress()) { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { if (GetTeamOfPlayer(static_cast(player)) == orbitedCraftTeam) { - const MetaPlayer *metaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + const MetaPlayer* metaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); if (metaPlayer) { foreignCostMult = metaPlayer->GetForeignCostMultiplier(); nativeCostMult = metaPlayer->GetNativeCostMultiplier(); @@ -817,7 +848,7 @@ void Activity::Clear() { float totalValue = orbitedCraft->GetTotalValue(0, foreignCostMult, nativeCostMult); std::string craftText = "Returned craft"; - if (!orbitedCraft->IsInventoryEmpty()) { + if (!orbitedCraft->IsInventoryEmpty()) { craftText += " + cargo"; } if (totalValue > 0.0F) { @@ -845,7 +876,7 @@ void Activity::Clear() { m_TeamDeaths[orbitedCraftTeam]--; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::GetBrainCount(bool getForHuman) const { int brainCount = 0; @@ -864,16 +895,16 @@ void Activity::Clear() { return brainCount; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Activity::SwitchToPrevOrNextActor(bool nextActor, int player, int team, const Actor *actorToSkip) { + void Activity::SwitchToPrevOrNextActor(bool nextActor, int player, int team, const Actor* actorToSkip) { if (team < Teams::TeamOne || team >= Teams::MaxTeamCount || player < Players::PlayerOne || player >= Players::MaxPlayerCount || !m_IsHuman[player]) { return; } - Actor *preSwitchActor = m_ControlledActor[player]; - Actor *actorToSwitchTo = nextActor ? g_MovableMan.GetNextTeamActor(team, preSwitchActor) : g_MovableMan.GetPrevTeamActor(team, preSwitchActor); - const Actor *firstAttemptedSwitchActor = nullptr; + Actor* preSwitchActor = m_ControlledActor[player]; + Actor* actorToSwitchTo = nextActor ? g_MovableMan.GetNextTeamActor(team, preSwitchActor) : g_MovableMan.GetPrevTeamActor(team, preSwitchActor); + const Actor* firstAttemptedSwitchActor = nullptr; bool actorSwitchSucceedOrTriedAllActors = false; while (!actorSwitchSucceedOrTriedAllActors) { @@ -891,23 +922,29 @@ void Activity::Clear() { actorSwitchSucceedOrTriedAllActors = (actorToSwitchTo != actorToSkip && SwitchToActor(actorToSwitchTo, player, team)); } firstAttemptedSwitchActor = firstAttemptedSwitchActor ? firstAttemptedSwitchActor : actorToSwitchTo; - if (!actorSwitchSucceedOrTriedAllActors) { actorToSwitchTo = nextActor ? g_MovableMan.GetNextTeamActor(team, actorToSwitchTo) : g_MovableMan.GetPrevTeamActor(team, actorToSwitchTo); } + if (!actorSwitchSucceedOrTriedAllActors) { + actorToSwitchTo = nextActor ? g_MovableMan.GetNextTeamActor(team, actorToSwitchTo) : g_MovableMan.GetPrevTeamActor(team, actorToSwitchTo); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Activity::Update() { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - if (m_MessageTimer[player].IsPastSimMS(5000)) { g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); } - if (m_IsActive[player]) { m_PlayerController[player].Update(); } + if (m_MessageTimer[player].IsPastSimMS(5000)) { + g_FrameMan.ClearScreenText(ScreenOfPlayer(player)); + } + if (m_IsActive[player]) { + m_PlayerController[player].Update(); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Activity::CanBeUserSaved() const { - if (const Scene *scene = g_SceneMan.GetScene(); (scene && scene->IsMetagameInternal()) || g_MetaMan.GameInProgress()) { + if (const Scene* scene = g_SceneMan.GetScene(); (scene && scene->IsMetagameInternal()) || g_MetaMan.GameInProgress()) { return false; } @@ -917,4 +954,4 @@ void Activity::Clear() { return m_AllowsUserSaving; } -} +} // namespace RTE diff --git a/Source/Entities/Activity.h b/Source/Entities/Activity.h index 0daac3a9e..8d58759c9 100644 --- a/Source/Entities/Activity.h +++ b/Source/Entities/Activity.h @@ -16,7 +16,6 @@ namespace RTE { class Activity : public Entity { public: - SerializableOverrideMethods; ClassInfoGetters; @@ -104,7 +103,7 @@ namespace RTE { /// /// A reference to the Activity to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Activity &reference); + int Create(const Activity& reference); #pragma endregion #pragma region Destruction @@ -117,7 +116,12 @@ namespace RTE { /// Destroys and resets (through Clear()) the Activity object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Entity::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Entity::Destroy(); + } + Clear(); + } #pragma endregion #pragma region Getters and Setters @@ -181,7 +185,7 @@ namespace RTE { /// The Scene to check if it supports this Activity. Ownership is NOT transferred! /// How many teams we're checking for. Some scenes may support and Activity but only for a limited number of teams. If -1, not applicable. /// Whether the Scene has the right stuff. - virtual bool SceneIsCompatible(Scene *scene, int teams = -1) { return scene && teams <= m_MinTeamsRequired; } + virtual bool SceneIsCompatible(Scene* scene, int teams = -1) { return scene && teams <= m_MinTeamsRequired; } /// /// Shows in which stage of the Campaign this appears. @@ -190,7 +194,7 @@ namespace RTE { int GetInCampaignStage() const { return m_InCampaignStage; } /// - /// + /// /// Sets in which stage of the Campaign this appears. /// /// The new stage to set. -1 means it doesn't appear in the campaign. @@ -244,14 +248,14 @@ namespace RTE { /// A pointer to a screen-sized BITMAP to draw on. /// The absolute position of the target bitmap's upper left corner in the scene. /// Which screen's GUI to draw onto the bitmap. - virtual void DrawGUI(BITMAP *targetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0) {} + virtual void DrawGUI(BITMAP* targetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0) {} /// /// Draws this Activity's current graphical representation to a BITMAP of choice. This includes all game-related graphics. /// /// A pointer to a BITMAP to draw on. /// The absolute position of the target bitmap's upper left corner in the scene. - virtual void Draw(BITMAP *targetBitmap, const Vector &targetPos = Vector()) {} + virtual void Draw(BITMAP* targetBitmap, const Vector& targetPos = Vector()) {} #pragma endregion #pragma region Player Handling @@ -284,7 +288,7 @@ namespace RTE { /// How many funds this player contributes to its Team's total funds. /// The team flag icon of this player. Ownership is NOT transferred! /// The new total number of active players in the current game. - int AddPlayer(int playerToAdd, bool isHuman, int team, float funds, const Icon *teamIcon = 0); + int AddPlayer(int playerToAdd, bool isHuman, int team, float funds, const Icon* teamIcon = 0); /// /// Sets all players as not active in the current Activity. @@ -357,14 +361,18 @@ namespace RTE { /// Resets the message timer for one player. /// /// The player to reset the message timer for. - void ResetMessageTimer(int player = 0) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { m_MessageTimer[player].Reset(); } } + void ResetMessageTimer(int player = 0) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { + m_MessageTimer[player].Reset(); + } + } /// /// Gets a pointer to the GUI controller of the specified player. /// /// Which player to get the Controller of. /// A pointer to the player's Controller. Ownership is NOT transferred! - Controller * GetPlayerController(int player = 0) { return (player >= Players::PlayerOne && player < Players::MaxPlayerCount) ? &m_PlayerController[player] : nullptr; } + Controller* GetPlayerController(int player = 0) { return (player >= Players::PlayerOne && player < Players::MaxPlayerCount) ? &m_PlayerController[player] : nullptr; } #pragma endregion #pragma region Team Handling @@ -386,21 +394,29 @@ namespace RTE { /// /// Which team to set the name of. 0 = first team. /// The name to set it to. - void SetTeamName(int whichTeam, const std::string &newName) { if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { m_TeamNames[whichTeam] = newName; } } + void SetTeamName(int whichTeam, const std::string& newName) { + if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { + m_TeamNames[whichTeam] = newName; + } + } /// /// Gets the Icon of a specific team. /// /// Which team to get the Icon of. 0 = first team. /// The current Icon of that team. - const Icon * GetTeamIcon(int whichTeam = 0) const { return (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) ? &m_TeamIcons[whichTeam] : nullptr; } + const Icon* GetTeamIcon(int whichTeam = 0) const { return (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) ? &m_TeamIcons[whichTeam] : nullptr; } /// /// Sets the Icon of a specific team. /// /// Which team to set the Icon of. 0 = first team. /// The Icon to set it to. - void SetTeamIcon(int whichTeam, const Icon &newIcon) { if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { m_TeamIcons[whichTeam] = newIcon; } } + void SetTeamIcon(int whichTeam, const Icon& newIcon) { + if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { + m_TeamIcons[whichTeam] = newIcon; + } + } /// /// Indicates whether a specific team is active in the current game. @@ -413,7 +429,11 @@ namespace RTE { /// Sets the given team as active, even if it shouldn't be considered as such normally. Useful for Activities that don't want to define/show all used teams. /// /// The team to force as active. - void ForceSetTeamAsActive(int team) { if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { m_TeamActive[team] = true; } } + void ForceSetTeamAsActive(int team) { + if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { + m_TeamActive[team] = true; + } + } /// /// Indicates whether a team is player controlled or not. @@ -458,7 +478,11 @@ namespace RTE { /// /// Which team to set the fund count for. 0 = first team. /// A float with the funds tally for the requested team. - void SetTeamFunds(float newFunds, int whichTeam = 0) { if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { m_TeamFunds[whichTeam] = newFunds; } } + void SetTeamFunds(float newFunds, int whichTeam = 0) { + if (whichTeam >= Teams::TeamOne && whichTeam < Teams::MaxTeamCount) { + m_TeamFunds[whichTeam] = newFunds; + } + } /// /// Changes a team's funds level by a certain amount. @@ -515,14 +539,14 @@ namespace RTE { /// /// Which player to get the brain actor for. /// A pointer to the Brain Actor. Ownership is NOT transferred! - Actor * GetPlayerBrain(int player = 0) const { return (player >= Players::PlayerOne && player < Players::MaxPlayerCount) ? m_Brain[player] : nullptr; } + Actor* GetPlayerBrain(int player = 0) const { return (player >= Players::PlayerOne && player < Players::MaxPlayerCount) ? m_Brain[player] : nullptr; } /// /// Sets the current Brain actor for a specific player. /// /// A pointer to the new brain Actor. Ownership is NOT transferred! /// Which team to set the brain actor for. - void SetPlayerBrain(Actor *newBrain, int player = 0); + void SetPlayerBrain(Actor* newBrain, int player = 0); /// /// Shows whether a specific player ever had a Brain yet. @@ -536,7 +560,10 @@ namespace RTE { /// /// Which player to set whether he had a Brain or not. /// Whether he should be flagged as having had a Brain. - void SetPlayerHadBrain(int player, bool hadBrain = true) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) m_HadBrain[player] = hadBrain; } + void SetPlayerHadBrain(int player, bool hadBrain = true) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) + m_HadBrain[player] = hadBrain; + } /// /// Shows whether a specific player's Brain was evacuated into orbit so far. @@ -550,7 +577,11 @@ namespace RTE { /// /// Which player to check whether their Brain was evacuated. /// Whether it was evacuated yet. - void SetBrainEvacuated(int player = 0, bool evacuated = true) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { m_BrainEvacuated[player] = evacuated; } } + void SetBrainEvacuated(int player = 0, bool evacuated = true) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { + m_BrainEvacuated[player] = evacuated; + } + } /// /// Shows whether ANY player evacuated their Brain. @@ -563,14 +594,14 @@ namespace RTE { /// /// Which Actor to check for player braininess. /// Whether any player's Brain or not. - bool IsAssignedBrain(Actor *actor) const; + bool IsAssignedBrain(Actor* actor) const; /// /// Shows which player has a specific actor as a Brain, if any. /// /// Which Actor to check for player braininess. /// Which player has this assigned as a Brain, if any. - int IsBrainOfWhichPlayer(Actor *actor) const; + int IsBrainOfWhichPlayer(Actor* actor) const; /// /// Shows whether the passed in actor is the Brain of any other player. @@ -578,7 +609,7 @@ namespace RTE { /// Which Actor to check for other player braininess. /// From which player's perspective to check. /// Whether other player's Brain or not. - bool IsOtherPlayerBrain(Actor *actor, int player) const; + bool IsOtherPlayerBrain(Actor* actor, int player) const; #pragma endregion #pragma region Difficulty Handling @@ -622,7 +653,11 @@ namespace RTE { /// /// The team to set for. /// AI skill level, 1-100. - void SetTeamAISkill(int team, int skill) { if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { m_TeamAISkillLevels[team] = Limit(skill, AISkillSetting::UnfairSkill, AISkillSetting::MinSkill); } } + void SetTeamAISkill(int team, int skill) { + if (team >= Teams::TeamOne && team < Teams::MaxTeamCount) { + m_TeamAISkillLevels[team] = Limit(skill, AISkillSetting::UnfairSkill, AISkillSetting::MinSkill); + } + } #pragma endregion #pragma region Actor Handling @@ -631,7 +666,7 @@ namespace RTE { /// /// Which player to get the controlled actor of. /// A pointer to the controlled Actor. Ownership is NOT transferred! 0 If no actor is currently controlled by this player. - Actor * GetControlledActor(int player = 0) { return (player >= Players::PlayerOne && player < Players::MaxPlayerCount) ? m_ControlledActor[player] : nullptr; } + Actor* GetControlledActor(int player = 0) { return (player >= Players::PlayerOne && player < Players::MaxPlayerCount) ? m_ControlledActor[player] : nullptr; } /// /// Makes the player's ControlledActor the leader of any squad it is a member of. @@ -647,7 +682,7 @@ namespace RTE { /// Player to force for. /// Which team to switch to next actor on. /// Whether the focus switch was successful or not. - virtual bool SwitchToActor(Actor *actor, int player = 0, int team = 0); + virtual bool SwitchToActor(Actor* actor, int player = 0, int team = 0); /// /// Forces the Activity to focus player control to the previous Actor of a specific team, other than the current one focused on. @@ -655,7 +690,7 @@ namespace RTE { /// Player to force for. /// Which team to switch to next Actor on. /// An Actor pointer to skip in the sequence. - virtual void SwitchToPrevActor(int player, int team, Actor *actorToSkip = 0) { SwitchToPrevOrNextActor(false, player, team, actorToSkip); } + virtual void SwitchToPrevActor(int player, int team, Actor* actorToSkip = 0) { SwitchToPrevOrNextActor(false, player, team, actorToSkip); } /// /// Forces the Activity to focus player control to the next Actor of a specific team, other than the current one focused on. @@ -663,7 +698,7 @@ namespace RTE { /// Player to force for. /// Which team to switch to next Actor on. /// An Actor pointer to skip in the sequence. - virtual void SwitchToNextActor(int player, int team, Actor *actorToSkip = 0) { SwitchToPrevOrNextActor(true, player, team, actorToSkip); } + virtual void SwitchToNextActor(int player, int team, Actor* actorToSkip = 0) { SwitchToPrevOrNextActor(true, player, team, actorToSkip); } /// /// Forces player to lose control of the currently selected Actor, as if it had died. @@ -675,7 +710,7 @@ namespace RTE { /// Handles when an ACraft has left the game scene and entered orbit, though does not delete it. Ownership is NOT transferred, as the ACraft's inventory is just 'unloaded'. /// /// The ACraft instance that entered orbit. Ownership is NOT transferred! - virtual void HandleCraftEnteringOrbit (ACraft *orbitedCraft); + virtual void HandleCraftEnteringOrbit(ACraft* orbitedCraft); #pragma endregion #pragma region Save and Load Handling @@ -702,30 +737,29 @@ namespace RTE { /// /// The key of the saved string. /// The string to save. - void SaveString(const std::string &key, const std::string &value) { m_SavedValues.SaveString(key, value); }; + void SaveString(const std::string& key, const std::string& value) { m_SavedValues.SaveString(key, value); }; /// /// Loads and returns a previously saved string. /// /// The key of the string to load. - const std::string & LoadString(const std::string &key) { return m_SavedValues.LoadString(key); }; + const std::string& LoadString(const std::string& key) { return m_SavedValues.LoadString(key); }; /// /// Saves a number which will be stored in our ini. /// /// The key of the saved number. /// The number to save. - void SaveNumber(const std::string &key, float value) { m_SavedValues.SaveNumber(key, value); }; + void SaveNumber(const std::string& key, float value) { m_SavedValues.SaveNumber(key, value); }; /// /// Loads and returns a previously saved number. /// /// The key of the string to load. - float LoadNumber(const std::string &key) { return m_SavedValues.LoadNumber(key); }; + float LoadNumber(const std::string& key) { return m_SavedValues.LoadNumber(key); }; #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. ActivityState m_ActivityState; //!< Current state of this Activity. @@ -765,11 +799,11 @@ namespace RTE { bool m_FundsChanged[Teams::MaxTeamCount]; //!< Whether the team funds have changed during the current frame. float m_FundsContribution[Players::MaxPlayerCount]; //!< How much this player contributed to his team's funds at the start of the Activity. - Actor *m_Brain[Players::MaxPlayerCount]; //!< The Brain of each player. Not owned! + Actor* m_Brain[Players::MaxPlayerCount]; //!< The Brain of each player. Not owned! bool m_HadBrain[Players::MaxPlayerCount]; //!< Whether each player has yet had a Brain. If not, then their Activity doesn't end if no brain is found. bool m_BrainEvacuated[Players::MaxPlayerCount]; //!< Whether a player has evacuated his Brain into orbit. - Actor *m_ControlledActor[Players::MaxPlayerCount]; //!< Currently controlled actor, not owned. + Actor* m_ControlledActor[Players::MaxPlayerCount]; //!< Currently controlled actor, not owned. Controller m_PlayerController[Players::MaxPlayerCount]; //!< The Controllers of all the players for the GUIs. Timer m_MessageTimer[Players::MaxPlayerCount]; //!< Message timer for each player. @@ -782,7 +816,6 @@ namespace RTE { GenericSavedData m_SavedValues; private: - /// /// Shared method to get the amount of human or AI controlled brains that are left in this Activity. /// @@ -797,7 +830,7 @@ namespace RTE { /// Player to force for. /// Which team to switch to next Actor on. /// An Actor pointer to skip in the sequence. - void SwitchToPrevOrNextActor(bool nextActor, int player, int team, const Actor *skip = 0); + void SwitchToPrevOrNextActor(bool nextActor, int player, int team, const Actor* skip = 0); /// /// Clears all the member variables of this Activity, effectively resetting the members of this abstraction level only. @@ -805,8 +838,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - Activity(const Activity &reference) = delete; - Activity & operator=(const Activity &rhs) = delete; + Activity(const Activity& reference) = delete; + Activity& operator=(const Activity& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/Actor.cpp b/Source/Entities/Actor.cpp index a94e3f94c..98cdc914b 100644 --- a/Source/Entities/Actor.cpp +++ b/Source/Entities/Actor.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -41,905 +40,1004 @@ namespace RTE { -ConcreteClassInfo(Actor, MOSRotating, 20); + ConcreteClassInfo(Actor, MOSRotating, 20); -std::vector Actor::m_apNoTeamIcon; -BITMAP *Actor::m_apAIIcons[AIMODE_COUNT]; -std::vector Actor::m_apSelectArrow; -std::vector Actor::m_apAlarmExclamation; -bool Actor::m_sIconsLoaded = false; + std::vector Actor::m_apNoTeamIcon; + BITMAP* Actor::m_apAIIcons[AIMODE_COUNT]; + std::vector Actor::m_apSelectArrow; + std::vector Actor::m_apAlarmExclamation; + bool Actor::m_sIconsLoaded = false; #define ARROWTIME 1000 + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: LuaBindRegister + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registration function for exposing this' members to a LuaBind module. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Actor, effectively + // resetting the members of this abstraction level only. + + void Actor::Clear() { + m_Controller.Reset(); + m_PlayerControllable = true; + m_BodyHitSound = nullptr; + m_AlarmSound = nullptr; + m_PainSound = nullptr; + m_DeathSound = nullptr; + m_DeviceSwitchSound = nullptr; + m_Status = STABLE; + m_Health = m_PrevHealth = m_MaxHealth = 100.0F; + m_pTeamIcon = nullptr; + m_pControllerIcon = nullptr; + m_LastSecondTimer.Reset(); + m_LastSecondPos.Reset(); + m_RecentMovement.Reset(); + m_TravelImpulseDamage = 750.0F; + m_StableVel.SetXY(15.0F, 25.0F); + m_StableRecoverDelay = 1000; + m_HeartBeat.Reset(); + m_NewControlTmr.Reset(); + m_DeathTmr.Reset(); + m_GoldCarried = 0; + m_GoldPicked = false; + m_AimState = AIMSTILL; + m_AimAngle = 0; + m_AimRange = c_HalfPI; + m_AimDistance = 0; + m_AimTmr.Reset(); + m_SharpAimTimer.Reset(); + m_SharpAimDelay = 250; + m_SharpAimProgress = 0; + m_SharpAimMaxedOut = false; + m_PointingTarget.Reset(); + m_SeenTargetPos.Reset(); + // Set the limit to soemthing reasonable, if the timer is over it, there's no alarm + m_AlarmTimer.SetSimTimeLimitMS(3000); + m_AlarmTimer.SetElapsedSimTimeMS(4000); + m_LastAlarmPos.Reset(); + m_SightDistance = 450.0F; + m_Perceptiveness = 0.5F; + m_PainThreshold = 15.0F; + m_CanRevealUnseen = true; + m_CharHeight = 0; + m_HolsterOffset.Reset(); + m_ReloadOffset.Reset(); + m_ViewPoint.Reset(); + m_Inventory.clear(); + m_MaxInventoryMass = -1.0F; + m_pItemInReach = nullptr; + m_HUDStack = 0; + m_DeploymentID = 0; + m_PassengerSlots = 1; + + m_AIMode = AIMODE_NONE; + m_Waypoints.clear(); + m_DrawWaypoints = false; + m_MoveTarget.Reset(); + m_pMOMoveTarget = nullptr; + m_PrevPathTarget.Reset(); + m_MoveVector.Reset(); + m_MovePath.clear(); + m_UpdateMovePath = true; + m_MoveProximityLimit = 20.0F; + m_AIBaseDigStrength = c_PathFindingDefaultDigStrength; + m_BaseMass = std::numeric_limits::infinity(); + + m_DamageMultiplier = 1.0F; + + m_Organic = false; + m_Mechanical = false; + + m_LimbPushForcesAndCollisionsDisabled = false; + + m_PieMenu.reset(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Actor object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: LuaBindRegister -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registration function for exposing this' members to a LuaBind module. + int Actor::Create() { + if (MOSRotating::Create() < 0) { + return -1; + } + // Set MO Type. + m_MOType = MovableObject::TypeActor; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Actor, effectively -// resetting the members of this abstraction level only. - -void Actor::Clear() { - m_Controller.Reset(); - m_PlayerControllable = true; - m_BodyHitSound = nullptr; - m_AlarmSound = nullptr; - m_PainSound = nullptr; - m_DeathSound = nullptr; - m_DeviceSwitchSound = nullptr; - m_Status = STABLE; - m_Health = m_PrevHealth = m_MaxHealth = 100.0F; - m_pTeamIcon = nullptr; - m_pControllerIcon = nullptr; - m_LastSecondTimer.Reset(); - m_LastSecondPos.Reset(); - m_RecentMovement.Reset(); - m_TravelImpulseDamage = 750.0F; - m_StableVel.SetXY(15.0F, 25.0F); - m_StableRecoverDelay = 1000; - m_HeartBeat.Reset(); - m_NewControlTmr.Reset(); - m_DeathTmr.Reset(); - m_GoldCarried = 0; - m_GoldPicked = false; - m_AimState = AIMSTILL; - m_AimAngle = 0; - m_AimRange = c_HalfPI; - m_AimDistance = 0; - m_AimTmr.Reset(); - m_SharpAimTimer.Reset(); - m_SharpAimDelay = 250; - m_SharpAimProgress = 0; - m_SharpAimMaxedOut = false; - m_PointingTarget.Reset(); - m_SeenTargetPos.Reset(); - // Set the limit to soemthing reasonable, if the timer is over it, there's no alarm - m_AlarmTimer.SetSimTimeLimitMS(3000); - m_AlarmTimer.SetElapsedSimTimeMS(4000); - m_LastAlarmPos.Reset(); - m_SightDistance = 450.0F; - m_Perceptiveness = 0.5F; - m_PainThreshold = 15.0F; - m_CanRevealUnseen = true; - m_CharHeight = 0; - m_HolsterOffset.Reset(); - m_ReloadOffset.Reset(); - m_ViewPoint.Reset(); - m_Inventory.clear(); - m_MaxInventoryMass = -1.0F; - m_pItemInReach = nullptr; - m_HUDStack = 0; - m_DeploymentID = 0; - m_PassengerSlots = 1; - - m_AIMode = AIMODE_NONE; - m_Waypoints.clear(); - m_DrawWaypoints = false; - m_MoveTarget.Reset(); - m_pMOMoveTarget = nullptr; - m_PrevPathTarget.Reset(); - m_MoveVector.Reset(); - m_MovePath.clear(); - m_UpdateMovePath = true; - m_MoveProximityLimit = 20.0F; - m_AIBaseDigStrength = c_PathFindingDefaultDigStrength; - m_BaseMass = std::numeric_limits::infinity(); - - m_DamageMultiplier = 1.0F; - - m_Organic = false; - m_Mechanical = false; - - m_LimbPushForcesAndCollisionsDisabled = false; - - m_PieMenu.reset(); -} + // Default to an interesting AI controller mode + m_Controller.SetInputMode(Controller::CIM_AI); + m_Controller.SetControlledActor(this); + m_UpdateMovePath = true; + m_ViewPoint = m_Pos; + m_HUDStack = -m_CharHeight / 2; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Actor object ready for use. + // Sets up the team icon + SetTeam(m_Team); -int Actor::Create() -{ - if (MOSRotating::Create() < 0) { - return -1; - } + if (const Actor* presetActor = static_cast(GetPreset())) { + m_BaseMass = presetActor->GetMass(); + } - // Set MO Type. - m_MOType = MovableObject::TypeActor; + // All brain actors by default avoid hitting each other on the same team + if (IsInGroup("Brains")) { + m_IgnoresTeamHits = true; + } - // Default to an interesting AI controller mode - m_Controller.SetInputMode(Controller::CIM_AI); - m_Controller.SetControlledActor(this); - m_UpdateMovePath = true; + if (!m_PieMenu) { + SetPieMenu(static_cast(g_PresetMan.GetEntityPreset("PieMenu", GetDefaultPieMenuName())->Clone())); + } else { + m_PieMenu->SetOwner(this); + } - m_ViewPoint = m_Pos; - m_HUDStack = -m_CharHeight / 2; + return 0; + } - // Sets up the team icon - SetTeam(m_Team); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Actor to be identical to another, by deep copy. - if (const Actor *presetActor = static_cast(GetPreset())) { - m_BaseMass = presetActor->GetMass(); - } + int Actor::Create(const Actor& reference) { + MOSRotating::Create(reference); - // All brain actors by default avoid hitting each other on the same team - if (IsInGroup("Brains")) { - m_IgnoresTeamHits = true; - } + // Set MO Type. + m_MOType = MovableObject::TypeActor; + + m_Controller = reference.m_Controller; + m_Controller.SetInputMode(Controller::CIM_AI); + m_Controller.SetControlledActor(this); + m_PlayerControllable = reference.m_PlayerControllable; + + if (reference.m_BodyHitSound) { + m_BodyHitSound = dynamic_cast(reference.m_BodyHitSound->Clone()); + } + if (reference.m_AlarmSound) { + m_AlarmSound = dynamic_cast(reference.m_AlarmSound->Clone()); + } + if (reference.m_PainSound) { + m_PainSound = dynamic_cast(reference.m_PainSound->Clone()); + } + if (reference.m_DeathSound) { + m_DeathSound = dynamic_cast(reference.m_DeathSound->Clone()); + } + if (reference.m_DeviceSwitchSound) { + m_DeviceSwitchSound = dynamic_cast(reference.m_DeviceSwitchSound->Clone()); + } + // m_FacingRight = reference.m_FacingRight; + m_Status = reference.m_Status; + m_Health = m_PrevHealth = reference.m_Health; + m_MaxHealth = reference.m_MaxHealth; + m_pTeamIcon = reference.m_pTeamIcon; + // m_LastSecondTimer.Reset(); + // m_LastSecondPos.Reset(); + // m_RecentMovement.Reset(); + m_LastSecondPos = reference.m_LastSecondPos; + m_TravelImpulseDamage = reference.m_TravelImpulseDamage; + m_StableVel = reference.m_StableVel; + m_StableRecoverDelay = reference.m_StableRecoverDelay; + m_GoldCarried = reference.m_GoldCarried; + m_AimState = reference.m_AimState; + m_AimRange = reference.m_AimRange; + m_AimAngle = reference.m_AimAngle; + m_AimDistance = reference.m_AimDistance; + m_SharpAimDelay = reference.m_SharpAimDelay; + m_SharpAimProgress = reference.m_SharpAimProgress; + m_PointingTarget = reference.m_PointingTarget; + m_SeenTargetPos = reference.m_SeenTargetPos; + m_SightDistance = reference.m_SightDistance; + m_Perceptiveness = reference.m_Perceptiveness; + m_PainThreshold = reference.m_PainThreshold; + m_CanRevealUnseen = reference.m_CanRevealUnseen; + m_CharHeight = reference.m_CharHeight; + m_HolsterOffset = reference.m_HolsterOffset; + m_ReloadOffset = reference.m_ReloadOffset; + + for (std::deque::const_iterator itr = reference.m_Inventory.begin(); itr != reference.m_Inventory.end(); ++itr) { + m_Inventory.push_back(dynamic_cast((*itr)->Clone())); + } - if (!m_PieMenu) { - SetPieMenu(static_cast(g_PresetMan.GetEntityPreset("PieMenu", GetDefaultPieMenuName())->Clone())); - } else { - m_PieMenu->SetOwner(this); + m_MaxInventoryMass = reference.m_MaxInventoryMass; + + // Only load the static AI mode icons once + if (!m_sIconsLoaded) { + ContentFile("Base.rte/GUIs/TeamIcons/NoTeam.png").GetAsAnimation(m_apNoTeamIcon, 2); + + ContentFile iconFile("Base.rte/GUIs/PieMenus/PieIcons/Blank000.png"); + m_apAIIcons[AIMODE_NONE] = iconFile.GetAsBitmap(); + m_apAIIcons[AIMODE_BOMB] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Eye000.png"); + m_apAIIcons[AIMODE_SENTRY] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Cycle000.png"); + m_apAIIcons[AIMODE_PATROL] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/GoTo000.png"); + m_apAIIcons[AIMODE_GOTO] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Brain000.png"); + m_apAIIcons[AIMODE_BRAINHUNT] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Dig000.png"); + m_apAIIcons[AIMODE_GOLDDIG] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Return000.png"); + m_apAIIcons[AIMODE_RETURN] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Land000.png"); + m_apAIIcons[AIMODE_STAY] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Launch000.png"); + m_apAIIcons[AIMODE_DELIVER] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Death000.png"); + m_apAIIcons[AIMODE_SCUTTLE] = iconFile.GetAsBitmap(); + iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Follow000.png"); + m_apAIIcons[AIMODE_SQUAD] = iconFile.GetAsBitmap(); + + ContentFile("Base.rte/GUIs/Indicators/SelectArrow.png").GetAsAnimation(m_apSelectArrow, 4); + ContentFile("Base.rte/GUIs/Indicators/AlarmExclamation.png").GetAsAnimation(m_apAlarmExclamation, 2); + + m_sIconsLoaded = true; + } + m_DeploymentID = reference.m_DeploymentID; + m_PassengerSlots = reference.m_PassengerSlots; + + m_AIMode = reference.m_AIMode; + m_Waypoints = reference.m_Waypoints; + m_DrawWaypoints = reference.m_DrawWaypoints; + m_MoveTarget = reference.m_MoveTarget; + m_pMOMoveTarget = reference.m_pMOMoveTarget; + m_PrevPathTarget = reference.m_PrevPathTarget; + m_MoveVector = reference.m_MoveVector; + m_MovePath.clear(); + m_UpdateMovePath = reference.m_UpdateMovePath; + m_MoveProximityLimit = reference.m_MoveProximityLimit; + m_AIBaseDigStrength = reference.m_AIBaseDigStrength; + m_BaseMass = reference.m_BaseMass; + + m_Organic = reference.m_Organic; + m_Mechanical = reference.m_Mechanical; + + m_LimbPushForcesAndCollisionsDisabled = reference.m_LimbPushForcesAndCollisionsDisabled; + + RTEAssert(reference.m_PieMenu != nullptr, "Tried to clone actor with no pie menu."); + SetPieMenu(static_cast(reference.m_PieMenu->Clone())); + m_PieMenu->AddWhilePieMenuOpenListener(this, std::bind(&Actor::WhilePieMenuOpenListener, this, m_PieMenu.get())); + + return 0; } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int Actor::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return MOSRotating::ReadProperty(propName, reader)); + + MatchProperty("PlayerControllable", { reader >> m_PlayerControllable; }); + MatchProperty("BodyHitSound", { + m_BodyHitSound = new SoundContainer; + reader >> m_BodyHitSound; + }); + MatchProperty("AlarmSound", { + m_AlarmSound = new SoundContainer; + reader >> m_AlarmSound; + }); + MatchProperty("PainSound", { + m_PainSound = new SoundContainer; + reader >> m_PainSound; + }); + MatchProperty("DeathSound", { + m_DeathSound = new SoundContainer; + reader >> m_DeathSound; + }); + MatchProperty("DeviceSwitchSound", { + m_DeviceSwitchSound = new SoundContainer; + reader >> m_DeviceSwitchSound; + }); + MatchProperty("Status", { reader >> m_Status; }); + MatchProperty("DeploymentID", { reader >> m_DeploymentID; }); + MatchProperty("PassengerSlots", { reader >> m_PassengerSlots; }); + MatchProperty("Health", + { + reader >> m_Health; + m_PrevHealth = m_Health; + if (m_Health > m_MaxHealth) + m_MaxHealth = m_Health; + }); + MatchProperty("MaxHealth", + { + reader >> m_MaxHealth; + if (m_MaxHealth < m_Health) { + m_Health = m_MaxHealth; + m_PrevHealth = m_Health; + } + }); + MatchProperty("ImpulseDamageThreshold", { reader >> m_TravelImpulseDamage; }); + MatchProperty("StableVelocityThreshold", { reader >> m_StableVel; }); + MatchProperty("StableRecoveryDelay", { reader >> m_StableRecoverDelay; }); + MatchProperty("AimAngle", { reader >> m_AimAngle; }); + MatchProperty("AimRange", { reader >> m_AimRange; }); + MatchProperty("AimDistance", { reader >> m_AimDistance; }); + MatchProperty("SharpAimDelay", { reader >> m_SharpAimDelay; }); + MatchProperty("SightDistance", { reader >> m_SightDistance; }); + MatchProperty("Perceptiveness", { reader >> m_Perceptiveness; }); + MatchProperty("PainThreshold", { reader >> m_PainThreshold; }); + MatchProperty("CanRevealUnseen", { reader >> m_CanRevealUnseen; }); + MatchProperty("CharHeight", { reader >> m_CharHeight; }); + MatchProperty("HolsterOffset", { reader >> m_HolsterOffset; }); + MatchProperty("ReloadOffset", { reader >> m_ReloadOffset; }); + MatchForwards("AddInventoryDevice") MatchProperty("AddInventory", + { + MovableObject* pInvMO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); + if (!pInvMO) { + reader.ReportError("Object added to inventory is broken."); + } + AddToInventoryBack(pInvMO); + }); + MatchProperty("MaxInventoryMass", { reader >> m_MaxInventoryMass; }); + MatchProperty("AIMode", { + int mode; + reader >> mode; + m_AIMode = static_cast(mode); + }); + MatchProperty("SpecialBehaviour_AddAISceneWaypoint", { + Vector waypointToAdd; + reader >> waypointToAdd; + AddAISceneWaypoint(waypointToAdd); + }); + MatchProperty("PieMenu", { + m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); + if (!m_PieMenu) { + reader.ReportError("Failed to set Actor's pie menu. Doublecheck your name and everything is correct."); + } + m_PieMenu->Create(this); + }); + MatchProperty("Organic", { reader >> m_Organic; }); + MatchProperty("Mechanical", { reader >> m_Mechanical; }); + MatchProperty("AIBaseDigStrength", { reader >> m_AIBaseDigStrength; }); + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Actor to be identical to another, by deep copy. - -int Actor::Create(const Actor &reference) -{ - MOSRotating::Create(reference); - - // Set MO Type. - m_MOType = MovableObject::TypeActor; - - m_Controller = reference.m_Controller; - m_Controller.SetInputMode(Controller::CIM_AI); - m_Controller.SetControlledActor(this); - m_PlayerControllable = reference.m_PlayerControllable; - - if (reference.m_BodyHitSound) { m_BodyHitSound = dynamic_cast(reference.m_BodyHitSound->Clone()); } - if (reference.m_AlarmSound) { m_AlarmSound = dynamic_cast(reference.m_AlarmSound->Clone()); } - if (reference.m_PainSound) { m_PainSound = dynamic_cast(reference.m_PainSound->Clone()); } - if (reference.m_DeathSound) { m_DeathSound = dynamic_cast(reference.m_DeathSound->Clone()); } - if (reference.m_DeviceSwitchSound) { m_DeviceSwitchSound = dynamic_cast(reference.m_DeviceSwitchSound->Clone()); } -// m_FacingRight = reference.m_FacingRight; - m_Status = reference.m_Status; - m_Health = m_PrevHealth = reference.m_Health; - m_MaxHealth = reference.m_MaxHealth; - m_pTeamIcon = reference.m_pTeamIcon; -// m_LastSecondTimer.Reset(); -// m_LastSecondPos.Reset(); -// m_RecentMovement.Reset(); - m_LastSecondPos = reference.m_LastSecondPos; - m_TravelImpulseDamage = reference.m_TravelImpulseDamage; - m_StableVel = reference.m_StableVel; - m_StableRecoverDelay = reference.m_StableRecoverDelay; - m_GoldCarried = reference.m_GoldCarried; - m_AimState = reference.m_AimState; - m_AimRange = reference.m_AimRange; - m_AimAngle = reference.m_AimAngle; - m_AimDistance = reference.m_AimDistance; - m_SharpAimDelay = reference.m_SharpAimDelay; - m_SharpAimProgress = reference.m_SharpAimProgress; - m_PointingTarget = reference.m_PointingTarget; - m_SeenTargetPos = reference.m_SeenTargetPos; - m_SightDistance = reference.m_SightDistance; - m_Perceptiveness = reference.m_Perceptiveness; - m_PainThreshold = reference.m_PainThreshold; - m_CanRevealUnseen = reference.m_CanRevealUnseen; - m_CharHeight = reference.m_CharHeight; - m_HolsterOffset = reference.m_HolsterOffset; - m_ReloadOffset = reference.m_ReloadOffset; - - for (std::deque::const_iterator itr = reference.m_Inventory.begin(); itr != reference.m_Inventory.end(); ++itr) { - m_Inventory.push_back(dynamic_cast((*itr)->Clone())); - } - - m_MaxInventoryMass = reference.m_MaxInventoryMass; - - // Only load the static AI mode icons once - if (!m_sIconsLoaded) - { - ContentFile("Base.rte/GUIs/TeamIcons/NoTeam.png").GetAsAnimation(m_apNoTeamIcon, 2); - - ContentFile iconFile("Base.rte/GUIs/PieMenus/PieIcons/Blank000.png"); - m_apAIIcons[AIMODE_NONE] = iconFile.GetAsBitmap(); - m_apAIIcons[AIMODE_BOMB] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Eye000.png"); - m_apAIIcons[AIMODE_SENTRY] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Cycle000.png"); - m_apAIIcons[AIMODE_PATROL] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/GoTo000.png"); - m_apAIIcons[AIMODE_GOTO] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Brain000.png"); - m_apAIIcons[AIMODE_BRAINHUNT] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Dig000.png"); - m_apAIIcons[AIMODE_GOLDDIG] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Return000.png"); - m_apAIIcons[AIMODE_RETURN] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Land000.png"); - m_apAIIcons[AIMODE_STAY] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Launch000.png"); - m_apAIIcons[AIMODE_DELIVER] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Death000.png"); - m_apAIIcons[AIMODE_SCUTTLE] = iconFile.GetAsBitmap(); - iconFile.SetDataPath("Base.rte/GUIs/PieMenus/PieIcons/Follow000.png"); - m_apAIIcons[AIMODE_SQUAD] = iconFile.GetAsBitmap(); - - ContentFile("Base.rte/GUIs/Indicators/SelectArrow.png").GetAsAnimation(m_apSelectArrow, 4); - ContentFile("Base.rte/GUIs/Indicators/AlarmExclamation.png").GetAsAnimation(m_apAlarmExclamation, 2); - - m_sIconsLoaded = true; - } - m_DeploymentID = reference.m_DeploymentID; - m_PassengerSlots = reference.m_PassengerSlots; - - m_AIMode = reference.m_AIMode; - m_Waypoints = reference.m_Waypoints; - m_DrawWaypoints = reference.m_DrawWaypoints; - m_MoveTarget = reference.m_MoveTarget; - m_pMOMoveTarget = reference.m_pMOMoveTarget; - m_PrevPathTarget = reference.m_PrevPathTarget; - m_MoveVector = reference.m_MoveVector; - m_MovePath.clear(); - m_UpdateMovePath = reference.m_UpdateMovePath; - m_MoveProximityLimit = reference.m_MoveProximityLimit; - m_AIBaseDigStrength = reference.m_AIBaseDigStrength; - m_BaseMass = reference.m_BaseMass; - - m_Organic = reference.m_Organic; - m_Mechanical = reference.m_Mechanical; - - m_LimbPushForcesAndCollisionsDisabled = reference.m_LimbPushForcesAndCollisionsDisabled; - - RTEAssert(reference.m_PieMenu != nullptr, "Tried to clone actor with no pie menu."); - SetPieMenu(static_cast(reference.m_PieMenu->Clone())); - m_PieMenu->AddWhilePieMenuOpenListener(this, std::bind(&Actor::WhilePieMenuOpenListener, this, m_PieMenu.get())); - - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Actor with a Writer for + // later recreation with Create(Reader &reader); + + int Actor::Save(Writer& writer) const { + MOSRotating::Save(writer); + + writer.NewPropertyWithValue("PlayerControllable", m_PlayerControllable); + writer.NewProperty("BodyHitSound"); + writer << m_BodyHitSound; + writer.NewProperty("AlarmSound"); + writer << m_AlarmSound; + writer.NewProperty("PainSound"); + writer << m_PainSound; + writer.NewProperty("DeathSound"); + writer << m_DeathSound; + writer.NewProperty("DeviceSwitchSound"); + writer << m_DeviceSwitchSound; + writer.NewProperty("Status"); + writer << m_Status; + writer.NewProperty("Health"); + writer << m_Health; + writer.NewProperty("MaxHealth"); + writer << m_MaxHealth; + if (m_DeploymentID) { + writer.NewProperty("DeploymentID"); + writer << m_DeploymentID; + } + writer.NewProperty("ImpulseDamageThreshold"); + writer << m_TravelImpulseDamage; + writer.NewProperty("StableVelocityThreshold"); + writer << m_StableVel; + writer.NewProperty("StableRecoveryDelay"); + writer << m_StableRecoverDelay; + writer.NewProperty("AimAngle"); + writer << m_AimAngle; + writer.NewProperty("AimRange"); + writer << m_AimRange; + writer.NewProperty("AimDistance"); + writer << m_AimDistance; + writer.NewProperty("SharpAimDelay"); + writer << m_SharpAimDelay; + writer.NewProperty("SightDistance"); + writer << m_SightDistance; + writer.NewProperty("Perceptiveness"); + writer << m_Perceptiveness; + writer.NewProperty("PainThreshold"); + writer << m_PainThreshold; + writer.NewProperty("CanRevealUnseen"); + writer << m_CanRevealUnseen; + writer.NewProperty("CharHeight"); + writer << m_CharHeight; + writer.NewProperty("HolsterOffset"); + writer << m_HolsterOffset; + writer.NewPropertyWithValue("ReloadOffset", m_ReloadOffset); + for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + writer.NewProperty("AddInventory"); + writer << **itr; + } + writer.NewProperty("MaxInventoryMass"); + writer << m_MaxInventoryMass; + writer.NewProperty("AIMode"); + writer << m_AIMode; + writer.NewProperty("PieMenu"); + writer << m_PieMenu.get(); + + writer.NewPropertyWithValue("Organic", m_Organic); + writer.NewPropertyWithValue("Mechanical", m_Mechanical); + writer.NewPropertyWithValue("AIBaseDigStrength", m_AIBaseDigStrength); + + return 0; + } + void Actor::DestroyScriptState() { + for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + (*itr)->DestroyScriptState(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int Actor::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return MOSRotating::ReadProperty(propName, reader)); - - MatchProperty("PlayerControllable", { reader >> m_PlayerControllable; }); - MatchProperty("BodyHitSound", { - m_BodyHitSound = new SoundContainer; - reader >> m_BodyHitSound; - }); - MatchProperty("AlarmSound", { - m_AlarmSound = new SoundContainer; - reader >> m_AlarmSound; - }); - MatchProperty("PainSound", { - m_PainSound = new SoundContainer; - reader >> m_PainSound; - }); - MatchProperty("DeathSound", { - m_DeathSound = new SoundContainer; - reader >> m_DeathSound; - }); - MatchProperty("DeviceSwitchSound", { - m_DeviceSwitchSound = new SoundContainer; - reader >> m_DeviceSwitchSound; - }); - MatchProperty("Status", { reader >> m_Status; }); - MatchProperty("DeploymentID", { reader >> m_DeploymentID; }); - MatchProperty("PassengerSlots", { reader >> m_PassengerSlots; }); - MatchProperty("Health", - { - reader >> m_Health; - m_PrevHealth = m_Health; - if (m_Health > m_MaxHealth) - m_MaxHealth = m_Health; - }); - MatchProperty("MaxHealth", - { - reader >> m_MaxHealth; - if (m_MaxHealth < m_Health) - { - m_Health = m_MaxHealth; - m_PrevHealth = m_Health; - } - }); - MatchProperty("ImpulseDamageThreshold", { reader >> m_TravelImpulseDamage; }); - MatchProperty("StableVelocityThreshold", { reader >> m_StableVel; }); - MatchProperty("StableRecoveryDelay", { reader >> m_StableRecoverDelay; }); - MatchProperty("AimAngle", { reader >> m_AimAngle; }); - MatchProperty("AimRange", { reader >> m_AimRange; }); - MatchProperty("AimDistance", { reader >> m_AimDistance; }); - MatchProperty("SharpAimDelay", { reader >> m_SharpAimDelay; }); - MatchProperty("SightDistance", { reader >> m_SightDistance; }); - MatchProperty("Perceptiveness", { reader >> m_Perceptiveness; }); - MatchProperty("PainThreshold", { reader >> m_PainThreshold; }); - MatchProperty("CanRevealUnseen", { reader >> m_CanRevealUnseen; }); - MatchProperty("CharHeight", { reader >> m_CharHeight; }); - MatchProperty("HolsterOffset", { reader >> m_HolsterOffset; }); - MatchProperty("ReloadOffset", { reader >> m_ReloadOffset; }); - MatchForwards("AddInventoryDevice") MatchProperty("AddInventory", - { - MovableObject *pInvMO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); - if (!pInvMO) { reader.ReportError("Object added to inventory is broken."); } - AddToInventoryBack(pInvMO); - }); - MatchProperty("MaxInventoryMass", { reader >> m_MaxInventoryMass; }); - MatchProperty("AIMode", { - int mode; - reader >> mode; - m_AIMode = static_cast(mode); - }); - MatchProperty("SpecialBehaviour_AddAISceneWaypoint", { - Vector waypointToAdd; - reader >> waypointToAdd; - AddAISceneWaypoint(waypointToAdd); - }); - MatchProperty("PieMenu", { - m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); - if (!m_PieMenu) { reader.ReportError("Failed to set Actor's pie menu. Doublecheck your name and everything is correct."); } - m_PieMenu->Create(this); - }); - MatchProperty("Organic", { reader >> m_Organic; }); - MatchProperty("Mechanical", { reader >> m_Mechanical; }); - MatchProperty("AIBaseDigStrength", { reader >> m_AIBaseDigStrength; }); - - - EndPropertyList; -} + MOSRotating::DestroyScriptState(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the Actor object. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Actor with a Writer for -// later recreation with Create(Reader &reader); - -int Actor::Save(Writer &writer) const -{ - MOSRotating::Save(writer); - - writer.NewPropertyWithValue("PlayerControllable", m_PlayerControllable); - writer.NewProperty("BodyHitSound"); - writer << m_BodyHitSound; - writer.NewProperty("AlarmSound"); - writer << m_AlarmSound; - writer.NewProperty("PainSound"); - writer << m_PainSound; - writer.NewProperty("DeathSound"); - writer << m_DeathSound; - writer.NewProperty("DeviceSwitchSound"); - writer << m_DeviceSwitchSound; - writer.NewProperty("Status"); - writer << m_Status; - writer.NewProperty("Health"); - writer << m_Health; - writer.NewProperty("MaxHealth"); - writer << m_MaxHealth; - if (m_DeploymentID) - { - writer.NewProperty("DeploymentID"); - writer << m_DeploymentID; + void Actor::Destroy(bool notInherited) { + delete m_DeviceSwitchSound; + delete m_BodyHitSound; + delete m_PainSound; + delete m_DeathSound; + delete m_AlarmSound; + + for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + delete (*itr); + } + + if (!notInherited) { + MOSRotating::Destroy(); + } + + Clear(); } - writer.NewProperty("ImpulseDamageThreshold"); - writer << m_TravelImpulseDamage; - writer.NewProperty("StableVelocityThreshold"); - writer << m_StableVel; - writer.NewProperty("StableRecoveryDelay"); - writer << m_StableRecoverDelay; - writer.NewProperty("AimAngle"); - writer << m_AimAngle; - writer.NewProperty("AimRange"); - writer << m_AimRange; - writer.NewProperty("AimDistance"); - writer << m_AimDistance; - writer.NewProperty("SharpAimDelay"); - writer << m_SharpAimDelay; - writer.NewProperty("SightDistance"); - writer << m_SightDistance; - writer.NewProperty("Perceptiveness"); - writer << m_Perceptiveness; - writer.NewProperty("PainThreshold"); - writer << m_PainThreshold; - writer.NewProperty("CanRevealUnseen"); - writer << m_CanRevealUnseen; - writer.NewProperty("CharHeight"); - writer << m_CharHeight; - writer.NewProperty("HolsterOffset"); - writer << m_HolsterOffset; - writer.NewPropertyWithValue("ReloadOffset", m_ReloadOffset); - for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - writer.NewProperty("AddInventory"); - writer << **itr; - } - writer.NewProperty("MaxInventoryMass"); - writer << m_MaxInventoryMass; - writer.NewProperty("AIMode"); - writer << m_AIMode; - writer.NewProperty("PieMenu"); - writer << m_PieMenu.get(); - - writer.NewPropertyWithValue("Organic", m_Organic); - writer.NewPropertyWithValue("Mechanical", m_Mechanical); - writer.NewPropertyWithValue("AIBaseDigStrength", m_AIBaseDigStrength); - - return 0; -} - -void Actor::DestroyScriptState() { - for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { - (*itr)->DestroyScriptState(); - } - - MOSRotating::DestroyScriptState(); -} -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the Actor object. - -void Actor::Destroy(bool notInherited) -{ - delete m_DeviceSwitchSound; - delete m_BodyHitSound; - delete m_PainSound; - delete m_DeathSound; - delete m_AlarmSound; - - for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { - delete (*itr); - } - - if (!notInherited) { - MOSRotating::Destroy(); - } - - Clear(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float Actor::GetInventoryMass() const { - float inventoryMass = 0.0F; - for (const MovableObject *inventoryItem : m_Inventory) { - inventoryMass += inventoryItem->GetMass(); - } - return inventoryMass; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float Actor::GetBaseMass() { - if (m_BaseMass == std::numeric_limits::infinity()) { - if (const Actor* presetActor = static_cast(GetPreset())) { - m_BaseMass = presetActor->GetMass(); - } else { - m_BaseMass = GetMass(); - } - } - - return m_BaseMass; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float Actor::GetInventoryMass() const { + float inventoryMass = 0.0F; + for (const MovableObject* inventoryItem: m_Inventory) { + inventoryMass += inventoryItem->GetMass(); + } + return inventoryMass; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsPlayerControlled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a player is currently controlling this. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool Actor::IsPlayerControlled() const -{ - return m_Controller.GetInputMode() == Controller::CIM_PLAYER && m_Controller.GetPlayer() >= 0; -} + float Actor::GetBaseMass() { + if (m_BaseMass == std::numeric_limits::infinity()) { + if (const Actor* presetActor = static_cast(GetPreset())) { + m_BaseMass = presetActor->GetMass(); + } else { + m_BaseMass = GetMass(); + } + } + return m_BaseMass; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this Actor and all its carried -// gold and inventory. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -float Actor::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const -{ - float totalValue = (GetGoldValue(nativeModule, foreignMult, nativeMult) / 2) + ((GetGoldValue(nativeModule, foreignMult, nativeMult) / 2) * (GetHealth() / GetMaxHealth())); - totalValue += GetGoldCarried(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsPlayerControlled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a player is currently controlling this. - MOSprite *pItem = 0; - for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - pItem = dynamic_cast(*itr); - if (pItem) - totalValue += pItem->GetTotalValue(nativeModule, foreignMult, nativeMult); - } + bool Actor::IsPlayerControlled() const { + return m_Controller.GetInputMode() == Controller::CIM_PLAYER && m_Controller.GetPlayer() >= 0; + } - return totalValue; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this Actor and all its carried + // gold and inventory. + + float Actor::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const { + float totalValue = (GetGoldValue(nativeModule, foreignMult, nativeMult) / 2) + ((GetGoldValue(nativeModule, foreignMult, nativeMult) / 2) * (GetHealth() / GetMaxHealth())); + totalValue += GetGoldCarried(); + + MOSprite* pItem = 0; + for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + pItem = dynamic_cast(*itr); + if (pItem) + totalValue += pItem->GetTotalValue(nativeModule, foreignMult, nativeMult); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this carries a specifically named object in its inventory. -// Also looks through the inventories of potential passengers, as applicable. + return totalValue; + } -bool Actor::HasObject(std::string objectName) const -{ - if (MOSRotating::HasObject(objectName)) - return true; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this carries a specifically named object in its inventory. + // Also looks through the inventories of potential passengers, as applicable. - for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - if ((*itr) && (*itr)->HasObject(objectName)) - return true; - } + bool Actor::HasObject(std::string objectName) const { + if (MOSRotating::HasObject(objectName)) + return true; - return false; -} + for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + if ((*itr) && (*itr)->HasObject(objectName)) + return true; + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObjectInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically grouped object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObjectInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically grouped object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. -bool Actor::HasObjectInGroup(std::string groupName) const -{ - if (MOSRotating::HasObjectInGroup(groupName)) - return true; + bool Actor::HasObjectInGroup(std::string groupName) const { + if (MOSRotating::HasObjectInGroup(groupName)) + return true; - for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - if ((*itr) && (*itr)->HasObjectInGroup(groupName)) - return true; - } + for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + if ((*itr) && (*itr)->HasObjectInGroup(groupName)) + return true; + } - return false; -} + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this Actor belongs to. + + void Actor::SetTeam(int team) { + MovableObject::SetTeam(team); + + // Change the Team Icon to display + m_pTeamIcon = 0; + if (g_ActivityMan.GetActivity()) + m_pTeamIcon = g_ActivityMan.GetActivity()->GetTeamIcon(m_Team); + + // Also set all actors in the inventory + Actor* pActor = 0; + for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) { + pActor = dynamic_cast(*itr); + if (pActor) + pActor->SetTeam(team); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this Actor belongs to. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetControllerMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this Actor's new Controller input mode. -void Actor::SetTeam(int team) -{ - MovableObject::SetTeam(team); + void Actor::SetControllerMode(Controller::InputMode newMode, int newPlayer) { - // Change the Team Icon to display - m_pTeamIcon = 0; - if (g_ActivityMan.GetActivity()) - m_pTeamIcon = g_ActivityMan.GetActivity()->GetTeamIcon(m_Team); + Controller::InputMode previousControllerMode = m_Controller.GetInputMode(); + int previousControllingPlayer = m_Controller.GetPlayer(); - // Also set all actors in the inventory - Actor *pActor = 0; - for (std::deque::const_iterator itr = m_Inventory.begin(); itr != m_Inventory.end(); ++itr) - { - pActor = dynamic_cast(*itr); - if (pActor) - pActor->SetTeam(team); - } -} + m_Controller.SetInputMode(newMode); + m_Controller.SetPlayer(newPlayer); + RunScriptedFunctionInAppropriateScripts("OnControllerInputModeChange", false, false, {}, {std::to_string(previousControllerMode), std::to_string(previousControllingPlayer)}); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetControllerMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this Actor's new Controller input mode. + m_NewControlTmr.Reset(); + } -void Actor::SetControllerMode(Controller::InputMode newMode, int newPlayer) -{ + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SwapControllerModes + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this Actor's Controller mode and gives back what it used to be. - Controller::InputMode previousControllerMode = m_Controller.GetInputMode(); - int previousControllingPlayer = m_Controller.GetPlayer(); + Controller::InputMode Actor::SwapControllerModes(Controller::InputMode newMode, int newPlayer) { + Controller::InputMode returnMode = m_Controller.GetInputMode(); + SetControllerMode(newMode, newPlayer); + return returnMode; + } - m_Controller.SetInputMode(newMode); - m_Controller.SetPlayer(newPlayer); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Look + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an unseen-revealing ray in the direction of where this is facing. + + bool Actor::Look(float FOVSpread, float range) { + if (!g_SceneMan.AnythingUnseen(m_Team) || m_CanRevealUnseen == false) + return false; + + // Use the 'eyes' on the 'head', if applicable + Vector aimPos = GetEyePos(); + /* + Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); + aimMatrix.SetXFlipped(m_HFlipped); + // Get the langth of the look vector + Vector aimDistance = m_ViewPoint - aimPos; + // Add half the screen width + Vector lookVector(fabs(aimDistance.m_X) + range, 0); + // Set the rotation to the acutal aiming angle + lookVector *= aimMatrix; + // Add the spread + lookVector.DegRotate(FOVSpread * NormalRand()); + // TEST: Really need so far? + lookVector /= 2; + */ + Vector lookVector = m_Vel; + // If there is no vel, just look in all directions + if (lookVector.GetLargest() < 0.01) { + lookVector.SetXY(range, 0); + lookVector.DegRotate(RandomNum(-180.0F, 180.0F)); + } else { + // Set the distance in the look direction + lookVector.SetMagnitude(range); + // Add the spread from the directed look + lookVector.DegRotate(FOVSpread * RandomNormalNum()); + } - RunScriptedFunctionInAppropriateScripts("OnControllerInputModeChange", false, false, {}, {std::to_string(previousControllerMode), std::to_string(previousControllingPlayer) }); + Vector ignored; + return g_SceneMan.CastSeeRay(m_Team, aimPos, lookVector, ignored, 25, g_SceneMan.GetUnseenResolution(m_Team).GetSmallest() / 2); + } - m_NewControlTmr.Reset(); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void Actor::AddGold(float goldOz) { + bool isHumanTeam = g_ActivityMan.GetActivity()->IsHumanTeam(m_Team); + if (g_SettingsMan.GetAutomaticGoldDeposit() || !isHumanTeam) { + // TODO: Allow AI to reliably deliver gold via craft + g_ActivityMan.GetActivity()->ChangeTeamFunds(goldOz, m_Team); + } else { + m_GoldCarried += goldOz; + m_GoldPicked = true; + if (isHumanTeam) { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { + if (g_ActivityMan.GetActivity()->GetTeamOfPlayer(player) == m_Team) { + g_GUISound.FundsChangedSound()->Play(player); + } + } + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Actor::RestDetection() { + MOSRotating::RestDetection(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SwapControllerModes -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this Actor's Controller mode and gives back what it used to be. + if (m_Status != DEAD) { + m_AngOscillations = 0; + m_VelOscillations = 0; + m_RestTimer.Reset(); + m_ToSettle = false; + } + } -Controller::InputMode Actor::SwapControllerModes(Controller::InputMode newMode, int newPlayer) -{ - Controller::InputMode returnMode = m_Controller.GetInputMode(); - SetControllerMode(newMode, newPlayer); - return returnMode; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: AddAIMOWaypoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an MO in the scene as the next waypoint for this to go to, in order + void Actor::AddAIMOWaypoint(const MovableObject* pMOWaypoint) { + if (g_MovableMan.ValidMO(pMOWaypoint)) + m_Waypoints.push_back(std::pair(pMOWaypoint->GetPos(), pMOWaypoint)); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Look -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an unseen-revealing ray in the direction of where this is facing. - -bool Actor::Look(float FOVSpread, float range) -{ - if (!g_SceneMan.AnythingUnseen(m_Team) || m_CanRevealUnseen == false) - return false; - - // Use the 'eyes' on the 'head', if applicable - Vector aimPos = GetEyePos(); -/* - Matrix aimMatrix(m_HFlipped ? -m_AimAngle : m_AimAngle); - aimMatrix.SetXFlipped(m_HFlipped); - // Get the langth of the look vector - Vector aimDistance = m_ViewPoint - aimPos; - // Add half the screen width - Vector lookVector(fabs(aimDistance.m_X) + range, 0); - // Set the rotation to the acutal aiming angle - lookVector *= aimMatrix; - // Add the spread - lookVector.DegRotate(FOVSpread * NormalRand()); -// TEST: Really need so far? - lookVector /= 2; -*/ - Vector lookVector = m_Vel; - // If there is no vel, just look in all directions - if (lookVector.GetLargest() < 0.01) - { - lookVector.SetXY(range, 0); - lookVector.DegRotate(RandomNum(-180.0F, 180.0F)); - } - else - { - // Set the distance in the look direction - lookVector.SetMagnitude(range); - // Add the spread from the directed look - lookVector.DegRotate(FOVSpread * RandomNormalNum()); - } - - Vector ignored; - return g_SceneMan.CastSeeRay(m_Team, aimPos, lookVector, ignored, 25, g_SceneMan.GetUnseenResolution(m_Team).GetSmallest() / 2); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void Actor::AddGold(float goldOz) { - bool isHumanTeam = g_ActivityMan.GetActivity()->IsHumanTeam(m_Team); - if (g_SettingsMan.GetAutomaticGoldDeposit() || !isHumanTeam) { - // TODO: Allow AI to reliably deliver gold via craft - g_ActivityMan.GetActivity()->ChangeTeamFunds(goldOz, m_Team); - } else { - m_GoldCarried += goldOz; - m_GoldPicked = true; - if (isHumanTeam) { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { - if (g_ActivityMan.GetActivity()->GetTeamOfPlayer(player) == m_Team) { g_GUISound.FundsChangedSound()->Play(player); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SwapNextInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Swaps the next MovableObject carried by this Actor and puts one not + // currently carried into the into the back of the inventory of this. + + MovableObject* Actor::SwapNextInventory(MovableObject* pSwapIn, bool muteSound) { + MovableObject* pRetDev = 0; + bool playSound = false; + if (!m_Inventory.empty()) { + pRetDev = m_Inventory.front(); + // Reset all the timers of the object being taken out of inventory so it doesn't emit a bunch of particles that have been backed up while dormant in inventory + pRetDev->ResetAllTimers(); + m_Inventory.pop_front(); + playSound = true; + } + if (pSwapIn) { + pSwapIn->SetAsNoID(); + AddToInventoryBack(pSwapIn); + playSound = true; + } + + if (m_DeviceSwitchSound && playSound && !muteSound) + m_DeviceSwitchSound->Play(m_Pos); + + return pRetDev; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void Actor::RemoveInventoryItem(const std::string& moduleName, const std::string& presetName) { + for (std::deque::iterator inventoryIterator = m_Inventory.begin(); inventoryIterator != m_Inventory.end(); ++inventoryIterator) { + if ((moduleName.empty() || (*inventoryIterator)->GetModuleName() == moduleName) && (*inventoryIterator)->GetPresetName() == presetName) { + (*inventoryIterator)->DestroyScriptState(); + delete (*inventoryIterator); + m_Inventory.erase(inventoryIterator); + break; } } } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + MovableObject* Actor::RemoveInventoryItemAtIndex(int inventoryIndex) { + if (inventoryIndex >= 0 && inventoryIndex < m_Inventory.size()) { + MovableObject* itemAtIndex = m_Inventory[inventoryIndex]; + m_Inventory.erase(m_Inventory.begin() + inventoryIndex); + return itemAtIndex; + } + return nullptr; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SwapPrevInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Swaps the prev MovableObject carried by this Actor and puts one not + // currently carried into the into the back of the inventory of this. + + MovableObject* Actor::SwapPrevInventory(MovableObject* pSwapIn) { + MovableObject* pRetDev = 0; + bool playSound = false; + if (!m_Inventory.empty()) { + pRetDev = m_Inventory.back(); + m_Inventory.pop_back(); + playSound = true; + } + if (pSwapIn) { + pSwapIn->SetAsNoID(); + AddToInventoryFront(pSwapIn); + playSound = true; + } -void Actor::RestDetection() { - MOSRotating::RestDetection(); + if (m_DeviceSwitchSound && playSound) + m_DeviceSwitchSound->Play(m_Pos); - if (m_Status != DEAD) { - m_AngOscillations = 0; - m_VelOscillations = 0; - m_RestTimer.Reset(); - m_ToSettle = false; + return pRetDev; } -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: AddAIMOWaypoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an MO in the scene as the next waypoint for this to go to, in order + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void Actor::AddAIMOWaypoint(const MovableObject *pMOWaypoint) -{ - if (g_MovableMan.ValidMO(pMOWaypoint)) - m_Waypoints.push_back(std::pair(pMOWaypoint->GetPos(), pMOWaypoint)); -} + bool Actor::SwapInventoryItemsByIndex(int inventoryIndex1, int inventoryIndex2) { + if (inventoryIndex1 < 0 || inventoryIndex2 < 0 || inventoryIndex1 >= m_Inventory.size() || inventoryIndex2 >= m_Inventory.size()) { + return false; + } + std::swap(m_Inventory.at(inventoryIndex1), m_Inventory.at(inventoryIndex2)); + return true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SwapNextInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Swaps the next MovableObject carried by this Actor and puts one not -// currently carried into the into the back of the inventory of this. - -MovableObject * Actor::SwapNextInventory(MovableObject *pSwapIn, bool muteSound) -{ - MovableObject *pRetDev = 0; - bool playSound = false; - if (!m_Inventory.empty()) { - pRetDev = m_Inventory.front(); - // Reset all the timers of the object being taken out of inventory so it doesn't emit a bunch of particles that have been backed up while dormant in inventory - pRetDev->ResetAllTimers(); - m_Inventory.pop_front(); - playSound = true; - } - if (pSwapIn) - { - pSwapIn->SetAsNoID(); - AddToInventoryBack(pSwapIn); - playSound = true; - } - - if (m_DeviceSwitchSound && playSound && !muteSound) - m_DeviceSwitchSound->Play(m_Pos); - - return pRetDev; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void Actor::RemoveInventoryItem(const std::string &moduleName, const std::string &presetName) { - for (std::deque::iterator inventoryIterator = m_Inventory.begin(); inventoryIterator != m_Inventory.end(); ++inventoryIterator) { - if ((moduleName.empty() || (*inventoryIterator)->GetModuleName() == moduleName) && (*inventoryIterator)->GetPresetName() == presetName) { - (*inventoryIterator)->DestroyScriptState(); - delete (*inventoryIterator); - m_Inventory.erase(inventoryIterator); - break; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + MovableObject* Actor::SetInventoryItemAtIndex(MovableObject* newInventoryItem, int inventoryIndex) { + if (!newInventoryItem) { + return RemoveInventoryItemAtIndex(inventoryIndex); + } + newInventoryItem->SetAsNoID(); + + if (inventoryIndex < 0 || inventoryIndex >= m_Inventory.size()) { + AddToInventoryBack(newInventoryItem); + return nullptr; + } + MovableObject* currentInventoryItemAtIndex = m_Inventory.at(inventoryIndex); + m_Inventory.at(inventoryIndex) = newInventoryItem; + return currentInventoryItemAtIndex; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DropAllInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Ejects all inventory items that this is carrying. It may not happen + // instantaneously, so check for ejection being complete with InventoryEmpty(). + + void Actor::DropAllInventory() { + MovableObject* pObject = 0; + Actor* pPassenger = 0; + float velMin, velMax, angularVel; + Vector gibROffset, gibVel; + for (std::deque::iterator gItr = m_Inventory.begin(); gItr != m_Inventory.end(); ++gItr) { + // Get handy handle to the object we're putting + pObject = *gItr; + if (pObject) { + // Generate the velocities procedurally + velMin = 3.0F; + velMax = velMin + std::sqrt(m_SpriteRadius); + + // Randomize the offset from center to be within the original object + gibROffset.SetXY(m_SpriteRadius * 0.35F * RandomNum(), 0); + gibROffset.RadRotate(c_PI * RandomNormalNum()); + // Set up its position and velocity according to the parameters of this AEmitter. + pObject->SetPos(m_Pos + gibROffset); + pObject->SetRotAngle(m_Rotation.GetRadAngle() + pObject->GetRotMatrix().GetRadAngle()); + // Rotational angle + pObject->SetAngularVel((pObject->GetAngularVel() * 0.35F) + (pObject->GetAngularVel() * 0.65F / (pObject->GetMass() != 0 ? pObject->GetMass() : 0.0001F)) * RandomNum()); + // Make it rotate away in the appropriate direction depending on which side of the object it is on + // If the object is far to the relft or right of the center, make it always rotate outwards to some degree + if (gibROffset.m_X > m_aSprite[0]->w / 3) { + float offCenterRatio = gibROffset.m_X / (m_aSprite[0]->w / 2); + angularVel = std::abs(pObject->GetAngularVel() * 0.5F); + angularVel += std::abs(pObject->GetAngularVel() * 0.5F * offCenterRatio); + pObject->SetAngularVel(angularVel * (gibROffset.m_X > 0.0F ? -1 : 1)); + } + // Gib is too close to center to always make it rotate in one direction, so give it a baseline rotation and then randomize + else { + pObject->SetAngularVel((pObject->GetAngularVel() * RandomNum(0.5F, 1.5F)) * (RandomNum() < 0.5F ? 1.0F : -1.0F)); + } + + // TODO: Optimize making the random angles!") + gibVel = gibROffset; + if (gibVel.IsZero()) { + gibVel.SetXY(RandomNum(velMin, velMax), 0.0F); + gibVel.RadRotate(c_PI * RandomNormalNum()); + } else { + gibVel.SetMagnitude(RandomNum(velMin, velMax)); + } + // Distribute any impact implse out over all the gibs + // gibVel += (impactImpulse / m_Gibs.size()) / pObject->GetMass(); + pObject->SetVel(m_Vel + gibVel); + // Reset all the timers of the object being shot out so it doesn't emit a bunch of particles that have been backed up while dormant in inventory + pObject->ResetAllTimers(); + + // Detect whether we're dealing with a passenger and add it as Actor instead + if (pPassenger = dynamic_cast(pObject)) { + pPassenger->SetRotAngle(c_HalfPI * RandomNormalNum()); + pPassenger->SetAngularVel(pPassenger->GetAngularVel() * 5.0F); + pPassenger->SetHFlipped(RandomNum() > 0.5F); + pPassenger->SetStatus(UNSTABLE); + g_MovableMan.AddActor(pPassenger); + } + // Add the gib to the scene, passing ownership from the inventory + else + g_MovableMan.AddParticle(pObject); + + pPassenger = 0; + pObject = 0; + } } + + // We have exhausted all teh inventory into the scene, passing ownership + m_Inventory.clear(); } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// -MovableObject * Actor::RemoveInventoryItemAtIndex(int inventoryIndex) { - if (inventoryIndex >= 0 && inventoryIndex < m_Inventory.size()) { - MovableObject *itemAtIndex = m_Inventory[inventoryIndex]; - m_Inventory.erase(m_Inventory.begin() + inventoryIndex); - return itemAtIndex; - } - return nullptr; -} + void Actor::DropAllGold() { + const Material* goldMaterial = g_SceneMan.GetMaterialFromID(g_MaterialGold); + float velMin = 3.0F; + float velMax = velMin + std::sqrt(m_SpriteRadius); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + for (int i = 0; i < static_cast(std::floor(m_GoldCarried)); i++) { + Vector dropOffset(m_SpriteRadius * 0.3F * RandomNum(), 0); + dropOffset.RadRotate(c_PI * RandomNormalNum()); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SwapPrevInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Swaps the prev MovableObject carried by this Actor and puts one not -// currently carried into the into the back of the inventory of this. - -MovableObject * Actor::SwapPrevInventory(MovableObject *pSwapIn) -{ - MovableObject *pRetDev = 0; - bool playSound = false; - if (!m_Inventory.empty()) { - pRetDev = m_Inventory.back(); - m_Inventory.pop_back(); - playSound = true; - } - if (pSwapIn) - { - pSwapIn->SetAsNoID(); - AddToInventoryFront(pSwapIn); - playSound = true; - } - - if (m_DeviceSwitchSound && playSound) - m_DeviceSwitchSound->Play(m_Pos); - - return pRetDev; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool Actor::SwapInventoryItemsByIndex(int inventoryIndex1, int inventoryIndex2) { - if (inventoryIndex1 < 0 || inventoryIndex2 < 0 || inventoryIndex1 >= m_Inventory.size() || inventoryIndex2 >= m_Inventory.size()) { - return false; - } - - std::swap(m_Inventory.at(inventoryIndex1), m_Inventory.at(inventoryIndex2)); - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -MovableObject * Actor::SetInventoryItemAtIndex(MovableObject *newInventoryItem, int inventoryIndex) { - if (!newInventoryItem) { - return RemoveInventoryItemAtIndex(inventoryIndex); - } - newInventoryItem->SetAsNoID(); - - if (inventoryIndex < 0 || inventoryIndex >= m_Inventory.size()) { - AddToInventoryBack(newInventoryItem); - return nullptr; - } - MovableObject *currentInventoryItemAtIndex = m_Inventory.at(inventoryIndex); - m_Inventory.at(inventoryIndex) = newInventoryItem; - return currentInventoryItemAtIndex; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Vector dropVelocity(dropOffset); + dropVelocity.SetMagnitude(RandomNum(velMin, velMax)); + Atom* goldMOPixelAtom = new Atom(Vector(), g_MaterialGold, nullptr, goldMaterial->GetColor(), 2); + + MOPixel* goldMOPixel = new MOPixel(goldMaterial->GetColor(), goldMaterial->GetPixelDensity(), m_Pos + dropOffset, dropVelocity, goldMOPixelAtom); + goldMOPixel->SetToHitMOs(false); + g_MovableMan.AddParticle(goldMOPixel); + } + m_GoldCarried = 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + bool Actor::AddToInventoryFront(MovableObject* itemToAdd) { + // This function is called often to add stuff we just removed from our hands, which may be set to delete so we need to guard against that lest we crash. + if (!itemToAdd || itemToAdd->IsSetToDelete()) { + return false; + } + + m_Inventory.push_front(itemToAdd); + return true; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + bool Actor::AddToInventoryBack(MovableObject* itemToAdd) { + // This function is called often to add stuff we just removed from our hands, which may be set to delete so we need to guard against that lest we crash. + if (!itemToAdd || itemToAdd->IsSetToDelete()) { + return false; + } + + m_Inventory.push_back(itemToAdd); + return true; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GibThis + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gibs this, effectively destroying it and creating multiple gibs or + // pieces in its place. + + void Actor::GibThis(const Vector& impactImpulse, MovableObject* movableObjectToIgnore) { + // Play death sound + // TODO: Don't attenuate since death is pretty important.. maybe only make this happen for teh brains + if (m_DeathSound) { + m_DeathSound->Play(m_Pos); + } + + // Gib all the regular gibs + MOSRotating::GibThis(impactImpulse, movableObjectToIgnore); + + // Throw out all the inventory with the appropriate force and directions + MovableObject* pObject = 0; + Actor* pPassenger = 0; + float velMin, velRange, angularVel; + Vector gibROffset, gibVel; + for (std::deque::iterator gItr = m_Inventory.begin(); gItr != m_Inventory.end(); ++gItr) { + // Get handy handle to the object we're putting + pObject = *gItr; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DropAllInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Ejects all inventory items that this is carrying. It may not happen -// instantaneously, so check for ejection being complete with InventoryEmpty(). - -void Actor::DropAllInventory() -{ - MovableObject *pObject = 0; - Actor *pPassenger = 0; - float velMin, velMax, angularVel; - Vector gibROffset, gibVel; - for (std::deque::iterator gItr = m_Inventory.begin(); gItr != m_Inventory.end(); ++gItr) - { - // Get handy handle to the object we're putting - pObject = *gItr; - if (pObject) - { // Generate the velocities procedurally - velMin = 3.0F; - velMax = velMin + std::sqrt(m_SpriteRadius); + velMin = m_GibBlastStrength / (pObject->GetMass() != 0 ? pObject->GetMass() : 0.0001F); + velRange = 10.0F; // Randomize the offset from center to be within the original object - gibROffset.SetXY(m_SpriteRadius * 0.35F * RandomNum(), 0); - gibROffset.RadRotate(c_PI * RandomNormalNum()); + gibROffset.SetXY(m_SpriteRadius * 0.35F * RandomNormalNum(), m_SpriteRadius * 0.35F * RandomNormalNum()); // Set up its position and velocity according to the parameters of this AEmitter. - pObject->SetPos(m_Pos + gibROffset); + pObject->SetPos(m_Pos + gibROffset /*Vector(m_Pos.m_X + 5 * NormalRand(), m_Pos.m_Y + 5 * NormalRand())*/); pObject->SetRotAngle(m_Rotation.GetRadAngle() + pObject->GetRotMatrix().GetRadAngle()); // Rotational angle pObject->SetAngularVel((pObject->GetAngularVel() * 0.35F) + (pObject->GetAngularVel() * 0.65F / (pObject->GetMass() != 0 ? pObject->GetMass() : 0.0001F)) * RandomNum()); // Make it rotate away in the appropriate direction depending on which side of the object it is on // If the object is far to the relft or right of the center, make it always rotate outwards to some degree - if (gibROffset.m_X > m_aSprite[0]->w / 3) - { + if (gibROffset.m_X > m_aSprite[0]->w / 3) { float offCenterRatio = gibROffset.m_X / (m_aSprite[0]->w / 2); - angularVel = std::abs(pObject->GetAngularVel() * 0.5F); - angularVel += std::abs(pObject->GetAngularVel() * 0.5F * offCenterRatio); - pObject->SetAngularVel(angularVel * (gibROffset.m_X > 0.0F ? -1 : 1)); + angularVel = fabs(pObject->GetAngularVel() * 0.5F); + angularVel += fabs(pObject->GetAngularVel() * 0.5F * offCenterRatio); + pObject->SetAngularVel(angularVel * (gibROffset.m_X > 0 ? -1 : 1)); } // Gib is too close to center to always make it rotate in one direction, so give it a baseline rotation and then randomize - else - { - pObject->SetAngularVel((pObject->GetAngularVel() * RandomNum(0.5F, 1.5F)) * (RandomNum() < 0.5F ? 1.0F : -1.0F)); + else { + pObject->SetAngularVel((pObject->GetAngularVel() * 0.5F + pObject->GetAngularVel() * RandomNum()) * (RandomNormalNum() > 0.0F ? 1.0F : -1.0F)); } // TODO: Optimize making the random angles!") gibVel = gibROffset; - if (gibVel.IsZero()) { - gibVel.SetXY(RandomNum(velMin, velMax), 0.0F); - gibVel.RadRotate(c_PI * RandomNormalNum()); - } else { - gibVel.SetMagnitude(RandomNum(velMin, velMax)); - } + if (gibVel.IsZero()) + gibVel.SetXY(velMin + RandomNum(0.0F, velRange), 0.0F); + else + gibVel.SetMagnitude(velMin + RandomNum(0.0F, velRange)); + gibVel.RadRotate(impactImpulse.GetAbsRadAngle()); + // Don't! the offset was already rotated! + // gibVel = RotateOffset(gibVel); // Distribute any impact implse out over all the gibs // gibVel += (impactImpulse / m_Gibs.size()) / pObject->GetMass(); pObject->SetVel(m_Vel + gibVel); // Reset all the timers of the object being shot out so it doesn't emit a bunch of particles that have been backed up while dormant in inventory pObject->ResetAllTimers(); + // Set the gib to not hit a specific MO + if (movableObjectToIgnore) + pObject->SetWhichMOToNotHit(movableObjectToIgnore); + // Detect whether we're dealing with a passenger and add it as Actor instead - if (pPassenger = dynamic_cast(pObject)) - { + if (pPassenger = dynamic_cast(pObject)) { pPassenger->SetRotAngle(c_HalfPI * RandomNormalNum()); pPassenger->SetAngularVel(pPassenger->GetAngularVel() * 5.0F); pPassenger->SetHFlipped(RandomNum() > 0.5F); @@ -953,925 +1051,753 @@ void Actor::DropAllInventory() pPassenger = 0; pObject = 0; } - } - // We have exhausted all teh inventory into the scene, passing ownership - m_Inventory.clear(); -} - -////////////////////////////////////////////////////////////////////////////////////////// + // We have exhausted all teh inventory into the scene, passing ownership + m_Inventory.clear(); + + // If this is the actual brain of any player, flash that player's screen when he's now dead + if (g_SettingsMan.FlashOnBrainDamage() && g_ActivityMan.IsInActivity()) { + int brainOfPlayer = g_ActivityMan.GetActivity()->IsBrainOfWhichPlayer(this); + // Only flash if player is human (AI players don't have screens!) + if (brainOfPlayer != Players::NoPlayer && g_ActivityMan.GetActivity()->PlayerHuman(brainOfPlayer)) { + // Croaked.. flash for a longer period + if (m_ToDelete || m_Status == DEAD) + g_FrameMan.FlashScreen(g_ActivityMan.GetActivity()->ScreenOfPlayer(brainOfPlayer), g_WhiteColor, 500); + } + } + } -void Actor::DropAllGold() { - const Material *goldMaterial = g_SceneMan.GetMaterialFromID(g_MaterialGold); - float velMin = 3.0F; - float velMax = velMin + std::sqrt(m_SpriteRadius); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + + bool Actor::CollideAtPoint(HitData& hd) { + return MOSRotating::CollideAtPoint(hd); + + // if (hd.ResImpulse[HITEE].MagnitudeIsGreaterThan(GetMaterial().strength)) { + // m_pParent-> + // } + /* Obsolete + // Set item as being reached if it collides with us + if (hd.Body[HITOR]->IsHeldDevice()) + m_pItemInReach = dynamic_cast(hd.Body[HITOR]); + */ + // if (Status != ACTIVE) + } - for (int i = 0; i < static_cast(std::floor(m_GoldCarried)); i++) { - Vector dropOffset(m_SpriteRadius * 0.3F * RandomNum(), 0); - dropOffset.RadRotate(c_PI * RandomNormalNum()); - - Vector dropVelocity(dropOffset); - dropVelocity.SetMagnitude(RandomNum(velMin, velMax)); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ParticlePenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Determines whether a particle which has hit this MO will penetrate, + // and if so, whether it gets lodged or exits on the other side of this + // MO. Appropriate effects will be determined and applied ONLY IF there + // was penetration! If not, nothing will be affected. + + bool Actor::ParticlePenetration(HitData& hd) { + bool penetrated = MOSRotating::ParticlePenetration(hd); + + MovableObject* hitor = hd.Body[HITOR]; + float damageToAdd = hitor->DamageOnCollision(); + damageToAdd += penetrated ? hitor->DamageOnPenetration() : 0; + if (hitor->GetApplyWoundDamageOnCollision()) { + damageToAdd += m_pEntryWound->GetEmitDamage() * hitor->WoundDamageMultiplier(); + } + if (hitor->GetApplyWoundBurstDamageOnCollision()) { + damageToAdd += m_pEntryWound->GetBurstDamage() * hitor->WoundDamageMultiplier(); + } - Atom *goldMOPixelAtom = new Atom(Vector(), g_MaterialGold, nullptr, goldMaterial->GetColor(), 2); + if (damageToAdd != 0) { + m_Health = std::min(m_Health - (damageToAdd * m_DamageMultiplier), m_MaxHealth); + } + if ((penetrated || damageToAdd != 0) && m_Perceptiveness > 0 && m_Health > 0) { + Vector extruded(hd.HitVel[HITOR]); + extruded.SetMagnitude(m_CharHeight); + extruded = m_Pos - extruded; + g_SceneMan.WrapPosition(extruded); + AlarmPoint(extruded); + } - MOPixel *goldMOPixel = new MOPixel(goldMaterial->GetColor(), goldMaterial->GetPixelDensity(), m_Pos + dropOffset, dropVelocity, goldMOPixelAtom); - goldMOPixel->SetToHitMOs(false); - g_MovableMan.AddParticle(goldMOPixel); + return penetrated; } - m_GoldCarried = 0; -} -////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAIModeIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the icon bitmap associated with this' current AI mode and team. -bool Actor::AddToInventoryFront(MovableObject *itemToAdd) { - // This function is called often to add stuff we just removed from our hands, which may be set to delete so we need to guard against that lest we crash. - if (!itemToAdd || itemToAdd->IsSetToDelete()) { - return false; + BITMAP* Actor::GetAIModeIcon() { + return m_apAIIcons[m_AIMode]; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLastMOWaypointID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ID of the last set AI MO waypoint of this. If none, g_NoMOID is returned. + // Arguments: None. + // Return value: The furthest set AI MO waypoint of this. + + MOID Actor::GetAIMOWaypointID() const { + if (g_MovableMan.ValidMO(m_pMOMoveTarget)) + return m_pMOMoveTarget->GetID(); + else + return g_NoMOID; } - m_Inventory.push_front(itemToAdd); - return true; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateMovePath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the path to move along to the currently set movetarget. -////////////////////////////////////////////////////////////////////////////////////////// + void Actor::UpdateMovePath() { + if (g_SceneMan.GetScene() == nullptr) { + return; + } -bool Actor::AddToInventoryBack(MovableObject *itemToAdd) { - // This function is called often to add stuff we just removed from our hands, which may be set to delete so we need to guard against that lest we crash. - if (!itemToAdd || itemToAdd->IsSetToDelete()) { - return false; + // Estimate how much material this actor can dig through + float digStrength = EstimateDigStrength(); + + // If we're following someone/thing, then never advance waypoints until that thing disappears + if (g_MovableMan.ValidMO(m_pMOMoveTarget)) { + m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight * 0.2, 10), m_pMOMoveTarget->GetPos(), digStrength, static_cast(m_Team)); + } else { + // Do we currently have a path to a static target we would like to still pursue? + if (m_MovePath.empty()) { + // Ok no path going, so get a new path to the next waypoint, if there is a next waypoint + if (!m_Waypoints.empty()) { + // Make sure the path starts from the ground and not somewhere up in the air if/when dropped out of ship + m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight * 0.2, 10), m_Waypoints.front().first, digStrength, static_cast(m_Team)); + + // If the waypoint was tied to an MO to pursue, then load it into the current MO target + if (g_MovableMan.ValidMO(m_Waypoints.front().second)) { + m_pMOMoveTarget = m_Waypoints.front().second; + } else { + m_pMOMoveTarget = 0; + } + + // We loaded the waypoint, no need to keep it + m_Waypoints.pop_front(); + } + // Just try to get to the last Move Target + else { + m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight * 0.2, 10), m_MoveTarget, digStrength, static_cast(m_Team)); + } + } + // We had a path before trying to update, so use its last point as the final destination + else { + m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight * 0.2, 10), Vector(m_MovePath.back()), digStrength, static_cast(m_Team)); + } + } + + m_UpdateMovePath = false; } - m_Inventory.push_back(itemToAdd); - return true; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GibThis -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gibs this, effectively destroying it and creating multiple gibs or -// pieces in its place. - -void Actor::GibThis(const Vector &impactImpulse, MovableObject *movableObjectToIgnore) -{ - // Play death sound -// TODO: Don't attenuate since death is pretty important.. maybe only make this happen for teh brains - if (m_DeathSound) { m_DeathSound->Play(m_Pos); } - - // Gib all the regular gibs - MOSRotating::GibThis(impactImpulse, movableObjectToIgnore); - - // Throw out all the inventory with the appropriate force and directions - MovableObject *pObject = 0; - Actor *pPassenger = 0; - float velMin, velRange, angularVel; - Vector gibROffset, gibVel; - for (std::deque::iterator gItr = m_Inventory.begin(); gItr != m_Inventory.end(); ++gItr) - { - // Get handy handle to the object we're putting - pObject = *gItr; - - // Generate the velocities procedurally - velMin = m_GibBlastStrength / (pObject->GetMass() != 0 ? pObject->GetMass() : 0.0001F); - velRange = 10.0F; - - // Randomize the offset from center to be within the original object - gibROffset.SetXY(m_SpriteRadius * 0.35F * RandomNormalNum(), m_SpriteRadius * 0.35F * RandomNormalNum()); - // Set up its position and velocity according to the parameters of this AEmitter. - pObject->SetPos(m_Pos + gibROffset/*Vector(m_Pos.m_X + 5 * NormalRand(), m_Pos.m_Y + 5 * NormalRand())*/); - pObject->SetRotAngle(m_Rotation.GetRadAngle() + pObject->GetRotMatrix().GetRadAngle()); - // Rotational angle - pObject->SetAngularVel((pObject->GetAngularVel() * 0.35F) + (pObject->GetAngularVel() * 0.65F / (pObject->GetMass() != 0 ? pObject->GetMass() : 0.0001F)) * RandomNum()); - // Make it rotate away in the appropriate direction depending on which side of the object it is on - // If the object is far to the relft or right of the center, make it always rotate outwards to some degree - if (gibROffset.m_X > m_aSprite[0]->w / 3) - { - float offCenterRatio = gibROffset.m_X / (m_aSprite[0]->w / 2); - angularVel = fabs(pObject->GetAngularVel() * 0.5F); - angularVel += fabs(pObject->GetAngularVel() * 0.5F * offCenterRatio); - pObject->SetAngularVel(angularVel * (gibROffset.m_X > 0 ? -1 : 1)); - } - // Gib is too close to center to always make it rotate in one direction, so give it a baseline rotation and then randomize - else - { - pObject->SetAngularVel((pObject->GetAngularVel() * 0.5F + pObject->GetAngularVel() * RandomNum()) * (RandomNormalNum() > 0.0F ? 1.0F : -1.0F)); - } - -// TODO: Optimize making the random angles!") - gibVel = gibROffset; - if (gibVel.IsZero()) - gibVel.SetXY(velMin + RandomNum(0.0F, velRange), 0.0F); - else - gibVel.SetMagnitude(velMin + RandomNum(0.0F, velRange)); - gibVel.RadRotate(impactImpulse.GetAbsRadAngle()); -// Don't! the offset was already rotated! -// gibVel = RotateOffset(gibVel); - // Distribute any impact implse out over all the gibs -// gibVel += (impactImpulse / m_Gibs.size()) / pObject->GetMass(); - pObject->SetVel(m_Vel + gibVel); - // Reset all the timers of the object being shot out so it doesn't emit a bunch of particles that have been backed up while dormant in inventory - pObject->ResetAllTimers(); - - // Set the gib to not hit a specific MO - if (movableObjectToIgnore) - pObject->SetWhichMOToNotHit(movableObjectToIgnore); - - // Detect whether we're dealing with a passenger and add it as Actor instead - if (pPassenger = dynamic_cast(pObject)) - { - pPassenger->SetRotAngle(c_HalfPI * RandomNormalNum()); - pPassenger->SetAngularVel(pPassenger->GetAngularVel() * 5.0F); - pPassenger->SetHFlipped(RandomNum() > 0.5F); - pPassenger->SetStatus(UNSTABLE); - g_MovableMan.AddActor(pPassenger); - } - // Add the gib to the scene, passing ownership from the inventory - else - g_MovableMan.AddParticle(pObject); - - pPassenger = 0; - pObject = 0; - } - - // We have exhausted all teh inventory into the scene, passing ownership - m_Inventory.clear(); - - // If this is the actual brain of any player, flash that player's screen when he's now dead - if (g_SettingsMan.FlashOnBrainDamage() && g_ActivityMan.IsInActivity()) - { - int brainOfPlayer = g_ActivityMan.GetActivity()->IsBrainOfWhichPlayer(this); - // Only flash if player is human (AI players don't have screens!) - if (brainOfPlayer != Players::NoPlayer && g_ActivityMan.GetActivity()->PlayerHuman(brainOfPlayer)) - { - // Croaked.. flash for a longer period - if (m_ToDelete || m_Status == DEAD) - g_FrameMan.FlashScreen(g_ActivityMan.GetActivity()->ScreenOfPlayer(brainOfPlayer), g_WhiteColor, 500); + float Actor::EstimateDigStrength() const { + return m_AIBaseDigStrength; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: VerifyMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Verifieis whether all actor's MO has correct IDs. Should be used in Debug mode only. + + void Actor::VerifyMOIDs() { + std::vector MOIDs; + GetMOIDs(MOIDs); + + for (std::vector::iterator it = MOIDs.begin(); it != MOIDs.end(); it++) { + RTEAssert(*it == g_NoMOID || *it < g_MovableMan.GetMOIDCount(), "Invalid MOID in actor"); } } -} + ////////////////////////////////////////////////////////////////////////////////////////// + + void Actor::OnNewMovePath() { + if (!m_MovePath.empty()) { + // Remove the first one; it's our position + m_PrevPathTarget = m_MovePath.front(); + m_MovePath.pop_front(); + // Also remove the one after that; it may move in opposite direction since it heads to the nearest PathNode center + // Unless it is the last one, in which case it shouldn't be removed + if (m_MovePath.size() > 1) { + m_PrevPathTarget = m_MovePath.front(); + m_MovePath.pop_front(); + } + } else if (m_pMOMoveTarget) { + m_MoveTarget = m_pMOMoveTarget->GetPos(); + } else { + // Nowhere to gooooo + m_MoveTarget = m_PrevPathTarget = m_Pos; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. - -bool Actor::CollideAtPoint(HitData &hd) -{ - return MOSRotating::CollideAtPoint(hd); - -// if (hd.ResImpulse[HITEE].MagnitudeIsGreaterThan(GetMaterial().strength)) { -// m_pParent-> -// } -/* Obsolete - // Set item as being reached if it collides with us - if (hd.Body[HITOR]->IsHeldDevice()) - m_pItemInReach = dynamic_cast(hd.Body[HITOR]); -*/ -// if (Status != ACTIVE) -} + ////////////////////////////////////////////////////////////////////////////////////////// + void Actor::PreControllerUpdate() { + if (m_PathRequest && m_PathRequest->complete) { + m_MovePath = const_cast&>(m_PathRequest->path); + m_PathRequest.reset(); + OnNewMovePath(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ParticlePenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Determines whether a particle which has hit this MO will penetrate, -// and if so, whether it gets lodged or exits on the other side of this -// MO. Appropriate effects will be determined and applied ONLY IF there -// was penetration! If not, nothing will be affected. - -bool Actor::ParticlePenetration(HitData &hd) { - bool penetrated = MOSRotating::ParticlePenetration(hd); - - MovableObject *hitor = hd.Body[HITOR]; - float damageToAdd = hitor->DamageOnCollision(); - damageToAdd += penetrated ? hitor->DamageOnPenetration() : 0; - if (hitor->GetApplyWoundDamageOnCollision()) { damageToAdd += m_pEntryWound->GetEmitDamage() * hitor->WoundDamageMultiplier(); } - if (hitor->GetApplyWoundBurstDamageOnCollision()) { damageToAdd += m_pEntryWound->GetBurstDamage() * hitor->WoundDamageMultiplier(); } - - if (damageToAdd != 0) { m_Health = std::min(m_Health - (damageToAdd * m_DamageMultiplier), m_MaxHealth); } - if ((penetrated || damageToAdd != 0) && m_Perceptiveness > 0 && m_Health > 0) { - Vector extruded(hd.HitVel[HITOR]); - extruded.SetMagnitude(m_CharHeight); - extruded = m_Pos - extruded; - g_SceneMan.WrapPosition(extruded); - AlarmPoint(extruded); + // We update this after, because pathing requests are forced to take at least 1 frame for the sake of determinism for now. + // In future maybe we can move this back, but it doesn't make much difference (the threadpool submission overhead makes it extremely unlikely that it would complete in less time anyways) + if (m_UpdateMovePath) { + UpdateMovePath(); + } } - return penetrated; -} + ////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAIModeIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the icon bitmap associated with this' current AI mode and team. + void Actor::Update() { + ZoneScoped; -BITMAP * Actor::GetAIModeIcon() -{ - return m_apAIIcons[m_AIMode]; -} + ///////////////////////////////// + // Hit Body update and handling + MOSRotating::Update(); + m_PieMenu->Update(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLastMOWaypointID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ID of the last set AI MO waypoint of this. If none, g_NoMOID is returned. -// Arguments: None. -// Return value: The furthest set AI MO waypoint of this. + // Update the viewpoint to be at least what the position is + m_ViewPoint = m_Pos; -MOID Actor::GetAIMOWaypointID() const -{ - if (g_MovableMan.ValidMO(m_pMOMoveTarget)) - return m_pMOMoveTarget->GetID(); - else - return g_NoMOID; -} + // "See" the location and surroundings of this actor on the unseen map + if (m_Status != Actor::INACTIVE) + Look(45 * m_Perceptiveness, g_FrameMan.GetPlayerScreenWidth() * 0.51 * m_Perceptiveness); + // Check if the MO we're following still exists, and if not, then clear the destination + if (m_pMOMoveTarget && !g_MovableMan.ValidMO(m_pMOMoveTarget)) + m_pMOMoveTarget = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateMovePath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the path to move along to the currently set movetarget. + /////////////////////////////////////////////////////////////////////////////// + // Check for manual player-made progress made toward the set AI goal -void Actor::UpdateMovePath() -{ - if (g_SceneMan.GetScene() == nullptr) { - return; - } + if ((m_AIMode == AIMODE_GOTO || m_AIMode == AIMODE_SQUAD) && m_Controller.IsPlayerControlled() && !m_Controller.IsDisabled()) { + Vector notUsed; + // See if we are close enough to the next move target that we should grab the next in the path that is out of proximity range + Vector pathPointVec; + for (std::list::iterator lItr = m_MovePath.begin(); lItr != m_MovePath.end();) { + pathPointVec = g_SceneMan.ShortestDistance(m_Pos, *lItr); + // Make sure we are within range AND have a clear sight to the path point we're about to eliminate, or it might be around a corner + if (pathPointVec.MagnitudeIsLessThan(m_MoveProximityLimit) && !g_SceneMan.CastStrengthRay(m_Pos, pathPointVec, 5, notUsed, 0)) { + lItr++; + // Save the last one before being popped off so we can use it to check if we need to dig (if there's any material between last and current) + m_PrevPathTarget = m_MovePath.front(); + m_MovePath.pop_front(); + } else { + break; + } + } - // Estimate how much material this actor can dig through - float digStrength = EstimateDigStrength(); - - // If we're following someone/thing, then never advance waypoints until that thing disappears - if (g_MovableMan.ValidMO(m_pMOMoveTarget)) { - m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight*0.2, 10), m_pMOMoveTarget->GetPos(), digStrength, static_cast(m_Team)); - } else { - // Do we currently have a path to a static target we would like to still pursue? - if (m_MovePath.empty()) - { - // Ok no path going, so get a new path to the next waypoint, if there is a next waypoint - if (!m_Waypoints.empty()) - { - // Make sure the path starts from the ground and not somewhere up in the air if/when dropped out of ship - m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight*0.2, 10), m_Waypoints.front().first, digStrength, static_cast(m_Team)); - - // If the waypoint was tied to an MO to pursue, then load it into the current MO target - if (g_MovableMan.ValidMO(m_Waypoints.front().second)) { - m_pMOMoveTarget = m_Waypoints.front().second; - } else { - m_pMOMoveTarget = 0; - } - - // We loaded the waypoint, no need to keep it - m_Waypoints.pop_front(); - } - // Just try to get to the last Move Target - else { - m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight*0.2, 10), m_MoveTarget, digStrength, static_cast(m_Team)); - } - } - // We had a path before trying to update, so use its last point as the final destination - else { - m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(g_SceneMan.MovePointToGround(m_Pos, m_CharHeight*0.2, 10), Vector(m_MovePath.back()), digStrength, static_cast(m_Team)); - } - } - - m_UpdateMovePath = false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float Actor::EstimateDigStrength() const { - return m_AIBaseDigStrength; -} + if (!m_MovePath.empty()) { + Vector notUsed; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: VerifyMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Verifieis whether all actor's MO has correct IDs. Should be used in Debug mode only. + // See if we are close enough to the last point in the current path, in which case we can toss teh whole current path and start ont he next + pathPointVec = g_SceneMan.ShortestDistance(m_Pos, m_MovePath.back()); + // Clear out the current path, the player apparently took a shortcut + if (pathPointVec.MagnitudeIsLessThan(m_MoveProximityLimit) && !g_SceneMan.CastStrengthRay(m_Pos, pathPointVec, 5, notUsed, 0, g_MaterialDoor)) { + m_MovePath.clear(); + } + } -void Actor::VerifyMOIDs() -{ - std::vector MOIDs; - GetMOIDs(MOIDs); + // If still stuff in the path, get the next point on it + if (!m_MovePath.empty()) + m_MoveTarget = m_MovePath.front(); + // No more path, so check if any more waypoints to make a new path to? This doesn't apply if we're following something + else if (m_MovePath.empty() && !m_Waypoints.empty() && !m_pMOMoveTarget) + UpdateMovePath(); + // Nope, so just conclude that we must have reached the ultimate AI target set and exit the goto mode + else if (!m_pMOMoveTarget) + m_AIMode = AIMODE_SENTRY; + } + // Save health state so we can compare next update + m_PrevHealth = m_Health; + ///////////////////////////////////// + // Take damage/heal from wounds and wounds on Attachables + for (AEmitter* wound: m_Wounds) { + m_Health -= wound->CollectDamage() * m_DamageMultiplier; + } + for (Attachable* attachable: m_Attachables) { + m_Health -= attachable->CollectDamage(); + } + m_Health = std::min(m_Health, m_MaxHealth); - for (std::vector::iterator it = MOIDs.begin(); it != MOIDs.end(); it++) - { - RTEAssert(*it == g_NoMOID || *it < g_MovableMan.GetMOIDCount(), "Invalid MOID in actor"); - } -} + ///////////////////////////// + // Stability logic -////////////////////////////////////////////////////////////////////////////////////////// + if (m_Status == STABLE) { + // If moving really fast, we're not able to be stable + if (std::abs(m_Vel.m_X) > std::abs(m_StableVel.m_X) || std::abs(m_Vel.m_Y) > std::abs(m_StableVel.m_Y)) { + m_Status = UNSTABLE; + } -void Actor::OnNewMovePath() { - if (!m_MovePath.empty()) { - // Remove the first one; it's our position - m_PrevPathTarget = m_MovePath.front(); - m_MovePath.pop_front(); - // Also remove the one after that; it may move in opposite direction since it heads to the nearest PathNode center - // Unless it is the last one, in which case it shouldn't be removed - if (m_MovePath.size() > 1) { - m_PrevPathTarget = m_MovePath.front(); - m_MovePath.pop_front(); - } - } else if (m_pMOMoveTarget) { - m_MoveTarget = m_pMOMoveTarget->GetPos(); - } else { - // Nowhere to gooooo - m_MoveTarget = m_PrevPathTarget = m_Pos; - } -} + m_StableRecoverTimer.Reset(); + } else if (m_Status == UNSTABLE) { + // Only regain stability if we're not moving too fast and it's been a while since we lost it + if (m_StableRecoverTimer.IsPastSimMS(m_StableRecoverDelay) && !(std::abs(m_Vel.m_X) > std::abs(m_StableVel.m_X) || std::abs(m_Vel.m_Y) > std::abs(m_StableVel.m_Y))) { + m_Status = STABLE; + } + } -////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////// + // Take damage from large hits during travel + + const float travelImpulseMagnitudeSqr = m_TravelImpulse.GetSqrMagnitude(); -void Actor::PreControllerUpdate() { - if (m_PathRequest && m_PathRequest->complete) { - m_MovePath = const_cast &>(m_PathRequest->path); - m_PathRequest.reset(); - OnNewMovePath(); - } + // If we're travelling at least half the speed to hurt ourselves, play the body hit noise + float halfTravelImpulseDamage = m_TravelImpulseDamage * 0.5F; + if (m_BodyHitSound && travelImpulseMagnitudeSqr > (halfTravelImpulseDamage * halfTravelImpulseDamage)) { + m_BodyHitSound->Play(m_Pos); + } - // We update this after, because pathing requests are forced to take at least 1 frame for the sake of determinism for now. - // In future maybe we can move this back, but it doesn't make much difference (the threadpool submission overhead makes it extremely unlikely that it would complete in less time anyways) - if (m_UpdateMovePath) { - UpdateMovePath(); - } -} + // But only actually damage ourselves if we're unstable + if (m_Status == Actor::UNSTABLE && travelImpulseMagnitudeSqr > (m_TravelImpulseDamage * m_TravelImpulseDamage)) { + const float impulse = std::sqrt(travelImpulseMagnitudeSqr) - m_TravelImpulseDamage; + const float damage = std::max(impulse / (m_GibImpulseLimit - m_TravelImpulseDamage) * m_MaxHealth, 0.0F); + m_Health -= damage; + m_ForceDeepCheck = true; + } -////////////////////////////////////////////////////////////////////////////////////////// + // Spread the carried items and gold around before death. + if (m_Status == DYING || m_Status == DEAD) { + // Actor may die for a long time, no need to call this more than once + if (m_Inventory.size() > 0) { + DropAllInventory(); + } + if (m_GoldCarried > 0) { + DropAllGold(); + } + } -void Actor::Update() -{ - ZoneScoped; - - ///////////////////////////////// - // Hit Body update and handling - MOSRotating::Update(); - - m_PieMenu->Update(); - - // Update the viewpoint to be at least what the position is - m_ViewPoint = m_Pos; - - // "See" the location and surroundings of this actor on the unseen map - if (m_Status != Actor::INACTIVE) - Look(45 * m_Perceptiveness, g_FrameMan.GetPlayerScreenWidth() * 0.51 * m_Perceptiveness); - - //Check if the MO we're following still exists, and if not, then clear the destination - if (m_pMOMoveTarget && !g_MovableMan.ValidMO(m_pMOMoveTarget)) - m_pMOMoveTarget = 0; - - /////////////////////////////////////////////////////////////////////////////// - // Check for manual player-made progress made toward the set AI goal - - if ((m_AIMode == AIMODE_GOTO || m_AIMode == AIMODE_SQUAD) && m_Controller.IsPlayerControlled() && !m_Controller.IsDisabled()) - { - Vector notUsed; - // See if we are close enough to the next move target that we should grab the next in the path that is out of proximity range - Vector pathPointVec; - for (std::list::iterator lItr = m_MovePath.begin(); lItr != m_MovePath.end();) - { - pathPointVec = g_SceneMan.ShortestDistance(m_Pos, *lItr); - // Make sure we are within range AND have a clear sight to the path point we're about to eliminate, or it might be around a corner - if (pathPointVec.MagnitudeIsLessThan(m_MoveProximityLimit) && !g_SceneMan.CastStrengthRay(m_Pos, pathPointVec, 5, notUsed, 0)) - { - lItr++; - // Save the last one before being popped off so we can use it to check if we need to dig (if there's any material between last and current) - m_PrevPathTarget = m_MovePath.front(); - m_MovePath.pop_front(); - } else { - break; - } - } - - if (!m_MovePath.empty()) - { - Vector notUsed; + //////////////////////////////// + // Death logic - // See if we are close enough to the last point in the current path, in which case we can toss teh whole current path and start ont he next - pathPointVec = g_SceneMan.ShortestDistance(m_Pos, m_MovePath.back()); - // Clear out the current path, the player apparently took a shortcut - if (pathPointVec.MagnitudeIsLessThan(m_MoveProximityLimit) && !g_SceneMan.CastStrengthRay(m_Pos, pathPointVec, 5, notUsed, 0, g_MaterialDoor)) { - m_MovePath.clear(); - } - } - - // If still stuff in the path, get the next point on it - if (!m_MovePath.empty()) - m_MoveTarget = m_MovePath.front(); - // No more path, so check if any more waypoints to make a new path to? This doesn't apply if we're following something - else if (m_MovePath.empty() && !m_Waypoints.empty() && !m_pMOMoveTarget) - UpdateMovePath(); - // Nope, so just conclude that we must have reached the ultimate AI target set and exit the goto mode - else if (!m_pMOMoveTarget) - m_AIMode = AIMODE_SENTRY; - } - // Save health state so we can compare next update - m_PrevHealth = m_Health; - ///////////////////////////////////// - // Take damage/heal from wounds and wounds on Attachables - for (AEmitter *wound : m_Wounds) { - m_Health -= wound->CollectDamage() * m_DamageMultiplier; - } - for (Attachable *attachable : m_Attachables) { - m_Health -= attachable->CollectDamage(); - } - m_Health = std::min(m_Health, m_MaxHealth); - - ///////////////////////////// - // Stability logic - - if (m_Status == STABLE) { - // If moving really fast, we're not able to be stable - if (std::abs(m_Vel.m_X) > std::abs(m_StableVel.m_X) || std::abs(m_Vel.m_Y) > std::abs(m_StableVel.m_Y)) { m_Status = UNSTABLE; } - - m_StableRecoverTimer.Reset(); - } - else if (m_Status == UNSTABLE) { - // Only regain stability if we're not moving too fast and it's been a while since we lost it - if (m_StableRecoverTimer.IsPastSimMS(m_StableRecoverDelay) && !(std::abs(m_Vel.m_X) > std::abs(m_StableVel.m_X) || std::abs(m_Vel.m_Y) > std::abs(m_StableVel.m_Y))) { m_Status = STABLE; } - } - - ///////////////////////////////////////////// - // Take damage from large hits during travel - - const float travelImpulseMagnitudeSqr = m_TravelImpulse.GetSqrMagnitude(); - - // If we're travelling at least half the speed to hurt ourselves, play the body hit noise - float halfTravelImpulseDamage = m_TravelImpulseDamage * 0.5F; - if (m_BodyHitSound && travelImpulseMagnitudeSqr > (halfTravelImpulseDamage * halfTravelImpulseDamage)) { m_BodyHitSound->Play(m_Pos); } - - // But only actually damage ourselves if we're unstable - if (m_Status == Actor::UNSTABLE && travelImpulseMagnitudeSqr > (m_TravelImpulseDamage * m_TravelImpulseDamage)) { - const float impulse = std::sqrt(travelImpulseMagnitudeSqr) - m_TravelImpulseDamage; - const float damage = std::max(impulse / (m_GibImpulseLimit - m_TravelImpulseDamage) * m_MaxHealth, 0.0F); - m_Health -= damage; - m_ForceDeepCheck = true; - } + if (m_Status != DYING && m_Status != DEAD && m_Health <= 0) { + if (m_DeathSound) { + m_DeathSound->Play(m_Pos); + } + DropAllInventory(); + m_Status = DYING; + m_DeathTmr.Reset(); + } - // Spread the carried items and gold around before death. - if (m_Status == DYING || m_Status == DEAD) { - // Actor may die for a long time, no need to call this more than once - if (m_Inventory.size() > 0) { DropAllInventory(); } - if (m_GoldCarried > 0) { DropAllGold(); } - } + // Prevent dead actors from rotating like mad + if (m_Status == DYING || m_Status == DEAD) { + m_AngularVel = m_AngularVel * 0.98F; + } - //////////////////////////////// - // Death logic + if (m_Status == DYING && m_DeathTmr.GetElapsedSimTimeMS() > 1000) { + m_Status = DEAD; + } - if (m_Status != DYING && m_Status != DEAD && m_Health <= 0) { - if (m_DeathSound) { m_DeathSound->Play(m_Pos); } - DropAllInventory(); - m_Status = DYING; - m_DeathTmr.Reset(); - } + ////////////////////////////////////////////////////// + // Save previous second's position so we can detect larger movement - // Prevent dead actors from rotating like mad - if (m_Status == DYING || m_Status == DEAD) { m_AngularVel = m_AngularVel * 0.98F; } - - if (m_Status == DYING && m_DeathTmr.GetElapsedSimTimeMS() > 1000) { m_Status = DEAD; } - - ////////////////////////////////////////////////////// - // Save previous second's position so we can detect larger movement - - if (m_LastSecondTimer.IsPastSimMS(1000)) - { - m_RecentMovement = m_Pos - m_LastSecondPos; - m_LastSecondPos = m_Pos; - m_LastSecondTimer.Reset(); - } - - //////////////////////////////////////// - // Animate the sprite, if applicable - - if (m_FrameCount > 1) - { - if (m_SpriteAnimMode == LOOPWHENACTIVE) - { - if (m_Controller.IsState(MOVE_LEFT) || m_Controller.IsState(MOVE_RIGHT) || m_Controller.GetAnalogMove().GetLargest() > 0.1) - { -// TODO: improve; make this - float cycleTime = ((long)m_SpriteAnimTimer.GetElapsedSimTimeMS()) % m_SpriteAnimDuration; - m_Frame = std::floor((cycleTime / (float)m_SpriteAnimDuration) * (float)m_FrameCount); - } - } - } - - ///////////////////////////////// - // Misc - - // If in AI setting mode prior to actor switch, made the team rosters get sorted so the lines are drawn correctly - if (m_Controller.IsState(PIE_MENU_ACTIVE)) - { - g_MovableMan.SortTeamRoster(m_Team); - } - - // Play PainSound if damage this frame exceeded PainThreshold - if (m_PainThreshold > 0 && m_PrevHealth - m_Health > m_PainThreshold && m_Health > 1 && m_PainSound) { m_PainSound->Play(m_Pos); } - - int brainOfPlayer = g_ActivityMan.GetActivity()->IsBrainOfWhichPlayer(this); - if (brainOfPlayer != Players::NoPlayer && g_ActivityMan.GetActivity()->PlayerHuman(brainOfPlayer)) { - if (m_PrevHealth - m_Health > 1.5F) { - // If this is a brain that's under attack, broadcast an alarm event so that the enemy AI won't dawdle in trying to kill it. - g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, 0.5F)); - if (g_SettingsMan.FlashOnBrainDamage()) { - g_FrameMan.FlashScreen(g_ActivityMan.GetActivity()->ScreenOfPlayer(brainOfPlayer), g_RedColor, 10); + if (m_LastSecondTimer.IsPastSimMS(1000)) { + m_RecentMovement = m_Pos - m_LastSecondPos; + m_LastSecondPos = m_Pos; + m_LastSecondTimer.Reset(); + } + + //////////////////////////////////////// + // Animate the sprite, if applicable + + if (m_FrameCount > 1) { + if (m_SpriteAnimMode == LOOPWHENACTIVE) { + if (m_Controller.IsState(MOVE_LEFT) || m_Controller.IsState(MOVE_RIGHT) || m_Controller.GetAnalogMove().GetLargest() > 0.1) { + // TODO: improve; make this + float cycleTime = ((long)m_SpriteAnimTimer.GetElapsedSimTimeMS()) % m_SpriteAnimDuration; + m_Frame = std::floor((cycleTime / (float)m_SpriteAnimDuration) * (float)m_FrameCount); + } } } - if ((m_ToDelete || m_Status == DEAD) && g_SettingsMan.FlashOnBrainDamage()) { - g_FrameMan.FlashScreen(g_ActivityMan.GetActivity()->ScreenOfPlayer(brainOfPlayer), g_WhiteColor, 500); + + ///////////////////////////////// + // Misc + + // If in AI setting mode prior to actor switch, made the team rosters get sorted so the lines are drawn correctly + if (m_Controller.IsState(PIE_MENU_ACTIVE)) { + g_MovableMan.SortTeamRoster(m_Team); } - } -// Do NOT mess witht he HUD stack in update... it should only be altered in DrawHUD, or it will jitter when multiple sim updates happen -// m_HUDStack = -m_CharHeight / 2; - -/* -// *** TEMP Hack for testing animation - int bajs = m_aSprite->GetVelX(); - bajs %= 5; - m_aSprite->SetVelX(++bajs); - - if (bajs == 1) - { - int frame = m_aSprite->GetFrame(); - if (++frame >= 7) - frame = 1; - m_aSprite->SetFrame(frame); - } -*/ -} - -void Actor::FullUpdate() { - PreControllerUpdate(); - m_Controller.Update(); - Update(); -} + // Play PainSound if damage this frame exceeded PainThreshold + if (m_PainThreshold > 0 && m_PrevHealth - m_Health > m_PainThreshold && m_Health > 1 && m_PainSound) { + m_PainSound->Play(m_Pos); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. - -void Actor::DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) -{ - // This should indeed be a local var and not alter a member one in a draw func! Can cause nasty jittering etc if multiple sim updates are done without a drawing in between etc - m_HUDStack = -m_CharHeight / 2; - - // Only do HUD if on a team - if (m_Team < 0) - return; - - // Only draw if the team viewing this is on the same team OR has seen the space where this is located. - int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); - if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { - return; - } + int brainOfPlayer = g_ActivityMan.GetActivity()->IsBrainOfWhichPlayer(this); + if (brainOfPlayer != Players::NoPlayer && g_ActivityMan.GetActivity()->PlayerHuman(brainOfPlayer)) { + if (m_PrevHealth - m_Health > 1.5F) { + // If this is a brain that's under attack, broadcast an alarm event so that the enemy AI won't dawdle in trying to kill it. + g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, 0.5F)); + if (g_SettingsMan.FlashOnBrainDamage()) { + g_FrameMan.FlashScreen(g_ActivityMan.GetActivity()->ScreenOfPlayer(brainOfPlayer), g_RedColor, 10); + } + } + if ((m_ToDelete || m_Status == DEAD) && g_SettingsMan.FlashOnBrainDamage()) { + g_FrameMan.FlashScreen(g_ActivityMan.GetActivity()->ScreenOfPlayer(brainOfPlayer), g_WhiteColor, 500); + } + } - // Draw stat info HUD - char str[64]; - - GUIFont *pSymbolFont = g_FrameMan.GetLargeFont(); - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); - Vector drawPos = m_Pos - targetPos; - Vector cpuPos = GetCPUPos() - targetPos; - - // If we have something to draw, adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam - if ((m_HUDVisible || m_PieMenu->IsVisible()) && !targetPos.IsZero()) - { - // Spans vertical scene seam - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) - { - if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) - { - drawPos.m_X -= sceneWidth; - cpuPos.m_X -= sceneWidth; - } - else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) - { - drawPos.m_X += sceneWidth; - cpuPos.m_X += sceneWidth; - } - } - // Spans horizontal scene seam - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) - { - if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) - { - drawPos.m_Y -= sceneHeight; - cpuPos.m_Y -= sceneHeight; - } - else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) - { - drawPos.m_Y += sceneHeight; - cpuPos.m_Y += sceneHeight; - } - } - } - - int actorScreen = g_ActivityMan.GetActivity() ? g_ActivityMan.GetActivity()->ScreenOfPlayer(m_Controller.GetPlayer()) : -1; - bool screenTeamIsSameAsActorTeam = g_ActivityMan.GetActivity() ? g_ActivityMan.GetActivity()->GetTeamOfPlayer(whichScreen) == m_Team : true; - if (m_PieMenu->IsVisible() && screenTeamIsSameAsActorTeam && (!m_PieMenu->IsInNormalAnimationMode() || (m_Controller.IsPlayerControlled() && actorScreen == whichScreen))) { - m_PieMenu->Draw(pTargetBitmap, targetPos); + // Do NOT mess witht he HUD stack in update... it should only be altered in DrawHUD, or it will jitter when multiple sim updates happen + // m_HUDStack = -m_CharHeight / 2; + + /* + // *** TEMP Hack for testing animation + int bajs = m_aSprite->GetVelX(); + bajs %= 5; + m_aSprite->SetVelX(++bajs); + + if (bajs == 1) + { + int frame = m_aSprite->GetFrame(); + if (++frame >= 7) + frame = 1; + m_aSprite->SetFrame(frame); + } + */ } - if (!m_HUDVisible) { - return; + void Actor::FullUpdate() { + PreControllerUpdate(); + m_Controller.Update(); + Update(); } - // Draw the selection arrow, if controlled and under the arrow's time limit - if (m_Controller.IsPlayerControlled() && m_NewControlTmr.GetElapsedSimTimeMS() < ARROWTIME) - { - // Draw the appropriate selection arrow color based on player team - draw_sprite(pTargetBitmap, m_apSelectArrow[m_Team], cpuPos.m_X, EaseOut(drawPos.m_Y + m_HUDStack - 60, drawPos.m_Y + m_HUDStack - 20, m_NewControlTmr.GetElapsedSimTimeMS() / (float)ARROWTIME)); - } - - // Draw the alarm exclamation mark if we are alarmed! - if (m_AlarmTimer.SimTimeLimitProgress() < 0.25) - draw_sprite(pTargetBitmap, m_apAlarmExclamation[m_AgeTimer.AlternateSim(100)], cpuPos.m_X - 3, EaseOut(drawPos.m_Y + m_HUDStack - 10, drawPos.m_Y + m_HUDStack - 25, m_AlarmTimer.SimTimeLimitProgress() / 0.25f)); - - if (pSmallFont && pSymbolFont) - { - AllegroBitmap bitmapInt(pTargetBitmap); - - if (!m_Controller.IsState(PIE_MENU_ACTIVE) || actorScreen != whichScreen) - { - // If we're still alive, show the team colors - if (m_Health > 0) - { - if (IsPlayerControlled() && g_FrameMan.IsInMultiplayerMode()) - { - m_pControllerIcon = 0; - if (m_Team == 0) - m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_1); - else if (m_Team == 1) - m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_2); - else if (m_Team == 2) - m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_3); - else if (m_Team == 3) - m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_4); - if (m_pControllerIcon) - { - std::vector apControllerBitmaps = m_pControllerIcon->GetBitmaps8(); - - masked_blit(apControllerBitmaps[0], pTargetBitmap, 0, 0, drawPos.m_X - apControllerBitmaps[0]->w - 2 + 10, drawPos.m_Y + m_HUDStack - (apControllerBitmaps[0]->h / 2) + 8, apControllerBitmaps[0]->w, apControllerBitmaps[0]->h); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. + + void Actor::DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { + // This should indeed be a local var and not alter a member one in a draw func! Can cause nasty jittering etc if multiple sim updates are done without a drawing in between etc + m_HUDStack = -m_CharHeight / 2; + + // Only do HUD if on a team + if (m_Team < 0) + return; + + // Only draw if the team viewing this is on the same team OR has seen the space where this is located. + int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); + if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam && (!g_SettingsMan.ShowEnemyHUD() || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam))) { + return; + } + + // Draw stat info HUD + char str[64]; + + GUIFont* pSymbolFont = g_FrameMan.GetLargeFont(); + GUIFont* pSmallFont = g_FrameMan.GetSmallFont(); + Vector drawPos = m_Pos - targetPos; + Vector cpuPos = GetCPUPos() - targetPos; + + // If we have something to draw, adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam + if ((m_HUDVisible || m_PieMenu->IsVisible()) && !targetPos.IsZero()) { + // Spans vertical scene seam + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) { + drawPos.m_X -= sceneWidth; + cpuPos.m_X -= sceneWidth; + } else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) { + drawPos.m_X += sceneWidth; + cpuPos.m_X += sceneWidth; + } + } + // Spans horizontal scene seam + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) { + drawPos.m_Y -= sceneHeight; + cpuPos.m_Y -= sceneHeight; + } else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) { + drawPos.m_Y += sceneHeight; + cpuPos.m_Y += sceneHeight; } + } + } + + int actorScreen = g_ActivityMan.GetActivity() ? g_ActivityMan.GetActivity()->ScreenOfPlayer(m_Controller.GetPlayer()) : -1; + bool screenTeamIsSameAsActorTeam = g_ActivityMan.GetActivity() ? g_ActivityMan.GetActivity()->GetTeamOfPlayer(whichScreen) == m_Team : true; + if (m_PieMenu->IsVisible() && screenTeamIsSameAsActorTeam && (!m_PieMenu->IsInNormalAnimationMode() || (m_Controller.IsPlayerControlled() && actorScreen == whichScreen))) { + m_PieMenu->Draw(pTargetBitmap, targetPos); + } + + if (!m_HUDVisible) { + return; + } - // Get the Icon bitmaps of this Actor's team, if any - std::vector apIconBitmaps; - if (m_pTeamIcon) - apIconBitmaps = m_pTeamIcon->GetBitmaps8(); - - // Team Icon could not be found, or of no team, so use the static noteam Icon instead - if (apIconBitmaps.empty()) - apIconBitmaps = m_apNoTeamIcon; - - // Now draw the Icon if we can - if (!apIconBitmaps.empty() && m_pTeamIcon && m_pTeamIcon->GetFrameCount() > 0) - { - // Make team icon blink faster as the health goes down - int f = m_HeartBeat.AlternateReal(200 + 800 * (m_Health / 100)) ? 0 : 1; - f = MIN(f, m_pTeamIcon ? m_pTeamIcon->GetFrameCount() - 1 : 1); - masked_blit(apIconBitmaps.at(f), pTargetBitmap, 0, 0, drawPos.m_X - apIconBitmaps.at(f)->w - 2, drawPos.m_Y + m_HUDStack - (apIconBitmaps.at(f)->h / 2) + 8, apIconBitmaps.at(f)->w, apIconBitmaps.at(f)->h); - } - } - // Draw death icon - else - { - str[0] = -39; - str[1] = 0; - pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 10, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); - } - -/* Obsolete red/gren heart Team icon - // Health - if (m_HeartBeat.GetElapsedSimTimeMS() > (m_Health > 90 ? 850 : (m_Health > 25 ? 350 : 100)) || m_Health <= 0) - { - str[0] = m_Health > 0 ? (m_Team == 0 ? -64 : -61) : -39; - str[1] = 0; - pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 10, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); - if (m_HeartBeat.GetElapsedSimTimeMS() > (m_Health > 90 ? 950 : (m_Health > 25 ? 500 : 175))) - m_HeartBeat.Reset(); - } - else - { - str[0] = m_Team == 0 ? -63 : -60; - str[1] = 0; - pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 11, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); - } -*/ - std::snprintf(str, sizeof(str), "%.0f", std::ceil(m_Health)); - pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 0, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); - - m_HUDStack += -12; - - if (IsPlayerControlled()) { - if (GetGoldCarried() > 0) { - str[0] = m_GoldPicked ? -57 : -58; str[1] = 0; - pSymbolFont->DrawAligned(&bitmapInt, drawPos.GetFloorIntX() - 11, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Left); - std::snprintf(str, sizeof(str), "%.0f oz", GetGoldCarried()); - pSmallFont->DrawAligned(&bitmapInt, drawPos.GetFloorIntX() - 0, drawPos.GetFloorIntY() + m_HUDStack + 2, str, GUIFont::Left); - - m_HUDStack -= 11; + // Draw the selection arrow, if controlled and under the arrow's time limit + if (m_Controller.IsPlayerControlled() && m_NewControlTmr.GetElapsedSimTimeMS() < ARROWTIME) { + // Draw the appropriate selection arrow color based on player team + draw_sprite(pTargetBitmap, m_apSelectArrow[m_Team], cpuPos.m_X, EaseOut(drawPos.m_Y + m_HUDStack - 60, drawPos.m_Y + m_HUDStack - 20, m_NewControlTmr.GetElapsedSimTimeMS() / (float)ARROWTIME)); + } + + // Draw the alarm exclamation mark if we are alarmed! + if (m_AlarmTimer.SimTimeLimitProgress() < 0.25) + draw_sprite(pTargetBitmap, m_apAlarmExclamation[m_AgeTimer.AlternateSim(100)], cpuPos.m_X - 3, EaseOut(drawPos.m_Y + m_HUDStack - 10, drawPos.m_Y + m_HUDStack - 25, m_AlarmTimer.SimTimeLimitProgress() / 0.25f)); + + if (pSmallFont && pSymbolFont) { + AllegroBitmap bitmapInt(pTargetBitmap); + + if (!m_Controller.IsState(PIE_MENU_ACTIVE) || actorScreen != whichScreen) { + // If we're still alive, show the team colors + if (m_Health > 0) { + if (IsPlayerControlled() && g_FrameMan.IsInMultiplayerMode()) { + m_pControllerIcon = 0; + if (m_Team == 0) + m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_1); + else if (m_Team == 1) + m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_2); + else if (m_Team == 2) + m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_3); + else if (m_Team == 3) + m_pControllerIcon = g_UInputMan.GetDeviceIcon(DEVICE_GAMEPAD_4); + if (m_pControllerIcon) { + std::vector apControllerBitmaps = m_pControllerIcon->GetBitmaps8(); + + masked_blit(apControllerBitmaps[0], pTargetBitmap, 0, 0, drawPos.m_X - apControllerBitmaps[0]->w - 2 + 10, drawPos.m_Y + m_HUDStack - (apControllerBitmaps[0]->h / 2) + 8, apControllerBitmaps[0]->w, apControllerBitmaps[0]->h); + } + } + + // Get the Icon bitmaps of this Actor's team, if any + std::vector apIconBitmaps; + if (m_pTeamIcon) + apIconBitmaps = m_pTeamIcon->GetBitmaps8(); + + // Team Icon could not be found, or of no team, so use the static noteam Icon instead + if (apIconBitmaps.empty()) + apIconBitmaps = m_apNoTeamIcon; + + // Now draw the Icon if we can + if (!apIconBitmaps.empty() && m_pTeamIcon && m_pTeamIcon->GetFrameCount() > 0) { + // Make team icon blink faster as the health goes down + int f = m_HeartBeat.AlternateReal(200 + 800 * (m_Health / 100)) ? 0 : 1; + f = MIN(f, m_pTeamIcon ? m_pTeamIcon->GetFrameCount() - 1 : 1); + masked_blit(apIconBitmaps.at(f), pTargetBitmap, 0, 0, drawPos.m_X - apIconBitmaps.at(f)->w - 2, drawPos.m_Y + m_HUDStack - (apIconBitmaps.at(f)->h / 2) + 8, apIconBitmaps.at(f)->w, apIconBitmaps.at(f)->h); + } } - // Player name - if (g_FrameMan.IsInMultiplayerMode()) { - if (GameActivity * gameActivity = dynamic_cast(g_ActivityMan.GetActivity())) { - pSmallFont->DrawAligned(&bitmapInt, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 2, gameActivity->GetNetworkPlayerName(m_Controller.GetPlayer()).c_str(), GUIFont::Centre); + // Draw death icon + else { + str[0] = -39; + str[1] = 0; + pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 10, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); + } + + /* Obsolete red/gren heart Team icon + // Health + if (m_HeartBeat.GetElapsedSimTimeMS() > (m_Health > 90 ? 850 : (m_Health > 25 ? 350 : 100)) || m_Health <= 0) + { + str[0] = m_Health > 0 ? (m_Team == 0 ? -64 : -61) : -39; + str[1] = 0; + pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 10, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); + if (m_HeartBeat.GetElapsedSimTimeMS() > (m_Health > 90 ? 950 : (m_Health > 25 ? 500 : 175))) + m_HeartBeat.Reset(); + } + else + { + str[0] = m_Team == 0 ? -63 : -60; + str[1] = 0; + pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 11, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); + } + */ + std::snprintf(str, sizeof(str), "%.0f", std::ceil(m_Health)); + pSymbolFont->DrawAligned(&bitmapInt, drawPos.m_X - 0, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); + + m_HUDStack += -12; + + if (IsPlayerControlled()) { + if (GetGoldCarried() > 0) { + str[0] = m_GoldPicked ? -57 : -58; + str[1] = 0; + pSymbolFont->DrawAligned(&bitmapInt, drawPos.GetFloorIntX() - 11, drawPos.GetFloorIntY() + m_HUDStack, str, GUIFont::Left); + std::snprintf(str, sizeof(str), "%.0f oz", GetGoldCarried()); + pSmallFont->DrawAligned(&bitmapInt, drawPos.GetFloorIntX() - 0, drawPos.GetFloorIntY() + m_HUDStack + 2, str, GUIFont::Left); + m_HUDStack -= 11; } + // Player name + if (g_FrameMan.IsInMultiplayerMode()) { + if (GameActivity* gameActivity = dynamic_cast(g_ActivityMan.GetActivity())) { + pSmallFont->DrawAligned(&bitmapInt, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() + m_HUDStack + 2, gameActivity->GetNetworkPlayerName(m_Controller.GetPlayer()).c_str(), GUIFont::Centre); + m_HUDStack -= 11; + } + } } + /* Obsolete + // Draw the contol pointer, if controlled and under the icon's time limit + if (m_Controller.IsPlayetControlled() && m_NewControlTmr.GetElapsedSimTimeMS() < 1500) + { + std::snprintf(str, sizeof(str), "%c", -38); + pSymbolFont->DrawAligned(&bitmapInt, cpuPos.m_X - 0, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); + } + */ + } + } + + // Don't proceed to draw all the secret stuff below if this screen is for a player on the other team! + if (g_ActivityMan.GetActivity() && g_ActivityMan.GetActivity()->GetTeamOfPlayer(whichScreen) != m_Team) + return; + + // AI waypoints or points of interest + if (m_DrawWaypoints && m_PlayerControllable && (m_AIMode == AIMODE_GOTO || m_AIMode == AIMODE_SQUAD)) { + // Draw the AI paths, from the ultimate destination back up to the actor's position. + // We do this backwards so the lines won't crawl and the dots can be evenly spaced throughout + Vector waypoint; + std::list>::reverse_iterator vLast, vItr; + std::list::reverse_iterator lLast, lItr; + int skipPhase = 0; + + // Draw the line between the end of the movepath and the first waypoint after that, if any + if (!m_Waypoints.empty()) { + // Draw the first destination/waypoint point + // waypoint = m_MoveTarget - targetPos; + // circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); + + // Draw the additional waypoint points beyond the first one + vLast = m_Waypoints.rbegin(); + vItr = m_Waypoints.rbegin(); + for (; vItr != m_Waypoints.rend(); ++vItr) { + // Draw the line + g_FrameMan.DrawLine(pTargetBitmap, (*vLast).first - targetPos, (*vItr).first - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); + vLast = vItr; + + // Draw the points + waypoint = (*vItr).first - targetPos; + circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); + // Add pixel glow area around it, in scene coordinates + g_PostProcessMan.RegisterGlowArea((*vItr).first, 5); + } + + // Draw line from the last movetarget on the current path to the first waypoint in queue after that + if (!m_MovePath.empty()) + g_FrameMan.DrawLine(pTargetBitmap, m_MovePath.back() - targetPos, m_Waypoints.front().first - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); + else + g_FrameMan.DrawLine(pTargetBitmap, m_MoveTarget - targetPos, m_Waypoints.front().first - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); } -/* Obsolete - // Draw the contol pointer, if controlled and under the icon's time limit - if (m_Controller.IsPlayetControlled() && m_NewControlTmr.GetElapsedSimTimeMS() < 1500) - { - std::snprintf(str, sizeof(str), "%c", -38); - pSymbolFont->DrawAligned(&bitmapInt, cpuPos.m_X - 0, drawPos.m_Y + m_HUDStack, str, GUIFont::Left); - } -*/ - } - } - - // Don't proceed to draw all the secret stuff below if this screen is for a player on the other team! - if (g_ActivityMan.GetActivity() && g_ActivityMan.GetActivity()->GetTeamOfPlayer(whichScreen) != m_Team) - return; - - // AI waypoints or points of interest - if (m_DrawWaypoints && m_PlayerControllable && (m_AIMode == AIMODE_GOTO || m_AIMode == AIMODE_SQUAD)) - { - // Draw the AI paths, from the ultimate destination back up to the actor's position. - // We do this backwards so the lines won't crawl and the dots can be evenly spaced throughout - Vector waypoint; - std::list >::reverse_iterator vLast, vItr; - std::list::reverse_iterator lLast, lItr; - int skipPhase = 0; - - // Draw the line between the end of the movepath and the first waypoint after that, if any - if (!m_Waypoints.empty()) - { - // Draw the first destination/waypoint point -// waypoint = m_MoveTarget - targetPos; -// circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); - - // Draw the additional waypoint points beyond the first one - vLast = m_Waypoints.rbegin(); - vItr = m_Waypoints.rbegin(); - for (; vItr != m_Waypoints.rend(); ++vItr) - { - // Draw the line - g_FrameMan.DrawLine(pTargetBitmap, (*vLast).first - targetPos, (*vItr).first - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); - vLast = vItr; - - // Draw the points - waypoint = (*vItr).first - targetPos; - circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); - // Add pixel glow area around it, in scene coordinates - g_PostProcessMan.RegisterGlowArea((*vItr).first, 5); - } - - // Draw line from the last movetarget on the current path to the first waypoint in queue after that - if (!m_MovePath.empty()) - g_FrameMan.DrawLine(pTargetBitmap, m_MovePath.back() - targetPos, m_Waypoints.front().first - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); - else - g_FrameMan.DrawLine(pTargetBitmap, m_MoveTarget - targetPos, m_Waypoints.front().first - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, 0, true); - } - - // Draw the current movepath, but backwards so the dot spacing can be even and they don't crawl as the guy approaches - if (!m_MovePath.empty()) - { - lLast = m_MovePath.rbegin(); - lItr = m_MovePath.rbegin(); - for (; lItr != m_MovePath.rend(); ++lItr) - { - // Draw these backwards so the skip phase works - skipPhase = g_FrameMan.DrawLine(pTargetBitmap, (*lLast) - targetPos, (*lItr) - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, skipPhase, true); - lLast = lItr; - } - - // Draw the line between the current position and to the start of the movepath, backwards so the dotted lines doesn't crawl - skipPhase = g_FrameMan.DrawLine(pTargetBitmap, m_MovePath.front() - targetPos, m_Pos - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, skipPhase, true); - // Draw the first destination/waypoint point - waypoint = m_MovePath.back() - targetPos; - circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); - // Add pixel glow area around it, in scene coordinates - g_PostProcessMan.RegisterGlowArea(m_MovePath.back(), 5); - } - // If no points left on movepath, then draw straight line to the movetarget - else - { - // Draw it backwards so the dotted lines doesn't crawl - skipPhase = g_FrameMan.DrawLine(pTargetBitmap, m_MoveTarget - targetPos, m_Pos - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, skipPhase, true); - // Draw the first destination/waypoint point - waypoint = m_MoveTarget - targetPos; - circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); - // Add pixel glow area around it, in scene coordinates - g_PostProcessMan.RegisterGlowArea(m_MoveTarget, 5); - } - } - - // AI Mode team roster HUD lines - if (m_PlayerControllable && g_ActivityMan.GetActivity()->GetViewState(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)) == Activity::ViewState::ActorSelect && g_SceneMan.ShortestDistance(m_Pos, g_CameraMan.GetScrollTarget(whichScreen), g_SceneMan.SceneWrapsX()).GetMagnitude() < 100) { - draw_sprite(pTargetBitmap, GetAIModeIcon(), cpuPos.m_X - 6, cpuPos.m_Y - 6); - } else if (m_Controller.IsState(ACTOR_NEXT_PREP) || m_Controller.IsState(ACTOR_PREV_PREP)) { - int prevColor = m_Controller.IsState(ACTOR_PREV_PREP) ? 122 : (m_Team == Activity::TeamOne ? 13 : 147); - int nextColor = m_Controller.IsState(ACTOR_NEXT_PREP) ? 122 : (m_Team == Activity::TeamOne ? 13 : 147); - int prevSpacing = m_Controller.IsState(ACTOR_PREV_PREP) ? 3 : 9; - int nextSpacing = m_Controller.IsState(ACTOR_NEXT_PREP) ? 3 : 9; - int altColor = m_Team == Activity::TeamOne ? 11 : 160; - - Actor *pPrevAdj = 0; - Actor *pNextAdj = 0; - std::list *pRoster = g_MovableMan.GetTeamRoster(m_Team); - - if (pRoster->size() > 1) - { - // Find this in the list, both ways - std::list::reverse_iterator selfRItr = find(pRoster->rbegin(), pRoster->rend(), this); - RTEAssert(selfRItr != pRoster->rend(), "Actor couldn't find self in Team roster!"); - std::list::iterator selfItr = find(pRoster->begin(), pRoster->end(), this); - RTEAssert(selfItr != pRoster->end(), "Actor couldn't find self in Team roster!"); - - // Find the adjacent actors - if (selfItr != pRoster->end()) - { - // Get the previous available actor in the list (not controlled by another player) - std::list::reverse_iterator prevItr = selfRItr; - do - { - if (++prevItr == pRoster->rend()) - prevItr = pRoster->rbegin(); - if ((*prevItr) == (*selfItr)) - break; - } - while(!(*prevItr)->IsPlayerControllable() || (*prevItr)->GetController()->IsPlayerControlled() || - g_ActivityMan.GetActivity()->IsOtherPlayerBrain((*prevItr), m_Controller.GetPlayer())); - - // Get the next actor in the list (not controlled by another player) - std::list::iterator nextItr = selfItr; - do - { - if (++nextItr == pRoster->end()) - nextItr = pRoster->begin(); - if ((*nextItr) == (*selfItr)) - break; - } - while(!(*nextItr)->IsPlayerControllable() || (*nextItr)->GetController()->IsPlayerControlled() || - g_ActivityMan.GetActivity()->IsOtherPlayerBrain((*prevItr), m_Controller.GetPlayer())); - - Vector iconPos = cpuPos; - // Only continue if there are available adjacent Actors - if ((*prevItr) != (*selfItr) && (*nextItr) != (*selfItr)) - { - pPrevAdj = *prevItr; - pNextAdj = *nextItr; - // Only draw both lines if they're not pointing to the same thing - if (pPrevAdj != pNextAdj) - { - g_FrameMan.DrawLine(pTargetBitmap, cpuPos, pPrevAdj->GetCPUPos() - targetPos, prevColor, prevColor, prevSpacing, 0, true); - g_FrameMan.DrawLine(pTargetBitmap, cpuPos, pNextAdj->GetCPUPos() - targetPos, nextColor, nextColor, nextSpacing, 0, true); - } - // If only one other available Actor, only draw one yellow line to it - else - g_FrameMan.DrawLine(pTargetBitmap, cpuPos, pNextAdj->GetCPUPos() - targetPos, 122, 122, 3, 0, true); - - // Prev selected icon - iconPos = pPrevAdj->GetCPUPos() - targetPos; - draw_sprite(pTargetBitmap, pPrevAdj->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); - - // Next selected icon - iconPos = pNextAdj->GetCPUPos() - targetPos; - draw_sprite(pTargetBitmap, pNextAdj->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); - } - - // Self selected icon - iconPos = cpuPos; - draw_sprite(pTargetBitmap, GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); -/* Too many lines, confusing! - // Again get the next and previous actors in the list - if (++prevItr == pRoster->rend()) - prevItr = pRoster->rbegin(); - if (++nextItr == pRoster->end()) - nextItr = pRoster->begin(); - g_FrameMan.DrawLine(pTargetBitmap, pPrevAdj->GetCPUPos() - targetPos, (*prevItr)->GetCPUPos() - targetPos, prevColor, prevColor, 12, 0, true); - g_FrameMan.DrawLine(pTargetBitmap, pNextAdj->GetCPUPos() - targetPos, (*nextItr)->GetCPUPos() - targetPos, nextColor, nextColor, 12, 0, true); - // Prev selected icon - iconPos = (*prevItr)->GetCPUPos(); - draw_sprite(pTargetBitmap, (*prevItr)->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); - // Next selected icon - iconPos = (*nextItr)->GetCPUPos(); - draw_sprite(pTargetBitmap, (*nextItr)->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); -*/ - } - } - } -} + // Draw the current movepath, but backwards so the dot spacing can be even and they don't crawl as the guy approaches + if (!m_MovePath.empty()) { + lLast = m_MovePath.rbegin(); + lItr = m_MovePath.rbegin(); + for (; lItr != m_MovePath.rend(); ++lItr) { + // Draw these backwards so the skip phase works + skipPhase = g_FrameMan.DrawLine(pTargetBitmap, (*lLast) - targetPos, (*lItr) - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, skipPhase, true); + lLast = lItr; + } + + // Draw the line between the current position and to the start of the movepath, backwards so the dotted lines doesn't crawl + skipPhase = g_FrameMan.DrawLine(pTargetBitmap, m_MovePath.front() - targetPos, m_Pos - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, skipPhase, true); + // Draw the first destination/waypoint point + waypoint = m_MovePath.back() - targetPos; + circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); + // Add pixel glow area around it, in scene coordinates + g_PostProcessMan.RegisterGlowArea(m_MovePath.back(), 5); + } + // If no points left on movepath, then draw straight line to the movetarget + else { + // Draw it backwards so the dotted lines doesn't crawl + skipPhase = g_FrameMan.DrawLine(pTargetBitmap, m_MoveTarget - targetPos, m_Pos - targetPos, g_YellowGlowColor, 0, AILINEDOTSPACING, skipPhase, true); + // Draw the first destination/waypoint point + waypoint = m_MoveTarget - targetPos; + circlefill(pTargetBitmap, waypoint.m_X, waypoint.m_Y, 2, g_YellowGlowColor); + // Add pixel glow area around it, in scene coordinates + g_PostProcessMan.RegisterGlowArea(m_MoveTarget, 5); + } + } + + // AI Mode team roster HUD lines + if (m_PlayerControllable && g_ActivityMan.GetActivity()->GetViewState(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)) == Activity::ViewState::ActorSelect && g_SceneMan.ShortestDistance(m_Pos, g_CameraMan.GetScrollTarget(whichScreen), g_SceneMan.SceneWrapsX()).GetMagnitude() < 100) { + draw_sprite(pTargetBitmap, GetAIModeIcon(), cpuPos.m_X - 6, cpuPos.m_Y - 6); + } else if (m_Controller.IsState(ACTOR_NEXT_PREP) || m_Controller.IsState(ACTOR_PREV_PREP)) { + int prevColor = m_Controller.IsState(ACTOR_PREV_PREP) ? 122 : (m_Team == Activity::TeamOne ? 13 : 147); + int nextColor = m_Controller.IsState(ACTOR_NEXT_PREP) ? 122 : (m_Team == Activity::TeamOne ? 13 : 147); + int prevSpacing = m_Controller.IsState(ACTOR_PREV_PREP) ? 3 : 9; + int nextSpacing = m_Controller.IsState(ACTOR_NEXT_PREP) ? 3 : 9; + int altColor = m_Team == Activity::TeamOne ? 11 : 160; + + Actor* pPrevAdj = 0; + Actor* pNextAdj = 0; + std::list* pRoster = g_MovableMan.GetTeamRoster(m_Team); + + if (pRoster->size() > 1) { + // Find this in the list, both ways + std::list::reverse_iterator selfRItr = find(pRoster->rbegin(), pRoster->rend(), this); + RTEAssert(selfRItr != pRoster->rend(), "Actor couldn't find self in Team roster!"); + std::list::iterator selfItr = find(pRoster->begin(), pRoster->end(), this); + RTEAssert(selfItr != pRoster->end(), "Actor couldn't find self in Team roster!"); + + // Find the adjacent actors + if (selfItr != pRoster->end()) { + // Get the previous available actor in the list (not controlled by another player) + std::list::reverse_iterator prevItr = selfRItr; + do { + if (++prevItr == pRoster->rend()) + prevItr = pRoster->rbegin(); + if ((*prevItr) == (*selfItr)) + break; + } while (!(*prevItr)->IsPlayerControllable() || (*prevItr)->GetController()->IsPlayerControlled() || + g_ActivityMan.GetActivity()->IsOtherPlayerBrain((*prevItr), m_Controller.GetPlayer())); + + // Get the next actor in the list (not controlled by another player) + std::list::iterator nextItr = selfItr; + do { + if (++nextItr == pRoster->end()) + nextItr = pRoster->begin(); + if ((*nextItr) == (*selfItr)) + break; + } while (!(*nextItr)->IsPlayerControllable() || (*nextItr)->GetController()->IsPlayerControlled() || + g_ActivityMan.GetActivity()->IsOtherPlayerBrain((*prevItr), m_Controller.GetPlayer())); + + Vector iconPos = cpuPos; + // Only continue if there are available adjacent Actors + if ((*prevItr) != (*selfItr) && (*nextItr) != (*selfItr)) { + pPrevAdj = *prevItr; + pNextAdj = *nextItr; + // Only draw both lines if they're not pointing to the same thing + if (pPrevAdj != pNextAdj) { + g_FrameMan.DrawLine(pTargetBitmap, cpuPos, pPrevAdj->GetCPUPos() - targetPos, prevColor, prevColor, prevSpacing, 0, true); + g_FrameMan.DrawLine(pTargetBitmap, cpuPos, pNextAdj->GetCPUPos() - targetPos, nextColor, nextColor, nextSpacing, 0, true); + } + // If only one other available Actor, only draw one yellow line to it + else + g_FrameMan.DrawLine(pTargetBitmap, cpuPos, pNextAdj->GetCPUPos() - targetPos, 122, 122, 3, 0, true); + + // Prev selected icon + iconPos = pPrevAdj->GetCPUPos() - targetPos; + draw_sprite(pTargetBitmap, pPrevAdj->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); + + // Next selected icon + iconPos = pNextAdj->GetCPUPos() - targetPos; + draw_sprite(pTargetBitmap, pNextAdj->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); + } + + // Self selected icon + iconPos = cpuPos; + draw_sprite(pTargetBitmap, GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); + /* Too many lines, confusing! + // Again get the next and previous actors in the list + if (++prevItr == pRoster->rend()) + prevItr = pRoster->rbegin(); + if (++nextItr == pRoster->end()) + nextItr = pRoster->begin(); + g_FrameMan.DrawLine(pTargetBitmap, pPrevAdj->GetCPUPos() - targetPos, (*prevItr)->GetCPUPos() - targetPos, prevColor, prevColor, 12, 0, true); + g_FrameMan.DrawLine(pTargetBitmap, pNextAdj->GetCPUPos() - targetPos, (*nextItr)->GetCPUPos() - targetPos, nextColor, nextColor, 12, 0, true); + // Prev selected icon + iconPos = (*prevItr)->GetCPUPos(); + draw_sprite(pTargetBitmap, (*prevItr)->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); + // Next selected icon + iconPos = (*nextItr)->GetCPUPos(); + draw_sprite(pTargetBitmap, (*nextItr)->GetAIModeIcon(), iconPos.m_X - 6, iconPos.m_Y - 6); + */ + } + } + } + } } // namespace RTE diff --git a/Source/Entities/Actor.h b/Source/Entities/Actor.h index 1f1f0e648..e12b27631 100644 --- a/Source/Entities/Actor.h +++ b/Source/Entities/Actor.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -18,1625 +17,1600 @@ #include "PieMenu.h" #include "PathFinder.h" -namespace RTE -{ - +namespace RTE { #pragma region Global Macro Definitions - #define DefaultPieMenuNameGetter(DEFAULTPIEMENUNAME) \ - std::string GetDefaultPieMenuName() const override { return DEFAULTPIEMENUNAME; } +#define DefaultPieMenuNameGetter(DEFAULTPIEMENUNAME) \ + std::string GetDefaultPieMenuName() const override { return DEFAULTPIEMENUNAME; } #pragma endregion -class AtomGroup; -class HeldDevice; + class AtomGroup; + class HeldDevice; #define AILINEDOTSPACING 16 -////////////////////////////////////////////////////////////////////////////////////////// -// Class: Actor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A sprite movable object that is autonomous. -// Parent(s): MOSRotating. -// Class history: 04/13/2001 Actor created. - -class Actor : public MOSRotating { - friend struct EntityLuaBindings; - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - enum Status - { - STABLE = 0, - UNSTABLE, - INACTIVE, - DYING, - DEAD, - StatusCount - }; - - // TODO - move into ALocomotable intermediate class under ACrab/AHuman - enum MovementState - { - NOMOVE = 0, - STAND, - WALK, - JUMP, - DISLODGE, - CROUCH, - CRAWL, - ARMCRAWL, - CLIMB, - MOVEMENTSTATECOUNT - }; - - enum AIMode - { - AIMODE_NONE = 0, - AIMODE_SENTRY, - AIMODE_PATROL, - AIMODE_GOTO, - AIMODE_BRAINHUNT, - AIMODE_GOLDDIG, - AIMODE_RETURN, - AIMODE_STAY, - AIMODE_SCUTTLE, - AIMODE_DELIVER, - AIMODE_BOMB, - AIMODE_SQUAD, - AIMODE_COUNT - }; - -// Concrete allocation and cloning definitions -EntityAllocation(Actor); -AddScriptFunctionNames(MOSRotating, "ThreadedUpdateAI", "UpdateAI", "OnControllerInputModeChange"); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: Actor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a Actor object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - Actor() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~Actor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a Actor object before deletion -// from system memory. -// Arguments: None. - - ~Actor() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Actor object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Actor to be identical to another, by deep copy. -// Arguments: A reference to the Actor to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const Actor &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire Actor, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); MOSRotating::Reset(); m_MOType = MovableObject::TypeActor; } - - /// - /// Cleans up and destroys the script state of this object, calling the Destroy callback in lua - /// - void DestroyScriptState(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - /// - /// Gets the mass of this Actor's inventory. Does not include any equipped item (for actor subtypes that have that). - /// - /// The mass of this Actor's inventory. - float GetInventoryMass() const; - - /// - /// Gets the mass of this Actor, including the mass of its Attachables, wounds and inventory. - /// - /// The mass of this Actor, its inventory and all its Attachables and wounds in Kilograms (kg). - float GetMass() const override { return MOSRotating::GetMass() + GetInventoryMass() + (m_GoldCarried * g_SceneMan.GetKgPerOz()); } - - /// - /// Gets the mass that this actor had upon spawning, i.e with ini-defined inventory, gold and holding no items - /// - /// The base mass of this Actor, in Kilograms (kg). - float GetBaseMass(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets this Actor's Controller. Ownership IS NOT transferred! -// Arguments: None. -// Return value: A const pointer to this Actor's Controller. - - Controller * GetController() { return &m_Controller; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsPlayerControlled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a player is currently controlling this. -// Arguments: None. -// Return value: Whether a player is controlling this. - - bool IsPlayerControlled() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsControllable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells wheter the player can switch control to this at all -// Arguments: None. -// Return value: Whether a player can control this at all. - - virtual bool IsControllable() const { return true; } - - /// - /// Gets whether or not this Actor can be controlled by human players. Note that this does not protect the Actor's Controller from having its input mode forced to CIM_PLAYER (e.g. via Lua). - /// - /// Whether or not this Actor can be controlled by human players. - bool IsPlayerControllable() const { return m_PlayerControllable; } - - /// - /// Sets whether or not this Actor can be controlled by human players. - /// - /// Whether or not this Actor should be able to be controlled by human players. - void SetPlayerControllable(bool playerControllable) { m_PlayerControllable = playerControllable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetStatus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the current Status of this. -// Arguments: None. -// Return value: The status. - - int GetStatus() const { return m_Status; } - - - /// - /// Gets this Actor's health value. - /// - /// A float describing this Actor's health. - float GetHealth() const { return m_Health; } - - /// - /// Gets this Actor's previous health value, prior to this frame. - /// - /// A float describing this Actor's previous health. - float GetPrevHealth() const { return m_PrevHealth; } - - /// - /// Gets this Actor's maximum health value. - /// - /// A float describing this Actor's max health. - float GetMaxHealth() const { return m_MaxHealth; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMaxHealth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets this Actor's maximum health value. -// Arguments: New max health value. -// Return value: None. - - void SetMaxHealth(int newValue) { m_MaxHealth = newValue; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAimDistance -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the distance between the actor and the view point when not -// sharp aiming. -// Arguments: None. -// Return value: A const int describing how far this actor aims/looks by default. - - int GetAimDistance() const { return m_AimDistance; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAimDistance -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the distance between the actor and the view point when not -// sharp aiming. -// Arguments: None. -// Return value: A const int describing how far this actor aims/looks by default. - - void SetAimDistance( int newValue ) { m_AimDistance = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldCarried -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how many ounces of gold this Actor is carrying. -// Arguments: None. -// Return value: The current amount of carried gold, in Oz. - - float GetGoldCarried() const { return m_GoldCarried; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this Actor and all its carried -// gold and inventory. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// Return value: The current value of this Actor and all his carried assets. - - float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically named object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The Preset name of the object to look for. -// Return value: Whetehr the object was found carried by this. - - bool HasObject(std::string objectName) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObjectInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically grouped object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The name of the group to look for. -// Return value: Whetehr the object in the group was found carried by this. - - bool HasObjectInGroup(std::string groupName) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAimAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets this Actor's aim angle. -// Arguments: Whether to adjust the angle for flipping or not. -// Return value: The angle, in radians. - - float GetAimAngle(bool adjustForFlipped = true) const { return adjustForFlipped ? FacingAngle(m_AimAngle) : m_AimAngle; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPassengerSlots -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets this Actor's passenger slots. -// Arguments: None. -// Return value: The Actor's passenger plots - - int GetPassengerSlots() const { return m_PassengerSlots; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetCPUPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' brain, or equivalent. -// Arguments: None. -// Return value: A Vector with the absolute position of this' brain. - - virtual Vector GetCPUPos() const { return m_Pos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEyePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of this' eye, or equivalent, where look -// vector starts from. -// Arguments: None. -// Return value: A Vector with the absolute position of this' eye or view point. - - virtual Vector GetEyePos() const { return m_Pos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAboveHUDPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of the top of this' HUD stack. -// Arguments: None. -// Return value: A Vector with the absolute position of this' HUD stack top point. - - Vector GetAboveHUDPos() const override { return m_Pos + Vector(0, m_HUDStack + 6); } - - - /// - /// Gets the offset position of the holster where this Actor draws his devices from. - /// - /// The offset position of the holster. - Vector GetHolsterOffset() const { return m_HolsterOffset; } - - /// - /// Sets the offset position of the holster where this Actor draws his devices from. - /// - /// A new holster offset. - void SetHolsterOffset(Vector newOffset) { m_HolsterOffset = newOffset; } - - /// - /// Gets the offset position of where this Actor reloads his devices from. - /// - /// The offset position of the where this Actor reloads his devices from. - Vector GetReloadOffset() const { return m_ReloadOffset; } - - /// - /// Sets the offset position of the where this Actor reloads his devices from. - /// - /// The new offset position of where this Actor reloads his devices from. - void SetReloadOffset(Vector newOffset) { m_ReloadOffset = newOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetViewPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the point at which this actor is viewing, or that the scene frame -// should be centered on if tracking this Actor's view. In absolute scene -// coordinates. -// Arguments: None. -// Return value: The point in absolute scene coordinates. - - Vector GetViewPoint() const { return m_ViewPoint.IsZero() ? m_Pos : m_ViewPoint; } - - - /// - /// Gets the item that is within reach of the Actor at this frame, ready to be be picked up. Ownership is NOT transferred! - /// - /// A pointer to the item that has been determined to be within reach of this Actor, if any. - HeldDevice * GetItemInReach() const { return m_pItemInReach; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLookVector -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the direction where this is looking/aiming. -// Arguments: None. -// Return value: A Vector with the direction in which this is looking along. - - Vector GetLookVector() const { return m_ViewPoint - GetEyePos(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSharpAimProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the normalized amount of sharp aim that has been achieved by this. -// Arguments: None. -// Return value: Sharp aim progress between 0 - 1.0. 1.0 is fully aimed. - - float GetSharpAimProgress() const { return m_SharpAimProgress; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the approximate height of this Actor, standing up. -// Arguments: None. -// Return value: A float with the approximate height, in pixels. - - float GetHeight() const { return m_CharHeight; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetControllerMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this Actor's new Controller input mode. -// Arguments: The new input mode. -// The player which will control this if the input mode was set to player. -// Return value: None. - - void SetControllerMode(Controller::InputMode newMode, int newPlayer = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SwapControllerModes -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this Actor's Controller mode and gives back what it used to be. -// Arguments: The new mode to set to. -// The player which will control this if the input mode was set to player. -// Return value: The old mode that it had before. - - Controller::InputMode SwapControllerModes(Controller::InputMode newMode, int newPlayer = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetStatus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this Actor's status. -// Arguments: A Status enumeration. -// Return value: None. - - void SetStatus(Actor::Status newStatus) { m_Status = newStatus; if (newStatus == Actor::Status::UNSTABLE) { m_StableRecoverTimer.Reset(); } } - - /// Gets this Actor's MovementState. - /// - /// This Actor's MovementState. - MovementState GetMovementState() const { return m_MoveState; } - - /// - /// Sets this Actor's MovementState to the new state. - /// - /// This Actor's new MovementState. - void SetMovementState(MovementState newMovementState) { m_MoveState = newMovementState; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this Actor belongs to. -// Arguments: The assigned team number. -// Return value: None. - - void SetTeam(int team) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetGoldCarried -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets how many ounces of gold this Actor is carrying. -// Arguments: The new amount of carried gold, in Oz. -// Return value: None. - - void SetGoldCarried(float goldOz) { m_GoldCarried = goldOz; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAimAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this Actor's aim angle. -// Arguments: A new angle, in radians. -// Return value: None. - - void SetAimAngle(float newAngle) { m_AimAngle = newAngle; Clamp(m_AimAngle, m_AimRange, -m_AimRange); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPassengerSlots -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this Actor's passenger slots. -// Arguments: A new amount of passenger slots. -// Return value: None. - - void SetPassengerSlots(int newPassengerSlots) { m_PassengerSlots = newPassengerSlots; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetViewPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the point at which this actor is viewing, or that the scene frame -// should be centered on if tracking this Actor's view. In absolute scene -// coordinates. -// Arguments: A new point in absolute scene coords. -// Return value: None. - - void SetViewPoint(Vector newPoint) { m_ViewPoint = newPoint; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetItemInReach -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the item that is within reach of the Actor at this frame, so that -// it may be picked up. Ownership is NOT transferred! -// Arguments: A pointer to the item that has been determined to be within reach of -// this Actor. Ownership is NOT transferred! -// Return value: None. - - void SetItemInReach(HeldDevice *pItem) { m_pItemInReach = pItem; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsWithinRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a point on the scene is within range of the currently -// used device and aiming status, if applicable. -// Arguments: A Vector witht he aboslute coordinates of a point to check. -// Return value: Whether the point is within range of this. - - virtual bool IsWithinRange(Vector &point) const { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Look -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Casts an unseen-revealing ray in the direction of where this is facing. -// Arguments: The degree angle to deviate from the current view point in the ray -// casting. A random ray will be chosen out of this +-range. -// The range, in pixels, that the ray will have. -// Return value: Whether any unseen pixels were revealed by this look. - - virtual bool Look(float FOVSpread, float range); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddGold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a certain amount of ounces of gold to this' team's total funds. -// Arguments: The amount in Oz with which to change this' team's gold tally. -// Return value: None. - - void AddGold(float goldOz); - - - /// - /// Does the calculations necessary to detect whether this Actor is at rest or not. IsAtRest() retrieves the answer. - /// - void RestDetection() override; - - /// - /// Adds health points to this Actor's current health value. - /// - /// A float specifying the value to add. - /// The resulting total health of this Actor. - const float AddHealth(const float addedHealth) { return m_Health += addedHealth; } - - /// - /// Sets this Actor's current health value. - /// - /// A float specifying the value to set to. - void SetHealth(const float setHealth) { m_Health = setHealth; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsStatus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if this Actor is in a specific status. -// Arguments: Which status to check for. -// Return value: A bool with the answer. - - bool IsStatus(Status which) const { return m_Status == which; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDead -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if this Actor is dead. -// Arguments: None. -// Return value: A const bool with the answer. - - bool IsDead() const { return m_Status == DEAD; } - - /// - /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. - /// - /// The SliceType of the PieSlice being handled. - /// Whether or not the activated PieSlice SliceType was able to be handled. - virtual bool HandlePieCommand(PieSlice::SliceType pieSliceType) { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAIMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets this' AI mode. -// Arguments: None. -// Return value: The current AI mode. - - int GetAIMode() const { return m_AIMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAIModeIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the icon bitmap associated with this' current AI mode and team. -// Arguments: None. -// Return value: The current AI mode icon of this. Ownership is NOT transferred! - - BITMAP * GetAIModeIcon(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetAIMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this' AI mode. -// Arguments: The new AI mode. -// Return value: None. - - void SetAIMode(AIMode newMode = AIMODE_SENTRY) { m_AIMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: AddAISceneWaypoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an absolute scene point to the list of waypoints this is going to -// go to, in order -// Arguments: The new scene point this should try to get to after all other waypoints -// are reached. -// Return value: None. - - void AddAISceneWaypoint(const Vector &waypoint) { m_Waypoints.push_back(std::pair(waypoint, (MovableObject*)NULL)); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: AddAIMOWaypoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an MO in the scene as the next waypoint for this to go to, in order -// Arguments: The new MO this should try to get to after all other waypoints are reached. -// OWNERSHIP IS NOT TRANSFERRED! -// Return value: None. - - void AddAIMOWaypoint(const MovableObject *pMOWaypoint); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ClearAIWaypoints -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes all AI waypoints and clears the current path to the current -// waypoint. The AI Actor will stop in its tracks. -// Arguments: None. -// Return value: None. - - void ClearAIWaypoints() { m_pMOMoveTarget = 0; m_Waypoints.clear(); m_MovePath.clear(); m_MoveTarget = m_Pos; m_MoveVector.Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLastAIWaypoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the last or furthest set AI waypoint of this. If none, this' pos -// is returned. -// Arguments: None. -// Return value: The furthest set AI waypoint of this. - - Vector GetLastAIWaypoint() const { if (!m_Waypoints.empty()) { return m_Waypoints.back().first; } else if (!m_MovePath.empty()) { return m_MovePath.back(); } return m_Pos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetLastMOWaypointID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ID of the last set AI MO waypoint of this. If none, g_NoMOID is returned. -// Arguments: None. -// Return value: The furthest set AI MO waypoint of this. - - MOID GetAIMOWaypointID() const; - - /// - /// Gets the list of waypoints for this Actor. - /// - /// The list of waypoints for this Actor. - const std::list> & GetWaypointList() const { return m_Waypoints; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetWaypointsSize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how many waypoints this actor have. -// Arguments: None. -// Return value: How many waypoints. - - int GetWaypointsSize() { return m_Waypoints.size(); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ClearMovePath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the list of coordinates in this' current MovePath, ie the path -// to the next Waypoint. -// Arguments: None. -// Return value: None. - - void ClearMovePath() { m_MovePath.clear(); m_MoveTarget = m_Pos; m_MoveVector.Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: AddToMovePathBeginning -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a coordinate to the beginning of the MovePath, meaning the one -// closest to this Actor. -// Arguments: The new coordinate to add to the front of the MovePath. -// Return value: None. - - void AddToMovePathBeginning(Vector newCoordinate) { m_MovePath.push_front(newCoordinate); m_MoveTarget = newCoordinate; m_MoveVector.Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: AddToMovePathEnd -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a coordinate to the end of the MovePath, meaning the one -// closest to this Actor's next waypoint. -// Arguments: The new coordinate to add to the end of the MovePath. -// Return value: None. - - void AddToMovePathEnd(Vector newCoordinate) { m_MovePath.push_back(newCoordinate); } - - /// - /// Gets the last position in this Actor's move path. - /// - /// The last position in this Actor's move path. - Vector GetMovePathEnd() const { return m_MovePath.back(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveMovePathBeginning -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a coordinate from the beginning of the MovePath, meaning the -// one closest to this Actor. -// Arguments: None. -// Return value: Whether there was any coordinate to remove. If false, the MovePath -// is empty. - - bool RemoveMovePathBeginning() { if (!m_MovePath.empty()) { m_MovePath.pop_front(); m_MoveTarget = m_MovePath.empty() ? m_Pos : m_MovePath.front(); m_MoveVector.Reset(); return true; } return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: RemoveMovePathEnd -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a coordinate from the end of the MovePath, meaning the -// one farthest from this Actor. -// Arguments: None. -// Return value: Whether there was any coordinate to remove. If false, the MovePath -// is empty. - - bool RemoveMovePathEnd() { if (!m_MovePath.empty()) { m_MovePath.pop_back(); return true; } return false; } - - /// - /// Gets a pointer to the MovableObject move target of this Actor. - /// - /// A pointer to the MovableObject move target of this Actor. - const MovableObject * GetMOMoveTarget() const { return m_pMOMoveTarget; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPerceptiveness -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this' perceptiveness to alarming events going on around him. -// Arguments: The current perceptiveness, 0.0 - 1.0 -// Return value: None. - - void SetPerceptiveness(float newPerceptiveness) { m_Perceptiveness = newPerceptiveness; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPerceptiveness -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets this' perceptiveness to alarming events going on around him. -// Arguments: None. -// Return value: The current perceptiveness, 0.0 - 1.0 - - float GetPerceptiveness() const { return m_Perceptiveness; } - - - /// - /// Gets whether this actor is able to reveal unseen areas by looking. - /// - /// Whether this actor can reveal unseen areas. - bool GetCanRevealUnseen() const { return m_CanRevealUnseen; } - - /// - /// Sets whether this actor can reveal unseen areas by looking. - /// - /// Whether this actor can reveal unseen areas. - void SetCanRevealUnseen(bool newCanRevealUnseen) { m_CanRevealUnseen = newCanRevealUnseen; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPainThreshold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this' PainThreshold value above which it will play PainSound -// Arguments: Desired PainThreshold value -// Return value: None. - - void SetPainThreshold(float newPainThreshold) { m_PainThreshold = newPainThreshold; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPainThreshold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets this' PainThreshold value above which it will play PainSound -// Arguments: None. -// Return value: The current PainThreshold - - float GetPainThreshold() const { return m_PainThreshold; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AlarmPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this alarmed about a certian point on in the scene, overriding -// the current AI mode until a certain time has passed. -// Arguments: The new scene point this should look at and see if anything dangerous -// is there. -// Return value: None. - - void AlarmPoint(const Vector &alarmPoint) { if (m_AlarmSound && m_AlarmTimer.IsPastSimTimeLimit()) { m_AlarmSound->Play(alarmPoint); } if (m_AlarmTimer.GetElapsedSimTimeMS() > 50) { m_AlarmTimer.Reset(); m_LastAlarmPos = m_PointingTarget = alarmPoint; } } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAlarmPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets any point on the scene this actor should be alarmed about this frame. -// Arguments: None. -// Return value: The new scene point this should look at and see if anything dangerous -// is there or (0,0) if nothing is alarming. - - Vector GetAlarmPoint() { if (m_AlarmTimer.GetElapsedSimTimeMS() > g_TimerMan.GetDeltaTimeMS()) { return Vector(); } return m_LastAlarmPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: AddInventoryItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an inventory item to this Actor. -// Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! -// Return value: None.. - - virtual void AddInventoryItem(MovableObject *pItemToAdd) { AddToInventoryBack(pItemToAdd); } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveInventoryItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a specified item from the actor's inventory. Only one item is removed at a time. -// Arguments: Preset name of an item to remove. -// Return value: None. - - void RemoveInventoryItem(const std::string &presetName) { RemoveInventoryItem("", presetName); } - - /// - /// Removes the first inventory item with the given module name and preset name. - /// - /// The module name of the item to remove. - /// The preset name of the item to remove. - void RemoveInventoryItem(const std::string &moduleName, const std::string &presetName); - - /// - /// Removes and returns the inventory item at the given index. Ownership IS transferred. - /// - /// The index of the inventory item to remove. - /// An owning pointer to the removed inventory item. - MovableObject * RemoveInventoryItemAtIndex(int inventoryIndex); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SwapNextInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Swaps the next MovableObject carried by this Actor and puts one not -// currently carried into the into the back of the inventory of this. -// Arguments: A pointer to the external MovableObject to trade in. Ownership IS xferred! -// If 0 is passed in, nothing will be added to the inventory. -// Whether to mute the sound on this event. Override for the loading screen hack. -// Return value: The next MovableObject in this Actor's inventory. Ownership IS xferred! -// If there are no MovableObject:s in inventory, 0 will be returned. - - virtual MovableObject * SwapNextInventory(MovableObject *pSwapIn = nullptr, bool muteSound = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SwapPrevInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Swaps the prev MovableObject carried by this Actor and puts one not -// currently carried into the into the back of the inventory of this. -// Arguments: A pointer to the external MovableObject to trade in. Ownership IS xferred! -// If 0 is passed in, nothing will be added to the inventory. -// Return value: The prev MovableObject in this Actor's inventory. Ownership IS xferred! -// If there are no MovableObject:s in inventory, 0 will be returned. - - virtual MovableObject * SwapPrevInventory(MovableObject *pSwapIn = nullptr); - - /// - /// Swaps the inventory items at the given indices. Will return false if a given index is invalid. - /// - /// The index of one item. - /// The index of the other item. - /// Whether or not the swap was successful. - bool SwapInventoryItemsByIndex(int inventoryIndex1, int inventoryIndex2); - - /// - /// Sets the inventory item at the given index as the new inventory item, and gives back the one that was originally there. - /// If an invalid index is given, the new item will be put in the back of the inventory, and nullptr will be returned. - /// - /// The new item that should be at the given inventory index. Cannot be a nullptr. Ownership IS transferred. - /// The inventory index the new item should be placed at. - /// The inventory item that used to be at the inventory index. Ownership IS transferred. - MovableObject * SetInventoryItemAtIndex(MovableObject *newInventoryItem, int inventoryIndex); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DropAllInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Ejects all inventory items that this is carrying. It may not happen -// instantaneously, so check for ejection being complete with -// IsInventoryEmpty(). -// Arguments: None. -// Return value: None. - - virtual void DropAllInventory(); - - /// - /// Converts all of the Gold carried by this Actor into MovableObjects and ejects them into the Scene. - /// - virtual void DropAllGold(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetInventorySize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells how many things are in the invetory -// Arguments: None. -// Return value: The number of things in the inventory - - int GetInventorySize() const { return m_Inventory.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsInventoryEmpty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether inventory is completely empty -// Arguments: None. -// Return value: Whether inventory is completely empty. - - bool IsInventoryEmpty() { return m_Inventory.empty(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetInventory -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the deque of inventory of this. Ownership is NOT transferred. -// Arguments: None. -// Return value: A const pointer to the inventory deque of this. OWNERSHIP IS NOT TRANSFERRED! - - const std::deque * GetInventory() const { return &m_Inventory; } - - /// - /// Returns the maximum total mass this Actor can carry in its inventory. - /// - /// The maximum carriable mass of this Actor. - float GetMaxInventoryMass() const { return m_MaxInventoryMass; } - - /// - /// Attempts to add an item to the front of our inventory. - /// - /// Whether we succeeded in adding the item. We may fail if the object doesn't exist or is set to delete. - bool AddToInventoryFront(MovableObject *itemToAdd); - - /// - /// Attempts to add an item to the back of our inventory. - /// - /// Whether we succeeded in adding the item. We may fail if the object doesn't exist or is set to delete. - bool AddToInventoryBack(MovableObject *itemToAdd); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAimRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The limit of this actors aiming angle, in each direction, in radians. -// Arguments: None. -// Return value: The arc range of the aiming angle in radians. -// Eg if HalfPI, it means full 180 degree range - - float GetAimRange() const { return m_AimRange; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetAimRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the limit of this actors aiming angle, in each direction, in radians. -// Arguments: The arc range of the aiming angle in radians. -// Eg if HalfPI, it means full 180 degree range -// Return value: None. - - void SetAimRange(float range) { m_AimRange = range; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawWaypoints -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this draw its current waypoints and related data on the scene in -// its HUD drawing stage. -// Arguments: Whether to enable or disable the drawing of the waypoints. -// Return value: None. - - void DrawWaypoints(bool drawWaypoints = true) { m_DrawWaypoints = drawWaypoints; } - - - /// - /// Destroys this MOSRotating and creates its specified Gibs in its place with appropriate velocities. - /// Any Attachables are removed and also given appropriate velocities. - /// - /// The impulse (kg * m/s) of the impact causing the gibbing to happen. - /// A pointer to an MO which the Gibs and Attachables should not be colliding with. - void GibThis(const Vector &impactImpulse = Vector(), MovableObject *movableObjectToIgnore = nullptr) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. -// Arguments: Reference to the HitData struct which describes the collision. This -// will be modified to represent the results of the collision. -// Return value: Whether the collision has been deemed valid. If false, then disregard -// any impulses in the Hitdata. - - bool CollideAtPoint(HitData &hitData) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ParticlePenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Determines whether a particle which has hit this MO will penetrate, -// and if so, whether it gets lodged or exits on the other side of this -// MO. Appropriate effects will be determined and applied ONLY IF there -// was penetration! If not, nothing will be affected. -// Arguments: The HitData describing the collision in detail, the impulses have to -// have been filled out! -// Return value: Whether the particle managed to penetrate into this MO or not. If -// somehting but a MOPixel or MOSParticle is being passed in as hitor, -// false will trivially be returned here. - - bool ParticlePenetration(HitData &hd) override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done before Travel(). Always call before -// calling Travel. -// Arguments: None. -// Return value: None. - - void PreTravel() override { MOSRotating::PreTravel(); m_GoldPicked = false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMovePathToUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this' AI's move path to be updated. Will update the path to the -// current waypoint, if any. -// Arguments: None. -// Return value: None. - - void SetMovePathToUpdate() { m_UpdateMovePath = true; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMovePathSize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how many waypoints there are in the MovePath currently -// Arguments: None. -// Return value: The number of waypoints in the MovePath. - - int GetMovePathSize() const { return m_MovePath.size(); } - - /// - /// Starts updating this Actor's movepath. - /// - virtual void UpdateMovePath(); - - /// - /// Returns whether we're waiting on a new pending movepath. - /// - /// Whether we're waiting on a new pending movepath. - bool IsWaitingOnNewMovePath() const { return m_PathRequest != nullptr || m_UpdateMovePath; } - - /// - /// Estimates what material strength this actor can penetrate. - /// - /// The actor's dig strength. - virtual float EstimateDigStrength() const; - - /// - /// Gets this Actor's base dig strength, or the strength of terrain they can expect to walk through without tools. - /// - /// The actors base dig strength. - float GetAIBaseDigStrength() const { return m_AIBaseDigStrength; } - - /// - /// Sets this Actor's base dig strength, or the strength of terrain they can expect to walk through without tools. - /// - /// The new base dig strength for this Actor. - void SetAIBaseDigStrength(float newAIBaseDigStrength) { m_AIBaseDigStrength = newAIBaseDigStrength; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreControllerUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - virtual void PreControllerUpdate(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: FullUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the full state of this object in one call. (PreControllerUpdate(), Controller::Update(), and Update()) -// Arguments: None. -// Return value: None. - - virtual void FullUpdate() override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetDeploymentID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets deployment ID for this actor -// Arguments: New deployment id. -// Return value: None. - - void SetDeploymentID(unsigned int newID) { m_DeploymentID = newID; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeploymentID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets deployment ID of this actor -// Arguments: None. -// Return value: Returns deployment id of this actor. - - unsigned int GetDeploymentID() const { return m_DeploymentID; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetSightDistance -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns actor's sight distance. -// Arguments: None. -// Return value: Returns actor's sight distance. - - float GetSightDistance() const { return m_SightDistance; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetSightDistance -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets actor's sight distance. -// Arguments: New sight distance value. -// Return value: None. - - void SetSightDistance(float newValue) { m_SightDistance = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// Which player's screen this is being drawn to. May affect what HUD elements -// get drawn etc. -// Return value: None. - - void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: VerifyMOIDIndex -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Verifieis whether all actor's MO has correct IDs. Should be used in Debug mode only. -// Arguments: None. -// Return value: None. - - void VerifyMOIDs(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTravelImpulseDamage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns Threshold for taking damage from travel impulses, in kg * m/s -// Arguments: None. -// Return value: Threshold for taking damage from travel impulses, in kg * m/s - - float GetTravelImpulseDamage() const { return m_TravelImpulseDamage; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTravelImpulseDamage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets Threshold for taking damage from travel impulses, in kg * m/s -// Arguments: Threshold for taking damage from travel impulses, in kg * m/s -// Return value: None. - - void SetTravelImpulseDamage(float value) { m_TravelImpulseDamage = value; } - - - /// - /// Gets this Actor's body hit sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this Actor's body hit sound. - SoundContainer * GetBodyHitSound() const { return m_BodyHitSound; } - - /// - /// Sets this Actor's body hit sound. Ownership IS transferred! - /// - /// The new SoundContainer for this Actor's body hit sound. - void SetBodyHitSound(SoundContainer *newSound) { m_BodyHitSound = newSound; } - - /// - /// Gets this Actor's alarm sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this Actor's alarm sound. - SoundContainer * GetAlarmSound() const { return m_AlarmSound; } - - /// - /// Sets this Actor's alarm sound. Ownership IS transferred! - /// - /// The new SoundContainer for this Actor's alarm sound. - void SetAlarmSound(SoundContainer *newSound) { m_AlarmSound = newSound; } - - /// - /// Gets this Actor's pain sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this Actor's pain sound. - SoundContainer * GetPainSound() const { return m_PainSound; } - - /// - /// Sets this Actor's pain sound. Ownership IS transferred! - /// - /// The new SoundContainer for this Actor's pain sound. - void SetPainSound(SoundContainer *newSound) { m_PainSound = newSound; } - - /// - /// Gets this Actor's death sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this Actor's death sound. - SoundContainer * GetDeathSound() const { return m_DeathSound; } - - /// - /// Sets this Actor's death sound. Ownership IS transferred! - /// - /// The new SoundContainer for this Actor's death sound. - void SetDeathSound(SoundContainer *newSound) { m_DeathSound = newSound; } - - /// - /// Gets this Actor's device switch sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this Actor's device switch sound. - SoundContainer * GetDeviceSwitchSound() const { return m_DeviceSwitchSound; } - - /// - /// Sets this Actor's device switch sound. Ownership IS transferred! - /// - /// The new SoundContainer for this Actor's device switch sound. - void SetDeviceSwitchSound(SoundContainer *newSound) { m_DeviceSwitchSound = newSound; } - - /// - /// Gets the X and Y thresholds for how fast the actor can travel before losing stability. - /// - /// A Vector with the X and Y thresholds for how fast the actor can travel before losing stability. - Vector GetStableVel() const { return m_StableVel; } - - /// - /// Sets the X and Y thresholds for how fast the actor can travel before losing stability. - /// - /// New value for how fast the actor can travel before losing stability on X axis. - /// New value for how fast the actor can travel before losing stability on Y axis. - void SetStableVel(float newVelX, float newVelY) { m_StableVel.SetXY(newVelX, newVelY); } - - /// - /// Sets the X and Y thresholds for how fast the actor can travel before losing stability. - /// - /// Vector with new values for how fast the actor can travel before losing stability on both axis. - void SetStableVel(Vector newVelVector) { m_StableVel = newVelVector; } - - /// - /// Gets the recovery delay from UNSTABLE to STABLE, in MS. - /// - /// The recovery delay, in MS. - int GetStableRecoverDelay() const { return m_StableRecoverDelay; } - - /// - /// Sets the recovery delay from UNSTABLE to STABLE, in MS. - /// - /// The recovery delay, in MS. - void SetStableRecoverDelay(int newRecoverDelay) { m_StableRecoverDelay = newRecoverDelay; } - - /// - /// Gets the distance in which the Actor will have considered itself to have reached it's waypoint. - /// - /// The move proximity limit. - float GetMoveProximityLimit() const { return m_MoveProximityLimit; } - - /// - /// Sets the distance in which the Actor will have considered itself to have reached it's waypoint. - /// - /// The move proximity limit. - void SetMoveProximityLimit(float newProximityLimit) { m_MoveProximityLimit = newProximityLimit; } - - /// - /// Gets whether or not this Actor has the organic flag set and should be considered as organic. - /// - /// Whether or not this Actor has the organic flag set and should be considered as organic. - bool IsOrganic() const { return m_Organic; } - - /// - /// Gets whether or not this Actor has the mechanical flag set and should be considered as mechanical. - /// - /// Whether or not this Actor has the mechanical flag set and should be considered as mechanical. - bool IsMechanical() const { return m_Mechanical; } - - /// - /// Gets whether or not this Actor's limb push forces have been disabled. - /// - /// Whether or not this Actor's limb push forces have been disabled. - bool GetLimbPushForcesAndCollisionsDisabled() const { return m_LimbPushForcesAndCollisionsDisabled; } - - /// - /// Sets whether or not this Actor's limb push forces should be disabled. - /// - /// Whether or not this Actor's limb push forces should be disabled. - void SetLimbPushForcesAndCollisionsDisabled(bool newLimbPushForcesAndCollisionsDisabled) { m_LimbPushForcesAndCollisionsDisabled = newLimbPushForcesAndCollisionsDisabled; } - - /// - /// Gets the default PieMenu name for this type. - /// - /// The default PieMenu name for this type. - virtual std::string GetDefaultPieMenuName() const { return "Default Actor Pie Menu"; } - - /// - /// Gets a pointer to the PieMenu for this Actor. Ownership is NOT transferred. - /// - /// The PieMenu for this Actor. - PieMenu * GetPieMenu() const { return m_PieMenu.get(); } - - /// - /// Sets the PieMenu for this Actor. Ownership IS transferred. - /// - /// The new PieMenu for this Actor. - void SetPieMenu(PieMenu *newPieMenu) { m_PieMenu = std::unique_ptr(newPieMenu); m_PieMenu->Create(this); m_PieMenu->AddWhilePieMenuOpenListener(this, std::bind(&Actor::WhilePieMenuOpenListener, this, m_PieMenu.get())); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Function that is called when we get a new movepath. - /// This processes and cleans up the movepath. - /// - virtual void OnNewMovePath(); - - // Member variables - static Entity::ClassInfo m_sClass; - - enum ActionState - { - MOVING = 0, - MOVING_FAST, - FIRING, - ActionStateCount - }; - - enum AimState - { - AIMSTILL = 0, - AIMUP, - AIMDOWN, - AimStateCount - }; - - AtomGroup *m_pHitBody; - Controller m_Controller; - bool m_PlayerControllable; //!< Whether or not this Actor can be controlled by human players. - - // Sounds - SoundContainer *m_BodyHitSound; - SoundContainer *m_AlarmSound; - SoundContainer *m_PainSound; - SoundContainer *m_DeathSound; - SoundContainer *m_DeviceSwitchSound; - - int m_Status; - float m_Health; - // Maximum health - float m_MaxHealth; - // The health of the previous frame, so we can track damage - float m_PrevHealth; - // Not owned by this! - const Icon *m_pTeamIcon; - // Not owned by this! - const Icon *m_pControllerIcon; - // Timing the last second to store the position each second so we can determine larger movement - Timer m_LastSecondTimer; - // This' position up to a second ago - Vector m_LastSecondPos; - // Movement since last whole second - Vector m_RecentMovement; - // Threshold for taking damage from travel impulses, in kg * m/s - float m_TravelImpulseDamage; - // Timer for timing the delay before regaining stability after losing it - Timer m_StableRecoverTimer; - // Thresholds in both x and y for how fast the actor can travel before losing stability. Meters per second (m/s). - Vector m_StableVel; - int m_StableRecoverDelay; //!< The delay before regaining stability after losing it, in MS - // Timer for the heartbeat of this Actor - Timer m_HeartBeat; - // Timer for timing how long this has been under Control - Timer m_NewControlTmr; - // Death timing timer - Timer m_DeathTmr; - // Amount of Gold carried, in ounces. - float m_GoldCarried; - // Whether or not any gold was picked up this frame. - bool m_GoldPicked; - // Aiming state - char m_AimState; - // The arc range of the aiming angle, in each direction, in radians. Eg if HalfPI, it means full 180 degree range - float m_AimRange; - // Current Aim angle within the AimRange - float m_AimAngle; - // How far the actor aims/looks by default - float m_AimDistance; - // Aiming timing timer - Timer m_AimTmr; - // For timing the transition from regular aim to sharp aim - Timer m_SharpAimTimer; - // The time it takes to achieve complete full sharp aiming - int m_SharpAimDelay; - // The velocity - float m_SharpAimSpeed; - // Normalzied scalar showing storing much sharp aim progress has been made - float m_SharpAimProgress; - // If sharp aim has been maxed out, ie it's either at its max, or being limited by some obstruction - bool m_SharpAimMaxedOut; - // Point at this target when devicestate is in POINTING mode - Vector m_PointingTarget; - // Last seen enemy target - Vector m_SeenTargetPos; - // Timer measuring how long this has been alarmed by a nearby gunshot etc. - Timer m_AlarmTimer; - // Position of the last thing that alarmed us - Vector m_LastAlarmPos; - // How far this guy's AI can see when he's just looking ahead - float m_SightDistance; - // How perceptive this is of alarming events going on around him, 0.0 - 1.0 - float m_Perceptiveness; - /// Damage value above which this will play PainSound - float m_PainThreshold; - // Whether or not this actor can reveal unseen areas by looking - bool m_CanRevealUnseen; - // About How tall is the Actor, in pixels? - float m_CharHeight; - // Speed at which the m_AimAngle will change, in radians/s. -// float - // The offset position of the holster where this Actor draws his devices from. - Vector m_HolsterOffset; - Vector m_ReloadOffset; //!< The offset position of where this Actor reloads his devices from. - // The point at which this actor is viewing, or the scene frame - // should be centered on if tracking this Actor's view. - // In absolute scene coordinates. - Vector m_ViewPoint; - // The inventory of carried MovableObjects of this Actor. They are also Owned by this. - std::deque m_Inventory; - float m_MaxInventoryMass; //!< The mass limit for this Actor's inventory. -1 means there's no limit. - // The device that can/will be picked up - HeldDevice *m_pItemInReach; - // HUD positioning aid - int m_HUDStack; - // ID of deployment which spawned this actor - unsigned int m_DeploymentID; - // How many passenger slots this actor will take in a craft - int m_PassengerSlots; - // Most actors can walk through stuff that's soft enough, so we start with a base penetration amount - float m_AIBaseDigStrength; - // The mass that this actor had upon spawning, i.e with no inventory, no gold and holding no items - float m_BaseMass; - - //////////////////// - // AI States - - enum LateralMoveState - { - LAT_STILL = 0, - LAT_LEFT, - LAT_RIGHT - }; - - enum ObstacleState - { - PROCEEDING = 0, - BACKSTEPPING, - DIGPAUSING, - JUMPING, - SOFTLANDING - }; - - enum TeamBlockState - { - NOTBLOCKED = 0, - BLOCKED, - IGNORINGBLOCK, - FOLLOWWAIT - }; - // Unknown team icon - static std::vector m_apNoTeamIcon; - // The AI mode icons - static BITMAP *m_apAIIcons[AIMODE_COUNT]; - // Selection arrow - static std::vector m_apSelectArrow; - // Selection arrow - static std::vector m_apAlarmExclamation; - // Whether the static icons have been loaded yet or not - static bool m_sIconsLoaded; - // The current mode the AI is set to perform as - AIMode m_AIMode; - // The list of waypoints remaining between which the paths are made. If this is empty, the last path is in teh MovePath - // The MO pointer in the pair is nonzero if the waypoint is tied to an MO in the scene, and gets updated each UpdateAI. This needs to be checked for validity/existence each UpdateAI - std::list > m_Waypoints; - // Whether to draw the waypoints or not in the HUD - bool m_DrawWaypoints; - // Absolute target to move to on the scene; this is usually the point at the front of the movepath list - Vector m_MoveTarget; - // The MO we're currently following, if any. If still valid, this' position will update the MoveTarget each UpdateAI. - const MovableObject *m_pMOMoveTarget; - // The point previous on the path to the one currently assigned the move target - Vector m_PrevPathTarget; - // The relative, scene-wrapped difference between the current m_Pos and the m_MoveTarget. - Vector m_MoveVector; - // The calculated path to get to that move-to target - std::list m_MovePath; - // The current pathfinding request - std::shared_ptr m_PathRequest; - // Whether it's time to update the path - bool m_UpdateMovePath; - // The minimum range to consider having reached a move target is considered - float m_MoveProximityLimit; - // Current movement state. - MovementState m_MoveState; - - bool m_Organic; //!< Flag for whether or not this Actor is organic. Useful for lua purposes and mod support. - bool m_Mechanical; //!< Flag for whether or not this Actor is robotic. Useful for lua purposes and mod support. - - bool m_LimbPushForcesAndCollisionsDisabled; // m_PieMenu; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Actor, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - // Disallow the use of some implicit methods. - Actor(const Actor &reference) = delete; - Actor & operator=(const Actor &rhs) = delete; - -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: Actor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A sprite movable object that is autonomous. + // Parent(s): MOSRotating. + // Class history: 04/13/2001 Actor created. + + class Actor : public MOSRotating { + friend struct EntityLuaBindings; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + enum Status { + STABLE = 0, + UNSTABLE, + INACTIVE, + DYING, + DEAD, + StatusCount + }; + + // TODO - move into ALocomotable intermediate class under ACrab/AHuman + enum MovementState { + NOMOVE = 0, + STAND, + WALK, + JUMP, + DISLODGE, + CROUCH, + CRAWL, + ARMCRAWL, + CLIMB, + MOVEMENTSTATECOUNT + }; + + enum AIMode { + AIMODE_NONE = 0, + AIMODE_SENTRY, + AIMODE_PATROL, + AIMODE_GOTO, + AIMODE_BRAINHUNT, + AIMODE_GOLDDIG, + AIMODE_RETURN, + AIMODE_STAY, + AIMODE_SCUTTLE, + AIMODE_DELIVER, + AIMODE_BOMB, + AIMODE_SQUAD, + AIMODE_COUNT + }; + + // Concrete allocation and cloning definitions + EntityAllocation(Actor); + AddScriptFunctionNames(MOSRotating, "ThreadedUpdateAI", "UpdateAI", "OnControllerInputModeChange"); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Actor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Actor object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Actor() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~Actor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a Actor object before deletion + // from system memory. + // Arguments: None. + + ~Actor() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Actor object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Actor to be identical to another, by deep copy. + // Arguments: A reference to the Actor to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Actor& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Actor, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + MOSRotating::Reset(); + m_MOType = MovableObject::TypeActor; + } + + /// + /// Cleans up and destroys the script state of this object, calling the Destroy callback in lua + /// + void DestroyScriptState(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + /// + /// Gets the mass of this Actor's inventory. Does not include any equipped item (for actor subtypes that have that). + /// + /// The mass of this Actor's inventory. + float GetInventoryMass() const; + + /// + /// Gets the mass of this Actor, including the mass of its Attachables, wounds and inventory. + /// + /// The mass of this Actor, its inventory and all its Attachables and wounds in Kilograms (kg). + float GetMass() const override { return MOSRotating::GetMass() + GetInventoryMass() + (m_GoldCarried * g_SceneMan.GetKgPerOz()); } + + /// + /// Gets the mass that this actor had upon spawning, i.e with ini-defined inventory, gold and holding no items + /// + /// The base mass of this Actor, in Kilograms (kg). + float GetBaseMass(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets this Actor's Controller. Ownership IS NOT transferred! + // Arguments: None. + // Return value: A const pointer to this Actor's Controller. + + Controller* GetController() { return &m_Controller; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsPlayerControlled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a player is currently controlling this. + // Arguments: None. + // Return value: Whether a player is controlling this. + + bool IsPlayerControlled() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsControllable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells wheter the player can switch control to this at all + // Arguments: None. + // Return value: Whether a player can control this at all. + + virtual bool IsControllable() const { return true; } + + /// + /// Gets whether or not this Actor can be controlled by human players. Note that this does not protect the Actor's Controller from having its input mode forced to CIM_PLAYER (e.g. via Lua). + /// + /// Whether or not this Actor can be controlled by human players. + bool IsPlayerControllable() const { return m_PlayerControllable; } + + /// + /// Sets whether or not this Actor can be controlled by human players. + /// + /// Whether or not this Actor should be able to be controlled by human players. + void SetPlayerControllable(bool playerControllable) { m_PlayerControllable = playerControllable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetStatus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the current Status of this. + // Arguments: None. + // Return value: The status. + + int GetStatus() const { return m_Status; } + + /// + /// Gets this Actor's health value. + /// + /// A float describing this Actor's health. + float GetHealth() const { return m_Health; } + + /// + /// Gets this Actor's previous health value, prior to this frame. + /// + /// A float describing this Actor's previous health. + float GetPrevHealth() const { return m_PrevHealth; } + + /// + /// Gets this Actor's maximum health value. + /// + /// A float describing this Actor's max health. + float GetMaxHealth() const { return m_MaxHealth; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMaxHealth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets this Actor's maximum health value. + // Arguments: New max health value. + // Return value: None. + + void SetMaxHealth(int newValue) { m_MaxHealth = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAimDistance + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the distance between the actor and the view point when not + // sharp aiming. + // Arguments: None. + // Return value: A const int describing how far this actor aims/looks by default. + + int GetAimDistance() const { return m_AimDistance; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAimDistance + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the distance between the actor and the view point when not + // sharp aiming. + // Arguments: None. + // Return value: A const int describing how far this actor aims/looks by default. + + void SetAimDistance(int newValue) { m_AimDistance = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldCarried + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how many ounces of gold this Actor is carrying. + // Arguments: None. + // Return value: The current amount of carried gold, in Oz. + + float GetGoldCarried() const { return m_GoldCarried; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this Actor and all its carried + // gold and inventory. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // Return value: The current value of this Actor and all his carried assets. + + float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically named object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The Preset name of the object to look for. + // Return value: Whetehr the object was found carried by this. + + bool HasObject(std::string objectName) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObjectInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically grouped object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The name of the group to look for. + // Return value: Whetehr the object in the group was found carried by this. + + bool HasObjectInGroup(std::string groupName) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAimAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets this Actor's aim angle. + // Arguments: Whether to adjust the angle for flipping or not. + // Return value: The angle, in radians. + + float GetAimAngle(bool adjustForFlipped = true) const { return adjustForFlipped ? FacingAngle(m_AimAngle) : m_AimAngle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPassengerSlots + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets this Actor's passenger slots. + // Arguments: None. + // Return value: The Actor's passenger plots + + int GetPassengerSlots() const { return m_PassengerSlots; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetCPUPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' brain, or equivalent. + // Arguments: None. + // Return value: A Vector with the absolute position of this' brain. + + virtual Vector GetCPUPos() const { return m_Pos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEyePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of this' eye, or equivalent, where look + // vector starts from. + // Arguments: None. + // Return value: A Vector with the absolute position of this' eye or view point. + + virtual Vector GetEyePos() const { return m_Pos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAboveHUDPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of the top of this' HUD stack. + // Arguments: None. + // Return value: A Vector with the absolute position of this' HUD stack top point. + + Vector GetAboveHUDPos() const override { return m_Pos + Vector(0, m_HUDStack + 6); } + + /// + /// Gets the offset position of the holster where this Actor draws his devices from. + /// + /// The offset position of the holster. + Vector GetHolsterOffset() const { return m_HolsterOffset; } + + /// + /// Sets the offset position of the holster where this Actor draws his devices from. + /// + /// A new holster offset. + void SetHolsterOffset(Vector newOffset) { m_HolsterOffset = newOffset; } + + /// + /// Gets the offset position of where this Actor reloads his devices from. + /// + /// The offset position of the where this Actor reloads his devices from. + Vector GetReloadOffset() const { return m_ReloadOffset; } + + /// + /// Sets the offset position of the where this Actor reloads his devices from. + /// + /// The new offset position of where this Actor reloads his devices from. + void SetReloadOffset(Vector newOffset) { m_ReloadOffset = newOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetViewPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the point at which this actor is viewing, or that the scene frame + // should be centered on if tracking this Actor's view. In absolute scene + // coordinates. + // Arguments: None. + // Return value: The point in absolute scene coordinates. + + Vector GetViewPoint() const { return m_ViewPoint.IsZero() ? m_Pos : m_ViewPoint; } + + /// + /// Gets the item that is within reach of the Actor at this frame, ready to be be picked up. Ownership is NOT transferred! + /// + /// A pointer to the item that has been determined to be within reach of this Actor, if any. + HeldDevice* GetItemInReach() const { return m_pItemInReach; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLookVector + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the direction where this is looking/aiming. + // Arguments: None. + // Return value: A Vector with the direction in which this is looking along. + + Vector GetLookVector() const { return m_ViewPoint - GetEyePos(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSharpAimProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the normalized amount of sharp aim that has been achieved by this. + // Arguments: None. + // Return value: Sharp aim progress between 0 - 1.0. 1.0 is fully aimed. + + float GetSharpAimProgress() const { return m_SharpAimProgress; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the approximate height of this Actor, standing up. + // Arguments: None. + // Return value: A float with the approximate height, in pixels. + + float GetHeight() const { return m_CharHeight; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetControllerMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this Actor's new Controller input mode. + // Arguments: The new input mode. + // The player which will control this if the input mode was set to player. + // Return value: None. + + void SetControllerMode(Controller::InputMode newMode, int newPlayer = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SwapControllerModes + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this Actor's Controller mode and gives back what it used to be. + // Arguments: The new mode to set to. + // The player which will control this if the input mode was set to player. + // Return value: The old mode that it had before. + + Controller::InputMode SwapControllerModes(Controller::InputMode newMode, int newPlayer = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetStatus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this Actor's status. + // Arguments: A Status enumeration. + // Return value: None. + + void SetStatus(Actor::Status newStatus) { + m_Status = newStatus; + if (newStatus == Actor::Status::UNSTABLE) { + m_StableRecoverTimer.Reset(); + } + } + + /// Gets this Actor's MovementState. + /// + /// This Actor's MovementState. + MovementState GetMovementState() const { return m_MoveState; } + + /// + /// Sets this Actor's MovementState to the new state. + /// + /// This Actor's new MovementState. + void SetMovementState(MovementState newMovementState) { m_MoveState = newMovementState; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this Actor belongs to. + // Arguments: The assigned team number. + // Return value: None. + + void SetTeam(int team) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetGoldCarried + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets how many ounces of gold this Actor is carrying. + // Arguments: The new amount of carried gold, in Oz. + // Return value: None. + + void SetGoldCarried(float goldOz) { m_GoldCarried = goldOz; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAimAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this Actor's aim angle. + // Arguments: A new angle, in radians. + // Return value: None. + + void SetAimAngle(float newAngle) { + m_AimAngle = newAngle; + Clamp(m_AimAngle, m_AimRange, -m_AimRange); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPassengerSlots + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this Actor's passenger slots. + // Arguments: A new amount of passenger slots. + // Return value: None. + + void SetPassengerSlots(int newPassengerSlots) { m_PassengerSlots = newPassengerSlots; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetViewPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the point at which this actor is viewing, or that the scene frame + // should be centered on if tracking this Actor's view. In absolute scene + // coordinates. + // Arguments: A new point in absolute scene coords. + // Return value: None. + + void SetViewPoint(Vector newPoint) { m_ViewPoint = newPoint; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetItemInReach + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the item that is within reach of the Actor at this frame, so that + // it may be picked up. Ownership is NOT transferred! + // Arguments: A pointer to the item that has been determined to be within reach of + // this Actor. Ownership is NOT transferred! + // Return value: None. + + void SetItemInReach(HeldDevice* pItem) { m_pItemInReach = pItem; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsWithinRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a point on the scene is within range of the currently + // used device and aiming status, if applicable. + // Arguments: A Vector witht he aboslute coordinates of a point to check. + // Return value: Whether the point is within range of this. + + virtual bool IsWithinRange(Vector& point) const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Look + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Casts an unseen-revealing ray in the direction of where this is facing. + // Arguments: The degree angle to deviate from the current view point in the ray + // casting. A random ray will be chosen out of this +-range. + // The range, in pixels, that the ray will have. + // Return value: Whether any unseen pixels were revealed by this look. + + virtual bool Look(float FOVSpread, float range); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddGold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a certain amount of ounces of gold to this' team's total funds. + // Arguments: The amount in Oz with which to change this' team's gold tally. + // Return value: None. + + void AddGold(float goldOz); + + /// + /// Does the calculations necessary to detect whether this Actor is at rest or not. IsAtRest() retrieves the answer. + /// + void RestDetection() override; + + /// + /// Adds health points to this Actor's current health value. + /// + /// A float specifying the value to add. + /// The resulting total health of this Actor. + const float AddHealth(const float addedHealth) { return m_Health += addedHealth; } + + /// + /// Sets this Actor's current health value. + /// + /// A float specifying the value to set to. + void SetHealth(const float setHealth) { m_Health = setHealth; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsStatus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if this Actor is in a specific status. + // Arguments: Which status to check for. + // Return value: A bool with the answer. + + bool IsStatus(Status which) const { return m_Status == which; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDead + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if this Actor is dead. + // Arguments: None. + // Return value: A const bool with the answer. + + bool IsDead() const { return m_Status == DEAD; } + + /// + /// Tries to handle the activated PieSlice in this object's PieMenu, if there is one, based on its SliceType. + /// + /// The SliceType of the PieSlice being handled. + /// Whether or not the activated PieSlice SliceType was able to be handled. + virtual bool HandlePieCommand(PieSlice::SliceType pieSliceType) { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAIMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets this' AI mode. + // Arguments: None. + // Return value: The current AI mode. + + int GetAIMode() const { return m_AIMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAIModeIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the icon bitmap associated with this' current AI mode and team. + // Arguments: None. + // Return value: The current AI mode icon of this. Ownership is NOT transferred! + + BITMAP* GetAIModeIcon(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetAIMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this' AI mode. + // Arguments: The new AI mode. + // Return value: None. + + void SetAIMode(AIMode newMode = AIMODE_SENTRY) { m_AIMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: AddAISceneWaypoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an absolute scene point to the list of waypoints this is going to + // go to, in order + // Arguments: The new scene point this should try to get to after all other waypoints + // are reached. + // Return value: None. + + void AddAISceneWaypoint(const Vector& waypoint) { m_Waypoints.push_back(std::pair(waypoint, (MovableObject*)NULL)); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: AddAIMOWaypoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an MO in the scene as the next waypoint for this to go to, in order + // Arguments: The new MO this should try to get to after all other waypoints are reached. + // OWNERSHIP IS NOT TRANSFERRED! + // Return value: None. + + void AddAIMOWaypoint(const MovableObject* pMOWaypoint); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ClearAIWaypoints + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes all AI waypoints and clears the current path to the current + // waypoint. The AI Actor will stop in its tracks. + // Arguments: None. + // Return value: None. + + void ClearAIWaypoints() { + m_pMOMoveTarget = 0; + m_Waypoints.clear(); + m_MovePath.clear(); + m_MoveTarget = m_Pos; + m_MoveVector.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLastAIWaypoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the last or furthest set AI waypoint of this. If none, this' pos + // is returned. + // Arguments: None. + // Return value: The furthest set AI waypoint of this. + + Vector GetLastAIWaypoint() const { + if (!m_Waypoints.empty()) { + return m_Waypoints.back().first; + } else if (!m_MovePath.empty()) { + return m_MovePath.back(); + } + return m_Pos; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetLastMOWaypointID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ID of the last set AI MO waypoint of this. If none, g_NoMOID is returned. + // Arguments: None. + // Return value: The furthest set AI MO waypoint of this. + + MOID GetAIMOWaypointID() const; + + /// + /// Gets the list of waypoints for this Actor. + /// + /// The list of waypoints for this Actor. + const std::list>& GetWaypointList() const { return m_Waypoints; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetWaypointsSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how many waypoints this actor have. + // Arguments: None. + // Return value: How many waypoints. + + int GetWaypointsSize() { return m_Waypoints.size(); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ClearMovePath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the list of coordinates in this' current MovePath, ie the path + // to the next Waypoint. + // Arguments: None. + // Return value: None. + + void ClearMovePath() { + m_MovePath.clear(); + m_MoveTarget = m_Pos; + m_MoveVector.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: AddToMovePathBeginning + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a coordinate to the beginning of the MovePath, meaning the one + // closest to this Actor. + // Arguments: The new coordinate to add to the front of the MovePath. + // Return value: None. + + void AddToMovePathBeginning(Vector newCoordinate) { + m_MovePath.push_front(newCoordinate); + m_MoveTarget = newCoordinate; + m_MoveVector.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: AddToMovePathEnd + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a coordinate to the end of the MovePath, meaning the one + // closest to this Actor's next waypoint. + // Arguments: The new coordinate to add to the end of the MovePath. + // Return value: None. + + void AddToMovePathEnd(Vector newCoordinate) { m_MovePath.push_back(newCoordinate); } + + /// + /// Gets the last position in this Actor's move path. + /// + /// The last position in this Actor's move path. + Vector GetMovePathEnd() const { return m_MovePath.back(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveMovePathBeginning + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a coordinate from the beginning of the MovePath, meaning the + // one closest to this Actor. + // Arguments: None. + // Return value: Whether there was any coordinate to remove. If false, the MovePath + // is empty. + + bool RemoveMovePathBeginning() { + if (!m_MovePath.empty()) { + m_MovePath.pop_front(); + m_MoveTarget = m_MovePath.empty() ? m_Pos : m_MovePath.front(); + m_MoveVector.Reset(); + return true; + } + return false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RemoveMovePathEnd + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a coordinate from the end of the MovePath, meaning the + // one farthest from this Actor. + // Arguments: None. + // Return value: Whether there was any coordinate to remove. If false, the MovePath + // is empty. + + bool RemoveMovePathEnd() { + if (!m_MovePath.empty()) { + m_MovePath.pop_back(); + return true; + } + return false; + } + + /// + /// Gets a pointer to the MovableObject move target of this Actor. + /// + /// A pointer to the MovableObject move target of this Actor. + const MovableObject* GetMOMoveTarget() const { return m_pMOMoveTarget; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPerceptiveness + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this' perceptiveness to alarming events going on around him. + // Arguments: The current perceptiveness, 0.0 - 1.0 + // Return value: None. + + void SetPerceptiveness(float newPerceptiveness) { m_Perceptiveness = newPerceptiveness; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPerceptiveness + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets this' perceptiveness to alarming events going on around him. + // Arguments: None. + // Return value: The current perceptiveness, 0.0 - 1.0 + + float GetPerceptiveness() const { return m_Perceptiveness; } + + /// + /// Gets whether this actor is able to reveal unseen areas by looking. + /// + /// Whether this actor can reveal unseen areas. + bool GetCanRevealUnseen() const { return m_CanRevealUnseen; } + + /// + /// Sets whether this actor can reveal unseen areas by looking. + /// + /// Whether this actor can reveal unseen areas. + void SetCanRevealUnseen(bool newCanRevealUnseen) { m_CanRevealUnseen = newCanRevealUnseen; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPainThreshold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this' PainThreshold value above which it will play PainSound + // Arguments: Desired PainThreshold value + // Return value: None. + + void SetPainThreshold(float newPainThreshold) { m_PainThreshold = newPainThreshold; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPainThreshold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets this' PainThreshold value above which it will play PainSound + // Arguments: None. + // Return value: The current PainThreshold + + float GetPainThreshold() const { return m_PainThreshold; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AlarmPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this alarmed about a certian point on in the scene, overriding + // the current AI mode until a certain time has passed. + // Arguments: The new scene point this should look at and see if anything dangerous + // is there. + // Return value: None. + + void AlarmPoint(const Vector& alarmPoint) { + if (m_AlarmSound && m_AlarmTimer.IsPastSimTimeLimit()) { + m_AlarmSound->Play(alarmPoint); + } + if (m_AlarmTimer.GetElapsedSimTimeMS() > 50) { + m_AlarmTimer.Reset(); + m_LastAlarmPos = m_PointingTarget = alarmPoint; + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAlarmPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets any point on the scene this actor should be alarmed about this frame. + // Arguments: None. + // Return value: The new scene point this should look at and see if anything dangerous + // is there or (0,0) if nothing is alarming. + + Vector GetAlarmPoint() { + if (m_AlarmTimer.GetElapsedSimTimeMS() > g_TimerMan.GetDeltaTimeMS()) { + return Vector(); + } + return m_LastAlarmPos; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: AddInventoryItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an inventory item to this Actor. + // Arguments: An pointer to the new item to add. Ownership IS TRANSFERRED! + // Return value: None.. + + virtual void AddInventoryItem(MovableObject* pItemToAdd) { AddToInventoryBack(pItemToAdd); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveInventoryItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a specified item from the actor's inventory. Only one item is removed at a time. + // Arguments: Preset name of an item to remove. + // Return value: None. + + void RemoveInventoryItem(const std::string& presetName) { RemoveInventoryItem("", presetName); } + + /// + /// Removes the first inventory item with the given module name and preset name. + /// + /// The module name of the item to remove. + /// The preset name of the item to remove. + void RemoveInventoryItem(const std::string& moduleName, const std::string& presetName); + + /// + /// Removes and returns the inventory item at the given index. Ownership IS transferred. + /// + /// The index of the inventory item to remove. + /// An owning pointer to the removed inventory item. + MovableObject* RemoveInventoryItemAtIndex(int inventoryIndex); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SwapNextInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Swaps the next MovableObject carried by this Actor and puts one not + // currently carried into the into the back of the inventory of this. + // Arguments: A pointer to the external MovableObject to trade in. Ownership IS xferred! + // If 0 is passed in, nothing will be added to the inventory. + // Whether to mute the sound on this event. Override for the loading screen hack. + // Return value: The next MovableObject in this Actor's inventory. Ownership IS xferred! + // If there are no MovableObject:s in inventory, 0 will be returned. + + virtual MovableObject* SwapNextInventory(MovableObject* pSwapIn = nullptr, bool muteSound = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SwapPrevInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Swaps the prev MovableObject carried by this Actor and puts one not + // currently carried into the into the back of the inventory of this. + // Arguments: A pointer to the external MovableObject to trade in. Ownership IS xferred! + // If 0 is passed in, nothing will be added to the inventory. + // Return value: The prev MovableObject in this Actor's inventory. Ownership IS xferred! + // If there are no MovableObject:s in inventory, 0 will be returned. + + virtual MovableObject* SwapPrevInventory(MovableObject* pSwapIn = nullptr); + + /// + /// Swaps the inventory items at the given indices. Will return false if a given index is invalid. + /// + /// The index of one item. + /// The index of the other item. + /// Whether or not the swap was successful. + bool SwapInventoryItemsByIndex(int inventoryIndex1, int inventoryIndex2); + + /// + /// Sets the inventory item at the given index as the new inventory item, and gives back the one that was originally there. + /// If an invalid index is given, the new item will be put in the back of the inventory, and nullptr will be returned. + /// + /// The new item that should be at the given inventory index. Cannot be a nullptr. Ownership IS transferred. + /// The inventory index the new item should be placed at. + /// The inventory item that used to be at the inventory index. Ownership IS transferred. + MovableObject* SetInventoryItemAtIndex(MovableObject* newInventoryItem, int inventoryIndex); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DropAllInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Ejects all inventory items that this is carrying. It may not happen + // instantaneously, so check for ejection being complete with + // IsInventoryEmpty(). + // Arguments: None. + // Return value: None. + + virtual void DropAllInventory(); + + /// + /// Converts all of the Gold carried by this Actor into MovableObjects and ejects them into the Scene. + /// + virtual void DropAllGold(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetInventorySize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells how many things are in the invetory + // Arguments: None. + // Return value: The number of things in the inventory + + int GetInventorySize() const { return m_Inventory.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsInventoryEmpty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether inventory is completely empty + // Arguments: None. + // Return value: Whether inventory is completely empty. + + bool IsInventoryEmpty() { return m_Inventory.empty(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetInventory + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the deque of inventory of this. Ownership is NOT transferred. + // Arguments: None. + // Return value: A const pointer to the inventory deque of this. OWNERSHIP IS NOT TRANSFERRED! + + const std::deque* GetInventory() const { return &m_Inventory; } + + /// + /// Returns the maximum total mass this Actor can carry in its inventory. + /// + /// The maximum carriable mass of this Actor. + float GetMaxInventoryMass() const { return m_MaxInventoryMass; } + + /// + /// Attempts to add an item to the front of our inventory. + /// + /// Whether we succeeded in adding the item. We may fail if the object doesn't exist or is set to delete. + bool AddToInventoryFront(MovableObject* itemToAdd); + + /// + /// Attempts to add an item to the back of our inventory. + /// + /// Whether we succeeded in adding the item. We may fail if the object doesn't exist or is set to delete. + bool AddToInventoryBack(MovableObject* itemToAdd); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAimRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The limit of this actors aiming angle, in each direction, in radians. + // Arguments: None. + // Return value: The arc range of the aiming angle in radians. + // Eg if HalfPI, it means full 180 degree range + + float GetAimRange() const { return m_AimRange; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetAimRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the limit of this actors aiming angle, in each direction, in radians. + // Arguments: The arc range of the aiming angle in radians. + // Eg if HalfPI, it means full 180 degree range + // Return value: None. + + void SetAimRange(float range) { m_AimRange = range; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawWaypoints + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this draw its current waypoints and related data on the scene in + // its HUD drawing stage. + // Arguments: Whether to enable or disable the drawing of the waypoints. + // Return value: None. + + void DrawWaypoints(bool drawWaypoints = true) { m_DrawWaypoints = drawWaypoints; } + + /// + /// Destroys this MOSRotating and creates its specified Gibs in its place with appropriate velocities. + /// Any Attachables are removed and also given appropriate velocities. + /// + /// The impulse (kg * m/s) of the impact causing the gibbing to happen. + /// A pointer to an MO which the Gibs and Attachables should not be colliding with. + void GibThis(const Vector& impactImpulse = Vector(), MovableObject* movableObjectToIgnore = nullptr) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + // Arguments: Reference to the HitData struct which describes the collision. This + // will be modified to represent the results of the collision. + // Return value: Whether the collision has been deemed valid. If false, then disregard + // any impulses in the Hitdata. + + bool CollideAtPoint(HitData& hitData) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ParticlePenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Determines whether a particle which has hit this MO will penetrate, + // and if so, whether it gets lodged or exits on the other side of this + // MO. Appropriate effects will be determined and applied ONLY IF there + // was penetration! If not, nothing will be affected. + // Arguments: The HitData describing the collision in detail, the impulses have to + // have been filled out! + // Return value: Whether the particle managed to penetrate into this MO or not. If + // somehting but a MOPixel or MOSParticle is being passed in as hitor, + // false will trivially be returned here. + + bool ParticlePenetration(HitData& hd) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done before Travel(). Always call before + // calling Travel. + // Arguments: None. + // Return value: None. + + void PreTravel() override { + MOSRotating::PreTravel(); + m_GoldPicked = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMovePathToUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this' AI's move path to be updated. Will update the path to the + // current waypoint, if any. + // Arguments: None. + // Return value: None. + + void SetMovePathToUpdate() { m_UpdateMovePath = true; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMovePathSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how many waypoints there are in the MovePath currently + // Arguments: None. + // Return value: The number of waypoints in the MovePath. + + int GetMovePathSize() const { return m_MovePath.size(); } + + /// + /// Starts updating this Actor's movepath. + /// + virtual void UpdateMovePath(); + + /// + /// Returns whether we're waiting on a new pending movepath. + /// + /// Whether we're waiting on a new pending movepath. + bool IsWaitingOnNewMovePath() const { return m_PathRequest != nullptr || m_UpdateMovePath; } + + /// + /// Estimates what material strength this actor can penetrate. + /// + /// The actor's dig strength. + virtual float EstimateDigStrength() const; + + /// + /// Gets this Actor's base dig strength, or the strength of terrain they can expect to walk through without tools. + /// + /// The actors base dig strength. + float GetAIBaseDigStrength() const { return m_AIBaseDigStrength; } + + /// + /// Sets this Actor's base dig strength, or the strength of terrain they can expect to walk through without tools. + /// + /// The new base dig strength for this Actor. + void SetAIBaseDigStrength(float newAIBaseDigStrength) { m_AIBaseDigStrength = newAIBaseDigStrength; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreControllerUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + virtual void PreControllerUpdate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: FullUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the full state of this object in one call. (PreControllerUpdate(), Controller::Update(), and Update()) + // Arguments: None. + // Return value: None. + + virtual void FullUpdate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetDeploymentID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets deployment ID for this actor + // Arguments: New deployment id. + // Return value: None. + + void SetDeploymentID(unsigned int newID) { m_DeploymentID = newID; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeploymentID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets deployment ID of this actor + // Arguments: None. + // Return value: Returns deployment id of this actor. + + unsigned int GetDeploymentID() const { return m_DeploymentID; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetSightDistance + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns actor's sight distance. + // Arguments: None. + // Return value: Returns actor's sight distance. + + float GetSightDistance() const { return m_SightDistance; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetSightDistance + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets actor's sight distance. + // Arguments: New sight distance value. + // Return value: None. + + void SetSightDistance(float newValue) { m_SightDistance = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // Which player's screen this is being drawn to. May affect what HUD elements + // get drawn etc. + // Return value: None. + + void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: VerifyMOIDIndex + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Verifieis whether all actor's MO has correct IDs. Should be used in Debug mode only. + // Arguments: None. + // Return value: None. + + void VerifyMOIDs(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTravelImpulseDamage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns Threshold for taking damage from travel impulses, in kg * m/s + // Arguments: None. + // Return value: Threshold for taking damage from travel impulses, in kg * m/s + + float GetTravelImpulseDamage() const { return m_TravelImpulseDamage; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTravelImpulseDamage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets Threshold for taking damage from travel impulses, in kg * m/s + // Arguments: Threshold for taking damage from travel impulses, in kg * m/s + // Return value: None. + + void SetTravelImpulseDamage(float value) { m_TravelImpulseDamage = value; } + + /// + /// Gets this Actor's body hit sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this Actor's body hit sound. + SoundContainer* GetBodyHitSound() const { return m_BodyHitSound; } + + /// + /// Sets this Actor's body hit sound. Ownership IS transferred! + /// + /// The new SoundContainer for this Actor's body hit sound. + void SetBodyHitSound(SoundContainer* newSound) { m_BodyHitSound = newSound; } + + /// + /// Gets this Actor's alarm sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this Actor's alarm sound. + SoundContainer* GetAlarmSound() const { return m_AlarmSound; } + + /// + /// Sets this Actor's alarm sound. Ownership IS transferred! + /// + /// The new SoundContainer for this Actor's alarm sound. + void SetAlarmSound(SoundContainer* newSound) { m_AlarmSound = newSound; } + + /// + /// Gets this Actor's pain sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this Actor's pain sound. + SoundContainer* GetPainSound() const { return m_PainSound; } + + /// + /// Sets this Actor's pain sound. Ownership IS transferred! + /// + /// The new SoundContainer for this Actor's pain sound. + void SetPainSound(SoundContainer* newSound) { m_PainSound = newSound; } + + /// + /// Gets this Actor's death sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this Actor's death sound. + SoundContainer* GetDeathSound() const { return m_DeathSound; } + + /// + /// Sets this Actor's death sound. Ownership IS transferred! + /// + /// The new SoundContainer for this Actor's death sound. + void SetDeathSound(SoundContainer* newSound) { m_DeathSound = newSound; } + + /// + /// Gets this Actor's device switch sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this Actor's device switch sound. + SoundContainer* GetDeviceSwitchSound() const { return m_DeviceSwitchSound; } + + /// + /// Sets this Actor's device switch sound. Ownership IS transferred! + /// + /// The new SoundContainer for this Actor's device switch sound. + void SetDeviceSwitchSound(SoundContainer* newSound) { m_DeviceSwitchSound = newSound; } + + /// + /// Gets the X and Y thresholds for how fast the actor can travel before losing stability. + /// + /// A Vector with the X and Y thresholds for how fast the actor can travel before losing stability. + Vector GetStableVel() const { return m_StableVel; } + + /// + /// Sets the X and Y thresholds for how fast the actor can travel before losing stability. + /// + /// New value for how fast the actor can travel before losing stability on X axis. + /// New value for how fast the actor can travel before losing stability on Y axis. + void SetStableVel(float newVelX, float newVelY) { m_StableVel.SetXY(newVelX, newVelY); } + + /// + /// Sets the X and Y thresholds for how fast the actor can travel before losing stability. + /// + /// Vector with new values for how fast the actor can travel before losing stability on both axis. + void SetStableVel(Vector newVelVector) { m_StableVel = newVelVector; } + + /// + /// Gets the recovery delay from UNSTABLE to STABLE, in MS. + /// + /// The recovery delay, in MS. + int GetStableRecoverDelay() const { return m_StableRecoverDelay; } + + /// + /// Sets the recovery delay from UNSTABLE to STABLE, in MS. + /// + /// The recovery delay, in MS. + void SetStableRecoverDelay(int newRecoverDelay) { m_StableRecoverDelay = newRecoverDelay; } + + /// + /// Gets the distance in which the Actor will have considered itself to have reached it's waypoint. + /// + /// The move proximity limit. + float GetMoveProximityLimit() const { return m_MoveProximityLimit; } + + /// + /// Sets the distance in which the Actor will have considered itself to have reached it's waypoint. + /// + /// The move proximity limit. + void SetMoveProximityLimit(float newProximityLimit) { m_MoveProximityLimit = newProximityLimit; } + + /// + /// Gets whether or not this Actor has the organic flag set and should be considered as organic. + /// + /// Whether or not this Actor has the organic flag set and should be considered as organic. + bool IsOrganic() const { return m_Organic; } + + /// + /// Gets whether or not this Actor has the mechanical flag set and should be considered as mechanical. + /// + /// Whether or not this Actor has the mechanical flag set and should be considered as mechanical. + bool IsMechanical() const { return m_Mechanical; } + + /// + /// Gets whether or not this Actor's limb push forces have been disabled. + /// + /// Whether or not this Actor's limb push forces have been disabled. + bool GetLimbPushForcesAndCollisionsDisabled() const { return m_LimbPushForcesAndCollisionsDisabled; } + + /// + /// Sets whether or not this Actor's limb push forces should be disabled. + /// + /// Whether or not this Actor's limb push forces should be disabled. + void SetLimbPushForcesAndCollisionsDisabled(bool newLimbPushForcesAndCollisionsDisabled) { m_LimbPushForcesAndCollisionsDisabled = newLimbPushForcesAndCollisionsDisabled; } + + /// + /// Gets the default PieMenu name for this type. + /// + /// The default PieMenu name for this type. + virtual std::string GetDefaultPieMenuName() const { return "Default Actor Pie Menu"; } + + /// + /// Gets a pointer to the PieMenu for this Actor. Ownership is NOT transferred. + /// + /// The PieMenu for this Actor. + PieMenu* GetPieMenu() const { return m_PieMenu.get(); } + + /// + /// Sets the PieMenu for this Actor. Ownership IS transferred. + /// + /// The new PieMenu for this Actor. + void SetPieMenu(PieMenu* newPieMenu) { + m_PieMenu = std::unique_ptr(newPieMenu); + m_PieMenu->Create(this); + m_PieMenu->AddWhilePieMenuOpenListener(this, std::bind(&Actor::WhilePieMenuOpenListener, this, m_PieMenu.get())); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Function that is called when we get a new movepath. + /// This processes and cleans up the movepath. + /// + virtual void OnNewMovePath(); + + // Member variables + static Entity::ClassInfo m_sClass; + + enum ActionState { + MOVING = 0, + MOVING_FAST, + FIRING, + ActionStateCount + }; + + enum AimState { + AIMSTILL = 0, + AIMUP, + AIMDOWN, + AimStateCount + }; + + AtomGroup* m_pHitBody; + Controller m_Controller; + bool m_PlayerControllable; //!< Whether or not this Actor can be controlled by human players. + + // Sounds + SoundContainer* m_BodyHitSound; + SoundContainer* m_AlarmSound; + SoundContainer* m_PainSound; + SoundContainer* m_DeathSound; + SoundContainer* m_DeviceSwitchSound; + + int m_Status; + float m_Health; + // Maximum health + float m_MaxHealth; + // The health of the previous frame, so we can track damage + float m_PrevHealth; + // Not owned by this! + const Icon* m_pTeamIcon; + // Not owned by this! + const Icon* m_pControllerIcon; + // Timing the last second to store the position each second so we can determine larger movement + Timer m_LastSecondTimer; + // This' position up to a second ago + Vector m_LastSecondPos; + // Movement since last whole second + Vector m_RecentMovement; + // Threshold for taking damage from travel impulses, in kg * m/s + float m_TravelImpulseDamage; + // Timer for timing the delay before regaining stability after losing it + Timer m_StableRecoverTimer; + // Thresholds in both x and y for how fast the actor can travel before losing stability. Meters per second (m/s). + Vector m_StableVel; + int m_StableRecoverDelay; //!< The delay before regaining stability after losing it, in MS + // Timer for the heartbeat of this Actor + Timer m_HeartBeat; + // Timer for timing how long this has been under Control + Timer m_NewControlTmr; + // Death timing timer + Timer m_DeathTmr; + // Amount of Gold carried, in ounces. + float m_GoldCarried; + // Whether or not any gold was picked up this frame. + bool m_GoldPicked; + // Aiming state + char m_AimState; + // The arc range of the aiming angle, in each direction, in radians. Eg if HalfPI, it means full 180 degree range + float m_AimRange; + // Current Aim angle within the AimRange + float m_AimAngle; + // How far the actor aims/looks by default + float m_AimDistance; + // Aiming timing timer + Timer m_AimTmr; + // For timing the transition from regular aim to sharp aim + Timer m_SharpAimTimer; + // The time it takes to achieve complete full sharp aiming + int m_SharpAimDelay; + // The velocity + float m_SharpAimSpeed; + // Normalzied scalar showing storing much sharp aim progress has been made + float m_SharpAimProgress; + // If sharp aim has been maxed out, ie it's either at its max, or being limited by some obstruction + bool m_SharpAimMaxedOut; + // Point at this target when devicestate is in POINTING mode + Vector m_PointingTarget; + // Last seen enemy target + Vector m_SeenTargetPos; + // Timer measuring how long this has been alarmed by a nearby gunshot etc. + Timer m_AlarmTimer; + // Position of the last thing that alarmed us + Vector m_LastAlarmPos; + // How far this guy's AI can see when he's just looking ahead + float m_SightDistance; + // How perceptive this is of alarming events going on around him, 0.0 - 1.0 + float m_Perceptiveness; + /// Damage value above which this will play PainSound + float m_PainThreshold; + // Whether or not this actor can reveal unseen areas by looking + bool m_CanRevealUnseen; + // About How tall is the Actor, in pixels? + float m_CharHeight; + // Speed at which the m_AimAngle will change, in radians/s. + // float + // The offset position of the holster where this Actor draws his devices from. + Vector m_HolsterOffset; + Vector m_ReloadOffset; //!< The offset position of where this Actor reloads his devices from. + // The point at which this actor is viewing, or the scene frame + // should be centered on if tracking this Actor's view. + // In absolute scene coordinates. + Vector m_ViewPoint; + // The inventory of carried MovableObjects of this Actor. They are also Owned by this. + std::deque m_Inventory; + float m_MaxInventoryMass; //!< The mass limit for this Actor's inventory. -1 means there's no limit. + // The device that can/will be picked up + HeldDevice* m_pItemInReach; + // HUD positioning aid + int m_HUDStack; + // ID of deployment which spawned this actor + unsigned int m_DeploymentID; + // How many passenger slots this actor will take in a craft + int m_PassengerSlots; + // Most actors can walk through stuff that's soft enough, so we start with a base penetration amount + float m_AIBaseDigStrength; + // The mass that this actor had upon spawning, i.e with no inventory, no gold and holding no items + float m_BaseMass; + + //////////////////// + // AI States + + enum LateralMoveState { + LAT_STILL = 0, + LAT_LEFT, + LAT_RIGHT + }; + + enum ObstacleState { + PROCEEDING = 0, + BACKSTEPPING, + DIGPAUSING, + JUMPING, + SOFTLANDING + }; + + enum TeamBlockState { + NOTBLOCKED = 0, + BLOCKED, + IGNORINGBLOCK, + FOLLOWWAIT + }; + // Unknown team icon + static std::vector m_apNoTeamIcon; + // The AI mode icons + static BITMAP* m_apAIIcons[AIMODE_COUNT]; + // Selection arrow + static std::vector m_apSelectArrow; + // Selection arrow + static std::vector m_apAlarmExclamation; + // Whether the static icons have been loaded yet or not + static bool m_sIconsLoaded; + // The current mode the AI is set to perform as + AIMode m_AIMode; + // The list of waypoints remaining between which the paths are made. If this is empty, the last path is in teh MovePath + // The MO pointer in the pair is nonzero if the waypoint is tied to an MO in the scene, and gets updated each UpdateAI. This needs to be checked for validity/existence each UpdateAI + std::list> m_Waypoints; + // Whether to draw the waypoints or not in the HUD + bool m_DrawWaypoints; + // Absolute target to move to on the scene; this is usually the point at the front of the movepath list + Vector m_MoveTarget; + // The MO we're currently following, if any. If still valid, this' position will update the MoveTarget each UpdateAI. + const MovableObject* m_pMOMoveTarget; + // The point previous on the path to the one currently assigned the move target + Vector m_PrevPathTarget; + // The relative, scene-wrapped difference between the current m_Pos and the m_MoveTarget. + Vector m_MoveVector; + // The calculated path to get to that move-to target + std::list m_MovePath; + // The current pathfinding request + std::shared_ptr m_PathRequest; + // Whether it's time to update the path + bool m_UpdateMovePath; + // The minimum range to consider having reached a move target is considered + float m_MoveProximityLimit; + // Current movement state. + MovementState m_MoveState; + + bool m_Organic; //!< Flag for whether or not this Actor is organic. Useful for lua purposes and mod support. + bool m_Mechanical; //!< Flag for whether or not this Actor is robotic. Useful for lua purposes and mod support. + + bool m_LimbPushForcesAndCollisionsDisabled; // m_PieMenu; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Actor, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + Actor(const Actor& reference) = delete; + Actor& operator=(const Actor& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/Arm.cpp b/Source/Entities/Arm.cpp index dcf8a8c5f..c8170a192 100644 --- a/Source/Entities/Arm.cpp +++ b/Source/Entities/Arm.cpp @@ -9,7 +9,7 @@ namespace RTE { ConcreteClassInfo(Arm, Attachable, 50); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Arm::Clear() { m_MaxLength = 0; @@ -35,7 +35,7 @@ namespace RTE { m_HeldDeviceThisArmIsTryingToSupport = nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Arm::Create() { if (Attachable::Create() < 0) { @@ -51,9 +51,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Arm::Create(const Arm &reference) { + int Arm::Create(const Arm& reference) { if (reference.m_HeldDevice) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_HeldDevice->GetUniqueID()); } @@ -80,17 +80,17 @@ namespace RTE { m_ThrowStrength = reference.m_ThrowStrength; if (reference.m_HeldDevice) { - SetHeldDevice(dynamic_cast(reference.m_HeldDevice->Clone())); + SetHeldDevice(dynamic_cast(reference.m_HeldDevice->Clone())); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Arm::ReadProperty(const std::string_view &propName, Reader &reader) { + int Arm::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Attachable::ReadProperty(propName, reader)); - + MatchProperty("MaxLength", { reader >> m_MaxLength; }); MatchProperty("MoveSpeed", { reader >> m_MoveSpeed; }); MatchForwards("HandIdleOffset") MatchProperty("IdleOffset", { reader >> m_HandIdleOffset; }); @@ -100,14 +100,14 @@ namespace RTE { }); MatchProperty("GripStrength", { reader >> m_GripStrength; }); MatchProperty("ThrowStrength", { reader >> m_ThrowStrength; }); - MatchProperty("HeldDevice", { SetHeldDevice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("HeldDevice", { SetHeldDevice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Arm::Save(Writer &writer) const { + int Arm::Save(Writer& writer) const { Attachable::Save(writer); writer.NewPropertyWithValue("MaxLength", m_MaxLength); @@ -121,45 +121,46 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Arm::SetHandPos(const Vector &newHandPos) { + void Arm::SetHandPos(const Vector& newHandPos) { SetHandCurrentOffset(g_SceneMan.ShortestDistance(m_JointPos, newHandPos, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY())); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Arm::AddHandTarget(const std::string &description, const Vector &handTargetPositionToAdd, float delayAtTarget) { + void Arm::AddHandTarget(const std::string& description, const Vector& handTargetPositionToAdd, float delayAtTarget) { Vector handTargetOffsetToAdd = g_SceneMan.ShortestDistance(m_JointPos, handTargetPositionToAdd, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); if (!handTargetOffsetToAdd.IsZero()) { handTargetOffsetToAdd.ClampMagnitude(m_MaxLength / 2.0F, m_MaxLength); if (m_HandTargets.empty()) { m_HandHasReachedCurrentTarget = false; } else if (description == m_HandTargets.back().Description) { - m_HandTargets.back() = { description, handTargetOffsetToAdd, std::max(m_HandTargets.back().DelayAtTarget, delayAtTarget), m_HFlipped }; + m_HandTargets.back() = {description, handTargetOffsetToAdd, std::max(m_HandTargets.back().DelayAtTarget, delayAtTarget), m_HFlipped}; return; } m_HandTargets.emplace(description, handTargetOffsetToAdd, delayAtTarget, m_HFlipped); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Arm::SetHeldDevice(HeldDevice *newHeldDevice) { - if (m_HeldDevice && m_HeldDevice->IsAttached()) { RemoveAndDeleteAttachable(m_HeldDevice); } + void Arm::SetHeldDevice(HeldDevice* newHeldDevice) { + if (m_HeldDevice && m_HeldDevice->IsAttached()) { + RemoveAndDeleteAttachable(m_HeldDevice); + } m_HeldDevice = newHeldDevice; if (newHeldDevice != nullptr) { AddAttachable(newHeldDevice); m_HardcodedAttachableUniqueIDsAndSetters.try_emplace( - newHeldDevice->GetUniqueID(), - [](MOSRotating *parent, Attachable *attachable) { - HeldDevice *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetHeldDevice."); - dynamic_cast(parent)->SetHeldDevice(castedAttachable); - } - ); + newHeldDevice->GetUniqueID(), + [](MOSRotating* parent, Attachable* attachable) { + HeldDevice* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetHeldDevice."); + dynamic_cast(parent)->SetHeldDevice(castedAttachable); + }); } // Reset our fire state, so that our activation of a prior device does not "leak" @@ -168,21 +169,21 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - HeldDevice * Arm::SwapHeldDevice(HeldDevice *newHeldDevice) { - Attachable *previousHeldDevice = RemoveAttachable(m_HeldDevice, false, false); + HeldDevice* Arm::SwapHeldDevice(HeldDevice* newHeldDevice) { + Attachable* previousHeldDevice = RemoveAttachable(m_HeldDevice, false, false); SetHeldDevice(newHeldDevice); - return dynamic_cast(previousHeldDevice); + return dynamic_cast(previousHeldDevice); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Arm::HandIsCloseToTargetOffset(const Vector &targetOffset) const { + bool Arm::HandIsCloseToTargetOffset(const Vector& targetOffset) const { return (m_HandCurrentOffset - targetOffset).MagnitudeIsLessThan(m_MaxLength / 10.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Arm::Update() { Attachable::PreUpdate(); @@ -198,7 +199,7 @@ namespace RTE { m_HeldDeviceThisArmIsTryingToSupport = nullptr; } - bool heldDeviceIsAThrownDevice = m_HeldDevice && dynamic_cast(m_HeldDevice); + bool heldDeviceIsAThrownDevice = m_HeldDevice && dynamic_cast(m_HeldDevice); // If there's no HeldDevice, or it's a ThrownDevice, the Arm should rotate to match the hand's current offset for visuals/aiming (instead of using the AHuman's aim angle). if (heldDeviceIsAThrownDevice || !m_HeldDevice) { @@ -231,7 +232,7 @@ namespace RTE { m_HandIdleRotation = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Arm::UpdateHandCurrentOffset(bool armHasParent, bool heldDeviceIsAThrownDevice) { if (armHasParent) { @@ -239,7 +240,7 @@ namespace RTE { if (m_HandTargets.empty()) { if (m_HeldDevice) { targetOffset = m_HeldDevice->GetStanceOffset(); - if (HDFirearm *heldFirearm = dynamic_cast(m_HeldDevice); heldFirearm && heldFirearm->GetCurrentReloadAngle() != 0) { + if (HDFirearm* heldFirearm = dynamic_cast(m_HeldDevice); heldFirearm && heldFirearm->GetCurrentReloadAngle() != 0) { if (heldFirearm->IsReloading()) { float reloadProgressSin = std::sin(heldFirearm->GetReloadProgress() * c_PI); // TODO: There are a few values available for customization here, but they need clear property names. The following plays out well as a default. @@ -251,13 +252,13 @@ namespace RTE { float reloadAngle = (heldFirearm->GetCurrentReloadAngle() - inheritedBodyAngle * GetFlipFactor()) * reloadProgressSin; heldFirearm->SetInheritedRotAngleOffset(reloadAngle); targetOffset.RadRotate(reloadAngle * GetFlipFactor()); - float retractionRate = 0.5F * noSupportFactor; // Another value potentially open for customization. + float retractionRate = 0.5F * noSupportFactor; // Another value potentially open for customization. targetOffset.SetMagnitude(targetOffset.GetMagnitude() * (1.0F - reloadProgressSin * retractionRate)); } else if (heldFirearm->DoneReloading()) { heldFirearm->SetInheritedRotAngleOffset(0); } } - } else if (bool parentIsStable = dynamic_cast(m_Parent)->IsStatus(Actor::Status::STABLE); parentIsStable && m_HeldDeviceThisArmIsTryingToSupport) { + } else if (bool parentIsStable = dynamic_cast(m_Parent)->IsStatus(Actor::Status::STABLE); parentIsStable && m_HeldDeviceThisArmIsTryingToSupport) { targetOffset = g_SceneMan.ShortestDistance(m_JointPos, m_HeldDeviceThisArmIsTryingToSupport->GetSupportPos(), g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); } else { targetOffset = m_HandIdleOffset.GetXFlipped(m_Parent->IsHFlipped()).GetRadRotatedCopy(m_Parent->GetRotAngle()); @@ -266,7 +267,7 @@ namespace RTE { targetOffset.RadRotate(m_HandIdleRotation); } } else { - const HandTarget &nextHandTarget = m_HandTargets.front(); + const HandTarget& nextHandTarget = m_HandTargets.front(); targetOffset = nextHandTarget.TargetOffset.GetXFlipped(nextHandTarget.HFlippedWhenTargetWasCreated != m_HFlipped); } @@ -302,18 +303,18 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Arm::AccountForHeldDeviceRecoil(const HeldDevice *heldDevice, Vector &targetOffset) { + void Arm::AccountForHeldDeviceRecoil(const HeldDevice* heldDevice, Vector& targetOffset) { if (!heldDevice->GetRecoilForce().IsZero()) { float totalGripStrength = m_GripStrength * heldDevice->GetGripStrengthMultiplier(); - if (totalGripStrength == 0.0F) { - totalGripStrength = heldDevice->GetJointStrength(); + if (totalGripStrength == 0.0F) { + totalGripStrength = heldDevice->GetJointStrength(); } if (heldDevice->GetSupported()) { - const AHuman *rootParentAsAHuman = dynamic_cast(GetRootParent()); - const Arm *supportingArm = rootParentAsAHuman ? rootParentAsAHuman->GetBGArm() : nullptr; + const AHuman* rootParentAsAHuman = dynamic_cast(GetRootParent()); + const Arm* supportingArm = rootParentAsAHuman ? rootParentAsAHuman->GetBGArm() : nullptr; if (supportingArm) { if (supportingArm->GetGripStrength() < 0) { totalGripStrength = -1.0F; @@ -341,11 +342,11 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Arm::AccountForHeldDeviceTerrainClipping(const HeldDevice *heldDevice, Vector &targetOffset) const { + void Arm::AccountForHeldDeviceTerrainClipping(const HeldDevice* heldDevice, Vector& targetOffset) const { Vector newMuzzlePos = (m_JointPos + targetOffset) - RotateOffset(heldDevice->GetJointOffset()) + RotateOffset(heldDevice->GetMuzzleOffset()); - Vector midToMuzzle = RotateOffset({ heldDevice->GetIndividualRadius(), 0 }); + Vector midToMuzzle = RotateOffset({heldDevice->GetIndividualRadius(), 0}); Vector midOfDevice = newMuzzlePos - midToMuzzle; Vector terrainOrMuzzlePosition; @@ -357,7 +358,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Arm::UpdateArmFrame() { float halfMaxLength = m_MaxLength / 2.0F; @@ -365,20 +366,22 @@ namespace RTE { m_Frame = static_cast(std::clamp(newFrame, 0.0F, static_cast(m_FrameCount - 1))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Arm::Draw(BITMAP *targetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { + void Arm::Draw(BITMAP* targetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { Attachable::Draw(targetBitmap, targetPos, mode, onlyPhysical); if (!onlyPhysical && (mode == DrawMode::g_DrawColor || mode == DrawMode::g_DrawWhite || mode == DrawMode::g_DrawTrans)) { DrawHand(targetBitmap, targetPos, mode); - if (m_HeldDevice && m_HeldDevice->IsDrawnAfterParent()) { m_HeldDevice->Draw(targetBitmap, targetPos, mode, onlyPhysical); } + if (m_HeldDevice && m_HeldDevice->IsDrawnAfterParent()) { + m_HeldDevice->Draw(targetBitmap, targetPos, mode, onlyPhysical); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Arm::DrawHand(BITMAP *targetBitmap, const Vector &targetPos, DrawMode mode) const { + void Arm::DrawHand(BITMAP* targetBitmap, const Vector& targetPos, DrawMode mode) const { Vector handPos(m_JointPos + m_HandCurrentOffset + (m_Recoiled ? m_RecoilOffset : Vector()) - targetPos); handPos -= Vector(static_cast(m_HandSpriteBitmap->w / 2), static_cast(m_HandSpriteBitmap->h / 2)); @@ -389,7 +392,7 @@ namespace RTE { draw_sprite(targetBitmap, m_HandSpriteBitmap, handPos.GetFloorIntX(), handPos.GetFloorIntY()); } } else { - //TODO this draw_character_ex won't draw flipped. It should draw onto a temp bitmap and then draw that flipped. Maybe it can reuse a temp bitmap from MOSR, maybe not? + // TODO this draw_character_ex won't draw flipped. It should draw onto a temp bitmap and then draw that flipped. Maybe it can reuse a temp bitmap from MOSR, maybe not? if (mode == DrawMode::g_DrawWhite) { draw_character_ex(targetBitmap, m_HandSpriteBitmap, handPos.GetFloorIntX(), handPos.GetFloorIntY(), g_WhiteColor, -1); } else { @@ -397,4 +400,4 @@ namespace RTE { } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/Arm.h b/Source/Entities/Arm.h index c9a983980..033b6f6df 100644 --- a/Source/Entities/Arm.h +++ b/Source/Entities/Arm.h @@ -13,7 +13,6 @@ namespace RTE { class Arm : public Attachable { public: - EntityAllocation(Arm); SerializableOverrideMethods; ClassInfoGetters; @@ -35,7 +34,7 @@ namespace RTE { /// /// A reference to the Arm to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Arm &reference); + int Create(const Arm& reference); #pragma endregion #pragma region Destruction @@ -48,12 +47,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the Arm object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Attachable::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Attachable::Destroy(); + } + Clear(); + } /// /// Resets the entire Arm, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Attachable::Reset(); } + void Reset() override { + Clear(); + Attachable::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -85,7 +92,7 @@ namespace RTE { /// Sets the default idle offset of this Arm's hand, i.e. the default offset from the joint position that this Arm will try to move to when not moving towards a position. /// /// The new idle offset of this Arm's hand. - void SetHandIdleOffset(const Vector &newDefaultIdleOffset) { m_HandIdleOffset = newDefaultIdleOffset; } + void SetHandIdleOffset(const Vector& newDefaultIdleOffset) { m_HandIdleOffset = newDefaultIdleOffset; } /// /// Gets the rotation that is being applied to this Arm's hand, if it's using an idle offset. @@ -109,8 +116,11 @@ namespace RTE { /// Sets the current offset of this Arm's hand, i.e. its distance from the joint position. The value is capped to the max length of the Arm. /// /// The new current offset of this Arm's hand. - //TODO maybe don't want this in favor of SetHandPos? - void SetHandCurrentOffset(const Vector &newHandOffset) { m_HandCurrentOffset = newHandOffset; m_HandCurrentOffset.CapMagnitude(m_MaxLength); } + // TODO maybe don't want this in favor of SetHandPos? + void SetHandCurrentOffset(const Vector& newHandOffset) { + m_HandCurrentOffset = newHandOffset; + m_HandCurrentOffset.CapMagnitude(m_MaxLength); + } /// /// Gets the current position of this Arm's hand in absolute Scene coordinates. @@ -122,7 +132,7 @@ namespace RTE { /// Sets the current position of this Arm's hand to an absolute scene coordinate. If needed, the set position is modified so its distance from the joint position of the Arm is capped to the max length of the Arm. /// /// The new current position of this Arm's hand as absolute scene coordinate. - void SetHandPos(const Vector &newHandPos); + void SetHandPos(const Vector& newHandPos); /// /// Gets the the strength with which this Arm will grip its HeldDevice. @@ -155,7 +165,7 @@ namespace RTE { /// /// The description of this HandTarget, for easy identification. /// The position, in absolute scene coordinates, to add the queue of hand targets. - void AddHandTarget(const std::string &description, const Vector &handTargetPositionToAdd) { AddHandTarget(description, handTargetPositionToAdd, 0); } + void AddHandTarget(const std::string& description, const Vector& handTargetPositionToAdd) { AddHandTarget(description, handTargetPositionToAdd, 0); } /// /// Adds a HandTarget position, in absolute scene coordinates, to the queue for the Arm to move its hand towards. Target positions are removed from the queue when they're reached (or as close to reached as is possible). @@ -164,12 +174,17 @@ namespace RTE { /// The description of this HandTarget, for easy identification. /// The position, in absolute scene coordinates, to add the queue of hand targets. /// The amount of time, in MS, that the hand should wait when it reaches the newly added HandTarget. - void AddHandTarget(const std::string &description, const Vector &handTargetPositionToAdd, float delayAtTarget); + void AddHandTarget(const std::string& description, const Vector& handTargetPositionToAdd, float delayAtTarget); /// /// Removes this Arm's next HandTarget, if there is one. /// - void RemoveNextHandTarget() { if (!m_HandTargets.empty()) { m_HandTargets.pop(); m_HandHasReachedCurrentTarget = false; } } + void RemoveNextHandTarget() { + if (!m_HandTargets.empty()) { + m_HandTargets.pop(); + m_HandHasReachedCurrentTarget = false; + } + } /// /// Gets whether or not this Arm has any HandTargets. @@ -212,32 +227,32 @@ namespace RTE { /// Gets the HeldDevice currently held by this Arm. /// /// The HeldDevice currently held by this Arm. Ownership is NOT transferred. - HeldDevice * GetHeldDevice() const { return m_HeldDevice; } + HeldDevice* GetHeldDevice() const { return m_HeldDevice; } /// /// Sets the HeldDevice held by this Arm. /// /// The new HeldDevice to be held by this Arm. Ownership IS transferred. - void SetHeldDevice(HeldDevice *newHeldDevice); + void SetHeldDevice(HeldDevice* newHeldDevice); /// /// Gets the HeldDevice this Arm is trying to support. /// /// The HeldDevice this Arm is trying to support. Ownership is NOT transferred. - HeldDevice * GetHeldDeviceThisArmIsTryingToSupport() const { return m_HeldDeviceThisArmIsTryingToSupport; } + HeldDevice* GetHeldDeviceThisArmIsTryingToSupport() const { return m_HeldDeviceThisArmIsTryingToSupport; } /// /// Sets the HeldDevice being this Arm is trying to support. /// /// The new HeldDevice this Arm should try to support. Ownership is NOT transferred. - void SetHeldDeviceThisArmIsTryingToSupport(HeldDevice *newHeldDeviceThisArmShouldTryToSupport) { m_HeldDeviceThisArmIsTryingToSupport = newHeldDeviceThisArmShouldTryToSupport; } + void SetHeldDeviceThisArmIsTryingToSupport(HeldDevice* newHeldDeviceThisArmShouldTryToSupport) { m_HeldDeviceThisArmIsTryingToSupport = newHeldDeviceThisArmShouldTryToSupport; } /// /// Replaces the HeldDevice currently held by this Arm with a new one, and returns the old one. Ownership IS transferred both ways. /// /// The new HeldDevice to be held by this Arm. Ownership IS transferred. /// The HeldDevice that was held by this Arm. Ownership IS transferred. - HeldDevice * SwapHeldDevice(HeldDevice *newHeldDevice); + HeldDevice* SwapHeldDevice(HeldDevice* newHeldDevice); #pragma endregion #pragma region Concrete Methods @@ -247,14 +262,19 @@ namespace RTE { /// A pointer to a BITMAP to draw on. /// The absolute position of the target bitmap's upper left corner in the Scene. /// Which mode to draw in. See the DrawMode enumeration for available modes. - void DrawHand(BITMAP *targetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor) const; + void DrawHand(BITMAP* targetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor) const; #pragma endregion #pragma region Override Methods /// /// Does stuff that needs to be done after Update(). /// - void PostTravel() override { if (IsAttached()) { m_AngularVel = 0; } MOSRotating::PostTravel(); } + void PostTravel() override { + if (IsAttached()) { + m_AngularVel = 0; + } + MOSRotating::PostTravel(); + } /// /// Updates this Arm. Supposed to be done every frame. @@ -268,11 +288,10 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// Which mode to draw in. See the DrawMode enumeration for the modes. /// Whether to not draw any extra 'ghost' items of this Arm. In this case, that means the hand sprite. - void Draw(BITMAP *targetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + void Draw(BITMAP* targetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; #pragma endregion private: - /// /// Struct for storing data about each target in the Arm's queue of HandTargets. /// @@ -280,7 +299,8 @@ namespace RTE { /// /// Constructor method used to instantiate a HandTarget object in system memory. /// - HandTarget(const std::string_view &description, const Vector &targetOffset, float delayAtTarget, bool hFlippedWhenTargetWasCreated) : Description(description), TargetOffset(targetOffset), DelayAtTarget(delayAtTarget), HFlippedWhenTargetWasCreated(hFlippedWhenTargetWasCreated) {} + HandTarget(const std::string_view& description, const Vector& targetOffset, float delayAtTarget, bool hFlippedWhenTargetWasCreated) : + Description(description), TargetOffset(targetOffset), DelayAtTarget(delayAtTarget), HFlippedWhenTargetWasCreated(hFlippedWhenTargetWasCreated) {} std::string Description = ""; Vector TargetOffset; @@ -303,20 +323,20 @@ namespace RTE { bool m_HandHasReachedCurrentTarget; //!< A flag for whether or not the hand has reached its current target. The target is either the front of the HandTarget queue, or the appropriate target to move to if the queue is empty. ContentFile m_HandSpriteFile; //!< The ContentFile containing this Arm's hand bitmap. - BITMAP *m_HandSpriteBitmap; //!< An unowned pointer to the Bitmap held by the hand sprite ContentFile. + BITMAP* m_HandSpriteBitmap; //!< An unowned pointer to the Bitmap held by the hand sprite ContentFile. float m_GripStrength; //!< The strength with which this Arm will grip its HeldDevice. Effectively supersedes the HeldDevice's JointStrength. float m_ThrowStrength; //!< The strength with which this Arm will throw a ThrownDevice. Effectively supersedes the ThrownDevice's ThrowVelocity values. - HeldDevice *m_HeldDevice; //!< A pointer to the HeldDevice this Arm is currently holding. Owned in the MOSRotating Attachables list, kept here for convenience. - HeldDevice *m_HeldDeviceThisArmIsTryingToSupport; //!< A pointer to the HeldDevice being supported by this Arm (i.e. this is the background Arm for another HeldDevice). + HeldDevice* m_HeldDevice; //!< A pointer to the HeldDevice this Arm is currently holding. Owned in the MOSRotating Attachables list, kept here for convenience. + HeldDevice* m_HeldDeviceThisArmIsTryingToSupport; //!< A pointer to the HeldDevice being supported by this Arm (i.e. this is the background Arm for another HeldDevice). /// /// Gets whether or not the hand is close to the given offset. /// /// The offset to check for closeness to the hand. /// Whether or not the hand is close to the given offset. - bool HandIsCloseToTargetOffset(const Vector &targetOffset) const; + bool HandIsCloseToTargetOffset(const Vector& targetOffset) const; #pragma region Update Breakdown /// @@ -332,14 +352,14 @@ namespace RTE { /// /// The held MO as a HeldDevice, for convenience. /// The target offset to have recoil applied to it. - void AccountForHeldDeviceRecoil(const HeldDevice *heldDevice, Vector &targetOffset); + void AccountForHeldDeviceRecoil(const HeldDevice* heldDevice, Vector& targetOffset); /// /// To be used in UpdateHandCurrentOffset. Ensures the HeldDevice won't clip through terrain by modifying the passed in target offset. /// /// The held MO as a HeldDevice, for convenience. /// The target offset to be modified to avoid any terrain clipping. - void AccountForHeldDeviceTerrainClipping(const HeldDevice *heldDevice, Vector &targetOffset) const; + void AccountForHeldDeviceTerrainClipping(const HeldDevice* heldDevice, Vector& targetOffset) const; /// /// Updates the frame for this Arm. Should only be called from Update. @@ -353,8 +373,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - Arm(const Arm &reference) = delete; - Arm & operator=(const Arm &rhs) = delete; + Arm(const Arm& reference) = delete; + Arm& operator=(const Arm& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/AtomGroup.cpp b/Source/Entities/AtomGroup.cpp index 69990ae17..ea424a4fb 100644 --- a/Source/Entities/AtomGroup.cpp +++ b/Source/Entities/AtomGroup.cpp @@ -13,12 +13,11 @@ namespace RTE { ConcreteClassInfo(AtomGroup, Entity, 500); const std::unordered_map AtomGroup::c_AreaDistributionTypeMap = { - {"Linear", AtomGroup::AreaDistributionType::Linear}, - {"Circle", AtomGroup::AreaDistributionType::Circle}, - {"Square", AtomGroup::AreaDistributionType::Square} - }; + {"Linear", AtomGroup::AreaDistributionType::Linear}, + {"Circle", AtomGroup::AreaDistributionType::Circle}, + {"Square", AtomGroup::AreaDistributionType::Square}}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AtomGroup::Clear() { m_Atoms.clear(); @@ -36,7 +35,7 @@ namespace RTE { m_IgnoreMOIDs.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int AtomGroup::Create() { if (Entity::Create() < 0) { @@ -48,7 +47,7 @@ namespace RTE { m_Resolution = 0; } if (m_Atoms.empty()) { - Atom *atom = new Atom(Vector(), m_Material, m_OwnerMOSR); + Atom* atom = new Atom(Vector(), m_Material, m_OwnerMOSR); m_Atoms.push_back(atom); } else if (m_Material->GetIndex() != m_Atoms.front()->GetMaterial()->GetIndex()) { m_Material = m_Atoms.front()->GetMaterial(); @@ -56,9 +55,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int AtomGroup::Create(const AtomGroup &reference, bool onlyCopyOwnerAtoms) { + int AtomGroup::Create(const AtomGroup& reference, bool onlyCopyOwnerAtoms) { Entity::Create(reference); m_OwnerMOSR = nullptr; // Needs to be set manually by the new MO owner. @@ -73,16 +72,16 @@ namespace RTE { m_Atoms.clear(); m_SubGroups.clear(); - for (const Atom *atom : reference.m_Atoms) { + for (const Atom* atom: reference.m_Atoms) { if (!onlyCopyOwnerAtoms || atom->GetSubID() == 0) { - Atom *atomCopy = new Atom(*atom); + Atom* atomCopy = new Atom(*atom); atomCopy->SetIgnoreMOIDsByGroup(&m_IgnoreMOIDs); m_Atoms.push_back(atomCopy); long subgroupID = atomCopy->GetSubID(); if (subgroupID != 0) { - if (m_SubGroups.find(subgroupID) == m_SubGroups.end()) { - m_SubGroups.insert({ subgroupID, std::vector() }); + if (m_SubGroups.find(subgroupID) == m_SubGroups.end()) { + m_SubGroups.insert({subgroupID, std::vector()}); } m_SubGroups.find(subgroupID)->second.push_back(atomCopy); @@ -92,20 +91,20 @@ namespace RTE { m_IgnoreMOIDs.clear(); - for (const MOID moidToIgnore : reference.m_IgnoreMOIDs) { + for (const MOID moidToIgnore: reference.m_IgnoreMOIDs) { m_IgnoreMOIDs.push_back(moidToIgnore); } - if (!reference.m_Atoms.empty()) { - m_Material = reference.m_Atoms.front()->GetMaterial(); + if (!reference.m_Atoms.empty()) { + m_Material = reference.m_Atoms.front()->GetMaterial(); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int AtomGroup::Create(MOSRotating *ownerMOSRotating, Material const *material, int resolution, int depth) { + int AtomGroup::Create(MOSRotating* ownerMOSRotating, Material const* material, int resolution, int depth) { RTEAssert(ownerMOSRotating, "Trying to generate an AtomGroup for a MOSRotating without a sprite!"); m_OwnerMOSR = ownerMOSRotating; @@ -119,11 +118,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int AtomGroup::ReadProperty(const std::string_view &propName, Reader &reader) { + int AtomGroup::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("Material", { Material mat; mat.Reset(); @@ -140,7 +139,7 @@ namespace RTE { MatchProperty("Resolution", { reader >> m_Resolution; }); MatchProperty("Depth", { reader >> m_Depth; }); MatchProperty("AddAtom", { - Atom *atom = new Atom; + Atom* atom = new Atom; reader >> *atom; m_Atoms.push_back(atom); }); @@ -153,20 +152,19 @@ namespace RTE { } else { try { m_AreaDistributionType = static_cast(std::stoi(areaDistributionTypeString)); - } catch (const std::invalid_argument &) { + } catch (const std::invalid_argument&) { reader.ReportError("AreaDistributionType " + areaDistributionTypeString + " is invalid."); } } }); MatchProperty("AreaDistributionSurfaceAreaMultiplier", { reader >> m_AreaDistributionSurfaceAreaMultiplier; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int AtomGroup::Save(Writer &writer) const { + int AtomGroup::Save(Writer& writer) const { Entity::Save(writer); writer.NewProperty("Material"); @@ -180,7 +178,7 @@ namespace RTE { // Only write out Atoms if they were manually specified if (!m_AutoGenerate) { - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { writer.NewProperty("AddAtom"); writer << *atom; } @@ -197,54 +195,58 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AtomGroup::Destroy(bool notInherited) { - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { delete atom; } - if (!notInherited) { Entity::Destroy(); } + if (!notInherited) { + Entity::Destroy(); + } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AtomGroup::SetAtomList(const std::vector &newAtoms) { - for (const Atom *atom : m_Atoms) { + void AtomGroup::SetAtomList(const std::vector& newAtoms) { + for (const Atom* atom: m_Atoms) { delete atom; } m_Atoms = newAtoms; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AtomGroup::CalculateMaxRadius() const { float sqrMagnitude = 0.0F; float sqrLongest = 0.0F; - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { sqrMagnitude = atom->GetOffset().GetSqrMagnitude(); - if (sqrMagnitude > sqrLongest) { sqrLongest = sqrMagnitude; } + if (sqrMagnitude > sqrLongest) { + sqrLongest = sqrMagnitude; + } } return std::sqrt(sqrLongest); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AtomGroup::SetOwner(MOSRotating *newOwner) { + void AtomGroup::SetOwner(MOSRotating* newOwner) { m_OwnerMOSR = newOwner; - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { atom->SetOwner(m_OwnerMOSR); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Vector AtomGroup::GetAdjustedAtomOffset(const Atom *atom) const { + Vector AtomGroup::GetAdjustedAtomOffset(const Atom* atom) const { return atom->GetOffset().GetXFlipped(m_OwnerMOSR->m_HFlipped) * m_OwnerMOSR->GetRotMatrix(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AtomGroup::GetMomentOfInertia() { float currentOwnerMass = (m_OwnerMOSR->GetMass() != 0 ? m_OwnerMOSR->GetMass() : 0.0001F); @@ -254,24 +256,28 @@ namespace RTE { m_StoredOwnerMass = currentOwnerMass; float distMass = m_StoredOwnerMass / static_cast(m_Atoms.size()); float radius = 0.0F; - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { radius = atom->GetOffset().GetMagnitude() * c_MPP; m_MomentOfInertia += distMass * radius * radius; } } // Avoid zero (if radius is nonexistent, for example), will cause divide by zero problems otherwise. - if (m_MomentOfInertia == 0.0F) { m_MomentOfInertia = 1.0F; } + if (m_MomentOfInertia == 0.0F) { + m_MomentOfInertia = 1.0F; + } return m_MomentOfInertia; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AtomGroup::AddAtoms(const std::vector &atomList, long subgroupID, const Vector &offset, const Matrix &offsetRotation) { - if (m_SubGroups.count(subgroupID) == 0) { m_SubGroups.insert({ subgroupID, std::vector() }); } + void AtomGroup::AddAtoms(const std::vector& atomList, long subgroupID, const Vector& offset, const Matrix& offsetRotation) { + if (m_SubGroups.count(subgroupID) == 0) { + m_SubGroups.insert({subgroupID, std::vector()}); + } - Atom *atomToAdd; - for (const Atom * atom : atomList) { + Atom* atomToAdd; + for (const Atom* atom: atomList) { atomToAdd = new Atom(*atom); atomToAdd->SetSubID(subgroupID); atomToAdd->SetOffset(offset + (atomToAdd->GetOriginalOffset() * offsetRotation)); @@ -282,59 +288,61 @@ namespace RTE { } if (!atomList.empty()) { m_MomentOfInertia = 0.0F; - if (m_OwnerMOSR) { GetMomentOfInertia(); } + if (m_OwnerMOSR) { + GetMomentOfInertia(); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AtomGroup::RemoveAtoms(long removeID) { std::size_t oldSize = m_Atoms.size(); m_Atoms.erase( - std::remove_if(m_Atoms.begin(), m_Atoms.end(), - [removeID](Atom *atom) { - return atom->GetSubID() == removeID; - }), - m_Atoms.end()); + std::remove_if(m_Atoms.begin(), m_Atoms.end(), + [removeID](Atom* atom) { + return atom->GetSubID() == removeID; + }), + m_Atoms.end()); m_SubGroups.erase(removeID); bool removedAny = oldSize != m_Atoms.size(); if (removedAny) { m_MomentOfInertia = 0.0F; - if (m_OwnerMOSR) { - GetMomentOfInertia(); + if (m_OwnerMOSR) { + GetMomentOfInertia(); } } return removedAny; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AtomGroup::UpdateSubAtoms(long subgroupID, const Vector &newOffset, const Matrix &newOffsetRotation) { + bool AtomGroup::UpdateSubAtoms(long subgroupID, const Vector& newOffset, const Matrix& newOffsetRotation) { if (m_SubGroups.empty() || m_SubGroups.count(subgroupID) == 0) { return false; } RTEAssert(!m_SubGroups.at(subgroupID).empty(), "Found an empty subgroup list in AtomGroup!?"); - for (Atom *subGroupAtom : m_SubGroups.at(subgroupID)) { + for (Atom* subGroupAtom: m_SubGroups.at(subgroupID)) { subGroupAtom->SetOffset(newOffset + (subGroupAtom->GetOriginalOffset() * newOffsetRotation)); } return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AtomGroup::Travel(float travelTime, bool callOnBounce, bool callOnSink, bool scenePreLocked) { return Travel(m_OwnerMOSR->m_Pos, m_OwnerMOSR->m_Vel, m_OwnerMOSR->m_Rotation, m_OwnerMOSR->m_AngularVel, m_OwnerMOSR->m_DidWrap, m_OwnerMOSR->m_TravelImpulse, m_OwnerMOSR->GetMass(), travelTime, callOnBounce, callOnSink, scenePreLocked); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: Break down and rework this trainwreck. - float AtomGroup::Travel(Vector &position, Vector &velocity, Matrix &rotation, float &angularVel, bool &didWrap, Vector &totalImpulse, float mass, float travelTime, bool callOnBounce, bool callOnSink, bool scenePreLocked) { + float AtomGroup::Travel(Vector& position, Vector& velocity, Matrix& rotation, float& angularVel, bool& didWrap, Vector& totalImpulse, float mass, float travelTime, bool callOnBounce, bool callOnSink, bool scenePreLocked) { ZoneScoped; RTEAssert(m_OwnerMOSR, "Tried to travel an AtomGroup that has no parent!"); @@ -360,30 +368,30 @@ namespace RTE { bool halted = false; // TODO: Look into pre-hit stuff and how it can be used to improve collision. - //Vector preHitPos; - //float preHitRot; + // Vector preHitPos; + // float preHitRot; Vector linSegTraj; // The planned travel trajectory of this AtomGroup's origin in pixels. HitData hitData; // Thread locals for performance (avoid memory allocs) - thread_local std::unordered_map> hitMOAtoms; + thread_local std::unordered_map> hitMOAtoms; hitMOAtoms.clear(); - thread_local std::vector hitTerrAtoms; + thread_local std::vector hitTerrAtoms; hitTerrAtoms.clear(); - thread_local std::vector penetratingAtoms; + thread_local std::vector penetratingAtoms; penetratingAtoms.clear(); - thread_local std::vector hitResponseAtoms; + thread_local std::vector hitResponseAtoms; hitResponseAtoms.clear(); // Lock all bitmaps involved outside the loop - only relevant for video bitmaps so disabled at the moment. - //if (!scenePreLocked) { g_SceneMan.LockScene(); } + // if (!scenePreLocked) { g_SceneMan.LockScene(); } // Loop for all the different straight segments (between bounces etc) that have to be traveled during the travelTime. do { // First see what Atoms are inside either the terrain or another MO, and cause collisions responses before even starting the segment - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { const Vector startOff = m_OwnerMOSR->RotateOffset(atom->GetOffset()); if (atom->SetupPos(position + startOff)) { @@ -431,7 +439,7 @@ namespace RTE { #ifdef DEBUG_BUILD // TODO: Remove this once AtomGroup drawing in Material layer draw mode is implemented. // Draw the positions of the Atoms at the start of each segment, for visual debugging. - //putpixel(g_SceneMan.GetMOColorBitmap(), atom->GetCurrentPos().GetFloorIntX(), atom->GetCurrentPos().GetFloorIntY(), 122); + // putpixel(g_SceneMan.GetMOColorBitmap(), atom->GetCurrentPos().GetFloorIntX(), atom->GetCurrentPos().GetFloorIntY(), 122); #endif } @@ -454,16 +462,18 @@ namespace RTE { break; } - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { // Calculate the segment trajectory for each individual Atom, with rotations considered. const Vector startOff = m_OwnerMOSR->RotateOffset(atom->GetOffset()); const Vector trajFromAngularTravel = Vector(startOff).RadRotate(rotDelta) - startOff; // Set up the initial rasterized step for each Atom and save the longest trajectory. - if (atom->SetupSeg(position + startOff, linSegTraj + trajFromAngularTravel) > stepsOnSeg) { stepsOnSeg = atom->GetStepsLeft(); } + if (atom->SetupSeg(position + startOff, linSegTraj + trajFromAngularTravel) > stepsOnSeg) { + stepsOnSeg = atom->GetStepsLeft(); + } } - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { atom->SetStepRatio(static_cast(atom->GetStepsLeft()) / static_cast(stepsOnSeg)); } @@ -483,7 +493,7 @@ namespace RTE { int atomsHitMOsCount = 0; - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { if (atom->StepForward()) { // If something was hit, first check for terrain hit. if (atom->HitWhatTerrMaterial()) { @@ -494,13 +504,15 @@ namespace RTE { const MOID tempMOID = atom->HitWhatMOID(); if (tempMOID != g_NoMOID) { m_OwnerMOSR->m_MOIDHit = tempMOID; - MovableObject *moCollidedWith = g_MovableMan.GetMOFromID(tempMOID); - if (moCollidedWith && moCollidedWith->HitWhatMOID() == g_NoMOID) { moCollidedWith->SetHitWhatMOID(m_OwnerMOSR->m_MOID); } + MovableObject* moCollidedWith = g_MovableMan.GetMOFromID(tempMOID); + if (moCollidedWith && moCollidedWith->HitWhatMOID() == g_NoMOID) { + moCollidedWith->SetHitWhatMOID(m_OwnerMOSR->m_MOID); + } hitMOAtoms[tempMOID].push_back(atom); // Add the hit MO to the ignore list of ignored MOIDs - //AddMOIDToIgnore(tempMOID); + // AddMOIDToIgnore(tempMOID); // Count the number of Atoms of this group that hit MOs this step. Used to properly distribute the mass of the owner MO in later collision responses during this step. atomsHitMOsCount++; @@ -512,7 +524,7 @@ namespace RTE { Vector tNorm = m_OwnerMOSR->RotateOffset(atom->GetNormal()) * 7; line(g_SceneMan.GetMOColorBitmap(), tPos.GetFloorIntX(), tPos.GetFloorIntY(), tPos.GetFloorIntX() + tNorm.GetFloorIntX(), tPos.GetFloorIntY() + tNorm.GetFloorIntY(), 244); // Draw the positions of the hit points on screen for easy debugging. - //putpixel(g_SceneMan.GetMOColorBitmap(), tPos.GetFloorIntX(), tPos.GetFloorIntY(), 5); + // putpixel(g_SceneMan.GetMOColorBitmap(), tPos.GetFloorIntX(), tPos.GetFloorIntY(), 5); #endif } } @@ -555,7 +567,7 @@ namespace RTE { const float momentInertiaDistribution = m_MomentOfInertia / static_cast(hitTerrAtoms.size() * (m_Resolution ? m_Resolution : 1)); // Determine which of the colliding Atoms will penetrate the terrain. - for (std::vector::iterator atomItr = hitTerrAtoms.begin(); atomItr != hitTerrAtoms.end(); ) { + for (std::vector::iterator atomItr = hitTerrAtoms.begin(); atomItr != hitTerrAtoms.end();) { // Calculate and store the accurate hit radius of the Atom in relation to the CoM hitData.HitRadius[HITOR] = m_OwnerMOSR->RotateOffset((*atomItr)->GetOffset()) * c_MPP; // Figure out the pre-collision velocity of the hitting Atom due to body translation and rotation. @@ -584,30 +596,32 @@ namespace RTE { // If some Atoms could not penetrate even though all the impulse was on them, gather the bounce results and apply them to the owner. if (!hitTerrAtoms.empty()) { // Step back all Atoms that previously took one during this step iteration. This is so we aren't intersecting the hit MO anymore. - for (Atom *hitTerrAtom : hitTerrAtoms) { + for (Atom* hitTerrAtom: hitTerrAtoms) { hitTerrAtom->StepBack(); } // Calculate the distributed mass that each bouncing Atom has. - //massDistribution = mass /*/ GetSurfaceArea(hitTerrAtoms.size() * (m_Resolution ? m_Resolution : 1))*/; - //momentInertiaDistribution = m_MomentOfInertia/* / (hitTerrAtoms.size() * (m_Resolution ? m_Resolution : 1))*/; + // massDistribution = mass /*/ GetSurfaceArea(hitTerrAtoms.size() * (m_Resolution ? m_Resolution : 1))*/; + // momentInertiaDistribution = m_MomentOfInertia/* / (hitTerrAtoms.size() * (m_Resolution ? m_Resolution : 1))*/; const float hitFactor = 1.0F / static_cast(hitTerrAtoms.size()); // Gather the collision response effects so that the impulse force can be calculated. - for (Atom *hitTerrAtom : hitTerrAtoms) { + for (Atom* hitTerrAtom: hitTerrAtoms) { hitTerrAtom->GetHitData().TotalMass[HITOR] = mass; hitTerrAtom->GetHitData().MomInertia[HITOR] = m_MomentOfInertia; hitTerrAtom->GetHitData().ImpulseFactor[HITOR] = hitFactor; // Get the HitData so far gathered for this Atom. - //hitData = hitTerrAtom->GetHitData(); + // hitData = hitTerrAtom->GetHitData(); // Call the call-on-bounce function, if requested. - if (m_OwnerMOSR && callOnBounce) { halted = halted || m_OwnerMOSR->OnBounce(hitTerrAtom->GetHitData()); } + if (m_OwnerMOSR && callOnBounce) { + halted = halted || m_OwnerMOSR->OnBounce(hitTerrAtom->GetHitData()); + } // Copy back the new HitData with all the info we have so far. - //hitTerrAtom->SetHitData(hitData); + // hitTerrAtom->SetHitData(hitData); // Compute and store this Atom's collision response impulse force. hitTerrAtom->TerrHitResponse(); @@ -622,7 +636,7 @@ namespace RTE { const float hitFactor = 1.0F / static_cast(penetratingAtoms.size()); // Calculate and store the collision response effects. - for (Atom *penetratingAtom : penetratingAtoms) { + for (Atom* penetratingAtom: penetratingAtoms) { /* // This gets re-set later according to the ortho pixel edges hit. hitData.BitmapNormal = -(hitData.HitVel[HITOR].GetNormalized()); @@ -635,7 +649,7 @@ namespace RTE { // Get the HitData so far gathered for this Atom. hitData = penetratingAtom->GetHitData(); - if (g_SceneMan.TryPenetrate(penetratingAtom->GetCurrentPos().GetFloorIntX(), penetratingAtom->GetCurrentPos().GetFloorIntY(), hitData.PreImpulse[HITOR], hitData.HitVel[HITOR], retardation, 1.0F, 1/*(*penetratingAtom)->GetNumPenetrations()*/)) { + if (g_SceneMan.TryPenetrate(penetratingAtom->GetCurrentPos().GetFloorIntX(), penetratingAtom->GetCurrentPos().GetFloorIntY(), hitData.PreImpulse[HITOR], hitData.HitVel[HITOR], retardation, 1.0F, 1 /*(*penetratingAtom)->GetNumPenetrations()*/)) { // Recalculate these here without the distributed mass and MI. const float sqrRadMag = hitData.HitRadius[HITOR].GetSqrMagnitude(); hitData.HitDenominator = (1.0F / mass) + (sqrRadMag / m_MomentOfInertia); @@ -647,7 +661,9 @@ namespace RTE { hitData.ResImpulse[HITOR] = ((hitData.HitVel[HITOR] * retardation) / hitData.HitDenominator) * hitFactor; // Call the call-on-sink function, if requested. - if (m_OwnerMOSR && callOnSink) { halted = halted || m_OwnerMOSR->OnSink(hitData); } + if (m_OwnerMOSR && callOnSink) { + halted = halted || m_OwnerMOSR->OnSink(hitData); + } // Copy back the new HitData with all the info we have so far. penetratingAtom->SetHitData(hitData); @@ -665,14 +681,14 @@ namespace RTE { hitData.MomInertia[HITOR] = m_MomentOfInertia; hitData.ImpulseFactor[HITOR] = 1.0F / static_cast(atomsHitMOsCount); - for (auto &MOAtomMapEntry : hitMOAtoms) { + for (auto& MOAtomMapEntry: hitMOAtoms) { // The denominator that the MovableObject being hit should divide its mass with for each Atom of this AtomGroup that is colliding with it during this step. hitData.ImpulseFactor[HITEE] = 1.0F / static_cast(MOAtomMapEntry.second.size()); - for (Atom *hitMOAtom : MOAtomMapEntry.second) { + for (Atom* hitMOAtom: MOAtomMapEntry.second) { // Step back all Atoms that hit MOs during this step iteration. This is so we aren't intersecting the hit MO anymore. hitMOAtom->StepBack(); - //hitData.HitPoint = hitMOAtom->GetCurrentPos(); + // hitData.HitPoint = hitMOAtom->GetCurrentPos(); // Calculate and store the accurate hit radius of the Atom in relation to the CoM hitData.HitRadius[HITOR] = m_OwnerMOSR->RotateOffset(hitMOAtom->GetOffset()) * c_MPP; @@ -683,7 +699,7 @@ namespace RTE { // Let the Atom calculate the impulse force resulting from the collision, and only add it if collision is valid if (hitMOAtom->MOHitResponse()) { // Report the hit to both MO's in collision - HitData &hd = hitMOAtom->GetHitData(); + HitData& hd = hitMOAtom->GetHitData(); // Don't count collision if either says they got terminated if (!hd.RootBody[HITOR]->OnMOHit(hd) && !hd.RootBody[HITEE]->OnMOHit(hd)) { // Save the filled out Atom in the list for later application in this step. @@ -701,7 +717,7 @@ namespace RTE { // If we hit anything, during this almost completed segment, and are about to start a new one, apply the calculated response effects to the owning MO. if (hitStep) { // Apply all the collision response impulse forces to the linear and angular velocities of the owner MO. - for (Atom *hitResponseAtom : hitResponseAtoms) { + for (Atom* hitResponseAtom: hitResponseAtoms) { // TODO: Investigate damping! hitData = hitResponseAtom->GetHitData(); velocity += hitData.ResImpulse[HITOR] / mass; @@ -711,7 +727,7 @@ namespace RTE { } // Make sub-pixel progress if there was a hit on the very first step. - //if (segProgress == 0) { segProgress = 0.1 / (float)stepsOnSeg; } + // if (segProgress == 0) { segProgress = 0.1 / (float)stepsOnSeg; } // Now calculate the total time left to travel, according to the progress made. timeLeft -= timeLeft * (segProgress * segRatio); @@ -735,7 +751,7 @@ namespace RTE { ResolveMOSIntersection(position); - //if (!scenePreLocked) { g_SceneMan.UnlockScene(); } + // if (!scenePreLocked) { g_SceneMan.UnlockScene(); } ClearMOIDIgnoreList(); @@ -743,7 +759,7 @@ namespace RTE { int ignoreCount = 0; int maxIgnore = m_Atoms.size() / 2; - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { if (atom->IsIgnoringTerrain()) { ++ignoreCount; @@ -769,10 +785,10 @@ namespace RTE { return timeLeft; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: Break down and rework this dumpsterfire. - Vector AtomGroup::PushTravel(Vector &position, const Vector &velocity, float pushForce, bool &didWrap, float travelTime, bool callOnBounce, bool callOnSink, bool scenePreLocked) { + Vector AtomGroup::PushTravel(Vector& position, const Vector& velocity, float pushForce, bool& didWrap, float travelTime, bool callOnBounce, bool callOnSink, bool scenePreLocked) { ZoneScoped; RTEAssert(m_OwnerMOSR, "Tried to push-travel an AtomGroup that has no parent!"); @@ -795,11 +811,11 @@ namespace RTE { bool halted = false; // TODO: Fix HitMOs issue!! - bool hitMOs = false /*m_OwnerMOSR->m_HitsMOs*/; + bool hitMOs = false /*m_OwnerMOSR->m_HitsMOs*/; - const Material *hitMaterial = nullptr; - const Material *domMaterial = nullptr; - const Material *subMaterial = nullptr; + const Material* hitMaterial = nullptr; + const Material* domMaterial = nullptr; + const Material* subMaterial = nullptr; Vector legProgress; Vector forceVel; @@ -810,17 +826,17 @@ namespace RTE { HitData hitData; // Thread locals for performance reasons (avoid memory allocs) - thread_local std::unordered_map> MOIgnoreMap; + thread_local std::unordered_map> MOIgnoreMap; MOIgnoreMap.clear(); - thread_local std::unordered_map>> hitMOAtoms; + thread_local std::unordered_map>> hitMOAtoms; hitMOAtoms.clear(); - thread_local std::deque> hitTerrAtoms; + thread_local std::deque> hitTerrAtoms; hitTerrAtoms.clear(); - thread_local std::deque> penetratingAtoms; + thread_local std::deque> penetratingAtoms; penetratingAtoms.clear(); // Lock all bitmaps involved outside the loop - only relevant for video bitmaps so disabled at the moment. - //if (!scenePreLocked) { g_SceneMan.LockScene(); } + // if (!scenePreLocked) { g_SceneMan.LockScene(); } // Before the very first step of the first leg of this travel, we find that we're already intersecting with another MO, then we completely ignore collisions with that MO for this entire travel. // This is to prevent MO's from getting stuck in each other. @@ -828,7 +844,7 @@ namespace RTE { intPos[X] = position.GetFloorIntX(); intPos[Y] = position.GetFloorIntY(); - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { const Vector flippedOffset = atom->GetOffset().GetXFlipped(m_OwnerMOSR->m_HFlipped); // See if the Atom is starting out on top of another MO MOID tempMOID = g_SceneMan.GetMOIDPixel(intPos[X] + flippedOffset.GetFloorIntX(), intPos[Y] + flippedOffset.GetFloorIntY(), m_OwnerMOSR->GetTeam()); @@ -896,12 +912,18 @@ namespace RTE { int error = delta2[sub] - delta[dom]; - if (delta[X] > 1000) { delta[X] = 1000; } - if (delta[Y] > 1000) { delta[Y] = 1000; } + if (delta[X] > 1000) { + delta[X] = 1000; + } + if (delta[Y] > 1000) { + delta[Y] = 1000; + } // Bresenham's line drawing algorithm execution for (int domSteps = 0; domSteps < delta[dom] && !(hit[X] || hit[Y]); ++domSteps) { - if (subStepped) { ++subSteps; } + if (subStepped) { + ++subSteps; + } subStepped = false; // Take one step forward along the leg. @@ -922,7 +944,7 @@ namespace RTE { hitMOAtoms.clear(); hitTerrAtoms.clear(); - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { const Vector flippedOffset = atom->GetOffset().GetXFlipped(m_OwnerMOSR->m_HFlipped); MOID tempMOID = g_NoMOID; @@ -931,23 +953,25 @@ namespace RTE { if (hitMOs) { tempMOID = g_SceneMan.GetMOIDPixel(intPos[X] + flippedOffset.GetFloorIntX(), intPos[Y] + flippedOffset.GetFloorIntY(), m_OwnerMOSR->GetTeam()); // Check the ignore map for Atoms that should ignore hits against certain MOs. - if (tempMOID != g_NoMOID && (MOIgnoreMap.count(tempMOID) != 0)) { ignoreHit = MOIgnoreMap.at(tempMOID).count(atom) != 0; } + if (tempMOID != g_NoMOID && (MOIgnoreMap.count(tempMOID) != 0)) { + ignoreHit = MOIgnoreMap.at(tempMOID).count(atom) != 0; + } } if (hitMOs && tempMOID && !ignoreHit) { - hitMOAtoms[tempMOID].push_back({ atom, flippedOffset }); + hitMOAtoms[tempMOID].push_back({atom, flippedOffset}); // Count the number of Atoms of this group that hit MOs this step. Used to properly distribute the mass of the owner MO in later collision responses during this step. atomsHitMOsCount++; - // If no MO has ever been hit yet during this step, then keep checking for terrain hits. + // If no MO has ever been hit yet during this step, then keep checking for terrain hits. } else if (atomsHitMOsCount == 0 && g_SceneMan.GetTerrMatter(intPos[X] + flippedOffset.GetFloorIntX(), intPos[Y] + flippedOffset.GetFloorIntY())) { - hitTerrAtoms.push_back({ atom, flippedOffset }); + hitTerrAtoms.push_back({atom, flippedOffset}); } #ifdef DEBUG_BUILD // TODO: Remove this once AtomGroup drawing in Material layer draw mode is implemented. // Draw the positions of the hit points on screen for easy debugging. - //putpixel(g_SceneMan.GetMOColorBitmap(), std::floor(position.GetFloorIntX() + flippedOffset.GetFloorIntX()), std::floor(position.GetFloorIntY() + flippedOffset.GetFloorIntY()), 122); + // putpixel(g_SceneMan.GetMOColorBitmap(), std::floor(position.GetFloorIntX() + flippedOffset.GetFloorIntX()), std::floor(position.GetFloorIntY() + flippedOffset.GetFloorIntY()), 122); #endif } @@ -976,7 +1000,9 @@ namespace RTE { if (hitMOs && !hitMOAtoms.empty()) { // Back up one step so that we're not intersecting the other MO(s) anymore intPos[dom] -= increment[dom]; - if (subStepped) { intPos[sub] -= increment[sub]; } + if (subStepped) { + intPos[sub] -= increment[sub]; + } // Undo wrap, if necessary. didWrap = !g_SceneMan.WrapPosition(intPos[X], intPos[Y]) && didWrap; @@ -988,16 +1014,16 @@ namespace RTE { hitData.HitVel[HITOR] = forceVel; // The distributed mass of one hitting Atom of the hitting (this AtomGroup's owner) MovableObject. - //float hitorMass = mass / ((atomsHitMOsCount/* + hitTerrAtoms.size()*/) * (m_Resolution ? m_Resolution : 1)); - //float hiteeMassDenom = 0; + // float hitorMass = mass / ((atomsHitMOsCount/* + hitTerrAtoms.size()*/) * (m_Resolution ? m_Resolution : 1)); + // float hiteeMassDenom = 0; - for (const auto &MOAtomMapEntry : hitMOAtoms) { + for (const auto& MOAtomMapEntry: hitMOAtoms) { // The denominator that the MovableObject being hit should divide its mass with for each Atom of this AtomGroup that is colliding with it during this step. hitData.ImpulseFactor[HITEE] = 1.0F / static_cast(MOAtomMapEntry.second.size()); - for (const std::pair &hitMOAtomEntry : MOAtomMapEntry.second) { + for (const std::pair& hitMOAtomEntry: MOAtomMapEntry.second) { // Bake in current Atom's offset into the int positions. - const Vector &atomOffset = hitMOAtomEntry.second; + const Vector& atomOffset = hitMOAtomEntry.second; intPos[X] += atomOffset.GetFloorIntX(); intPos[Y] += atomOffset.GetFloorIntY(); hitPos[X] += atomOffset.GetFloorIntX(); @@ -1019,13 +1045,13 @@ namespace RTE { if (subStepped && delta[sub] && ((sub == X && g_SceneMan.GetMOIDPixel(hitPos[X], intPos[Y], m_OwnerMOSR->GetTeam()) != g_NoMOID) || (sub == Y && g_SceneMan.GetMOIDPixel(intPos[X], hitPos[Y], m_OwnerMOSR->GetTeam()) != g_NoMOID))) { hit[sub] = true; - //if (hitData.HitPoint.IsZero()) { - // NOTE: THis can actually be wrong since there may not in fact be a corner pixel, but two pixels hit on X and Y directions - hitData.HitPoint = (sub == X) ? Vector(static_cast(hitPos[X]), static_cast(intPos[Y])) : Vector(static_cast(intPos[X]), static_cast(hitPos[Y])); + // if (hitData.HitPoint.IsZero()) { + // NOTE: THis can actually be wrong since there may not in fact be a corner pixel, but two pixels hit on X and Y directions + hitData.HitPoint = (sub == X) ? Vector(static_cast(hitPos[X]), static_cast(intPos[Y])) : Vector(static_cast(intPos[X]), static_cast(hitPos[Y])); /* // We hit pixels in both sub and dom directions on the other MO, a corner hit. } else { - hitData.HitPoint.SetXY(hitPos[X], hitPos[Y]); + hitData.HitPoint.SetXY(hitPos[X], hitPos[Y]); } */ hitData.BitmapNormal[sub] = static_cast(-increment[sub]); @@ -1078,10 +1104,10 @@ namespace RTE { float massDistribution = mass / GetSurfaceArea(hitTerrAtoms.size() * (m_Resolution ? m_Resolution : 1)); - for (std::deque>::iterator atomItr = hitTerrAtoms.begin(); atomItr != hitTerrAtoms.end(); ) { + for (std::deque>::iterator atomItr = hitTerrAtoms.begin(); atomItr != hitTerrAtoms.end();) { if (g_SceneMan.WillPenetrate(intPos[X] + (*atomItr).second.GetFloorIntX(), intPos[Y] + (*atomItr).second.GetFloorIntY(), forceVel, massDistribution)) { // Move the penetrating Atom to the penetrating list from the collision list. - penetratingAtoms.push_back({ (*atomItr).first, (*atomItr).second }); + penetratingAtoms.push_back({(*atomItr).first, (*atomItr).second}); atomItr = hitTerrAtoms.erase(atomItr); somethingPenetrated = true; } else { @@ -1096,20 +1122,22 @@ namespace RTE { if (!hitTerrAtoms.empty()) { // Back up one step so that we're not intersecting the terrain anymore intPos[dom] -= increment[dom]; - if (subStepped) { intPos[sub] -= increment[sub]; } + if (subStepped) { + intPos[sub] -= increment[sub]; + } // Undo wrap, if necessary. didWrap = !g_SceneMan.WrapPosition(intPos[X], intPos[Y]) && didWrap; // Call the call-on-bounce function, if requested. - //if (m_OwnerMOSR && callOnBounce) { halted = m_OwnerMOSR->OnBounce(position); } + // if (m_OwnerMOSR && callOnBounce) { halted = m_OwnerMOSR->OnBounce(position); } - float massDistribution = mass / GetSurfaceArea((hitTerrAtoms.size()/* + atomsHitMOsCount*/) * (m_Resolution ? m_Resolution : 1)); + float massDistribution = mass / GetSurfaceArea((hitTerrAtoms.size() /* + atomsHitMOsCount*/) * (m_Resolution ? m_Resolution : 1)); // Gather the collision response effects so that the impulse force can be calculated. - for (const std::pair &hitTerrAtomsEntry : hitTerrAtoms) { + for (const std::pair& hitTerrAtomsEntry: hitTerrAtoms) { // Bake in current Atom's offset into the int positions. - const Vector &atomOffset = hitTerrAtomsEntry.second; + const Vector& atomOffset = hitTerrAtomsEntry.second; intPos[X] += atomOffset.GetFloorIntX(); intPos[Y] += atomOffset.GetFloorIntY(); hitPos[X] += atomOffset.GetFloorIntX(); @@ -1169,17 +1197,17 @@ namespace RTE { // All Atoms must have penetrated and therefore the entire group has sunken into the terrain. Get the penetration resistance results and apply them to the owner. else if (!penetratingAtoms.empty()) { - //bool sinkHit = true; + // bool sinkHit = true; hit[dom] = true; hit[sub] = true; // Call the call-on-sink function, if requested. - //if (m_OwnerMOSR && callOnSink) { halted = m_OwnerMOSR->OnSink(position); } + // if (m_OwnerMOSR && callOnSink) { halted = m_OwnerMOSR->OnSink(position); } float massDistribution = mass / GetSurfaceArea(penetratingAtoms.size() * (m_Resolution ? m_Resolution : 1)); // Apply the collision response effects. - for (const std::pair &penetratingAtomsEntry : penetratingAtoms) { + for (const std::pair& penetratingAtomsEntry: penetratingAtoms) { if (g_SceneMan.TryPenetrate(intPos[X] + penetratingAtomsEntry.second.GetFloorIntX(), intPos[Y] + penetratingAtomsEntry.second.GetFloorIntY(), forceVel * massDistribution, forceVel, retardation, 1.0F, penetratingAtomsEntry.first->GetNumPenetrations())) { ownerVel += (forceVel * massDistribution * retardation) / mass; returnPush += forceVel * massDistribution * retardation; @@ -1196,7 +1224,9 @@ namespace RTE { didWrap = didWrap || g_SceneMan.WrapPosition(position); // Stunt travel time if there is no more velocity - if (ownerVel.IsZero()) { timeLeft = 0; } + if (ownerVel.IsZero()) { + timeLeft = 0; + } } ++stepCount; } @@ -1212,9 +1242,9 @@ namespace RTE { return returnPush; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AtomGroup::PushAsLimb(const Vector &jointPos, const Vector &velocity, const Matrix &rotation, LimbPath &limbPath, const float travelTime, bool *restarted, bool affectRotation, Vector rotationOffset, Vector positionOffset) { + bool AtomGroup::PushAsLimb(const Vector& jointPos, const Vector& velocity, const Matrix& rotation, LimbPath& limbPath, const float travelTime, bool* restarted, bool affectRotation, Vector rotationOffset, Vector positionOffset) { RTEAssert(m_OwnerMOSR, "Tried to push-as-limb an AtomGroup that has no parent!"); bool didWrap = false; @@ -1251,7 +1281,9 @@ namespace RTE { // TODO: Change this to a regular while loop if possible. do { if (limbPath.PathEnded()) { - if (restarted) { *restarted = true; } + if (restarted) { + *restarted = true; + } if (!limbPath.RestartFree(m_LimbPos, m_OwnerMOSR->GetRootID(), m_OwnerMOSR->IgnoresWhichTeam())) { return false; } @@ -1260,10 +1292,12 @@ namespace RTE { limbPath.ReportProgress(m_LimbPos); } while (!limbPath.FrameDone() && !limbPath.PathEnded()); - if (pushImpulse.GetLargest() > 10000.0F) { pushImpulse.Reset(); } + if (pushImpulse.GetLargest() > 10000.0F) { + pushImpulse.Reset(); + } - if (Actor *owner = dynamic_cast(m_OwnerMOSR)) { - bool againstTravelDirection = owner->GetController()->IsState(MOVE_LEFT) && pushImpulse.m_X > 0.0F || + if (Actor* owner = dynamic_cast(m_OwnerMOSR)) { + bool againstTravelDirection = owner->GetController()->IsState(MOVE_LEFT) && pushImpulse.m_X > 0.0F || owner->GetController()->IsState(MOVE_RIGHT) && pushImpulse.m_X < 0.0F; if (againstTravelDirection) { // Filter some of our impulse out. We're pushing against an obstacle, but we don't want to kick backwards! @@ -1283,9 +1317,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AtomGroup::FlailAsLimb(const Vector &ownerPos, const Vector &jointOffset, const float limbRadius, const Vector &velocity, const float angularVel, const float mass, const float travelTime) { + void AtomGroup::FlailAsLimb(const Vector& ownerPos, const Vector& jointOffset, const float limbRadius, const Vector& velocity, const float angularVel, const float mass, const float travelTime) { RTEAssert(m_OwnerMOSR, "Tried to flail an AtomGroup that has no parent!"); bool didWrap = false; @@ -1305,18 +1339,18 @@ namespace RTE { return; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AtomGroup::InTerrain() const { RTEAssert(m_OwnerMOSR, "Tried to check overlap with terrain for an AtomGroup that has no parent!"); // Only relevant for video bitmaps so disabled at the moment. - //if (!g_SceneMan.SceneIsLocked()) { g_SceneMan.LockScene(); } + // if (!g_SceneMan.SceneIsLocked()) { g_SceneMan.LockScene(); } bool penetrates = false; Vector atomPos; - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { atomPos = m_OwnerMOSR->GetPos() + GetAdjustedAtomOffset(atom); if (g_SceneMan.GetTerrMatter(atomPos.GetFloorIntX(), atomPos.GetFloorIntY()) != g_MaterialAir) { penetrates = true; @@ -1324,37 +1358,39 @@ namespace RTE { } } - //if (g_SceneMan.SceneIsLocked()) { g_SceneMan.UnlockScene(); } + // if (g_SceneMan.SceneIsLocked()) { g_SceneMan.UnlockScene(); } return penetrates; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AtomGroup::RatioInTerrain() const { RTEAssert(m_OwnerMOSR, "Tried to check ratio in terrain for an AtomGroup that has no parent!"); // Only relevant for video bitmaps so disabled at the moment. - //if (!g_SceneMan.SceneIsLocked()) { g_SceneMan.LockScene(); } + // if (!g_SceneMan.SceneIsLocked()) { g_SceneMan.LockScene(); } Vector atomPos; int inTerrain = 0; - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { atomPos = m_OwnerMOSR->GetPos() + GetAdjustedAtomOffset(atom); - if (g_SceneMan.GetTerrMatter(atomPos.GetFloorIntX(), atomPos.GetFloorIntY()) != g_MaterialAir) { inTerrain++; } + if (g_SceneMan.GetTerrMatter(atomPos.GetFloorIntX(), atomPos.GetFloorIntY()) != g_MaterialAir) { + inTerrain++; + } } - //if (g_SceneMan.SceneIsLocked()) { g_SceneMan.UnlockScene(); } + // if (g_SceneMan.SceneIsLocked()) { g_SceneMan.UnlockScene(); } return static_cast(inTerrain) / static_cast(m_Atoms.size()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: Look into breaking this into smaller methods. - bool AtomGroup::ResolveTerrainIntersection(Vector &position, unsigned char strongerThan) const { - thread_local std::vector intersectingAtoms; + bool AtomGroup::ResolveTerrainIntersection(Vector& position, unsigned char strongerThan) const { + thread_local std::vector intersectingAtoms; intersectingAtoms.clear(); MOID hitMaterial = g_MaterialAir; @@ -1365,7 +1401,7 @@ namespace RTE { Vector atomPos = Vector(); // First go through all Atoms to find the first intersection and get the intersected MO - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { atomOffset = m_OwnerMOSR->RotateOffset(atom->GetOffset()); atom->SetupPos(position + atomOffset); atomPos = atom->GetCurrentPos(); @@ -1384,7 +1420,7 @@ namespace RTE { Vector exitDirection = Vector(); // Go through all intersecting Atoms and find their average inverse normal - for (const Atom *intersectingAtom : intersectingAtoms) { + for (const Atom* intersectingAtom: intersectingAtoms) { exitDirection += m_OwnerMOSR->RotateOffset(intersectingAtom->GetNormal()); } @@ -1403,7 +1439,7 @@ namespace RTE { Vector atomExitVector = Vector(); Vector totalExitVector = Vector(); - for (const Atom *intersectingAtom : intersectingAtoms) { + for (const Atom* intersectingAtom: intersectingAtoms) { bool rayHit = false; atomPos = intersectingAtom->GetCurrentPos(); @@ -1435,15 +1471,15 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: Look into breaking this into smaller methods. - bool AtomGroup::ResolveMOSIntersection(Vector &position) { + bool AtomGroup::ResolveMOSIntersection(Vector& position) { if (!m_OwnerMOSR->m_HitsMOs) { return true; } - MovableObject *intersectedMO = nullptr; + MovableObject* intersectedMO = nullptr; MOID currentMOID = g_NoMOID; MOID hitMOID = g_NoMOID; @@ -1451,7 +1487,7 @@ namespace RTE { Vector atomPos = Vector(); // First go through all Atoms to find the first intersection and get the intersected MO - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { atomOffset = m_OwnerMOSR->RotateOffset(atom->GetOffset()); atom->SetupPos(position + atomOffset); atomPos = atom->GetCurrentPos(); @@ -1462,7 +1498,7 @@ namespace RTE { currentMOID = hitMOID; // Get the MO we seem to be intersecting - MovableObject *tempMO = g_MovableMan.GetMOFromID(hitMOID); + MovableObject* tempMO = g_MovableMan.GetMOFromID(hitMOID); RTEAssert(tempMO, "Intersected MOID couldn't be translated to a real MO!"); tempMO = tempMO->GetRootParent(); @@ -1480,10 +1516,10 @@ namespace RTE { return false; } - std::vector intersectingAtoms; + std::vector intersectingAtoms; // Restart and go through all Atoms to find all intersecting the specific intersected MO - for (Atom *atom : m_Atoms) { + for (Atom* atom: m_Atoms) { atomPos = atom->GetCurrentPos(); if (g_SceneMan.GetMOIDPixel(atomPos.GetFloorIntX(), atomPos.GetFloorIntY(), m_OwnerMOSR->GetTeam()) == currentMOID) { // Add atom to list of intersecting ones @@ -1496,7 +1532,7 @@ namespace RTE { Vector totalExitVector = Vector(); // Go through all intersecting Atoms and find their average inverse normal - for (const Atom *intersectingAtom : intersectingAtoms) { + for (const Atom* intersectingAtom: intersectingAtoms) { exitDirection += m_OwnerMOSR->RotateOffset(intersectingAtom->GetNormal()); } @@ -1512,7 +1548,7 @@ namespace RTE { // See which of the intersecting Atoms has the longest to travel along the exit direction before it clears float sqrLongestDistance = 0.0F; - for (const Atom *intersectingAtom : intersectingAtoms) { + for (const Atom* intersectingAtom: intersectingAtoms) { atomPos = intersectingAtom->GetCurrentPos(); if (g_SceneMan.CastFindMORay(atomPos, exitDirection, g_NoMOID, clearPos, 0, true, 0)) { atomExitVector = clearPos - atomPos.GetFloored(); @@ -1539,8 +1575,8 @@ namespace RTE { float normMassA = invMassA / (invMassA + invMassB); float normMassB = invMassB / (invMassA + invMassB); - //TODO investigate whether we should apply some (relatively small) amount of movement to the object even if it's a lot heavier, for more realistic physics - // If the intersected is much larger than this' MO, then only move this. Otherwise, apply the movements to both this and the intersected MO's, proportional to their respective masses. + // TODO investigate whether we should apply some (relatively small) amount of movement to the object even if it's a lot heavier, for more realistic physics + // If the intersected is much larger than this' MO, then only move this. Otherwise, apply the movements to both this and the intersected MO's, proportional to their respective masses. if (normMassB < 0.33F) { thisExit = totalExitVector; } else { @@ -1550,12 +1586,12 @@ namespace RTE { } // Now actually apply the exit vectors to both, but only if the jump isn't too jarring - if (thisExit.MagnitudeIsLessThan(m_OwnerMOSR->GetIndividualRadius())) { - position += thisExit; + if (thisExit.MagnitudeIsLessThan(m_OwnerMOSR->GetIndividualRadius())) { + position += thisExit; } - if (!intersectedExit.IsZero() && intersectedExit.MagnitudeIsLessThan(intersectedMO->GetRadius())) { - intersectedMO->SetPos(intersectedMO->GetPos() + intersectedExit); + if (!intersectedExit.IsZero() && intersectedExit.MagnitudeIsLessThan(intersectedMO->GetRadius())) { + intersectedMO->SetPos(intersectedMO->GetPos() + intersectedExit); } if (m_OwnerMOSR->CanBeSquished() && RatioInTerrain() > 0.75F) /* && totalExitVector.MagnitudeIsGreaterThan(m_OwnerMOSR->GetDiameter())) */ { @@ -1564,7 +1600,7 @@ namespace RTE { m_OwnerMOSR->GibThis(-totalExitVector); } - MOSRotating *intersectedMOS = dynamic_cast(intersectedMO); + MOSRotating* intersectedMOS = dynamic_cast(intersectedMO); if (intersectedMOS && intersectedMOS->CanBeSquished() && intersectedMOS->GetAtomGroup()->RatioInTerrain() > 0.75F) /* && totalExitVector.MagnitudeIsGreaterThan(intersectedMO->GetDiameter())) */ { // Move back before gibbing so gibs don't end up inside terrain @@ -1576,7 +1612,7 @@ namespace RTE { return intersectingAtoms.empty(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AtomGroup::GetSurfaceArea(int pixelWidth) const { float distributionAmount; @@ -1586,10 +1622,10 @@ namespace RTE { distributionAmount = static_cast(pixelWidth); break; case AreaDistributionType::Circle: { - const float radius = static_cast(pixelWidth) * 0.5F; - distributionAmount = c_PI * radius * radius; - break; - } + const float radius = static_cast(pixelWidth) * 0.5F; + distributionAmount = c_PI * radius * radius; + break; + } case AreaDistributionType::Square: distributionAmount = static_cast(pixelWidth * pixelWidth); break; @@ -1601,15 +1637,15 @@ namespace RTE { return distributionAmount * m_AreaDistributionSurfaceAreaMultiplier; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AtomGroup::Draw(BITMAP *targetBitmap, const Vector &targetPos, bool useLimbPos, unsigned char color) const { + void AtomGroup::Draw(BITMAP* targetBitmap, const Vector& targetPos, bool useLimbPos, unsigned char color) const { Vector atomPos; Vector normal; acquire_bitmap(targetBitmap); - for (const Atom *atom : m_Atoms) { + for (const Atom* atom: m_Atoms) { if (!useLimbPos) { atomPos = m_OwnerMOSR->GetPos() + GetAdjustedAtomOffset(atom); } else { @@ -1624,11 +1660,11 @@ namespace RTE { release_bitmap(targetBitmap); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: dan pls. - void AtomGroup::GenerateAtomGroup(MOSRotating *ownerMOSRotating) { - BITMAP *refSprite = ownerMOSRotating->GetSpriteFrame(); + void AtomGroup::GenerateAtomGroup(MOSRotating* ownerMOSRotating) { + BITMAP* refSprite = ownerMOSRotating->GetSpriteFrame(); const Vector spriteOffset = ownerMOSRotating->GetSpriteOffset(); const int spriteWidth = refSprite->w * static_cast(m_OwnerMOSR->GetScale()); const int spriteHeight = refSprite->h * static_cast(m_OwnerMOSR->GetScale()); @@ -1639,7 +1675,7 @@ namespace RTE { int y; bool inside; - BITMAP *checkBitmap = create_bitmap_ex(8, spriteWidth, spriteHeight); + BITMAP* checkBitmap = create_bitmap_ex(8, spriteWidth, spriteHeight); clear_to_color(checkBitmap, g_MaskColor); acquire_bitmap(refSprite); @@ -1826,15 +1862,19 @@ namespace RTE { } // If no Atoms were made, just place a default one in the middle - if (m_Atoms.empty()) { AddAtomToGroup(ownerMOSRotating, spriteOffset, spriteWidth / 2, spriteHeight / 2, false); } + if (m_Atoms.empty()) { + AddAtomToGroup(ownerMOSRotating, spriteOffset, spriteWidth / 2, spriteHeight / 2, false); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AtomGroup::AddAtomToGroup(MOSRotating *ownerMOSRotating, const Vector &spriteOffset, int x, int y, bool calcNormal) { - Atom *atomToAdd = new Atom(Vector(static_cast(x) + spriteOffset.GetFloorIntX(), static_cast(y) + spriteOffset.GetFloorIntY()), m_Material, ownerMOSRotating); - if (calcNormal) { atomToAdd->CalculateNormal(ownerMOSRotating->GetSpriteFrame(), -ownerMOSRotating->GetSpriteOffset()); } + void AtomGroup::AddAtomToGroup(MOSRotating* ownerMOSRotating, const Vector& spriteOffset, int x, int y, bool calcNormal) { + Atom* atomToAdd = new Atom(Vector(static_cast(x) + spriteOffset.GetFloorIntX(), static_cast(y) + spriteOffset.GetFloorIntY()), m_Material, ownerMOSRotating); + if (calcNormal) { + atomToAdd->CalculateNormal(ownerMOSRotating->GetSpriteFrame(), -ownerMOSRotating->GetSpriteOffset()); + } atomToAdd->SetIgnoreMOIDsByGroup(&m_IgnoreMOIDs); m_Atoms.push_back(atomToAdd); } -} +} // namespace RTE diff --git a/Source/Entities/AtomGroup.h b/Source/Entities/AtomGroup.h index 403ed2901..564d980fb 100644 --- a/Source/Entities/AtomGroup.h +++ b/Source/Entities/AtomGroup.h @@ -14,7 +14,6 @@ namespace RTE { class AtomGroup : public Entity { public: - EntityAllocation(AtomGroup); SerializableOverrideMethods; ClassInfoGetters; @@ -29,7 +28,10 @@ namespace RTE { /// Copy constructor method used to instantiate an AtomGroup object identical to an already existing one. /// /// An AtomGroup object which is passed in by reference. - AtomGroup(const AtomGroup &reference) { Clear(); Create(reference); } + AtomGroup(const AtomGroup& reference) { + Clear(); + Create(reference); + } /// /// Makes the AtomGroup object ready for use. @@ -42,7 +44,7 @@ namespace RTE { /// /// A reference to the AtomGroup to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const AtomGroup &reference) { return Create(reference, false); } + int Create(const AtomGroup& reference) { return Create(reference, false); } /// /// Creates an AtomGroup to be identical to another, by deep copy, with the option to only copy Atoms that belong to the reference AtomGroup's owner thereby excluding any Atom subgroups. @@ -50,15 +52,15 @@ namespace RTE { /// A reference to the AtomGroup to deep copy. /// Whether or not to only copy Atoms that belong to the reference AtomGroup's owner directly. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const AtomGroup &reference, bool onlyCopyOwnerAtoms); + int Create(const AtomGroup& reference, bool onlyCopyOwnerAtoms); /// - /// Creates an AtomGroup after the silhouette shape of a passed in MOSRotating by dotting the outline of the sprite with Atoms. + /// Creates an AtomGroup after the silhouette shape of a passed in MOSRotating by dotting the outline of the sprite with Atoms. /// The passed in MOSRotating will also be made the owner of this AtomGroup! Ownership of the MOSRotating is NOT transferred! /// /// A pointer to a MOSRotating whose outline will be approximated by Atoms of this AtomGroup, and that will be set as the owner of this AtomGroup. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(MOSRotating *ownerMOSRotating) { return Create(ownerMOSRotating, m_Material, m_Resolution, m_Depth); } + int Create(MOSRotating* ownerMOSRotating) { return Create(ownerMOSRotating, m_Material, m_Resolution, m_Depth); } /// /// Creates an AtomGroup after the silhouette shape of a passed in MOSRotating by dotting the outline of the sprite with Atoms. @@ -69,7 +71,7 @@ namespace RTE { /// Resolution, or density of the Atoms in representing the MOSRotating's outline. Lower value equals higher density. /// The depth into the sprite that the Atoms should be placed. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(MOSRotating *ownerMOSRotating, Material const *material, int resolution = 1, int depth = 0); + int Create(MOSRotating* ownerMOSRotating, Material const* material, int resolution = 1, int depth = 0); #pragma endregion #pragma region Destruction @@ -87,7 +89,10 @@ namespace RTE { /// /// Resets the entire AtomGroup, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -95,13 +100,13 @@ namespace RTE { /// Gets the current list of Atoms that make up the group. /// /// A const reference to the Atom list. - const std::vector & GetAtomList() const { return m_Atoms; } + const std::vector& GetAtomList() const { return m_Atoms; } /// /// Sets the a new list of Atoms that make up the group. /// /// List of Atoms that make up the group. - void SetAtomList(const std::vector &newAtoms); + void SetAtomList(const std::vector& newAtoms); /// /// Gets the current number of Atoms that make up the group. @@ -119,19 +124,19 @@ namespace RTE { /// Gets the current owner MOSRotating of this AtomGroup. /// /// A pointer to the owner. - MOSRotating * GetOwner() const { return m_OwnerMOSR; } + MOSRotating* GetOwner() const { return m_OwnerMOSR; } /// /// Sets the current owner MOSRotating of this AtomGroup. /// /// A pointer to the new owner. Ownership is NOT transferred! - void SetOwner(MOSRotating *newOwner); + void SetOwner(MOSRotating* newOwner); /// /// Gets the Material of this AtomGroup. /// /// A const pointer to the Material. - const Material * GetMaterial() const { return (m_Material) ? m_Material : g_SceneMan.GetMaterialFromID(g_MaterialAir); } + const Material* GetMaterial() const { return (m_Material) ? m_Material : g_SceneMan.GetMaterialFromID(g_MaterialAir); } /// /// Gets whether this AtomGroup's Atoms are to be automatically generated based on a bitmap, or manually specified. @@ -156,7 +161,7 @@ namespace RTE { /// /// The individual Atom to get the offset for. /// The offset of an Atom in this AtomGroup adjusted to the Owner MOSRotating horizontal flip and rotation. - Vector GetAdjustedAtomOffset(const Atom *atom) const; + Vector GetAdjustedAtomOffset(const Atom* atom) const; /// /// Gets the current position of this AtomGroup as a limb. @@ -170,7 +175,7 @@ namespace RTE { /// /// The Vector with the new absolute position. /// Whether to adjust the new position for horizontal flip or not. - void SetLimbPos(const Vector &newPos, bool hFlipped = false) { m_LimbPos = newPos - m_JointOffset.GetXFlipped(hFlipped); } + void SetLimbPos(const Vector& newPos, bool hFlipped = false) { m_LimbPos = newPos - m_JointOffset.GetXFlipped(hFlipped); } /// /// Gets the current mass moment of inertia of this AtomGroup. @@ -182,7 +187,7 @@ namespace RTE { /// Sets the offset of the joint relative to this AtomGroup's origin when used as a limb. /// /// The new joint offset. - void SetJointOffset(const Vector &newOffset) { m_JointOffset = newOffset; } + void SetJointOffset(const Vector& newOffset) { m_JointOffset = newOffset; } #pragma endregion #pragma region Atom Management @@ -192,7 +197,11 @@ namespace RTE { /// /// A pointer to an Atom that will pushed onto the end of the list. Ownership IS transferred! /// The subgroup ID that the new Atom will have within the group. - void AddAtom(Atom *newAtom, long subgroupID = 0) { newAtom->SetSubID(subgroupID); m_Atoms.push_back(newAtom); m_MomentOfInertia = 0.0F; } + void AddAtom(Atom* newAtom, long subgroupID = 0) { + newAtom->SetSubID(subgroupID); + m_Atoms.push_back(newAtom); + m_MomentOfInertia = 0.0F; + } /// /// Adds a list of new Atoms to the internal list that makes up this AtomGroup. Ownership of all Atoms in the list IS NOT transferred! @@ -201,7 +210,7 @@ namespace RTE { /// The desired subgroup ID for the Atoms being added. /// An offset that should be applied to all added Atoms. /// The rotation of the placed Atoms around the specified offset. - void AddAtoms(const std::vector &atomList, long subgroupID = 0, const Vector &offset = Vector(), const Matrix &offsetRotation = Matrix()); + void AddAtoms(const std::vector& atomList, long subgroupID = 0, const Vector& offset = Vector(), const Matrix& offsetRotation = Matrix()); /// /// Removes all Atoms of a specific subgroup ID from this AtomGroup. @@ -213,7 +222,12 @@ namespace RTE { /// /// Removes all atoms in this AtomGroup, leaving it empty of Atoms. /// - void RemoveAllAtoms() { m_Atoms.clear(); m_SubGroups.clear(); m_MomentOfInertia = 0.0F; m_StoredOwnerMass = 0.0F; } + void RemoveAllAtoms() { + m_Atoms.clear(); + m_SubGroups.clear(); + m_MomentOfInertia = 0.0F; + m_StoredOwnerMass = 0.0F; + } /// /// Gets whether the AtomGroup contains a subgroup with the given subgroupID. @@ -229,7 +243,7 @@ namespace RTE { /// The change in offset for the Atoms of the specified subgroup. /// The rotation of the updated Atoms around the specified offset. /// Whether any Atoms were found and updated for the specified subgroup. - bool UpdateSubAtoms(long subgroupID = 0, const Vector &newOffset = Vector(), const Matrix& newOffsetRotation = Matrix()); + bool UpdateSubAtoms(long subgroupID = 0, const Vector& newOffset = Vector(), const Matrix& newOffsetRotation = Matrix()); #pragma endregion #pragma region Travel @@ -261,7 +275,7 @@ namespace RTE { /// /// Pseudocode explaining how this works can be found at: https://github.com/cortex-command-community/Cortex-Command-Community-Project-Source/wiki/Notes-on-AtomGroup::Travel. /// - float Travel(Vector &position, Vector &velocity, Matrix &rotation, float &angularVel, bool &didWrap, Vector &totalImpulse, float mass, float travelTime, bool callOnBounce = false, bool callOnSink = false, bool scenePreLocked = false); + float Travel(Vector& position, Vector& velocity, Matrix& rotation, float& angularVel, bool& didWrap, Vector& totalImpulse, float mass, float travelTime, bool callOnBounce = false, bool callOnSink = false, bool scenePreLocked = false); /// /// Makes this AtomGroup travel without rotation and react with the scene by pushing against it. @@ -275,7 +289,7 @@ namespace RTE { /// Whether to call the parent MOSR's OnSink function upon sinking into anything or not. /// Whether the Scene has been pre-locked or not. /// A Vector with the resulting push impulse force, in Newton-second (Ns). - Vector PushTravel(Vector &position, const Vector &velocity, float pushForce, bool &didWrap, float travelTime, bool callOnBounce = false, bool callOnSink = false, bool scenePreLocked = false); + Vector PushTravel(Vector& position, const Vector& velocity, float pushForce, bool& didWrap, float travelTime, bool callOnBounce = false, bool callOnSink = false, bool scenePreLocked = false); /// /// Makes this AtomGroup travel as a pushing entity relative to the position of the owning MOSRotating. @@ -291,7 +305,7 @@ namespace RTE { /// The position, relative to the owning actor's position, that we should rotate around. /// The positional offset to apply to our limb path. /// Whether the LimbPath passed in could start free of terrain or not. - bool PushAsLimb(const Vector &jointPos, const Vector &velocity, const Matrix &rotation, LimbPath &limbPath, const float travelTime, bool *restarted = nullptr, bool affectRotation = true, Vector rotationOffset = Vector(), Vector positionOffset = Vector()); + bool PushAsLimb(const Vector& jointPos, const Vector& velocity, const Matrix& rotation, LimbPath& limbPath, const float travelTime, bool* restarted = nullptr, bool affectRotation = true, Vector rotationOffset = Vector(), Vector positionOffset = Vector()); /// /// Makes this AtomGroup travel as a lifeless limb, constrained to a radius around the joint pin in the center. @@ -303,7 +317,7 @@ namespace RTE { /// A float with the angular velocity in rad/sec of the owning MOSRotating. /// The mass of this dead weight limb. /// The amount of time in seconds that this AtomGroup is supposed to travel. - void FlailAsLimb(const Vector &ownerPos, const Vector &jointOffset, const float limbRadius, const Vector &velocity, const float angularVel, const float mass, const float travelTime); + void FlailAsLimb(const Vector& ownerPos, const Vector& jointOffset, const float limbRadius, const Vector& velocity, const float angularVel, const float mass, const float travelTime); #pragma endregion #pragma region Collision @@ -344,14 +358,14 @@ namespace RTE { /// Current position of the owner MOSR. /// Only attempt to move out of materials stronger than this specific ID. /// Whether any intersection was successfully resolved. Will return true even if there wasn't any intersections to begin with. - bool ResolveTerrainIntersection(Vector &position, unsigned char strongerThan = 0) const; + bool ResolveTerrainIntersection(Vector& position, unsigned char strongerThan = 0) const; /// /// Checks whether any of the Atoms in this AtomGroup are on top of MOSprites, and if so, attempt to move the OwnerMO out so none of the Atoms are inside the other MOSprite's silhouette anymore. /// /// Current position of the owner MOSR.> /// Whether all intersections were successfully resolved. - bool ResolveMOSIntersection(Vector &position); + bool ResolveMOSIntersection(Vector& position); /// /// Returns the surface area for a given pixel width. @@ -368,14 +382,18 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// Whether to use the limb position of this AtomGroup, or the owner's position. /// The color to draw the Atoms' pixels as. - void Draw(BITMAP *targetBitmap, const Vector &targetPos, bool useLimbPos = false, unsigned char color = 34) const; + void Draw(BITMAP* targetBitmap, const Vector& targetPos, bool useLimbPos = false, unsigned char color = 34) const; #pragma endregion protected: /// /// Enumeration for how the AtomGroup's area is distributed. Linear means it acts a 2D line whereas Circle/Square acts as a pseudo-3d circle/square. /// - enum class AreaDistributionType { Linear, Circle, Square }; + enum class AreaDistributionType { + Linear, + Circle, + Square + }; static const std::unordered_map c_AreaDistributionTypeMap; //!< A map of strings to AreaDistributionTypes to support string parsing for the AreaDistributionType enum. @@ -383,12 +401,12 @@ namespace RTE { // TODO: It's probably worth trying out changing this from a list to a vector. m_Atoms is iterated over often and we could probably get some big gainz by doing this swap. // The downside is anytime attachables with atoms get added we may have the cost of resizing the vector but that's an uncommon use case while iterating over atoms happens multiple times per frame. - std::vector m_Atoms; //!< List of Atoms that constitute the group. Owned by this. - std::unordered_map> m_SubGroups; //!< Sub groupings of Atoms. Points to Atoms owned in m_Atoms. Not owned. + std::vector m_Atoms; //!< List of Atoms that constitute the group. Owned by this. + std::unordered_map> m_SubGroups; //!< Sub groupings of Atoms. Points to Atoms owned in m_Atoms. Not owned. - MOSRotating *m_OwnerMOSR; //!< The owner of this AtomGroup. The owner is obviously not owned by this AtomGroup. + MOSRotating* m_OwnerMOSR; //!< The owner of this AtomGroup. The owner is obviously not owned by this AtomGroup. float m_StoredOwnerMass; //!< The stored mass for the owner MOSR. Used to figure out when the moment of inertia needs to be recalculated due to significant mass changes. - const Material *m_Material; //!< Material of this AtomGroup. + const Material* m_Material; //!< Material of this AtomGroup. bool m_AutoGenerate; //!< Whether the Atoms in this AtomGroup were automatically generated based on a sprite, or manually defined. @@ -408,19 +426,18 @@ namespace RTE { float m_MomentOfInertia; //!< Moment of Inertia for this AtomGroup. std::vector m_IgnoreMOIDs; //!< List of MOIDs this AtomGroup will ignore collisions with. - + AreaDistributionType m_AreaDistributionType; //!< How this AtomGroup will distribute energy when it collides with something. - + float m_AreaDistributionSurfaceAreaMultiplier; //!< A multiplier for the AtomGroup's surface area, which affects how much it digs into terrain. 0.5 would halve the surface area so it would dig into terrain twice as much, 2.0 would make it dig into terrain half as much. private: - #pragma region Create Breakdown /// /// Generates an AtomGroup using the owner MOSRotating's sprite outline. /// /// MOSRotating whose outline will be approximated by Atoms of this AtomGroup. - void GenerateAtomGroup(MOSRotating *ownerMOSRotating); + void GenerateAtomGroup(MOSRotating* ownerMOSRotating); /// /// Create and add an Atom to this AtomGroup's list of Atoms. This is called during GenerateAtomGroup(). @@ -430,7 +447,7 @@ namespace RTE { /// X coordinate in the sprite frame. /// Y coordinate in the sprite frame. /// Whether to set a normal for the Atom. Should be true for surface Atoms. - void AddAtomToGroup(MOSRotating *ownerMOSRotating, const Vector &spriteOffset, int x, int y, bool calcNormal); + void AddAtomToGroup(MOSRotating* ownerMOSRotating, const Vector& spriteOffset, int x, int y, bool calcNormal); #pragma endregion /// @@ -438,5 +455,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/Attachable.cpp b/Source/Entities/Attachable.cpp index 53a77be3f..c86309246 100644 --- a/Source/Entities/Attachable.cpp +++ b/Source/Entities/Attachable.cpp @@ -11,7 +11,7 @@ namespace RTE { ConcreteClassInfo(Attachable, MOSRotating, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::Clear() { m_Parent = nullptr; @@ -53,7 +53,7 @@ namespace RTE { m_PreUpdateHasRunThisFrame = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Attachable::Create() { MOSRotating::Create(); @@ -63,9 +63,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Attachable::Create(const Attachable &reference) { + int Attachable::Create(const Attachable& reference) { MOSRotating::Create(reference); m_ParentOffset = reference.m_ParentOffset; @@ -98,8 +98,8 @@ namespace RTE { m_CollidesWithTerrainWhileAttached = reference.m_CollidesWithTerrainWhileAttached; m_IgnoresParticlesWhileAttached = reference.m_IgnoresParticlesWhileAttached; - for (const std::unique_ptr &pieSlice : reference.m_PieSlices) { - m_PieSlices.emplace_back(std::unique_ptr(dynamic_cast(pieSlice->Clone()))); + for (const std::unique_ptr& pieSlice: reference.m_PieSlices) { + m_PieSlices.emplace_back(std::unique_ptr(dynamic_cast(pieSlice->Clone()))); } m_PrevRotAngleOffset = reference.m_PrevRotAngleOffset; @@ -107,11 +107,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Attachable::ReadProperty(const std::string_view &propName, Reader &reader) { + int Attachable::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return MOSRotating::ReadProperty(propName, reader)); - + MatchProperty("ParentOffset", { reader >> m_ParentOffset; }); MatchProperty("DrawAfterParent", { reader >> m_DrawAfterParent; }); MatchProperty("DeleteWhenRemovedFromParent", { reader >> m_DeleteWhenRemovedFromParent; }); @@ -127,13 +127,17 @@ namespace RTE { }); MatchProperty("JointOffset", { reader >> m_JointOffset; }); MatchProperty("BreakWound", { - m_BreakWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); - if (!m_ParentBreakWound) { m_ParentBreakWound = m_BreakWound; } + m_BreakWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); + if (!m_ParentBreakWound) { + m_ParentBreakWound = m_BreakWound; + } }); - MatchProperty("ParentBreakWound", { m_ParentBreakWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); + MatchProperty("ParentBreakWound", { m_ParentBreakWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); MatchProperty("InheritsHFlipped", { reader >> m_InheritsHFlipped; - if (m_InheritsHFlipped != 0 && m_InheritsHFlipped != 1) { m_InheritsHFlipped = -1; } + if (m_InheritsHFlipped != 0 && m_InheritsHFlipped != 1) { + m_InheritsHFlipped = -1; + } }); MatchProperty("InheritsRotAngle", { reader >> m_InheritsRotAngle; }); MatchForwards("InheritedRotAngleRadOffset") MatchProperty("InheritedRotAngleOffset", { reader >> m_InheritedRotAngleOffset; }); @@ -141,14 +145,14 @@ namespace RTE { MatchProperty("InheritsFrame", { reader >> m_InheritsFrame; }); MatchProperty("CollidesWithTerrainWhileAttached", { reader >> m_CollidesWithTerrainWhileAttached; }); MatchProperty("IgnoresParticlesWhileAttached", { reader >> m_IgnoresParticlesWhileAttached; }); - MatchProperty("AddPieSlice", { m_PieSlices.emplace_back(std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)))); }); + MatchProperty("AddPieSlice", { m_PieSlices.emplace_back(std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)))); }); EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Attachable::Save(Writer &writer) const { + int Attachable::Save(Writer& writer) const { MOSRotating::Save(writer); writer.NewPropertyWithValue("ParentOffset", m_ParentOffset); @@ -171,16 +175,16 @@ namespace RTE { writer.NewPropertyWithValue("CollidesWithTerrainWhileAttached", m_CollidesWithTerrainWhileAttached); writer.NewPropertyWithValue("IgnoresParticlesWhileAttached", m_IgnoresParticlesWhileAttached); - for (const std::unique_ptr &pieSlice : m_PieSlices) { + for (const std::unique_ptr& pieSlice: m_PieSlices) { writer.NewPropertyWithValue("AddPieSlice", pieSlice.get()); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Attachable::TransferJointForces(Vector &jointForces) { + bool Attachable::TransferJointForces(Vector& jointForces) { if (!m_Parent) { return false; } @@ -193,9 +197,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Attachable::TransferJointImpulses(Vector &jointImpulses, float jointStiffnessValueToUse, float jointStrengthValueToUse, float gibImpulseLimitValueToUse) { + bool Attachable::TransferJointImpulses(Vector& jointImpulses, float jointStiffnessValueToUse, float jointStrengthValueToUse, float gibImpulseLimitValueToUse) { if (!m_Parent) { return false; } @@ -205,11 +209,15 @@ namespace RTE { jointStiffnessValueToUse = jointStiffnessValueToUse > 0 ? jointStiffnessValueToUse : m_JointStiffness; jointStrengthValueToUse = jointStrengthValueToUse > 0 ? jointStrengthValueToUse : m_JointStrength; gibImpulseLimitValueToUse = gibImpulseLimitValueToUse > 0 ? gibImpulseLimitValueToUse : m_GibImpulseLimit; - if (jointStrengthValueToUse == 0) { gibImpulseLimitValueToUse = 0; } - if (gibImpulseLimitValueToUse > 0) { gibImpulseLimitValueToUse = std::max(gibImpulseLimitValueToUse, jointStrengthValueToUse); } + if (jointStrengthValueToUse == 0) { + gibImpulseLimitValueToUse = 0; + } + if (gibImpulseLimitValueToUse > 0) { + gibImpulseLimitValueToUse = std::max(gibImpulseLimitValueToUse, jointStrengthValueToUse); + } Vector totalImpulseForce; - for (const auto &[impulseForce, impulseForceOffset] : m_ImpulseForces) { + for (const auto& [impulseForce, impulseForceOffset]: m_ImpulseForces) { totalImpulseForce += impulseForce; } totalImpulseForce *= jointStiffnessValueToUse; @@ -218,8 +226,10 @@ namespace RTE { // The first part is getting the Dot/Scalar product of the perpendicular of the offset vector for the force onto the force vector itself (dot product is the amount two vectors are pointing in the same direction). // The second part is dividing that Dot product by the moment of inertia, i.e. the torque needed to make it turn. All of this is multiplied by 1 - JointStiffness, because max stiffness joints transfer all force to parents (leaving none to affect the Attachable) and min stiffness transfer none. if (!m_InheritsRotAngle) { - for (const auto &[impulseForce, impulseForceOffset] : m_ImpulseForces) { - if (!impulseForceOffset.IsZero()) { m_AngularVel += (impulseForceOffset.GetPerpendicular().Dot(impulseForce) / m_pAtomGroup->GetMomentOfInertia()) * (1.0F - std::clamp(jointStiffnessValueToUse, 0.0F, 1.0F)); } + for (const auto& [impulseForce, impulseForceOffset]: m_ImpulseForces) { + if (!impulseForceOffset.IsZero()) { + m_AngularVel += (impulseForceOffset.GetPerpendicular().Dot(impulseForce) / m_pAtomGroup->GetMomentOfInertia()) * (1.0F - std::clamp(jointStiffnessValueToUse, 0.0F, 1.0F)); + } } } @@ -240,17 +250,17 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Attachable::CollectDamage() { if (m_DamageMultiplier != 0) { float totalDamage = m_DamageCount; m_DamageCount = 0; - for (AEmitter *wound : m_Wounds) { + for (AEmitter* wound: m_Wounds) { totalDamage += wound->CollectDamage(); } - for (Attachable *attachable : m_Attachables) { + for (Attachable* attachable: m_Attachables) { totalDamage += attachable->CollectDamage(); } return totalDamage * m_DamageMultiplier; @@ -258,7 +268,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::SetCollidesWithTerrainWhileAttached(bool collidesWithTerrainWhileAttached) { if (m_CollidesWithTerrainWhileAttached != collidesWithTerrainWhileAttached) { @@ -271,39 +281,47 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Attachable::CanCollideWithTerrain() const { if (m_CollidesWithTerrainWhileAttached && IsAttached() && GetParent() != GetRootParent()) { - if (const Attachable *parentAsAttachable = dynamic_cast(GetParent())) { return parentAsAttachable->CanCollideWithTerrain(); } + if (const Attachable* parentAsAttachable = dynamic_cast(GetParent())) { + return parentAsAttachable->CanCollideWithTerrain(); + } } return m_CollidesWithTerrainWhileAttached; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Attachable::CollideAtPoint(HitData &hd) { - if (m_IgnoresParticlesWhileAttached && m_Parent && !m_Parent->ToDelete() && !dynamic_cast(hd.Body[HITOR])) { + bool Attachable::CollideAtPoint(HitData& hd) { + if (m_IgnoresParticlesWhileAttached && m_Parent && !m_Parent->ToDelete() && !dynamic_cast(hd.Body[HITOR])) { return false; } return MOSRotating::CollideAtPoint(hd); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Attachable::ParticlePenetration(HitData &hd) { + bool Attachable::ParticlePenetration(HitData& hd) { bool penetrated = MOSRotating::ParticlePenetration(hd); if (m_Parent) { - MovableObject *hitor = hd.Body[HITOR]; + MovableObject* hitor = hd.Body[HITOR]; float damageToAdd = hitor->DamageOnCollision(); damageToAdd += penetrated ? hitor->DamageOnPenetration() : 0; - if (hitor->GetApplyWoundDamageOnCollision()) { damageToAdd += m_pEntryWound->GetEmitDamage() * hitor->WoundDamageMultiplier(); } - if (hitor->GetApplyWoundBurstDamageOnCollision()) { damageToAdd += m_pEntryWound->GetBurstDamage() * hitor->WoundDamageMultiplier(); } + if (hitor->GetApplyWoundDamageOnCollision()) { + damageToAdd += m_pEntryWound->GetEmitDamage() * hitor->WoundDamageMultiplier(); + } + if (hitor->GetApplyWoundBurstDamageOnCollision()) { + damageToAdd += m_pEntryWound->GetBurstDamage() * hitor->WoundDamageMultiplier(); + } - if (damageToAdd != 0) { AddDamage(damageToAdd); } + if (damageToAdd != 0) { + AddDamage(damageToAdd); + } if (penetrated || damageToAdd != 0) { - if (Actor *parentAsActor = dynamic_cast(GetRootParent()); parentAsActor && parentAsActor->GetPerceptiveness() > 0) { + if (Actor* parentAsActor = dynamic_cast(GetRootParent()); parentAsActor && parentAsActor->GetPerceptiveness() > 0) { Vector extruded(hd.HitVel[HITOR]); extruded.SetMagnitude(parentAsActor->GetHeight()); extruded = m_Pos - extruded; @@ -316,47 +334,51 @@ namespace RTE { return penetrated; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Attachable::GibThis(const Vector &impactImpulse, MovableObject *movableObjectToIgnore) { - if (m_Parent) { m_Parent->RemoveAttachable(this, true, true); } + void Attachable::GibThis(const Vector& impactImpulse, MovableObject* movableObjectToIgnore) { + if (m_Parent) { + m_Parent->RemoveAttachable(this, true, true); + } MOSRotating::GibThis(impactImpulse, movableObjectToIgnore); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Attachable::HandlePotentialRadiusAffectingAttachable(const Attachable *attachable) { + bool Attachable::HandlePotentialRadiusAffectingAttachable(const Attachable* attachable) { if (MOSRotating::HandlePotentialRadiusAffectingAttachable(attachable)) { - if (IsAttached()) { m_Parent->HandlePotentialRadiusAffectingAttachable(this); } + if (IsAttached()) { + m_Parent->HandlePotentialRadiusAffectingAttachable(this); + } return true; } return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Attachable::UpdateScripts() { if (m_Parent && !m_AllLoadedScripts.empty() && !ObjectScriptsInitialized()) { - RunScriptedFunctionInAppropriateScripts("OnAttach", false, false, { m_Parent }, {}, {}); + RunScriptedFunctionInAppropriateScripts("OnAttach", false, false, {m_Parent}, {}, {}); } return MOSRotating::UpdateScripts(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::Update() { - if (!m_PreUpdateHasRunThisFrame) { - PreUpdate(); + if (!m_PreUpdateHasRunThisFrame) { + PreUpdate(); } UpdatePositionAndJointPositionBasedOnOffsets(); if (m_Parent) { - if (m_ParentOffset != m_PrevParentOffset || m_JointOffset != m_PrevJointOffset) { + if (m_ParentOffset != m_PrevParentOffset || m_JointOffset != m_PrevJointOffset) { m_PrevParentOffset = m_ParentOffset; m_PrevJointOffset = m_JointOffset; - m_Parent->HandlePotentialRadiusAffectingAttachable(this); + m_Parent->HandlePotentialRadiusAffectingAttachable(this); } m_PrevVel = m_Vel; @@ -364,11 +386,13 @@ namespace RTE { m_Team = m_Parent->GetTeam(); - MOSRotating *rootParentAsMOSR = dynamic_cast(GetRootParent()); + MOSRotating* rootParentAsMOSR = dynamic_cast(GetRootParent()); float currentRotAngleOffset = (GetRotAngle() * GetFlipFactor()) - rootParentAsMOSR->GetRotAngle(); if (rootParentAsMOSR && CanCollideWithTerrain()) { // Note: This safety check exists to ensure the parent's AtomGroup contains this Attachable's Atoms in a subgroup. Hardcoded Attachables need this in order to work, since they're cloned before their parent's AtomGroup exists. - if (!rootParentAsMOSR->GetAtomGroup()->ContainsSubGroup(m_AtomSubgroupID)) { AddOrRemoveAtomsFromRootParentAtomGroup(true, false); } + if (!rootParentAsMOSR->GetAtomGroup()->ContainsSubGroup(m_AtomSubgroupID)) { + AddOrRemoveAtomsFromRootParentAtomGroup(true, false); + } if (std::abs(currentRotAngleOffset - m_PrevRotAngleOffset) > 0.01745F) { // Update for 1 degree differences Matrix atomRotationForSubgroup(rootParentAsMOSR->FacingAngle(GetRotAngle()) - rootParentAsMOSR->FacingAngle(rootParentAsMOSR->GetRotAngle())); @@ -392,7 +416,7 @@ namespace RTE { if (m_Parent && GetRootParent()->HasEverBeenAddedToMovableMan()) { g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); if (!m_AllLoadedScripts.empty() && !ObjectScriptsInitialized()) { - RunScriptedFunctionInAppropriateScripts("OnAttach", false, false, { m_Parent }, {}, {}); + RunScriptedFunctionInAppropriateScripts("OnAttach", false, false, {m_Parent}, {}, {}); } UpdateScripts(); g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); @@ -401,12 +425,14 @@ namespace RTE { m_PreUpdateHasRunThisFrame = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::PreUpdate() { if (!m_PreUpdateHasRunThisFrame) { if (m_Parent) { - if (InheritsHFlipped() != 0) { m_HFlipped = m_InheritsHFlipped == 1 ? m_Parent->IsHFlipped() : !m_Parent->IsHFlipped(); } + if (InheritsHFlipped() != 0) { + m_HFlipped = m_InheritsHFlipped == 1 ? m_Parent->IsHFlipped() : !m_Parent->IsHFlipped(); + } if (InheritsRotAngle()) { SetRotAngle(m_Parent->GetRotAngle() + m_InheritedRotAngleOffset * m_Parent->GetFlipFactor()); m_AngularVel = 0.0F; @@ -416,85 +442,101 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::SetMass(const float newMass) { float currentMass = GetMass(); if (newMass != currentMass) { float previousMassForUpdatingParent = m_Parent ? currentMass : 0.0F; MovableObject::SetMass(newMass); - if (m_Parent) { m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); } + if (m_Parent) { + m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::UpdateAttachableAndWoundMass(float oldAttachableOrWoundMass, float newAttachableOrWoundMass) { float previousMassForUpdatingParent = m_Parent ? GetMass() : 0.0F; MOSRotating::UpdateAttachableAndWoundMass(oldAttachableOrWoundMass, newAttachableOrWoundMass); - if (m_Parent) { m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); } + if (m_Parent) { + m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Attachable::AddAttachable(Attachable *attachable, const Vector &parentOffsetToSet) { + void Attachable::AddAttachable(Attachable* attachable, const Vector& parentOffsetToSet) { float previousMassForUpdatingParent = m_Parent ? GetMass() : 0.0F; MOSRotating::AddAttachable(attachable, parentOffsetToSet); - if (m_Parent) { m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); } + if (m_Parent) { + m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Attachable * Attachable::RemoveAttachable(Attachable *attachable, bool addToMovableMan, bool addBreakWounds) { + Attachable* Attachable::RemoveAttachable(Attachable* attachable, bool addToMovableMan, bool addBreakWounds) { float previousMassForUpdatingParent = m_Parent ? GetMass() : 0.0F; - Attachable *removedAttachable = MOSRotating::RemoveAttachable(attachable, addToMovableMan, addBreakWounds); - if (m_Parent) { m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); } + Attachable* removedAttachable = MOSRotating::RemoveAttachable(attachable, addToMovableMan, addBreakWounds); + if (m_Parent) { + m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); + } return removedAttachable; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Attachable::AddWound(AEmitter *woundToAdd, const Vector &parentOffsetToSet, bool checkGibWoundLimit) { + void Attachable::AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit) { float previousMassForUpdatingParent = m_Parent ? GetMass() : 0.0F; MOSRotating::AddWound(woundToAdd, parentOffsetToSet, checkGibWoundLimit); - if (m_Parent) { m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); } + if (m_Parent) { + m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Attachable::RemoveWounds(int numberOfWoundsToRemove, bool includeAttachablesWithAPositiveDamageMultiplier, bool includeAttachablesWithANegativeDamageMultiplier, bool includeAttachablesWithNoDamageMultiplier) { float previousMassForUpdatingParent = m_Parent ? GetMass() : 0.0F; float result = MOSRotating::RemoveWounds(numberOfWoundsToRemove, includeAttachablesWithAPositiveDamageMultiplier, includeAttachablesWithANegativeDamageMultiplier, includeAttachablesWithNoDamageMultiplier); - if (m_Parent) { m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); } + if (m_Parent) { + m_Parent->UpdateAttachableAndWoundMass(previousMassForUpdatingParent, GetMass()); + } return result; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Attachable::SetParent(MOSRotating *newParent) { + void Attachable::SetParent(MOSRotating* newParent) { if (newParent == m_Parent) { return; } RTEAssert(!(m_Parent && newParent), "Tried to set an Attachable's " + GetModuleAndPresetName() + " parent without first unsetting its old parent, " + (IsAttached() ? GetParent()->GetModuleAndPresetName() : "ERROR") + "."); - MOSRotating *parentToUseForScriptCall = newParent ? newParent : m_Parent; + MOSRotating* parentToUseForScriptCall = newParent ? newParent : m_Parent; - //TODO Get rid of the need for calling ResetAllTimers, if something like inventory swapping needs timers reset it should do it itself! This blanket handling probably has side-effects. - // Timers are reset here as a precaution, so that if something was sitting in an inventory, it doesn't cause backed up emissions. + // TODO Get rid of the need for calling ResetAllTimers, if something like inventory swapping needs timers reset it should do it itself! This blanket handling probably has side-effects. + // Timers are reset here as a precaution, so that if something was sitting in an inventory, it doesn't cause backed up emissions. ResetAllTimers(); if (newParent) { m_Parent = newParent; m_Team = newParent->GetTeam(); - if (InheritsHFlipped() != 0) { m_HFlipped = m_InheritsHFlipped == 1 ? m_Parent->IsHFlipped() : !m_Parent->IsHFlipped(); } + if (InheritsHFlipped() != 0) { + m_HFlipped = m_InheritsHFlipped == 1 ? m_Parent->IsHFlipped() : !m_Parent->IsHFlipped(); + } if (InheritsRotAngle()) { SetRotAngle(m_Parent->GetRotAngle() + m_InheritedRotAngleOffset * m_Parent->GetFlipFactor()); m_AngularVel = 0.0F; } UpdatePositionAndJointPositionBasedOnOffsets(); - if (CanCollideWithTerrain()) { AddOrRemoveAtomsFromRootParentAtomGroup(true, true); } + if (CanCollideWithTerrain()) { + AddOrRemoveAtomsFromRootParentAtomGroup(true, true); + } - if (const Actor *rootParentAsActor = dynamic_cast(GetRootParent())) { - if (PieMenu *rootParentAsActorPieMenu = rootParentAsActor->GetPieMenu()) { + if (const Actor* rootParentAsActor = dynamic_cast(GetRootParent())) { + if (PieMenu* rootParentAsActorPieMenu = rootParentAsActor->GetPieMenu()) { AddOrRemovePieSlicesAndListenersFromPieMenu(rootParentAsActorPieMenu, true); } } @@ -504,9 +546,9 @@ namespace RTE { m_Team = -1; m_IsWound = false; - if (MovableObject *rootParent = GetRootParent()) { - const MovableObject *whichMOToNotHit = GetWhichMOToNotHit(); - const MovableObject *rootParentMOToNotHit = rootParent->GetWhichMOToNotHit(); + if (MovableObject* rootParent = GetRootParent()) { + const MovableObject* whichMOToNotHit = GetWhichMOToNotHit(); + const MovableObject* rootParentMOToNotHit = rootParent->GetWhichMOToNotHit(); if ((whichMOToNotHit && whichMOToNotHit != rootParent) || (rootParentMOToNotHit && rootParentMOToNotHit != this)) { m_pMOToNotHit = nullptr; } else { @@ -514,18 +556,22 @@ namespace RTE { rootParent->SetWhichMOToNotHit(this); } - if (const Actor *rootParentAsActor = dynamic_cast(rootParent)) { - if (PieMenu *rootParentAsActorPieMenu = rootParentAsActor->GetPieMenu()) { + if (const Actor* rootParentAsActor = dynamic_cast(rootParent)) { + if (PieMenu* rootParentAsActorPieMenu = rootParentAsActor->GetPieMenu()) { AddOrRemovePieSlicesAndListenersFromPieMenu(rootParentAsActorPieMenu, false); } } } - if (CanCollideWithTerrain()) { AddOrRemoveAtomsFromRootParentAtomGroup(false, true); } + if (CanCollideWithTerrain()) { + AddOrRemoveAtomsFromRootParentAtomGroup(false, true); + } m_Parent = newParent; - for (Attachable *attachable : m_Attachables) { - if (attachable->m_CollidesWithTerrainWhileAttached) { attachable->AddOrRemoveAtomsFromRootParentAtomGroup(true, true); } + for (Attachable* attachable: m_Attachables) { + if (attachable->m_CollidesWithTerrainWhileAttached) { + attachable->AddOrRemoveAtomsFromRootParentAtomGroup(true, true); + } } } @@ -534,7 +580,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::UpdatePositionAndJointPositionBasedOnOffsets() { if (m_Parent) { @@ -546,12 +592,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Attachable::AddOrRemoveAtomsFromRootParentAtomGroup(bool addAtoms, bool propagateToChildAttachables) { if (IsAttached()) { - MOSRotating *rootParentAsMOSR = dynamic_cast(GetRootParent()); - AtomGroup *rootParentAtomGroup = rootParentAsMOSR ? rootParentAsMOSR->GetAtomGroup() : nullptr; + MOSRotating* rootParentAsMOSR = dynamic_cast(GetRootParent()); + AtomGroup* rootParentAtomGroup = rootParentAsMOSR ? rootParentAsMOSR->GetAtomGroup() : nullptr; if (rootParentAtomGroup) { if (addAtoms && !rootParentAtomGroup->ContainsSubGroup(GetAtomSubgroupID())) { Vector atomOffsetForSubgroup = g_SceneMan.ShortestDistance(rootParentAsMOSR->GetPos(), m_Pos, g_SceneMan.SceneWrapsX()); @@ -563,34 +609,36 @@ namespace RTE { } if (propagateToChildAttachables) { - for (Attachable *attachable : m_Attachables) { - if (attachable->m_CollidesWithTerrainWhileAttached) { attachable->AddOrRemoveAtomsFromRootParentAtomGroup(addAtoms, propagateToChildAttachables); } + for (Attachable* attachable: m_Attachables) { + if (attachable->m_CollidesWithTerrainWhileAttached) { + attachable->AddOrRemoveAtomsFromRootParentAtomGroup(addAtoms, propagateToChildAttachables); + } } } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Attachable::AddOrRemovePieSlicesAndListenersFromPieMenu(PieMenu *pieMenuToModify, bool addToPieMenu) { + void Attachable::AddOrRemovePieSlicesAndListenersFromPieMenu(PieMenu* pieMenuToModify, bool addToPieMenu) { RTEAssert(pieMenuToModify, "Cannot add or remove Attachable PieSlices and listeners from a non-existant PieMenu."); if (addToPieMenu) { if (m_FunctionsAndScripts.find("WhilePieMenuOpen") != m_FunctionsAndScripts.end() && !m_FunctionsAndScripts.find("WhilePieMenuOpen")->second.empty()) { pieMenuToModify->AddWhilePieMenuOpenListener(this, std::bind(&MovableObject::WhilePieMenuOpenListener, this, pieMenuToModify)); } - for (const std::unique_ptr &pieSlice : m_PieSlices) { - pieMenuToModify->AddPieSlice(dynamic_cast(pieSlice.get()->Clone()), this, true); + for (const std::unique_ptr& pieSlice: m_PieSlices) { + pieMenuToModify->AddPieSlice(dynamic_cast(pieSlice.get()->Clone()), this, true); } } else { pieMenuToModify->RemoveWhilePieMenuOpenListener(this); pieMenuToModify->RemovePieSlicesByOriginalSource(this); } - for (Attachable *attachable : m_Attachables) { + for (Attachable* attachable: m_Attachables) { attachable->AddOrRemovePieSlicesAndListenersFromPieMenu(pieMenuToModify, addToPieMenu); } - for (AEmitter *wound : m_Wounds) { + for (AEmitter* wound: m_Wounds) { wound->AddOrRemovePieSlicesAndListenersFromPieMenu(pieMenuToModify, addToPieMenu); } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/Attachable.h b/Source/Entities/Attachable.h index 7a3d702ed..141265e42 100644 --- a/Source/Entities/Attachable.h +++ b/Source/Entities/Attachable.h @@ -15,7 +15,6 @@ namespace RTE { friend class MOSRotating; public: - EntityAllocation(Attachable); AddScriptFunctionNames(MOSRotating, "OnAttach", "OnDetach"); SerializableOverrideMethods; @@ -38,7 +37,7 @@ namespace RTE { /// /// A reference to the Attachable to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Attachable &reference); + int Create(const Attachable& reference); #pragma endregion #pragma region Destruction @@ -51,12 +50,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the Attachable object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { MOSRotating::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + MOSRotating::Destroy(); + } + Clear(); + } /// /// Resets the entire Attachable, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); MOSRotating::Reset(); } + void Reset() override { + Clear(); + MOSRotating::Reset(); + } #pragma endregion #pragma region Parent Getters and Setters @@ -64,13 +71,13 @@ namespace RTE { /// Gets the MOSRotating which is the parent of this Attachable. /// /// A pointer to the parent of this Attachable. - MOSRotating * GetParent() override { return m_Parent; } + MOSRotating* GetParent() override { return m_Parent; } /// /// Gets the MOSRotating which is the parent of this Attachable. /// /// A pointer to the parent of this Attachable. - const MOSRotating * GetParent() const override { return m_Parent; } + const MOSRotating* GetParent() const override { return m_Parent; } /// /// Indicates whether this Attachable is attached to an MOSRotating parent or not. @@ -83,31 +90,31 @@ namespace RTE { /// /// A pointer to which MOSRotating you want to check for. /// Whether it's attached or not. - bool IsAttachedTo(const MOSRotating *parentToCheck) const { return m_Parent == parentToCheck; } + bool IsAttachedTo(const MOSRotating* parentToCheck) const { return m_Parent == parentToCheck; } /// /// Gets the MO which is the ultimate root parent of this Attachable and its parent. /// /// A pointer to the highest root parent of this Attachable. - MovableObject * GetRootParent() override { return m_Parent ? m_Parent->GetRootParent() : this; } + MovableObject* GetRootParent() override { return m_Parent ? m_Parent->GetRootParent() : this; } /// /// Gets the MO which is the ultimate root parent of this Attachable and its parent. /// /// A pointer to the highest root parent of this Attachable. - const MovableObject * GetRootParent() const override { return m_Parent ? m_Parent->GetRootParent() : this; } + const MovableObject* GetRootParent() const override { return m_Parent ? m_Parent->GetRootParent() : this; } /// /// Gets the stored offset between this Attachable's parent's position and the joint position. This should be maintained by the parent. /// /// A const reference Vector describing the offset from the parent's position to the joint position. - const Vector & GetParentOffset() const { return m_ParentOffset; } + const Vector& GetParentOffset() const { return m_ParentOffset; } /// /// Sets the stored offset between this Attachable's parent's Pos and the joint position. This should be maintained by the parent. /// /// A const reference to the new parent offset. - void SetParentOffset(const Vector &newParentOffset) { m_ParentOffset = newParentOffset; } + void SetParentOffset(const Vector& newParentOffset) { m_ParentOffset = newParentOffset; } /// /// Gets whether this Attachable is to be drawn after (in front of) or before (behind) its parent. @@ -243,19 +250,19 @@ namespace RTE { /// Gets the offset of the joint (the point around which this Attachable and its parent hinge) from this Attachable's center of mass/origin. /// /// A const reference Vector describing the offset of the joint relative to this Attachable's origin/center of mass position. - const Vector & GetJointOffset() const { return m_JointOffset; } + const Vector& GetJointOffset() const { return m_JointOffset; } /// /// Sets the offset of the joint (the point around which this Attachable and its parent hinge) from this Attachable's center of mass/origin. /// /// A Vector describing the offset of the joint relative to the this Attachable's origin/center of mass position. - void SetJointOffset(const Vector &newJointOffset) { m_JointOffset = newJointOffset; } + void SetJointOffset(const Vector& newJointOffset) { m_JointOffset = newJointOffset; } /// /// Gets the absolute position of the joint that the parent of this Attachable sets upon Update(). /// /// A Vector describing the current absolute position of the joint. - const Vector & GetJointPos() const { return m_JointPos; } + const Vector& GetJointPos() const { return m_JointPos; } #pragma endregion #pragma region Force Transferral @@ -266,7 +273,7 @@ namespace RTE { /// /// A vector that will have the forces affecting the joint ADDED to it. /// False if the Attachable has no parent or its accumulated forces are greater than its joint strength, otherwise true. - bool TransferJointForces(Vector &jointForces); + bool TransferJointForces(Vector& jointForces); /// /// Bundles up all the accumulated impulse forces of this Attachable and calculates how they transfer to the joint, and therefore to the parent. @@ -278,7 +285,7 @@ namespace RTE { /// An optional override for the Attachable's joint strength for this function call. Primarily used to allow subclasses to perform special behavior. /// An optional override for the Attachable's gib impulse limit for this function call. Primarily used to allow subclasses to perform special behavior. /// False if the Attachable has no parent or its accumulated forces are greater than its joint strength or gib impulse limit, otherwise true. - virtual bool TransferJointImpulses(Vector &jointImpulses, float jointStiffnessValueToUse = -1, float jointStrengthValueToUse = -1, float gibImpulseLimitValueToUse = -1); + virtual bool TransferJointImpulses(Vector& jointImpulses, float jointStiffnessValueToUse = -1, float jointStrengthValueToUse = -1, float gibImpulseLimitValueToUse = -1); #pragma endregion #pragma region Damage and Wound Management @@ -299,25 +306,25 @@ namespace RTE { /// Gets the AEmitter that represents the wound added to this Attachable when it gets detached from its parent. OWNERSHIP IS NOT TRANSFERRED! /// /// A const pointer to the break wound AEmitter. - const AEmitter * GetBreakWound() const { return m_BreakWound; } + const AEmitter* GetBreakWound() const { return m_BreakWound; } /// /// Sets the AEmitter that represents the wound added to this Attachable when it gets detached from its parent. OWNERSHIP IS NOT TRANSFERRED! /// /// The AEmitter to use for this Attachable's breakwound. - void SetBreakWound(AEmitter *breakWound) { m_BreakWound = breakWound; } + void SetBreakWound(AEmitter* breakWound) { m_BreakWound = breakWound; } /// /// Gets the AEmitter that represents the wound added to this Attachable's parent when this Attachable gets detached from its parent. OWNERSHIP IS NOT TRANSFERRED! /// /// A const pointer to the parent break wound AEmitter. - const AEmitter * GetParentBreakWound() const { return m_ParentBreakWound; } + const AEmitter* GetParentBreakWound() const { return m_ParentBreakWound; } /// /// Sets the AEmitter that represents the wound added to this Attachable's parent when this Attachable gets detached from its parent. OWNERSHIP IS NOT TRANSFERRED! /// /// The AEmitter to use for the parent's breakwound. - void SetParentBreakWound(AEmitter *breakWound) { m_ParentBreakWound = breakWound; } + void SetParentBreakWound(AEmitter* breakWound) { m_ParentBreakWound = breakWound; } #pragma endregion #pragma region Inherited Value Getters and Setters @@ -420,11 +427,11 @@ namespace RTE { #pragma region Override Methods /// /// Calculates the collision response when another MO's Atom collides with this MO's physical representation. - /// The effects will be applied directly to this MO, and also represented in the passed in HitData. + /// The effects will be applied directly to this MO, and also represented in the passed in HitData. /// /// Reference to the HitData struct which describes the collision. This will be modified to represent the results of the collision. /// Whether the collision has been deemed valid. If false, then disregard any impulses in the HitData. - bool CollideAtPoint(HitData &hitData) override; + bool CollideAtPoint(HitData& hitData) override; /// /// Determines whether a particle which has hit this MO will penetrate, and if so, whether it gets lodged or exits on the other side of this MO. @@ -435,7 +442,7 @@ namespace RTE { /// Whether the particle managed to penetrate into this MO or not. /// If something other than an MOPixel or MOSParticle is being passed in as the hitor, false will trivially be returned here. /// - bool ParticlePenetration(HitData &hitData) override; + bool ParticlePenetration(HitData& hitData) override; /// /// Destroys this Attachable and creates its specified Gibs in its place with appropriate velocities. @@ -443,14 +450,14 @@ namespace RTE { /// /// The impulse (kg * m/s) of the impact causing the gibbing to happen. /// A pointer to an MO which the Gibs and Attachables should not be colliding with. - void GibThis(const Vector &impactImpulse = Vector(), MovableObject *movableObjectToIgnore = nullptr) override; + void GibThis(const Vector& impactImpulse = Vector(), MovableObject* movableObjectToIgnore = nullptr) override; /// /// Checks if the given Attachable should affect radius, and handles it if it should. /// /// The Attachable to check. /// Whether the radius affecting Attachable changed as a result of this call. - bool HandlePotentialRadiusAffectingAttachable(const Attachable *attachable) override; + bool HandlePotentialRadiusAffectingAttachable(const Attachable* attachable) override; /// /// Updates this Attachable's Lua scripts. @@ -488,21 +495,21 @@ namespace RTE { /// Adds the passed in Attachable the list of Attachables and sets its parent to this Attachable. /// /// The Attachable to add. - void AddAttachable(Attachable *attachable) final { MOSRotating::AddAttachable(attachable); } + void AddAttachable(Attachable* attachable) final { MOSRotating::AddAttachable(attachable); } /// /// Adds the passed in Attachable the list of Attachables, changes its parent offset to the passed in Vector, and sets its parent to this Attachable. /// /// The Attachable to add. /// The Vector to set as the Attachable's parent offset. - void AddAttachable(Attachable *attachable, const Vector &parentOffsetToSet) final; + void AddAttachable(Attachable* attachable, const Vector& parentOffsetToSet) final; /// /// Removes the Attachable corresponding to the passed in UniqueID and sets its parent to nullptr. Does not add it to MovableMan or add break wounds. /// /// The UniqueID of the Attachable to remove. /// A pointer to the removed Attachable. Ownership IS transferred! - Attachable * RemoveAttachable(long attachableUniqueID) final { return MOSRotating::RemoveAttachable(attachableUniqueID); } + Attachable* RemoveAttachable(long attachableUniqueID) final { return MOSRotating::RemoveAttachable(attachableUniqueID); } /// /// Removes the Attachable corresponding to the passed in UniqueID and sets its parent to nullptr. Optionally adds it to MovableMan and/or adds break wounds. @@ -512,14 +519,14 @@ namespace RTE { /// Whether or not to add the Attachable to MovableMan once it has been removed. /// Whether or not to add break wounds to the removed Attachable and this Attachable. /// A pointer to the removed Attachable, if it wasn't added to MovableMan or nullptr if it was. Ownership IS transferred! - Attachable * RemoveAttachable(long attachableUniqueID, bool addToMovableMan, bool addBreakWounds) final { return MOSRotating::RemoveAttachable(attachableUniqueID, addToMovableMan, addBreakWounds); } + Attachable* RemoveAttachable(long attachableUniqueID, bool addToMovableMan, bool addBreakWounds) final { return MOSRotating::RemoveAttachable(attachableUniqueID, addToMovableMan, addBreakWounds); } /// /// Removes the passed in Attachable and sets its parent to nullptr. Does not add it to MovableMan or add break wounds. /// /// The Attachable to remove. /// A pointer to the removed Attachable. Ownership IS transferred! - Attachable * RemoveAttachable(Attachable *attachable) final { return MOSRotating::RemoveAttachable(attachable); } + Attachable* RemoveAttachable(Attachable* attachable) final { return MOSRotating::RemoveAttachable(attachable); } /// /// Removes the passed in Attachable and sets its parent to nullptr. Optionally adds it to MovableMan and/or adds break wounds. @@ -529,7 +536,7 @@ namespace RTE { /// Whether or not to add the Attachable to MovableMan once it has been removed. /// Whether or not to add break wounds to the removed Attachable and this Attachable. /// A pointer to the removed Attachable, if it wasn't added to MovableMan or nullptr if it was. Ownership IS transferred! - Attachable * RemoveAttachable(Attachable *attachable, bool addToMovableMan, bool addBreakWounds) final; + Attachable* RemoveAttachable(Attachable* attachable, bool addToMovableMan, bool addBreakWounds) final; /// /// Adds the passed in wound AEmitter to the list of wounds and changes its parent offset to the passed in Vector. @@ -537,7 +544,7 @@ namespace RTE { /// The wound AEmitter to add. /// The vector to set as the wound AEmitter's parent offset. /// Whether to gib this Attachable if adding this wound raises its wound count past its gib wound limit. Defaults to true. - void AddWound(AEmitter *woundToAdd, const Vector &parentOffsetToSet, bool checkGibWoundLimit = true) final; + void AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit = true) final; /// /// Removes the specified number of wounds from this Attachable, and returns damage caused by these removed wounds. @@ -560,10 +567,9 @@ namespace RTE { #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - MOSRotating *m_Parent; //!< Pointer to the MOSRotating this attachable is attached to. + MOSRotating* m_Parent; //!< Pointer to the MOSRotating this attachable is attached to. Vector m_ParentOffset; //!< The offset from the parent's Pos to the joint point this Attachable is attached with. bool m_DrawAfterParent; //!< Whether to draw this Attachable after (in front of) or before (behind) the parent. bool m_DrawnNormallyByParent; //!< Whether this Attachable will be drawn normally when attached, or will require special handling by some non-MOSR parent type. @@ -574,7 +580,7 @@ namespace RTE { float m_GibWithParentChance; //!< The percentage chance that this Attachable will gib when its parent does. 0 means never, 1 means always. float m_ParentGibBlastStrengthMultiplier; //!< The multiplier for how strongly this Attachable's parent's gib blast strength will be applied to it when its parent's gibs. - //TODO This is a stopgap for a dedicated Wound class, that would be helpful to simplify things like this and default damage multiplier handling. + // TODO This is a stopgap for a dedicated Wound class, that would be helpful to simplify things like this and default damage multiplier handling. bool m_IsWound; //!< Whether or not this Attachable has been added as a wound. Only set and applied for Attachables with parents. float m_JointStrength; //!< The amount of impulse force needed on this to detach it from the host Actor, in kg * m/s. A value of 0 means the join is infinitely strong and will never break naturally. @@ -583,8 +589,8 @@ namespace RTE { Vector m_JointPos; //!< The absolute position of the joint that the parent sets upon Update() if this Attachable is attached to it. float m_DamageCount; //!< The number of damage points that this Attachable has accumulated since the last time CollectDamage() was called. - const AEmitter *m_BreakWound; //!< The wound this Attachable will receive when it breaks from its parent. - const AEmitter *m_ParentBreakWound; //!< The wound this Attachable's parent will receive when the Attachable breaks from its parent. + const AEmitter* m_BreakWound; //!< The wound this Attachable will receive when it breaks from its parent. + const AEmitter* m_ParentBreakWound; //!< The wound this Attachable's parent will receive when the Attachable breaks from its parent. int m_InheritsHFlipped; //!< Whether this Attachable should inherit its parent's HFlipped. Defaults to 1 (normal inheritance). bool m_InheritsRotAngle; //!< Whether this Attachable should inherit its parent's RotAngle. Defaults to true. @@ -606,10 +612,9 @@ namespace RTE { /// Sets this Attachable's parent MOSRotating, and also sets its Team based on its parent and, if the Attachable is set to collide, adds/removes Atoms to its new/old parent. /// /// A pointer to the MOSRotating to set as the new parent. Ownership is NOT transferred! - virtual void SetParent(MOSRotating *newParent); + virtual void SetParent(MOSRotating* newParent); private: - /// /// Updates the position of this Attachable based on its parent offset and joint offset. Used during update and when something sets these offsets through setters. /// @@ -628,7 +633,7 @@ namespace RTE { /// /// The PieMenu to modify, passed in to keep the recursion simple and clean. /// Whether to add this Attachable's PieSlices and listeners to, or remove them from, the root parent's PieMenu. - void AddOrRemovePieSlicesAndListenersFromPieMenu(PieMenu *pieMenuToModify, bool addToPieMenu); + void AddOrRemovePieSlicesAndListenersFromPieMenu(PieMenu* pieMenuToModify, bool addToPieMenu); /// /// Clears all the member variables of this Attachable, effectively resetting the members of this abstraction level only. @@ -636,8 +641,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - Attachable(const Attachable &reference) = delete; - Attachable & operator=(const Attachable &rhs) = delete; + Attachable(const Attachable& reference) = delete; + Attachable& operator=(const Attachable& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/BunkerAssembly.cpp b/Source/Entities/BunkerAssembly.cpp index 16ace93bc..6e8c4fbd6 100644 --- a/Source/Entities/BunkerAssembly.cpp +++ b/Source/Entities/BunkerAssembly.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,513 +19,456 @@ namespace RTE { -ConcreteClassInfo(BunkerAssembly, SceneObject, 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this BunkerAssembly, effectively -// resetting the members of this abstraction level only. - -void BunkerAssembly::Clear() -{ - m_FGColorFile.Reset(); - m_MaterialFile.Reset(); - m_BGColorFile.Reset(); - m_FGColorBitmap = 0; - m_MaterialBitmap = 0; - m_BGColorBitmap = 0; - m_BitmapOffset.Reset(); - m_OffsetDefined = false; - m_ChildObjects.clear(); - m_PlacedObjects.clear(); - m_ParentAssemblyScheme.clear(); - m_pPresentationBitmap = 0; - m_SymmetricAssembly.clear(); - m_ParentSchemeGroup.clear(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BunkerAssembly object ready for use. + ConcreteClassInfo(BunkerAssembly, SceneObject, 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this BunkerAssembly, effectively + // resetting the members of this abstraction level only. + + void BunkerAssembly::Clear() { + m_FGColorFile.Reset(); + m_MaterialFile.Reset(); + m_BGColorFile.Reset(); + m_FGColorBitmap = 0; + m_MaterialBitmap = 0; + m_BGColorBitmap = 0; + m_BitmapOffset.Reset(); + m_OffsetDefined = false; + m_ChildObjects.clear(); + m_PlacedObjects.clear(); + m_ParentAssemblyScheme.clear(); + m_pPresentationBitmap = 0; + m_SymmetricAssembly.clear(); + m_ParentSchemeGroup.clear(); + } -int BunkerAssembly::Create() -{ - if (TerrainObject::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BunkerAssembly object ready for use. - return 0; -} + int BunkerAssembly::Create() { + if (TerrainObject::Create() < 0) + return -1; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds placed object to the internallist of placed objects for this assembly, -// applies it's image to presentation bitmap and sets assembly price accordingly. -// Added scene object MUST have coordinates relative to this assembly. - -void BunkerAssembly::AddPlacedObject(SceneObject * pSO) -{ - m_PlacedObjects.push_back(pSO); - - //Increase gold value for every bunker module if it's not a deployment - Deployment * pDeployment = dynamic_cast(pSO); - //Set fixed price - //if (!pDeployment && !pSO->IsInGroup("Bunker Backgrounds")) - // m_OzValue += pSO->GetGoldValue(); - - // Draw this terrain object to presentaion bitmap - TerrainObject * pTObject = dynamic_cast(pSO); - if (pTObject) - { - Vector objectPos = pTObject->GetPos() + pTObject->GetBitmapOffset(); - - // Regular drawing - if (pTObject->HasMaterialBitmap()) { draw_sprite(m_MaterialBitmap, pTObject->GetMaterialBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); } - if (pTObject->HasBGColorBitmap()) { - draw_sprite(m_BGColorBitmap, pTObject->GetBGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); - draw_sprite(m_pPresentationBitmap, pTObject->GetBGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); - } - if (pTObject->HasFGColorBitmap()) { - draw_sprite(m_FGColorBitmap, pTObject->GetFGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); - draw_sprite(m_pPresentationBitmap, pTObject->GetFGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds placed object to the internallist of placed objects for this assembly, + // applies it's image to presentation bitmap and sets assembly price accordingly. + // Added scene object MUST have coordinates relative to this assembly. + + void BunkerAssembly::AddPlacedObject(SceneObject* pSO) { + m_PlacedObjects.push_back(pSO); + + // Increase gold value for every bunker module if it's not a deployment + Deployment* pDeployment = dynamic_cast(pSO); + // Set fixed price + // if (!pDeployment && !pSO->IsInGroup("Bunker Backgrounds")) + // m_OzValue += pSO->GetGoldValue(); + + // Draw this terrain object to presentaion bitmap + TerrainObject* pTObject = dynamic_cast(pSO); + if (pTObject) { + Vector objectPos = pTObject->GetPos() + pTObject->GetBitmapOffset(); + + // Regular drawing + if (pTObject->HasMaterialBitmap()) { + draw_sprite(m_MaterialBitmap, pTObject->GetMaterialBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); + } + if (pTObject->HasBGColorBitmap()) { + draw_sprite(m_BGColorBitmap, pTObject->GetBGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); + draw_sprite(m_pPresentationBitmap, pTObject->GetBGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); + } + if (pTObject->HasFGColorBitmap()) { + draw_sprite(m_FGColorBitmap, pTObject->GetFGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); + draw_sprite(m_pPresentationBitmap, pTObject->GetFGColorBitmap(), objectPos.GetFloorIntX(), objectPos.GetFloorIntY()); + } - // Read and add all child objects - pTObject->SetTeam(GetTeam()); + // Read and add all child objects + pTObject->SetTeam(GetTeam()); - for (const SceneObject::SOPlacer &childObject : pTObject->GetChildObjects()) { - SceneObject::SOPlacer newPlacer = childObject; - newPlacer.SetTeam(pTObject->GetTeam()); - // Explicitly set child object's offset, because it will be a part of a bigger 'terrain object' - newPlacer.SetOffset(newPlacer.GetOffset() + pTObject->GetPos() + m_BitmapOffset); - m_ChildObjects.push_back(newPlacer); + for (const SceneObject::SOPlacer& childObject: pTObject->GetChildObjects()) { + SceneObject::SOPlacer newPlacer = childObject; + newPlacer.SetTeam(pTObject->GetTeam()); + // Explicitly set child object's offset, because it will be a part of a bigger 'terrain object' + newPlacer.SetOffset(newPlacer.GetOffset() + pTObject->GetPos() + m_BitmapOffset); + m_ChildObjects.push_back(newPlacer); + } } } -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BunkerAssembly object ready for use. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BunkerAssembly object ready for use. -int BunkerAssembly::Create(BunkerAssemblyScheme * pScheme) -{ - if (TerrainObject::Create() < 0) - return -1; + int BunkerAssembly::Create(BunkerAssemblyScheme* pScheme) { + if (TerrainObject::Create() < 0) + return -1; - m_pPresentationBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_pPresentationBitmap, g_MaskColor); + m_pPresentationBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_pPresentationBitmap, g_MaskColor); - m_FGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_FGColorBitmap, g_MaskColor); + m_FGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_FGColorBitmap, g_MaskColor); - m_MaterialBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_MaterialBitmap, g_MaskColor); + m_MaterialBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_MaterialBitmap, g_MaskColor); - m_BGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_BGColorBitmap, g_MaskColor); + m_BGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_BGColorBitmap, g_MaskColor); - m_BitmapOffset = pScheme->GetBitmapOffset(); - m_ParentAssemblyScheme = pScheme->GetPresetName(); - m_Pos = pScheme->GetPos(); + m_BitmapOffset = pScheme->GetBitmapOffset(); + m_ParentAssemblyScheme = pScheme->GetPresetName(); + m_Pos = pScheme->GetPos(); - AddToGroup("Assemblies"); - AddToGroup(m_ParentAssemblyScheme); - if (pScheme->GetAssemblyGroup().length() > 0) - { - AddToGroup(pScheme->GetAssemblyGroup()); - m_ParentSchemeGroup = pScheme->GetAssemblyGroup(); + AddToGroup("Assemblies"); + AddToGroup(m_ParentAssemblyScheme); + if (pScheme->GetAssemblyGroup().length() > 0) { + AddToGroup(pScheme->GetAssemblyGroup()); + m_ParentSchemeGroup = pScheme->GetAssemblyGroup(); + } + + return 0; } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOPixel to be identical to another, by deep copy. + int BunkerAssembly::Create(const BunkerAssembly& reference) { + TerrainObject::Create(reference); + for (std::list::const_iterator oItr = reference.m_PlacedObjects.begin(); oItr != reference.m_PlacedObjects.end(); ++oItr) + m_PlacedObjects.push_back(dynamic_cast((*oItr)->Clone())); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOPixel to be identical to another, by deep copy. + m_ParentAssemblyScheme = reference.m_ParentAssemblyScheme; + m_pPresentationBitmap = reference.m_pPresentationBitmap; + m_SymmetricAssembly = reference.m_SymmetricAssembly; + m_ParentSchemeGroup = reference.m_ParentSchemeGroup; -int BunkerAssembly::Create(const BunkerAssembly &reference) -{ - TerrainObject::Create(reference); + return 0; + } - for (std::list::const_iterator oItr = reference.m_PlacedObjects.begin(); oItr != reference.m_PlacedObjects.end(); ++oItr) - m_PlacedObjects.push_back(dynamic_cast((*oItr)->Clone())); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int BunkerAssembly::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return SceneObject::ReadProperty(propName, reader)); + + // Ignore TerrainObject's specific properties, but don't let parent class process them + MatchProperty("FGColorFile", {}); + MatchProperty("MaterialFile", {}); + MatchProperty("BGColorFile", {}); + MatchProperty("BitmapOffset", {}); + MatchProperty("Location", {}); + MatchProperty("AddChildObject", {}); + + MatchProperty("SymmetricAssembly", + { + reader >> m_SymmetricAssembly; + }); + MatchProperty("PlaceObject", + { + SceneObject* pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); + if (pSO) + AddPlacedObject(pSO); + }); + MatchProperty("ParentScheme", { + // Add to group like Entity::ReadProperty does + std::string parentScheme; + reader >> parentScheme; + AddToGroup(parentScheme); + g_PresetMan.RegisterGroup(parentScheme, reader.GetReadModuleID()); + + // Find the scheme's group, read it's dimensions and create presentation bitmap + const BunkerAssemblyScheme* pScheme = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssemblyScheme", parentScheme, -1)); + if (pScheme) { + // Calculate fixed scheme price based on the scheme size + if (pScheme->GetGoldValue() == 0) + m_OzValue = pScheme->GetArea() * 3; + else + pScheme->GetGoldValue(); + + // Delete existing bitmaps to avoid leaks if someone adds assembly to multiple groups by mistake + delete m_pPresentationBitmap; + m_pPresentationBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_pPresentationBitmap, g_MaskColor); + + delete m_FGColorBitmap; + m_FGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_FGColorBitmap, g_MaskColor); + + delete m_MaterialBitmap; + m_MaterialBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_MaterialBitmap, g_MaskColor); + + delete m_BGColorBitmap; + m_BGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth(), pScheme->GetBitmapHeight()); + clear_to_color(m_BGColorBitmap, g_MaskColor); + + m_ParentAssemblyScheme = parentScheme; + m_BitmapOffset = pScheme->GetBitmapOffset(); + if (pScheme->GetAssemblyGroup().length() > 0) { + AddToGroup(pScheme->GetAssemblyGroup()); + m_ParentSchemeGroup = pScheme->GetAssemblyGroup(); + g_PresetMan.RegisterGroup(pScheme->GetAssemblyGroup(), reader.GetReadModuleID()); + } + + // Also add to Assemblies group + AddToGroup("Assemblies"); + g_PresetMan.RegisterGroup("Assemblies", reader.GetReadModuleID()); + } else { + // Do not allow to define assemblies prior to corresponding assembly scheme + char s[256]; + std::snprintf(s, sizeof(s), "Required BunkerAssemblyScheme '%s%' not found when trying to load BunkerAssembly '%s'! BunkerAssemblySchemes MUST be defined before dependent BunkerAssmeblies.", parentScheme.c_str(), m_PresetName.c_str()); + RTEAbort(s); + } + }); - m_ParentAssemblyScheme = reference.m_ParentAssemblyScheme; - m_pPresentationBitmap = reference.m_pPresentationBitmap; - m_SymmetricAssembly = reference.m_SymmetricAssembly; - m_ParentSchemeGroup = reference.m_ParentSchemeGroup; + EndPropertyList; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this BunkerAssembly with a Writer for + // later recreation with Create(Reader &reader); + int BunkerAssembly::Save(Writer& writer) const { + SceneObject::Save(writer); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int BunkerAssembly::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return SceneObject::ReadProperty(propName, reader)); - - // Ignore TerrainObject's specific properties, but don't let parent class process them - MatchProperty("FGColorFile", { }); - MatchProperty("MaterialFile", { }); - MatchProperty("BGColorFile", { }); - MatchProperty("BitmapOffset", { }); - MatchProperty("Location", { }); - MatchProperty("AddChildObject", { }); - - MatchProperty("SymmetricAssembly", - { - reader >> m_SymmetricAssembly; - }); - MatchProperty("PlaceObject", - { - SceneObject *pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); - if (pSO) - AddPlacedObject(pSO); - }); - MatchProperty("ParentScheme", { - //Add to group like Entity::ReadProperty does - std::string parentScheme; - reader >> parentScheme; - AddToGroup(parentScheme); - g_PresetMan.RegisterGroup(parentScheme, reader.GetReadModuleID()); - - // Find the scheme's group, read it's dimensions and create presentation bitmap - const BunkerAssemblyScheme * pScheme = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssemblyScheme", parentScheme, -1)); - if (pScheme) - { - //Calculate fixed scheme price based on the scheme size - if (pScheme->GetGoldValue() == 0) - m_OzValue = pScheme->GetArea() * 3; - else - pScheme->GetGoldValue(); - - //Delete existing bitmaps to avoid leaks if someone adds assembly to multiple groups by mistake - delete m_pPresentationBitmap; - m_pPresentationBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_pPresentationBitmap, g_MaskColor); - - delete m_FGColorBitmap; - m_FGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_FGColorBitmap, g_MaskColor); - - delete m_MaterialBitmap; - m_MaterialBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_MaterialBitmap, g_MaskColor); - - delete m_BGColorBitmap; - m_BGColorBitmap = create_bitmap_ex(8, pScheme->GetBitmapWidth() , pScheme->GetBitmapHeight()); - clear_to_color(m_BGColorBitmap, g_MaskColor); - - m_ParentAssemblyScheme = parentScheme; - m_BitmapOffset = pScheme->GetBitmapOffset(); - if (pScheme->GetAssemblyGroup().length() > 0) - { - AddToGroup(pScheme->GetAssemblyGroup()); - m_ParentSchemeGroup = pScheme->GetAssemblyGroup(); - g_PresetMan.RegisterGroup(pScheme->GetAssemblyGroup(), reader.GetReadModuleID()); + // Groups are essential for BunkerAssemblies so save them, because entity seem to ignore them + for (auto itr = m_Groups.begin(); itr != m_Groups.end(); ++itr) { + if ((*itr) != m_ParentAssemblyScheme && (*itr) != m_ParentSchemeGroup) { + writer.NewProperty("AddToGroup"); + writer << *itr; } - - // Also add to Assemblies group - AddToGroup("Assemblies"); - g_PresetMan.RegisterGroup("Assemblies", reader.GetReadModuleID()); - } else { - // Do not allow to define assemblies prior to corresponding assembly scheme - char s[256]; - std::snprintf(s, sizeof(s), "Required BunkerAssemblyScheme '%s%' not found when trying to load BunkerAssembly '%s'! BunkerAssemblySchemes MUST be defined before dependent BunkerAssmeblies.", parentScheme.c_str(), m_PresetName.c_str()); - RTEAbort(s); } - }); - - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this BunkerAssembly with a Writer for -// later recreation with Create(Reader &reader); - -int BunkerAssembly::Save(Writer &writer) const -{ - SceneObject::Save(writer); - - // Groups are essential for BunkerAssemblies so save them, because entity seem to ignore them - for (auto itr = m_Groups.begin(); itr != m_Groups.end(); ++itr) - { - if ((*itr) != m_ParentAssemblyScheme && (*itr) != m_ParentSchemeGroup) - { - writer.NewProperty("AddToGroup"); - writer << *itr; + if (m_SymmetricAssembly.size() > 0) { + writer.NewProperty("SymmetricAssembly"); + writer << m_SymmetricAssembly; } - } - if (m_SymmetricAssembly.size() > 0) - { - writer.NewProperty("SymmetricAssembly"); - writer << m_SymmetricAssembly; - } - if (m_ParentAssemblyScheme.size() > 0) - { - writer.NewProperty("ParentScheme"); - writer << m_ParentAssemblyScheme; - } - - for (std::list::const_iterator oItr = m_PlacedObjects.begin(); oItr != m_PlacedObjects.end(); ++oItr) - { - writer.NewProperty("PlaceObject"); - writer.ObjectStart((*oItr)->GetClassName()); - writer.NewProperty("CopyOf"); - writer << (*oItr)->GetModuleAndPresetName(); - - writer.NewProperty("Position"); - writer << (*oItr)->GetPos(); - - // Only write certain properties if they are applicable to the type of SceneObject being written - MOSRotating *pSpriteObj = dynamic_cast(*oItr); - if (pSpriteObj) - { - writer.NewProperty("HFlipped"); - writer << pSpriteObj->IsHFlipped(); - Actor *pActor = dynamic_cast(pSpriteObj); - if (pActor) - { - writer.NewProperty("Team"); - writer << pActor->GetTeam(); - // Rotation of doors is important - ADoor *pDoor = dynamic_cast(pActor); - if (pDoor) - { - writer.NewProperty("Rotation"); - writer << pDoor->GetRotMatrix(); - } - } - } - TerrainObject *pTObject = dynamic_cast(*oItr); - if (pTObject && !pTObject->GetChildObjects().empty()) - { - writer.NewProperty("Team"); - writer << pTObject->GetTeam(); - } - Deployment *pDeployment = dynamic_cast(*oItr); - if (pDeployment) - { - writer.NewProperty("HFlipped"); - writer << pDeployment->IsHFlipped(); + if (m_ParentAssemblyScheme.size() > 0) { + writer.NewProperty("ParentScheme"); + writer << m_ParentAssemblyScheme; } + for (std::list::const_iterator oItr = m_PlacedObjects.begin(); oItr != m_PlacedObjects.end(); ++oItr) { + writer.NewProperty("PlaceObject"); + writer.ObjectStart((*oItr)->GetClassName()); + writer.NewProperty("CopyOf"); + writer << (*oItr)->GetModuleAndPresetName(); + + writer.NewProperty("Position"); + writer << (*oItr)->GetPos(); + + // Only write certain properties if they are applicable to the type of SceneObject being written + MOSRotating* pSpriteObj = dynamic_cast(*oItr); + if (pSpriteObj) { + writer.NewProperty("HFlipped"); + writer << pSpriteObj->IsHFlipped(); + Actor* pActor = dynamic_cast(pSpriteObj); + if (pActor) { + writer.NewProperty("Team"); + writer << pActor->GetTeam(); + // Rotation of doors is important + ADoor* pDoor = dynamic_cast(pActor); + if (pDoor) { + writer.NewProperty("Rotation"); + writer << pDoor->GetRotMatrix(); + } + } + } + TerrainObject* pTObject = dynamic_cast(*oItr); + if (pTObject && !pTObject->GetChildObjects().empty()) { + writer.NewProperty("Team"); + writer << pTObject->GetTeam(); + } + Deployment* pDeployment = dynamic_cast(*oItr); + if (pDeployment) { + writer.NewProperty("HFlipped"); + writer << pDeployment->IsHFlipped(); + } - writer.ObjectEnd(); - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the BunkerAssembly object. - -void BunkerAssembly::Destroy(bool notInherited) -{ - for (std::list::iterator oItr = m_PlacedObjects.begin(); oItr != m_PlacedObjects.end(); ++oItr) - { - delete (*oItr); - *oItr = 0; - } - - // Probably no need to delete those, as bitmaps are only created when preset is read from file - // and then they just copy pointers in via Clone() - //delete m_pPresentationBitmap; - //m_pPresentationBitmap = 0; - - //delete m_FGColorBitmap; - //m_FGColorBitmap = 0; - - //delete m_MaterialBitmap; - //m_MaterialBitmap = 0; - - //delete m_BGColorBitmap; - //m_BGColorBitmap = 0; - - if (!notInherited) - SceneObject::Destroy(); - Clear(); -} + writer.ObjectEnd(); + } + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the BunkerAssembly object. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetDeployments -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Retrieves the list of random deployemtns selected to be deployed by this assembly -// based on it's parent scheme MaxDeployments value. This list will always include all -// brain deployments so it can be longer that MaxDeployments. OWNERSHIP NOT TRANSFERRED. - -std::vector BunkerAssembly::GetDeployments() -{ - std::vector deploymentsList; - std::vector candidatesList; - - // Sort objects, brains are added by default, everything else are candidates - for (std::list::const_iterator itr = m_PlacedObjects.begin(); itr != m_PlacedObjects.end() ; ++itr) - { - Deployment * pDeployment = dynamic_cast(*itr); - - if (pDeployment) - { - if (pDeployment->IsInGroup("Brains")) - deploymentsList.push_back(pDeployment); - else - candidatesList.push_back(pDeployment); + void BunkerAssembly::Destroy(bool notInherited) { + for (std::list::iterator oItr = m_PlacedObjects.begin(); oItr != m_PlacedObjects.end(); ++oItr) { + delete (*oItr); + *oItr = 0; } - } - int maxDeployments = 0; + // Probably no need to delete those, as bitmaps are only created when preset is read from file + // and then they just copy pointers in via Clone() + // delete m_pPresentationBitmap; + // m_pPresentationBitmap = 0; - const BunkerAssemblyScheme * pScheme = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssemblyScheme", m_ParentAssemblyScheme, -1)); - if (pScheme) - maxDeployments = pScheme->GetMaxDeployments(); + // delete m_FGColorBitmap; + // m_FGColorBitmap = 0; - int selected = 0; - for (int i = 0; i(0, candidatesList.size() - 1); - deploymentsList.push_back(candidatesList.at(selection)); - candidatesList.erase(candidatesList.begin() + selection); + // delete m_BGColorBitmap; + // m_BGColorBitmap = 0; + + if (!notInherited) + SceneObject::Destroy(); + Clear(); } - return deploymentsList; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetDeployments + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Retrieves the list of random deployemtns selected to be deployed by this assembly + // based on it's parent scheme MaxDeployments value. This list will always include all + // brain deployments so it can be longer that MaxDeployments. OWNERSHIP NOT TRANSFERRED. + + std::vector BunkerAssembly::GetDeployments() { + std::vector deploymentsList; + std::vector candidatesList; + + // Sort objects, brains are added by default, everything else are candidates + for (std::list::const_iterator itr = m_PlacedObjects.begin(); itr != m_PlacedObjects.end(); ++itr) { + Deployment* pDeployment = dynamic_cast(*itr); + + if (pDeployment) { + if (pDeployment->IsInGroup("Brains")) + deploymentsList.push_back(pDeployment); + else + candidatesList.push_back(pDeployment); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. + int maxDeployments = 0; -bool BunkerAssembly::IsOnScenePoint(Vector &scenePoint) const -{ - if (!m_pPresentationBitmap) - return false; + const BunkerAssemblyScheme* pScheme = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssemblyScheme", m_ParentAssemblyScheme, -1)); + if (pScheme) + maxDeployments = pScheme->GetMaxDeployments(); - Vector bitmapPos = m_Pos + m_BitmapOffset; - if (WithinBox(scenePoint, bitmapPos, m_pPresentationBitmap->w, m_pPresentationBitmap->h)) - { - // Scene point on the bitmap - Vector bitmapPoint = scenePoint - bitmapPos; - if (getpixel(m_pPresentationBitmap, bitmapPoint.m_X, bitmapPoint.m_Y) != g_MaskColor) - return true; - } + int selected = 0; + for (int i = 0; i < maxDeployments; i++) { + if (candidatesList.size() == 0) + break; - return false; -} + int selection = RandomNum(0, candidatesList.size() - 1); + deploymentsList.push_back(candidatesList.at(selection)); + candidatesList.erase(candidatesList.begin() + selection); + } + return deploymentsList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this Actor belongs to. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + + bool BunkerAssembly::IsOnScenePoint(Vector& scenePoint) const { + if (!m_pPresentationBitmap) + return false; + + Vector bitmapPos = m_Pos + m_BitmapOffset; + if (WithinBox(scenePoint, bitmapPos, m_pPresentationBitmap->w, m_pPresentationBitmap->h)) { + // Scene point on the bitmap + Vector bitmapPoint = scenePoint - bitmapPos; + if (getpixel(m_pPresentationBitmap, bitmapPoint.m_X, bitmapPoint.m_Y) != g_MaskColor) + return true; + } -void BunkerAssembly::SetTeam(int team) -{ - TerrainObject::SetTeam(team); + return false; + } - // Make sure all the objects to be placed will be of the same team - for (std::list::iterator itr = m_PlacedObjects.begin(); itr != m_PlacedObjects.end(); ++itr) - (*itr)->SetTeam(team); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this Actor belongs to. + void BunkerAssembly::SetTeam(int team) { + TerrainObject::SetTeam(team); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this TerrainObject's current graphical representation to a -// BITMAP of choice. - -void BunkerAssembly::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const -{ - if (!m_FGColorBitmap) - RTEAbort("TerrainObject's bitmaps are null when drawing!"); - - // Take care of wrapping situations - Vector aDrawPos[4]; - aDrawPos[0] = m_Pos + m_BitmapOffset - targetPos; - int passes = 1; - - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero() && g_SceneMan.GetSceneWidth() <= pTargetBitmap->w) - { - if (aDrawPos[0].m_X < m_FGColorBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += pTargetBitmap->w; - passes++; - } - else if (aDrawPos[0].m_X > pTargetBitmap->w - m_FGColorBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= pTargetBitmap->w; - passes++; - } - } - // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam - else - { - if (g_SceneMan.SceneWrapsX()) - { - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (targetPos.m_X < 0) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= sceneWidth; - passes++; - } - if (targetPos.m_X + pTargetBitmap->w > sceneWidth) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += sceneWidth; - passes++; - } - } - } - - // Draw all the passes needed - for (int i = 0; i < passes; ++i) - { - if (mode == g_DrawColor) - { - masked_blit(m_pPresentationBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_BGColorBitmap->w, m_BGColorBitmap->h); - } - else if (mode == g_DrawMaterial) - { - masked_blit(m_MaterialBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_MaterialBitmap->w, m_MaterialBitmap->h); - } - else if (mode == g_DrawTrans) - { - draw_trans_sprite(pTargetBitmap, m_pPresentationBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); - } - } -} + // Make sure all the objects to be placed will be of the same team + for (std::list::iterator itr = m_PlacedObjects.begin(); itr != m_PlacedObjects.end(); ++itr) + (*itr)->SetTeam(team); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this TerrainObject's current graphical representation to a + // BITMAP of choice. + + void BunkerAssembly::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + if (!m_FGColorBitmap) + RTEAbort("TerrainObject's bitmaps are null when drawing!"); + + // Take care of wrapping situations + Vector aDrawPos[4]; + aDrawPos[0] = m_Pos + m_BitmapOffset - targetPos; + int passes = 1; + + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero() && g_SceneMan.GetSceneWidth() <= pTargetBitmap->w) { + if (aDrawPos[0].m_X < m_FGColorBitmap->w) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += pTargetBitmap->w; + passes++; + } else if (aDrawPos[0].m_X > pTargetBitmap->w - m_FGColorBitmap->w) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= pTargetBitmap->w; + passes++; + } + } + // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam + else { + if (g_SceneMan.SceneWrapsX()) { + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (targetPos.m_X < 0) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= sceneWidth; + passes++; + } + if (targetPos.m_X + pTargetBitmap->w > sceneWidth) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += sceneWidth; + passes++; + } + } + } + + // Draw all the passes needed + for (int i = 0; i < passes; ++i) { + if (mode == g_DrawColor) { + masked_blit(m_pPresentationBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_BGColorBitmap->w, m_BGColorBitmap->h); + } else if (mode == g_DrawMaterial) { + masked_blit(m_MaterialBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_MaterialBitmap->w, m_MaterialBitmap->h); + } else if (mode == g_DrawTrans) { + draw_trans_sprite(pTargetBitmap, m_pPresentationBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); + } + } + } } // namespace RTE diff --git a/Source/Entities/BunkerAssembly.h b/Source/Entities/BunkerAssembly.h index ffa49fadb..cf47b9340 100644 --- a/Source/Entities/BunkerAssembly.h +++ b/Source/Entities/BunkerAssembly.h @@ -10,271 +10,246 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "TerrainObject.h" -namespace RTE -{ - -class BunkerAssemblyScheme; -class Deployment; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: BunkerAssembly -////////////////////////////////////////////////////////////////////////////////////////// -// Description: An assembly of a few terrain objects. -// material layer and optional background layer. -// Parent(s): SceneObject. -// Class history: 08/23/2002 BunkerAssembly created. - -class BunkerAssembly : public TerrainObject { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - -// Concrete allocation and cloning definitions -EntityAllocation(BunkerAssembly); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: BunkerAssembly -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a BunkerAssembly object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - BunkerAssembly() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~BunkerAssembly -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a BunkerAssembly object before deletion -// from system memory. -// Arguments: None. - - ~BunkerAssembly() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BunkerAssembly object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BunkerAssembly object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(BunkerAssemblyScheme * scheme); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a BunkerAssembly to be identical to another, by deep copy. -// Arguments: A reference to the BunkerAssembly to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const BunkerAssembly &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire BunkerAssembly, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); SceneObject::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the BunkerAssembly object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetParentAssemblySchemeName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// -// Arguments: None. -// Return value: -// - - std::string GetParentAssemblySchemeName() const { return m_ParentAssemblyScheme; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. -// Arguments: The point in absolute scene coordinates. -// Return value: Whether this' graphical rep overlaps the scene point. - - bool IsOnScenePoint(Vector &scenePoint) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeployments -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Retrieves the list of random deployemtns selected to be deployed by this assembly -// based on it's parent scheme MaxDeployments value. This list will always include all -// brain deployments so it can be longer that MaxDeployments. -// Arguments: None. -// Return value: List of deployments. - - std::vector GetDeployments(); +namespace RTE { + class BunkerAssemblyScheme; + class Deployment; ////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this belongs to. -// Arguments: The assigned team number. -// Return value: None. - - void SetTeam(int team) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlacedObjects -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of SceneObject:s which are placed in this assembly on loading. -// Arguments: None. -// Return value: The list of of placed objects. Ownership is NOT transferred! - - const std::list * GetPlacedObjects() const { return &m_PlacedObjects; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds placed object to the internallist of placed objects for this assembly, -// applies it's image to presentation bitmap and sets assembly price accordingly. -// Added scene object MUST have coordinates relative to this assembly. -// Arguments: Object to add. -// Return value: None. - - void AddPlacedObject(SceneObject * pSO); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGraphicalIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a bitmap showing a good identifyable icon of this, for use in -// GUI lists etc. -// Arguments: None. -// Return value: A good identifyable graphical representation of this in a BITMAP, if -// available. If not, 0 is returned. Ownership is NOT TRANSFERRED! - - BITMAP * GetGraphicalIcon() const override { return m_pPresentationBitmap; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSymmetricAssemblyName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the name of an assembly symmetric to this one. -// Arguments: None. -// Return value: Symmetric assembly name. - - std::string GetSymmetricAssemblyName() const { return m_SymmetricAssembly; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSymmetricAssemblyName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the name of an assembly symmetric to this one. -// Arguments: Symmetric assembly name. -// Return value: None. - - void SetSymmetricAssemblyName(std::string newSymmetricAssembly) { m_SymmetricAssembly = newSymmetricAssembly; }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this TerrainObject's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// like indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - // SceneObject:s to be placed in the scene, OWNED HERE - std::list m_PlacedObjects; - // Parent bunker assembly scheme - std::string m_ParentAssemblyScheme; - // Group proveded by parent scheme to which this assembly was added - std::string m_ParentSchemeGroup; - // Bitmap shown during draw and icon creation - BITMAP * m_pPresentationBitmap; - //Assembly symmetric to this one - std::string m_SymmetricAssembly; - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this BunkerAssembly, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - BunkerAssembly(const BunkerAssembly &reference) = delete; - void operator=(const BunkerAssembly &rhs) = delete; - -}; + // Class: BunkerAssembly + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: An assembly of a few terrain objects. + // material layer and optional background layer. + // Parent(s): SceneObject. + // Class history: 08/23/2002 BunkerAssembly created. + + class BunkerAssembly : public TerrainObject { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(BunkerAssembly); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: BunkerAssembly + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a BunkerAssembly object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + BunkerAssembly() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~BunkerAssembly + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a BunkerAssembly object before deletion + // from system memory. + // Arguments: None. + + ~BunkerAssembly() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BunkerAssembly object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BunkerAssembly object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(BunkerAssemblyScheme* scheme); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a BunkerAssembly to be identical to another, by deep copy. + // Arguments: A reference to the BunkerAssembly to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const BunkerAssembly& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire BunkerAssembly, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + SceneObject::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the BunkerAssembly object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetParentAssemblySchemeName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // + // Arguments: None. + // Return value: + // + + std::string GetParentAssemblySchemeName() const { return m_ParentAssemblyScheme; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + // Arguments: The point in absolute scene coordinates. + // Return value: Whether this' graphical rep overlaps the scene point. + + bool IsOnScenePoint(Vector& scenePoint) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeployments + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Retrieves the list of random deployemtns selected to be deployed by this assembly + // based on it's parent scheme MaxDeployments value. This list will always include all + // brain deployments so it can be longer that MaxDeployments. + // Arguments: None. + // Return value: List of deployments. + + std::vector GetDeployments(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this belongs to. + // Arguments: The assigned team number. + // Return value: None. + + void SetTeam(int team) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlacedObjects + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of SceneObject:s which are placed in this assembly on loading. + // Arguments: None. + // Return value: The list of of placed objects. Ownership is NOT transferred! + + const std::list* GetPlacedObjects() const { return &m_PlacedObjects; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds placed object to the internallist of placed objects for this assembly, + // applies it's image to presentation bitmap and sets assembly price accordingly. + // Added scene object MUST have coordinates relative to this assembly. + // Arguments: Object to add. + // Return value: None. + + void AddPlacedObject(SceneObject* pSO); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGraphicalIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a bitmap showing a good identifyable icon of this, for use in + // GUI lists etc. + // Arguments: None. + // Return value: A good identifyable graphical representation of this in a BITMAP, if + // available. If not, 0 is returned. Ownership is NOT TRANSFERRED! + + BITMAP* GetGraphicalIcon() const override { return m_pPresentationBitmap; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSymmetricAssemblyName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of an assembly symmetric to this one. + // Arguments: None. + // Return value: Symmetric assembly name. + + std::string GetSymmetricAssemblyName() const { return m_SymmetricAssembly; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSymmetricAssemblyName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the name of an assembly symmetric to this one. + // Arguments: Symmetric assembly name. + // Return value: None. + + void SetSymmetricAssemblyName(std::string newSymmetricAssembly) { m_SymmetricAssembly = newSymmetricAssembly; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this TerrainObject's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // like indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + // SceneObject:s to be placed in the scene, OWNED HERE + std::list m_PlacedObjects; + // Parent bunker assembly scheme + std::string m_ParentAssemblyScheme; + // Group proveded by parent scheme to which this assembly was added + std::string m_ParentSchemeGroup; + // Bitmap shown during draw and icon creation + BITMAP* m_pPresentationBitmap; + // Assembly symmetric to this one + std::string m_SymmetricAssembly; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this BunkerAssembly, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + BunkerAssembly(const BunkerAssembly& reference) = delete; + void operator=(const BunkerAssembly& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/BunkerAssemblyScheme.cpp b/Source/Entities/BunkerAssemblyScheme.cpp index 9676269be..0252f7163 100644 --- a/Source/Entities/BunkerAssemblyScheme.cpp +++ b/Source/Entities/BunkerAssemblyScheme.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,385 +19,346 @@ namespace RTE { -ConcreteClassInfo(BunkerAssemblyScheme, SceneObject, 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this BunkerAssemblyScheme, effectively -// resetting the members of this abstraction level only. - -void BunkerAssemblyScheme::Clear() -{ - m_pPresentationBitmap = 0; - m_ChildObjects.clear(); - m_BitmapOffset = Vector(0,0); - m_IsOneTypePerScene = false; - m_Limit = 0; - m_MaxDeployments = 1; - m_SymmetricScheme.clear(); - m_AssemblyGroup.clear(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BunkerAssemblyScheme object ready for use. - -int BunkerAssemblyScheme::Create() -{ - if (SceneObject::Create() < 0) - return -1; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOPixel to be identical to another, by deep copy. - -int BunkerAssemblyScheme::Create(const BunkerAssemblyScheme &reference) -{ - SceneObject::Create(reference); - - m_pBitmap = reference.m_pBitmap; - m_pPresentationBitmap = reference.m_pPresentationBitmap; - m_pIconBitmap = reference.m_pIconBitmap; - - for (std::list::const_iterator itr = reference.m_ChildObjects.begin(); itr != reference.m_ChildObjects.end(); ++itr) - m_ChildObjects.push_back(*itr); - - m_BitmapOffset = reference.m_BitmapOffset; - - m_IsOneTypePerScene = reference.m_IsOneTypePerScene; - m_Limit = reference.m_Limit; - m_MaxDeployments = reference.m_MaxDeployments; - m_SymmetricScheme = reference.m_SymmetricScheme; - m_AssemblyGroup = reference.m_AssemblyGroup; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int BunkerAssemblyScheme::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return SceneObject::ReadProperty(propName, reader)); - - MatchProperty("BitmapFile", - { - reader >> m_BitmapFile; - m_pBitmap = m_BitmapFile.GetAsBitmap(); - - m_pPresentationBitmap = create_bitmap_ex(8, m_pBitmap->w * ScaleX, m_pBitmap->h * ScaleY); - clear_to_color(m_pPresentationBitmap, g_MaskColor); - - // Create internal presentation bitmap which will be drawn by editor - // Create horizontal outlines - for (int x = 0; x < m_pBitmap->w; ++x) - { - //Top to bottom - for (int y = 0; y < m_pBitmap->h ; ++y) - { - int px = getpixel(m_pBitmap, x, y); - int pxp = getpixel(m_pBitmap, x, y - 1) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x, y - 1); - - if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + w, x * ScaleX + ScaleX - 1, y * ScaleY + w, PAINT_COLOR_WALL); - - if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + w, x * ScaleX + ScaleX -1, y * ScaleY + w, PAINT_COLOR_PASSABLE); - - if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + w, x * ScaleX + ScaleX -1, y * ScaleY + w, PAINT_COLOR_VARIABLE); - } - - //Bottom to top - for (int y = m_pBitmap->h - 1; y >= 0 ; --y) - { - int px = getpixel(m_pBitmap, x, y); - int pxp = getpixel(m_pBitmap, x, y + 1) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x, y + 1); - - if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + ScaleX - 1 - w, x * ScaleX + ScaleX - 1, y * ScaleY + ScaleY - 1 - w, PAINT_COLOR_WALL); - - if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + ScaleX - 1 - w, x * ScaleX + ScaleX - 1, y * ScaleY + ScaleY - 1 - w, PAINT_COLOR_PASSABLE); - - if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + ScaleX - 1 - w, x * ScaleX + ScaleX - 1, y * ScaleY + ScaleY - 1 - w, PAINT_COLOR_VARIABLE); - } + ConcreteClassInfo(BunkerAssemblyScheme, SceneObject, 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this BunkerAssemblyScheme, effectively + // resetting the members of this abstraction level only. + + void BunkerAssemblyScheme::Clear() { + m_pPresentationBitmap = 0; + m_ChildObjects.clear(); + m_BitmapOffset = Vector(0, 0); + m_IsOneTypePerScene = false; + m_Limit = 0; + m_MaxDeployments = 1; + m_SymmetricScheme.clear(); + m_AssemblyGroup.clear(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BunkerAssemblyScheme object ready for use. + + int BunkerAssemblyScheme::Create() { + if (SceneObject::Create() < 0) + return -1; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOPixel to be identical to another, by deep copy. + + int BunkerAssemblyScheme::Create(const BunkerAssemblyScheme& reference) { + SceneObject::Create(reference); + + m_pBitmap = reference.m_pBitmap; + m_pPresentationBitmap = reference.m_pPresentationBitmap; + m_pIconBitmap = reference.m_pIconBitmap; + + for (std::list::const_iterator itr = reference.m_ChildObjects.begin(); itr != reference.m_ChildObjects.end(); ++itr) + m_ChildObjects.push_back(*itr); + + m_BitmapOffset = reference.m_BitmapOffset; + + m_IsOneTypePerScene = reference.m_IsOneTypePerScene; + m_Limit = reference.m_Limit; + m_MaxDeployments = reference.m_MaxDeployments; + m_SymmetricScheme = reference.m_SymmetricScheme; + m_AssemblyGroup = reference.m_AssemblyGroup; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int BunkerAssemblyScheme::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return SceneObject::ReadProperty(propName, reader)); + + MatchProperty("BitmapFile", + { + reader >> m_BitmapFile; + m_pBitmap = m_BitmapFile.GetAsBitmap(); + + m_pPresentationBitmap = create_bitmap_ex(8, m_pBitmap->w * ScaleX, m_pBitmap->h * ScaleY); + clear_to_color(m_pPresentationBitmap, g_MaskColor); + + // Create internal presentation bitmap which will be drawn by editor + // Create horizontal outlines + for (int x = 0; x < m_pBitmap->w; ++x) { + // Top to bottom + for (int y = 0; y < m_pBitmap->h; ++y) { + int px = getpixel(m_pBitmap, x, y); + int pxp = getpixel(m_pBitmap, x, y - 1) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x, y - 1); + + if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + w, x * ScaleX + ScaleX - 1, y * ScaleY + w, PAINT_COLOR_WALL); + + if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + w, x * ScaleX + ScaleX - 1, y * ScaleY + w, PAINT_COLOR_PASSABLE); + + if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + w, x * ScaleX + ScaleX - 1, y * ScaleY + w, PAINT_COLOR_VARIABLE); + } + + // Bottom to top + for (int y = m_pBitmap->h - 1; y >= 0; --y) { + int px = getpixel(m_pBitmap, x, y); + int pxp = getpixel(m_pBitmap, x, y + 1) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x, y + 1); + + if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + ScaleX - 1 - w, x * ScaleX + ScaleX - 1, y * ScaleY + ScaleY - 1 - w, PAINT_COLOR_WALL); + + if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + ScaleX - 1 - w, x * ScaleX + ScaleX - 1, y * ScaleY + ScaleY - 1 - w, PAINT_COLOR_PASSABLE); + + if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX, y * ScaleY + ScaleX - 1 - w, x * ScaleX + ScaleX - 1, y * ScaleY + ScaleY - 1 - w, PAINT_COLOR_VARIABLE); + } + } + + // Create vertical outlines + for (int y = 0; y < m_pBitmap->h; ++y) { + // Left + for (int x = 0; x < m_pBitmap->w; ++x) { + int px = getpixel(m_pBitmap, x, y); + int pxp = getpixel(m_pBitmap, x - 1, y) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x - 1, y); + + if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX + w, y * ScaleY, x * ScaleX + w, y * ScaleY + ScaleY - 1, PAINT_COLOR_WALL); + + if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX + w, y * ScaleY, x * ScaleX + w, y * ScaleY + ScaleY - 1, PAINT_COLOR_PASSABLE); + + if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX + w, y * ScaleY, x * ScaleX + w, y * ScaleY + ScaleY - 1, PAINT_COLOR_VARIABLE); + } + + for (int x = m_pBitmap->w - 1; x >= 0; --x) { + int px = getpixel(m_pBitmap, x, y); + int pxp = getpixel(m_pBitmap, x + 1, y) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x + 1, y); + + if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX + ScaleX - 1 - w, y * ScaleY, x * ScaleX + ScaleX - 1 - w, y * ScaleY + ScaleY - 1, PAINT_COLOR_WALL); + + if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX + ScaleX - 1 - w, y * ScaleY, x * ScaleX + ScaleX - 1 - w, y * ScaleY + ScaleY - 1, PAINT_COLOR_PASSABLE); + + if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) + for (int w = 0; w < SchemeWidth; w++) + line(m_pPresentationBitmap, x * ScaleX + ScaleX - 1 - w, y * ScaleY, x * ScaleX + ScaleX - 1 - w, y * ScaleY + ScaleY - 1, PAINT_COLOR_VARIABLE); + } + } + + // Print scheme name + GUIFont* pSmallFont = g_FrameMan.GetSmallFont(); + AllegroBitmap allegroBitmap(m_pPresentationBitmap); + pSmallFont->DrawAligned(&allegroBitmap, 4, 4, m_PresetName, GUIFont::Left); + + // Calculate bitmap offset + int width = m_pBitmap->w / 2; + int height = m_pBitmap->h / 2; + m_BitmapOffset = Vector(-width * ScaleX, -height * ScaleY); + + // Count max deployments if not set + if (m_MaxDeployments == 0) { + m_MaxDeployments = (int)((float)GetArea() / AREA_PER_DEPLOYMENT); + if (m_MaxDeployments == 0) + m_MaxDeployments = 1; + } + + float scale = (float)ICON_WIDTH / (float)m_pPresentationBitmap->w; + + m_pIconBitmap = create_bitmap_ex(8, m_pPresentationBitmap->w * scale, m_pPresentationBitmap->h * scale); + clear_to_color(m_pIconBitmap, g_MaskColor); + + for (int x = 0; x < m_pBitmap->w; ++x) + for (int y = 0; y < m_pBitmap->h; ++y) { + int px = getpixel(m_pBitmap, x, y); + + if (px == SCHEME_COLOR_WALL) + rectfill(m_pIconBitmap, x * ScaleX * scale, y * ScaleY * scale, x * ScaleX * scale + ScaleX - 1, y * ScaleY + ScaleY - 1, PAINT_COLOR_WALL); + else if (px == SCHEME_COLOR_PASSABLE) + rectfill(m_pIconBitmap, x * ScaleX * scale, y * ScaleY * scale, x * ScaleX * scale + ScaleX - 1, y * ScaleY + ScaleY - 1, PAINT_COLOR_PASSABLE); + else if (px == SCHEME_COLOR_VARIABLE) + rectfill(m_pIconBitmap, x * ScaleX * scale, y * ScaleY * scale, x * ScaleX * scale + ScaleX - 1, y * ScaleY + ScaleY - 1, PAINT_COLOR_VARIABLE); + } + }); + MatchProperty("AddChildObject", + { + SOPlacer newChild; + reader >> newChild; + newChild.SetTeam(m_Team); + m_ChildObjects.push_back(newChild); + }); + MatchProperty("Limit", { reader >> m_Limit; }); + MatchProperty("OneTypePerScene", { reader >> m_IsOneTypePerScene; }); + MatchProperty("MaxDeployments", { reader >> m_MaxDeployments; }); + MatchProperty("SymmetricScheme", { reader >> m_SymmetricScheme; }); + MatchProperty("AssemblyGroup", { reader >> m_AssemblyGroup; }); + + EndPropertyList; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this BunkerAssemblyScheme with a Writer for + // later recreation with Create(Reader &reader); + + int BunkerAssemblyScheme::Save(Writer& writer) const { + SceneObject::Save(writer); + + writer.NewProperty("BitmapFile"); + writer << m_BitmapFile; + for (std::list::const_iterator itr = m_ChildObjects.begin(); itr != m_ChildObjects.end(); ++itr) { + writer.NewProperty("AddChildObject"); + writer << (*itr); } - // Create vertical outlines - for (int y = 0; y < m_pBitmap->h; ++y) - { - // Left - for (int x = 0; x < m_pBitmap->w ; ++x) - { - int px = getpixel(m_pBitmap, x, y); - int pxp = getpixel(m_pBitmap, x - 1, y) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x - 1, y); - - if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX + w, y * ScaleY, x * ScaleX + w, y * ScaleY + ScaleY - 1, PAINT_COLOR_WALL); - - if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX + w, y * ScaleY, x * ScaleX + w, y * ScaleY + ScaleY - 1, PAINT_COLOR_PASSABLE); - - if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX + w, y * ScaleY, x * ScaleX + w, y * ScaleY + ScaleY - 1, PAINT_COLOR_VARIABLE); - } - - for (int x = m_pBitmap->w - 1; x >= 0 ; --x) - { - int px = getpixel(m_pBitmap, x, y); - int pxp = getpixel(m_pBitmap, x + 1, y) == -1 ? SCHEME_COLOR_EMPTY : getpixel(m_pBitmap, x + 1, y); - - if (px == SCHEME_COLOR_WALL && pxp != SCHEME_COLOR_WALL) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX + ScaleX - 1 - w, y * ScaleY, x * ScaleX + ScaleX - 1 - w, y * ScaleY + ScaleY - 1,PAINT_COLOR_WALL); - - if (px == SCHEME_COLOR_PASSABLE && pxp != SCHEME_COLOR_PASSABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX + ScaleX - 1 - w, y * ScaleY, x * ScaleX + ScaleX - 1 - w, y * ScaleY + ScaleY - 1,PAINT_COLOR_PASSABLE); - - if (px == SCHEME_COLOR_VARIABLE && pxp != SCHEME_COLOR_VARIABLE) - for (int w = 0; w < SchemeWidth; w++) - line(m_pPresentationBitmap, x * ScaleX + ScaleX - 1 - w, y * ScaleY, x * ScaleX + ScaleX - 1 - w, y * ScaleY + ScaleY - 1,PAINT_COLOR_VARIABLE); - } + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the BunkerAssemblyScheme object. + + void BunkerAssemblyScheme::Destroy(bool notInherited) { + // Probably no need to delete those, as bitmaps are only created when preset is read from file + // and then they just copy pointers in via Clone() + // delete m_pPresentationBitmap; + // m_pPresentationBitmap = 0; + + if (!notInherited) + SceneObject::Destroy(); + Clear(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGraphicalIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a bitmap showing a good identifyable icon of this, for use in + // GUI lists etc. + + BITMAP* BunkerAssemblyScheme::GetGraphicalIcon() const { + return m_pIconBitmap; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + + bool BunkerAssemblyScheme::IsOnScenePoint(Vector& scenePoint) const { + if (!m_pBitmap) + return false; + + Vector bitmapPos = m_Pos + m_BitmapOffset; + if (WithinBox(scenePoint, bitmapPos, m_pPresentationBitmap->w, m_pPresentationBitmap->h)) { + // Scene point on the bitmap + Vector bitmapPoint = scenePoint - bitmapPos; + + int x = bitmapPoint.m_X / ScaleX; + int y = bitmapPoint.m_Y / ScaleY; + + if (getpixel(m_pBitmap, x, y) != SCHEME_COLOR_EMPTY) + return true; } - // Print scheme name - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); - AllegroBitmap allegroBitmap(m_pPresentationBitmap); - pSmallFont->DrawAligned(&allegroBitmap, 4, 4, m_PresetName, GUIFont::Left); - - // Calculate bitmap offset - int width = m_pBitmap->w / 2; - int height = m_pBitmap->h / 2; - m_BitmapOffset = Vector(-width * ScaleX, -height * ScaleY); - - // Count max deployments if not set - if (m_MaxDeployments == 0) - { - m_MaxDeployments = (int)((float)GetArea() / AREA_PER_DEPLOYMENT); - if (m_MaxDeployments == 0) - m_MaxDeployments = 1; + return false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this Actor belongs to. + + void BunkerAssemblyScheme::SetTeam(int team) { + SceneObject::SetTeam(team); + + // Make sure all the objects to be placed will be of the same team + for (std::list::iterator itr = m_ChildObjects.begin(); itr != m_ChildObjects.end(); ++itr) + (*itr).SetTeam(team); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this BunkerAssemblyScheme's current graphical representation to a + // BITMAP of choice. + + void BunkerAssemblyScheme::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + if (!m_pPresentationBitmap) + RTEAbort("BunkerAssemblyScheme's bitmaps are null when drawing!"); + + // Take care of wrapping situations + Vector aDrawPos[4]; + aDrawPos[0] = m_Pos - targetPos + m_BitmapOffset; + int passes = 1; + + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero() && g_SceneMan.GetSceneWidth() <= pTargetBitmap->w) { + if (aDrawPos[0].m_X < m_pPresentationBitmap->w) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += pTargetBitmap->w; + passes++; + } else if (aDrawPos[0].m_X > pTargetBitmap->w - m_pPresentationBitmap->w) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= pTargetBitmap->w; + passes++; + } } - - float scale = (float)ICON_WIDTH / (float)m_pPresentationBitmap->w; - - m_pIconBitmap = create_bitmap_ex(8, m_pPresentationBitmap->w * scale, m_pPresentationBitmap->h * scale); - clear_to_color(m_pIconBitmap, g_MaskColor); - - for (int x = 0; x < m_pBitmap->w ; ++x) - for (int y = 0; y < m_pBitmap->h; ++y) - { - int px = getpixel(m_pBitmap, x, y); - - if (px == SCHEME_COLOR_WALL) - rectfill(m_pIconBitmap, x * ScaleX * scale, y * ScaleY * scale, x * ScaleX * scale + ScaleX-1, y * ScaleY + ScaleY-1, PAINT_COLOR_WALL); - else if (px == SCHEME_COLOR_PASSABLE) - rectfill(m_pIconBitmap, x * ScaleX * scale, y * ScaleY * scale, x * ScaleX * scale + ScaleX-1, y * ScaleY + ScaleY-1, PAINT_COLOR_PASSABLE); - else if (px == SCHEME_COLOR_VARIABLE) - rectfill(m_pIconBitmap, x * ScaleX * scale, y * ScaleY * scale, x * ScaleX * scale + ScaleX-1, y * ScaleY + ScaleY-1, PAINT_COLOR_VARIABLE); + // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam + else { + if (g_SceneMan.SceneWrapsX()) { + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (targetPos.m_X < 0) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= sceneWidth; + passes++; + } + if (targetPos.m_X + pTargetBitmap->w > sceneWidth) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += sceneWidth; + passes++; + } } - }); - MatchProperty("AddChildObject", - { - SOPlacer newChild; - reader >> newChild; - newChild.SetTeam(m_Team); - m_ChildObjects.push_back(newChild); - }); - MatchProperty("Limit", { reader >> m_Limit; }); - MatchProperty("OneTypePerScene", { reader >> m_IsOneTypePerScene; }); - MatchProperty("MaxDeployments", { reader >> m_MaxDeployments; }); - MatchProperty("SymmetricScheme", { reader >> m_SymmetricScheme; }); - MatchProperty("AssemblyGroup", { reader >> m_AssemblyGroup; }); - - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this BunkerAssemblyScheme with a Writer for -// later recreation with Create(Reader &reader); - -int BunkerAssemblyScheme::Save(Writer &writer) const -{ - SceneObject::Save(writer); - - writer.NewProperty("BitmapFile"); - writer << m_BitmapFile; - for (std::list::const_iterator itr = m_ChildObjects.begin(); itr != m_ChildObjects.end(); ++itr) - { - writer.NewProperty("AddChildObject"); - writer << (*itr); - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the BunkerAssemblyScheme object. - -void BunkerAssemblyScheme::Destroy(bool notInherited) -{ - // Probably no need to delete those, as bitmaps are only created when preset is read from file - // and then they just copy pointers in via Clone() - //delete m_pPresentationBitmap; - //m_pPresentationBitmap = 0; - - if (!notInherited) - SceneObject::Destroy(); - Clear(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGraphicalIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a bitmap showing a good identifyable icon of this, for use in -// GUI lists etc. - -BITMAP * BunkerAssemblyScheme::GetGraphicalIcon() const -{ - return m_pIconBitmap; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. - -bool BunkerAssemblyScheme::IsOnScenePoint(Vector &scenePoint) const -{ - if (!m_pBitmap) - return false; - - Vector bitmapPos = m_Pos + m_BitmapOffset; - if (WithinBox(scenePoint, bitmapPos, m_pPresentationBitmap->w, m_pPresentationBitmap->h)) - { - // Scene point on the bitmap - Vector bitmapPoint = scenePoint - bitmapPos; - - int x = bitmapPoint.m_X / ScaleX; - int y = bitmapPoint.m_Y / ScaleY; - - if (getpixel(m_pBitmap, x, y) != SCHEME_COLOR_EMPTY) - return true; - } - - return false; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this Actor belongs to. - -void BunkerAssemblyScheme::SetTeam(int team) -{ - SceneObject::SetTeam(team); - - // Make sure all the objects to be placed will be of the same team - for (std::list::iterator itr = m_ChildObjects.begin(); itr != m_ChildObjects.end(); ++itr) - (*itr).SetTeam(team); -} - + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this BunkerAssemblyScheme's current graphical representation to a -// BITMAP of choice. - -void BunkerAssemblyScheme::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const -{ - if (!m_pPresentationBitmap) - RTEAbort("BunkerAssemblyScheme's bitmaps are null when drawing!"); - - // Take care of wrapping situations - Vector aDrawPos[4]; - aDrawPos[0] = m_Pos - targetPos + m_BitmapOffset; - int passes = 1; - - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero() && g_SceneMan.GetSceneWidth() <= pTargetBitmap->w) - { - if (aDrawPos[0].m_X < m_pPresentationBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += pTargetBitmap->w; - passes++; - } - else if (aDrawPos[0].m_X > pTargetBitmap->w - m_pPresentationBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= pTargetBitmap->w; - passes++; - } - } - // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam - else - { - if (g_SceneMan.SceneWrapsX()) - { - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (targetPos.m_X < 0) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= sceneWidth; - passes++; - } - if (targetPos.m_X + pTargetBitmap->w > sceneWidth) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += sceneWidth; - passes++; - } - } - } - - // Draw all the passes needed - for (int i = 0; i < passes; ++i) - { - if (mode == g_DrawColor) - masked_blit(m_pPresentationBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_pPresentationBitmap->w, m_pPresentationBitmap->h); - else if (mode == g_DrawMaterial) - masked_blit(m_pPresentationBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_pPresentationBitmap->w, m_pPresentationBitmap->h); - else if (mode == g_DrawTrans) - draw_trans_sprite(pTargetBitmap, m_pPresentationBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); - } -} + // Draw all the passes needed + for (int i = 0; i < passes; ++i) { + if (mode == g_DrawColor) + masked_blit(m_pPresentationBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_pPresentationBitmap->w, m_pPresentationBitmap->h); + else if (mode == g_DrawMaterial) + masked_blit(m_pPresentationBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), m_pPresentationBitmap->w, m_pPresentationBitmap->h); + else if (mode == g_DrawTrans) + draw_trans_sprite(pTargetBitmap, m_pPresentationBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); + } + } } // namespace RTE diff --git a/Source/Entities/BunkerAssemblyScheme.h b/Source/Entities/BunkerAssemblyScheme.h index 0c08eb22b..ff0cbbed4 100644 --- a/Source/Entities/BunkerAssemblyScheme.h +++ b/Source/Entities/BunkerAssemblyScheme.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,319 +19,295 @@ #define ICON_WIDTH 69 #define AREA_PER_DEPLOYMENT 64 -namespace RTE -{ - -class ContentFile; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: BunkerAssemblyScheme -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A feature of the terrain, which includes foreground color layer, -// material layer and optional background layer. -// Parent(s): SceneObject. -// Class history: 08/23/2002 BunkerAssemblyScheme created. - -class BunkerAssemblyScheme : public SceneObject { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - // Different scheme properties are encoded on colors of scheme bitmap - enum SchemeColor - { - SCHEME_COLOR_EMPTY = g_MaskColor, // Empty sections, MUST BE ALWAYS EMPTY - SCHEME_COLOR_PASSABLE = 5, // Passable sections, MUST BE ALWAYS PASSBLE, I.E. HAVE ONLY BACKGROUNDS - SCHEME_COLOR_VARIABLE = 4, // May be passable or not. Expect air. - SCHEME_COLOR_WALL = 3 // Always impassable, but may be empty. Expect terrain. - }; - - // Scheme properties, when drawed in game UIs - enum PresentationColor - { - PAINT_COLOR_PASSABLE = 5, - PAINT_COLOR_VARIABLE = 48, - PAINT_COLOR_WALL = 13 +namespace RTE { + + class ContentFile; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: BunkerAssemblyScheme + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A feature of the terrain, which includes foreground color layer, + // material layer and optional background layer. + // Parent(s): SceneObject. + // Class history: 08/23/2002 BunkerAssemblyScheme created. + + class BunkerAssemblyScheme : public SceneObject { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Different scheme properties are encoded on colors of scheme bitmap + enum SchemeColor { + SCHEME_COLOR_EMPTY = g_MaskColor, // Empty sections, MUST BE ALWAYS EMPTY + SCHEME_COLOR_PASSABLE = 5, // Passable sections, MUST BE ALWAYS PASSBLE, I.E. HAVE ONLY BACKGROUNDS + SCHEME_COLOR_VARIABLE = 4, // May be passable or not. Expect air. + SCHEME_COLOR_WALL = 3 // Always impassable, but may be empty. Expect terrain. + }; + + // Scheme properties, when drawed in game UIs + enum PresentationColor { + PAINT_COLOR_PASSABLE = 5, + PAINT_COLOR_VARIABLE = 48, + PAINT_COLOR_WALL = 13 + }; + + const static int ScaleX = 24; + const static int ScaleY = 24; + const static int SchemeWidth = 2; + + // Concrete allocation and cloning definitions + EntityAllocation(BunkerAssemblyScheme); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: BunkerAssemblyScheme + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a BunkerAssemblyScheme object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + BunkerAssemblyScheme() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~BunkerAssemblyScheme + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a BunkerAssemblyScheme object before deletion + // from system memory. + // Arguments: None. + + ~BunkerAssemblyScheme() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BunkerAssemblyScheme object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a BunkerAssemblyScheme to be identical to another, by deep copy. + // Arguments: A reference to the BunkerAssemblyScheme to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const BunkerAssemblyScheme& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire BunkerAssemblyScheme, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + SceneObject::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the BunkerAssemblyScheme object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBitmapWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the width this' bitmap. + // Arguments: None. + // Return value: Width of bitmap. + + const int GetBitmapWidth() const { return m_pPresentationBitmap->w; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBitmapHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the height this' material bitmap. + // Arguments: None. + // Return value: Height of 'material' bitmap. + + const int GetBitmapHeight() const { return m_pPresentationBitmap->h; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBitmapOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the offset of presentation bitmap + // Arguments: None. + // Return value: Offset of bitmap + + const Vector GetBitmapOffset() const { return m_BitmapOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the BITMAP object that this BunkerAssemblyScheme uses for its fore- + // ground color representation. + // Arguments: None. + // Return value: A pointer to the foreground color BITMAP object. Ownership is not + // transferred. + + BITMAP* GetBitmap() const { return m_pPresentationBitmap; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the area of the structure bitmap. + // Arguments: None. + // Return value: None. + + int GetArea() const { return m_pBitmap->h * m_pBitmap->w; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGraphicalIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a bitmap showing a good identifyable icon of this, for use in + // GUI lists etc. + // Arguments: None. + // Return value: A good identifyable graphical representation of this in a BITMAP, if + // available. If not, 0 is returned. Ownership is NOT TRANSFERRED! + + BITMAP* GetGraphicalIcon() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this belongs to. + // Arguments: The assigned team number. + // Return value: None. + + void SetTeam(int team) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + // Arguments: The point in absolute scene coordinates. + // Return value: Whether this' graphical rep overlaps the scene point. + + bool IsOnScenePoint(Vector& scenePoint) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this BunkerAssemblyScheme's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // like indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOneTypePerScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether sceneman should select just a single assembly for this scheme + // and use it everywhere on the scene. + // Arguments: None. + // Return value: Whether we allowed to use just one type of assembly for this scheme + + bool IsOneTypePerScene() { return m_IsOneTypePerScene; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSymmetricSchemeName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of the scheme symmetric to this one. + // Arguments: None. + // Return value: Symmetric scheme name. + + std::string GetSymmetricSchemeName() const { return m_SymmetricScheme; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAssemblyGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of group to which assemblies linked with this scheme must be added. + // Arguments: None. + // Return value: Assembly group name. + + std::string GetAssemblyGroup() const { return m_AssemblyGroup; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLimit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the limit of these schemes per scene. 0 - no limit. + // Arguments: None. + // Return value: Scheme limit. + + int GetLimit() { return m_Limit; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaxDeployments + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the number of deployments this scheme is allowed to place. + // Arguments: None. + // Return value: Deployments limit. + + int GetMaxDeployments() const { return m_MaxDeployments; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + + ContentFile m_BitmapFile; + + // Not owned by this + BITMAP* m_pBitmap; + BITMAP* m_pPresentationBitmap; + BITMAP* m_pIconBitmap; + + // The objects that are placed along with this in the scene + std::list m_ChildObjects; + + // If this is true then sceneman must select a single assembly for this scheme and use it everywhere on the scene + bool m_IsOneTypePerScene; + // How many assemblies can placed on one scene? + int m_Limit; + // Drawable bitmap offset of this bunker assembly + Vector m_BitmapOffset; + // How many deployments should be selected during placement + int m_MaxDeployments; + // Scheme symmetric to this one + std::string m_SymmetricScheme; + // To which group we should add assemblies linked to this scheme + std::string m_AssemblyGroup; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this BunkerAssemblyScheme, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + BunkerAssemblyScheme(const BunkerAssemblyScheme& reference) = delete; + void operator=(const BunkerAssemblyScheme& rhs) = delete; }; - const static int ScaleX = 24; - const static int ScaleY = 24; - const static int SchemeWidth = 2; - -// Concrete allocation and cloning definitions -EntityAllocation(BunkerAssemblyScheme); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: BunkerAssemblyScheme -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a BunkerAssemblyScheme object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - BunkerAssemblyScheme() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~BunkerAssemblyScheme -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a BunkerAssemblyScheme object before deletion -// from system memory. -// Arguments: None. - - ~BunkerAssemblyScheme() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BunkerAssemblyScheme object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a BunkerAssemblyScheme to be identical to another, by deep copy. -// Arguments: A reference to the BunkerAssemblyScheme to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const BunkerAssemblyScheme &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire BunkerAssemblyScheme, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); SceneObject::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the BunkerAssemblyScheme object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBitmapWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the width this' bitmap. -// Arguments: None. -// Return value: Width of bitmap. - - const int GetBitmapWidth() const { return m_pPresentationBitmap->w; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBitmapHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the height this' material bitmap. -// Arguments: None. -// Return value: Height of 'material' bitmap. - - const int GetBitmapHeight() const { return m_pPresentationBitmap->h; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBitmapOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the offset of presentation bitmap -// Arguments: None. -// Return value: Offset of bitmap - - const Vector GetBitmapOffset() const { return m_BitmapOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the BITMAP object that this BunkerAssemblyScheme uses for its fore- -// ground color representation. -// Arguments: None. -// Return value: A pointer to the foreground color BITMAP object. Ownership is not -// transferred. - - BITMAP * GetBitmap() const { return m_pPresentationBitmap; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the area of the structure bitmap. -// Arguments: None. -// Return value: None. - - int GetArea() const { return m_pBitmap->h * m_pBitmap->w; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGraphicalIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a bitmap showing a good identifyable icon of this, for use in -// GUI lists etc. -// Arguments: None. -// Return value: A good identifyable graphical representation of this in a BITMAP, if -// available. If not, 0 is returned. Ownership is NOT TRANSFERRED! - - BITMAP * GetGraphicalIcon() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this belongs to. -// Arguments: The assigned team number. -// Return value: None. - - void SetTeam(int team) override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. -// Arguments: The point in absolute scene coordinates. -// Return value: Whether this' graphical rep overlaps the scene point. - - bool IsOnScenePoint(Vector &scenePoint) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this BunkerAssemblyScheme's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// like indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOneTypePerScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether sceneman should select just a single assembly for this scheme -// and use it everywhere on the scene. -// Arguments: None. -// Return value: Whether we allowed to use just one type of assembly for this scheme - - bool IsOneTypePerScene() { return m_IsOneTypePerScene; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSymmetricSchemeName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the name of the scheme symmetric to this one. -// Arguments: None. -// Return value: Symmetric scheme name. - - std::string GetSymmetricSchemeName() const { return m_SymmetricScheme; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAssemblyGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the name of group to which assemblies linked with this scheme must be added. -// Arguments: None. -// Return value: Assembly group name. - - std::string GetAssemblyGroup() const { return m_AssemblyGroup; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLimit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the limit of these schemes per scene. 0 - no limit. -// Arguments: None. -// Return value: Scheme limit. - - int GetLimit() { return m_Limit; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaxDeployments -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the number of deployments this scheme is allowed to place. -// Arguments: None. -// Return value: Deployments limit. - - int GetMaxDeployments() const { return m_MaxDeployments; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - - ContentFile m_BitmapFile; - - // Not owned by this - BITMAP *m_pBitmap; - BITMAP *m_pPresentationBitmap; - BITMAP *m_pIconBitmap; - - // The objects that are placed along with this in the scene - std::list m_ChildObjects; - - // If this is true then sceneman must select a single assembly for this scheme and use it everywhere on the scene - bool m_IsOneTypePerScene; - // How many assemblies can placed on one scene? - int m_Limit; - // Drawable bitmap offset of this bunker assembly - Vector m_BitmapOffset; - // How many deployments should be selected during placement - int m_MaxDeployments; - // Scheme symmetric to this one - std::string m_SymmetricScheme; - // To which group we should add assemblies linked to this scheme - std::string m_AssemblyGroup; - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this BunkerAssemblyScheme, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - BunkerAssemblyScheme(const BunkerAssemblyScheme &reference) = delete; - void operator=(const BunkerAssemblyScheme &rhs) = delete; - -}; - } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/Deployment.cpp b/Source/Entities/Deployment.cpp index 5a3d7c0ec..a9710c3fb 100644 --- a/Source/Entities/Deployment.cpp +++ b/Source/Entities/Deployment.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -24,785 +23,692 @@ namespace RTE { -ConcreteClassInfo(Deployment, SceneObject, 0); - + ConcreteClassInfo(Deployment, SceneObject, 0); -std::vector Deployment::m_apArrowLeftBitmap; -std::vector Deployment::m_apArrowRightBitmap; + std::vector Deployment::m_apArrowLeftBitmap; + std::vector Deployment::m_apArrowRightBitmap; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Deployment, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Deployment, effectively -// resetting the members of this abstraction level only. - -void Deployment::Clear() -{ - m_LoadoutName = "Default"; - m_Icon.Reset(); - m_SpawnRadius = 40; - m_WalkRadius = 250; - m_ID = 0; - m_HFlipped = false; -} + void Deployment::Clear() { + m_LoadoutName = "Default"; + m_Icon.Reset(); + m_SpawnRadius = 40; + m_WalkRadius = 250; + m_ID = 0; + m_HFlipped = false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Deployment object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Deployment object ready for use. + int Deployment::Create() { + if (SceneObject::Create() < 0) + return -1; -int Deployment::Create() -{ - if (SceneObject::Create() < 0) - return -1; + if (m_apArrowLeftBitmap.empty()) { + ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowLeft.png").GetAsAnimation(m_apArrowLeftBitmap, 1); + } + if (m_apArrowRightBitmap.empty()) { + ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowRight.png").GetAsAnimation(m_apArrowRightBitmap, 1); + } - if (m_apArrowLeftBitmap.empty()) - { - ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowLeft.png").GetAsAnimation(m_apArrowLeftBitmap, 1); + return 0; } - if (m_apArrowRightBitmap.empty()) - { - ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowRight.png").GetAsAnimation(m_apArrowRightBitmap, 1); - } - - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Deployment object ready for use. + + int Deployment::Create(std::string loadoutName, const Icon& icon, float spawnRadius) { + m_LoadoutName = loadoutName; + m_Icon = icon; + m_SpawnRadius = spawnRadius; + m_WalkRadius = 250; + m_ID = 0; + m_HFlipped = false; + + if (m_apArrowLeftBitmap.empty()) { + ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowLeft.png").GetAsAnimation(m_apArrowLeftBitmap, 1); + } + if (m_apArrowRightBitmap.empty()) { + ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowRight.png").GetAsAnimation(m_apArrowRightBitmap, 1); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Deployment object ready for use. - -int Deployment::Create(std::string loadoutName, const Icon &icon, float spawnRadius) -{ - m_LoadoutName = loadoutName; - m_Icon = icon; - m_SpawnRadius = spawnRadius; - m_WalkRadius = 250; - m_ID = 0; - m_HFlipped = false; - - if (m_apArrowLeftBitmap.empty()) - { - ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowLeft.png").GetAsAnimation(m_apArrowLeftBitmap, 1); + return 0; } - if (m_apArrowRightBitmap.empty()) - { - ContentFile("Base.rte/GUIs/DeploymentIcons/ArrowRight.png").GetAsAnimation(m_apArrowRightBitmap, 1); - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOPixel to be identical to another, by deep copy. - -int Deployment::Create(const Deployment &reference) -{ - SceneObject::Create(reference); - - m_LoadoutName = reference.m_LoadoutName; - m_Icon = reference.m_Icon; - m_SpawnRadius = reference.m_SpawnRadius; - m_WalkRadius = reference.m_WalkRadius; - m_ID = reference.m_ID; - m_HFlipped = reference.m_HFlipped; - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOPixel to be identical to another, by deep copy. + int Deployment::Create(const Deployment& reference) { + SceneObject::Create(reference); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int Deployment::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return SceneObject::ReadProperty(propName, reader)); - - MatchProperty("LoadoutName", { reader >> m_LoadoutName; }); - MatchProperty("Icon", { reader >> m_Icon; }); - MatchProperty("SpawnRadius", { reader >> m_SpawnRadius; }); - MatchProperty("WalkRadius", { reader >> m_WalkRadius; }); - MatchProperty("ID", { reader >> m_ID; }); - MatchProperty("HFlipped", { reader >> m_HFlipped; }); - - EndPropertyList; -} + m_LoadoutName = reference.m_LoadoutName; + m_Icon = reference.m_Icon; + m_SpawnRadius = reference.m_SpawnRadius; + m_WalkRadius = reference.m_WalkRadius; + m_ID = reference.m_ID; + m_HFlipped = reference.m_HFlipped; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Deployment with a Writer for -// later recreation with Create(Reader &reader); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int Deployment::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return SceneObject::ReadProperty(propName, reader)); + + MatchProperty("LoadoutName", { reader >> m_LoadoutName; }); + MatchProperty("Icon", { reader >> m_Icon; }); + MatchProperty("SpawnRadius", { reader >> m_SpawnRadius; }); + MatchProperty("WalkRadius", { reader >> m_WalkRadius; }); + MatchProperty("ID", { reader >> m_ID; }); + MatchProperty("HFlipped", { reader >> m_HFlipped; }); + + EndPropertyList; + } -int Deployment::Save(Writer &writer) const -{ - SceneObject::Save(writer); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Deployment with a Writer for + // later recreation with Create(Reader &reader); + + int Deployment::Save(Writer& writer) const { + SceneObject::Save(writer); + + writer.NewProperty("LoadoutName"); + writer << m_LoadoutName; + writer.NewProperty("Icon"); + writer << m_Icon; + writer.NewProperty("SpawnRadius"); + writer << m_SpawnRadius; + writer.NewProperty("WalkRadius"); + writer << m_WalkRadius; + writer.NewProperty("HFlipped"); + writer << m_HFlipped; + + return 0; + } - writer.NewProperty("LoadoutName"); - writer << m_LoadoutName; - writer.NewProperty("Icon"); - writer << m_Icon; - writer.NewProperty("SpawnRadius"); - writer << m_SpawnRadius; - writer.NewProperty("WalkRadius"); - writer << m_WalkRadius; - writer.NewProperty("HFlipped"); - writer << m_HFlipped; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the Deployment object. - return 0; -} + void Deployment::Destroy(bool notInherited) { + if (!notInherited) + SceneObject::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the Deployment object. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the Actor that this Deployment dictates should + // spawn here. Ownership IS transferred!! All items of the Loadout of + // this Deployment will be added to the Actor's inventory as well (and + // also owned by it) + + Actor* Deployment::CreateDeployedActor() { + float cost; + return CreateDeployedActor(-1, cost); + } -void Deployment::Destroy(bool notInherited) -{ - + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the Actor that this Deployment dictates should + // spawn here. Ownership IS transferred!! All items of the Loadout of + // this Deployment will be added to the Actor's inventory as well (and + // also owned by it) + + Actor* Deployment::CreateDeployedActor(int player, float& costTally) { + // The Actor instance we return and pass ownership of + Actor* pReturnActor = 0; + + // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + // Put + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); + // Also set the team of this Deployable to match the player's + m_Team = pMetaPlayer->GetTeam(); + } else { + GameActivity* activity = dynamic_cast(g_ActivityMan.GetActivity()); + if (activity) { + // Also set the team of this Deployable to match the player's + // m_Team = activity->GetTeamOfPlayer(player); + nativeModule = g_PresetMan.GetModuleID(activity->GetTeamTech(m_Team)); + // Select some random module if player selected all or something else + if (nativeModule < 0) { + std::vector moduleList; + + for (int moduleID = 0; moduleID < g_PresetMan.GetTotalModuleCount(); ++moduleID) { + if (const DataModule* dataModule = g_PresetMan.GetDataModule(moduleID)) { + if (dataModule->IsFaction()) { + moduleList.emplace_back(dataModule->GetFileName()); + } + } + } + int selection = RandomNum(1, moduleList.size() - 1); + nativeModule = g_PresetMan.GetModuleID(moduleList.at(selection)); + } + foreignCostMult = 1.0; + nativeCostMult = 1.0; + } + } - if (!notInherited) - SceneObject::Destroy(); - Clear(); -} + // Find the Loadout that this Deployment is referring to + if (const Loadout* pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule))) { + if (std::unique_ptr rawLoadoutActor = std::unique_ptr(pLoadout->CreateFirstActor(nativeModule, foreignCostMult, nativeCostMult, costTally))) { + rawLoadoutActor->SetPos(m_Pos); + rawLoadoutActor->SetTeam(m_Team); + rawLoadoutActor->SetHFlipped(m_HFlipped); + rawLoadoutActor->SetControllerMode(Controller::CIM_AI); + rawLoadoutActor->SetAIMode(Actor::AIMODE_SENTRY); + rawLoadoutActor->SetDeploymentID(m_ID); + pReturnActor = dynamic_cast(rawLoadoutActor->Clone()); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the Actor that this Deployment dictates should -// spawn here. Ownership IS transferred!! All items of the Loadout of -// this Deployment will be added to the Actor's inventory as well (and -// also owned by it) + // PASSING OWNERSHIP + return pReturnActor; + } -Actor * Deployment::CreateDeployedActor() -{ - float cost; - return CreateDeployedActor(-1, cost); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Device that Deployment dictates should + // spawn here. Ownership IS transferred!! Only the first Device is created. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the Actor that this Deployment dictates should -// spawn here. Ownership IS transferred!! All items of the Loadout of -// this Deployment will be added to the Actor's inventory as well (and -// also owned by it) - -Actor * Deployment::CreateDeployedActor(int player, float &costTally) -{ - // The Actor instance we return and pass ownership of - Actor *pReturnActor = 0; - - // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - // Put - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - // Also set the team of this Deployable to match the player's - m_Team = pMetaPlayer->GetTeam(); + SceneObject* Deployment::CreateDeployedObject() { + float cost; + return CreateDeployedObject(-1, cost); } - else - { - GameActivity * activity = dynamic_cast(g_ActivityMan.GetActivity()); - if (activity) - { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Device that Deployment dictates should + // spawn here. Ownership IS transferred!! Only the first Device is created. + + SceneObject* Deployment::CreateDeployedObject(int player, float& costTally) { + // The Actor instance we return and pass ownership of + SceneObject* pReturnObject = 0; + + // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); // Also set the team of this Deployable to match the player's - //m_Team = activity->GetTeamOfPlayer(player); - nativeModule = g_PresetMan.GetModuleID(activity->GetTeamTech(m_Team)); - // Select some random module if player selected all or something else - if (nativeModule < 0) { - std::vector moduleList; - - for (int moduleID = 0; moduleID < g_PresetMan.GetTotalModuleCount(); ++moduleID) { - if (const DataModule *dataModule = g_PresetMan.GetDataModule(moduleID)) { - if (dataModule->IsFaction()) { moduleList.emplace_back(dataModule->GetFileName()); } + m_Team = pMetaPlayer->GetTeam(); + } else { + GameActivity* activity = dynamic_cast(g_ActivityMan.GetActivity()); + if (activity) { + // Also set the team of this Deployable to match the player's + // m_Team = activity->GetTeamOfPlayer(player); + nativeModule = g_PresetMan.GetModuleID(activity->GetTeamTech(m_Team)); + // Select some random module if player selected all or something else + if (nativeModule < 0) { + std::vector moduleList; + + for (int moduleID = 0; moduleID < g_PresetMan.GetTotalModuleCount(); ++moduleID) { + if (const DataModule* dataModule = g_PresetMan.GetDataModule(moduleID)) { + if (dataModule->IsFaction()) { + moduleList.emplace_back(dataModule->GetFileName()); + } + } } + int selection = RandomNum(1, moduleList.size() - 1); + nativeModule = g_PresetMan.GetModuleID(moduleList.at(selection)); } - int selection = RandomNum(1, moduleList.size() - 1); - nativeModule = g_PresetMan.GetModuleID(moduleList.at(selection)); + foreignCostMult = 1.0; + nativeCostMult = 1.0; } - foreignCostMult = 1.0; - nativeCostMult = 1.0; } - } - - // Find the Loadout that this Deployment is referring to - if (const Loadout *pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule))) { - if (std::unique_ptr rawLoadoutActor = std::unique_ptr(pLoadout->CreateFirstActor(nativeModule, foreignCostMult, nativeCostMult, costTally))) { - rawLoadoutActor->SetPos(m_Pos); - rawLoadoutActor->SetTeam(m_Team); - rawLoadoutActor->SetHFlipped(m_HFlipped); - rawLoadoutActor->SetControllerMode(Controller::CIM_AI); - rawLoadoutActor->SetAIMode(Actor::AIMODE_SENTRY); - rawLoadoutActor->SetDeploymentID(m_ID); - pReturnActor = dynamic_cast(rawLoadoutActor->Clone()); - } - } - - // PASSING OWNERSHIP - return pReturnActor; -} + // Find the Loadout that this Deployment is referring to + const Loadout* pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule)); + if (pLoadout) { + // Get the first object in the Loadout + pReturnObject = pLoadout->CreateFirstDevice(nativeModule, foreignCostMult, nativeCostMult, costTally); + // Set the position and team etc for the Actor we are prepping to spawn + pReturnObject->SetPos(m_Pos); + pReturnObject->SetHFlipped(m_HFlipped); + pReturnObject->SetTeam(m_Team); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Device that Deployment dictates should -// spawn here. Ownership IS transferred!! Only the first Device is created. - -SceneObject * Deployment::CreateDeployedObject() -{ - float cost; - return CreateDeployedObject(-1, cost); -} + // PASSING OWNERSHIP + return pReturnObject; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DeploymentBlocked + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tests whether the Object this is supposed to spawn/deploy is blocked + // by an already exiting object in the a list being positioned within the + // spawn radius of this. + + bool Deployment::DeploymentBlocked(int player, const std::list& existingObjects) { + bool blocked = false; + + // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Device that Deployment dictates should -// spawn here. Ownership IS transferred!! Only the first Device is created. - -SceneObject * Deployment::CreateDeployedObject(int player, float &costTally) -{ - // The Actor instance we return and pass ownership of - SceneObject *pReturnObject = 0; - - // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - // Also set the team of this Deployable to match the player's - m_Team = pMetaPlayer->GetTeam(); - } else { - GameActivity * activity = dynamic_cast(g_ActivityMan.GetActivity()); - if (activity) - { - // Also set the team of this Deployable to match the player's - //m_Team = activity->GetTeamOfPlayer(player); - nativeModule = g_PresetMan.GetModuleID(activity->GetTeamTech(m_Team)); - // Select some random module if player selected all or something else - if (nativeModule < 0) { - std::vector moduleList; - - for (int moduleID = 0; moduleID < g_PresetMan.GetTotalModuleCount(); ++moduleID) { - if (const DataModule *dataModule = g_PresetMan.GetDataModule(moduleID)) { - if (dataModule->IsFaction()) { moduleList.emplace_back(dataModule->GetFileName()); } + // First try to find an object via ID's, objects with ID can be far enough + // Go through all already-placed things in the Scene to see if there's anything with matching spawn ID + if (m_ID) { + for (std::list::const_iterator existingItr = existingObjects.begin(); existingItr != existingObjects.end(); ++existingItr) { + Actor* pActor = dynamic_cast(*existingItr); + if (pActor && pActor->GetDeploymentID() == m_ID) { + // Do ghetto distance calc between the thing we want to place and the similar thing we found already placed + // Note this doesn't take into account Scene wrapping, which is problematic when the Scene might not be loaded.. it's okay in this case though + Vector distance = (*existingItr)->GetPos() - m_Pos; + // If the same thing is within the spawn radius, then signal that this Deployment location is indeed BLOCKED + if (distance.MagnitudeIsLessThan(m_WalkRadius)) { + blocked = true; + break; } } - int selection = RandomNum(1, moduleList.size() - 1); - nativeModule = g_PresetMan.GetModuleID(moduleList.at(selection)); } - foreignCostMult = 1.0; - nativeCostMult = 1.0; } - } + // No need to do expensive search if it's already blocked + if (blocked) + return blocked; + + // The object we would spawn by this Deployment, IF it's not blocked by somehting already + const SceneObject* pSpawnObject = 0; + + // Find the Loadout that this Deployment is referring to + Loadout* pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule)->Clone()); + if (pLoadout) { + // Now go through the Loadout list of items and tally the cost of all devices that would go into inventory of the first Actor found in the list + const std::list* pMOList = pLoadout->GetCargoList(); + if (pMOList && !pMOList->empty()) { + // Go through the list of things ordered, and give any actors all the items that is present after them, + // until the next actor. Also, the first actor gets all stuff in the list above him. + const MovableObject* pInventoryObject = 0; + const Actor* pActor = 0; + for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) { + // Save pointer of the preset in the list + pInventoryObject = dynamic_cast(*itr); + // See if it's actually a passenger, as opposed to a regular item + pActor = dynamic_cast(pInventoryObject); + // If it's an actor, then that's the guy which would be spawned, so use him to check agianst blockage + if (pActor) { + pSpawnObject = pActor; + // We're done looking for the object that would be spawned + break; + } + // If not an Actor, then skip because we're still looking for one + } + pActor = 0; - // Find the Loadout that this Deployment is referring to - const Loadout *pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule)); - if (pLoadout) - { - // Get the first object in the Loadout - pReturnObject = pLoadout->CreateFirstDevice(nativeModule, foreignCostMult, nativeCostMult, costTally); - // Set the position and team etc for the Actor we are prepping to spawn - pReturnObject->SetPos(m_Pos); - pReturnObject->SetHFlipped(m_HFlipped); - pReturnObject->SetTeam(m_Team); - } + // If no Actor was found, then see if we can use the delivery Craft instead + if (!pSpawnObject && pLoadout->GetDeliveryCraft()) { + // The craft is now the Actor we are looking at spawning + pSpawnObject = pLoadout->GetDeliveryCraft(); + } - // PASSING OWNERSHIP - return pReturnObject; -} + // If there's no Actor in this Deployment's Loadout at all, then we should just count the first Item or device in the Loadout + if (!pSpawnObject) { + // Find the first non-actor + for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) { + // If not an Actor, then we should count it and then stop + if (!dynamic_cast(*itr)) { + pSpawnObject = *itr; + // We're done finding the spawning object + break; + } + } + } + } + // Delete the Loadout instance we have + delete pLoadout; + pLoadout = 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DeploymentBlocked -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tests whether the Object this is supposed to spawn/deploy is blocked -// by an already exiting object in the a list being positioned within the -// spawn radius of this. - -bool Deployment::DeploymentBlocked(int player, const std::list &existingObjects) -{ - bool blocked = false; - - // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - } - - // First try to find an object via ID's, objects with ID can be far enough - // Go through all already-placed things in the Scene to see if there's anything with matching spawn ID - if (m_ID) - { - for (std::list::const_iterator existingItr = existingObjects.begin(); existingItr != existingObjects.end(); ++existingItr) - { - Actor *pActor = dynamic_cast(*existingItr); - if (pActor && pActor->GetDeploymentID() == m_ID) - { - // Do ghetto distance calc between the thing we want to place and the similar thing we found already placed - // Note this doesn't take into account Scene wrapping, which is problematic when the Scene might not be loaded.. it's okay in this case though - Vector distance = (*existingItr)->GetPos() - m_Pos; - // If the same thing is within the spawn radius, then signal that this Deployment location is indeed BLOCKED - if (distance.MagnitudeIsLessThan(m_WalkRadius)) - { - blocked = true; - break; + // Now check for whether the object that is going to be spawned is blocked by anyhting sufficently similar positioned within the spawn radius + if (pSpawnObject) { + // Go through all already-placed things in the Scene to see if there's anything similar/same + for (std::list::const_iterator existingItr = existingObjects.begin(); existingItr != existingObjects.end(); ++existingItr) { + if (((*existingItr)->GetClassName() == pSpawnObject->GetClassName()) && ((*existingItr)->GetPresetName() == pSpawnObject->GetPresetName())) { + // Do ghetto distance calc between the thing we want to place and the similar thing we found already placed + // Note this doesn't take into account Scene wrapping, which is problematic when the Scene might not be loaded.. it's okay in this case though + Vector distance = (*existingItr)->GetPos() - m_Pos; + // If the same thing is within the spawn radius, then signal that this Deployment location is indeed BLOCKED + if (distance.MagnitudeIsLessThan(m_SpawnRadius)) { + blocked = true; + break; + } } } } - } - // No need to do expensive search if it's already blocked - if (blocked) return blocked; + } - // The object we would spawn by this Deployment, IF it's not blocked by somehting already - const SceneObject *pSpawnObject = 0; - - // Find the Loadout that this Deployment is referring to - Loadout *pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule)->Clone()); - if (pLoadout) - { - // Now go through the Loadout list of items and tally the cost of all devices that would go into inventory of the first Actor found in the list - const std::list *pMOList = pLoadout->GetCargoList(); - if (pMOList && !pMOList->empty()) - { - // Go through the list of things ordered, and give any actors all the items that is present after them, - // until the next actor. Also, the first actor gets all stuff in the list above him. - const MovableObject *pInventoryObject = 0; - const Actor *pActor = 0; - for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) - { - // Save pointer of the preset in the list - pInventoryObject = dynamic_cast(*itr); - // See if it's actually a passenger, as opposed to a regular item - pActor = dynamic_cast(pInventoryObject); - // If it's an actor, then that's the guy which would be spawned, so use him to check agianst blockage - if (pActor) - { - pSpawnObject = pActor; - // We're done looking for the object that would be spawned - break; - } - // If not an Actor, then skip because we're still looking for one - } - pActor = 0; - - // If no Actor was found, then see if we can use the delivery Craft instead - if (!pSpawnObject && pLoadout->GetDeliveryCraft()) - { - // The craft is now the Actor we are looking at spawning - pSpawnObject = pLoadout->GetDeliveryCraft(); - } - - // If there's no Actor in this Deployment's Loadout at all, then we should just count the first Item or device in the Loadout - if (!pSpawnObject) - { - // Find the first non-actor - for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) - { - // If not an Actor, then we should count it and then stop - if (!dynamic_cast(*itr)) - { - pSpawnObject = *itr; - // We're done finding the spawning object - break; - } - } - } - } - - // Delete the Loadout instance we have - delete pLoadout; - pLoadout = 0; - } - - // Now check for whether the object that is going to be spawned is blocked by anyhting sufficently similar positioned within the spawn radius - if (pSpawnObject) - { - // Go through all already-placed things in the Scene to see if there's anything similar/same - for (std::list::const_iterator existingItr = existingObjects.begin(); existingItr != existingObjects.end(); ++existingItr) - { - if (((*existingItr)->GetClassName() == pSpawnObject->GetClassName()) && ((*existingItr)->GetPresetName() == pSpawnObject->GetPresetName())) - { - // Do ghetto distance calc between the thing we want to place and the similar thing we found already placed - // Note this doesn't take into account Scene wrapping, which is problematic when the Scene might not be loaded.. it's okay in this case though - Vector distance = (*existingItr)->GetPos() - m_Pos; - // If the same thing is within the spawn radius, then signal that this Deployment location is indeed BLOCKED - if (distance.MagnitudeIsLessThan(m_SpawnRadius)) - { - blocked = true; - break; - } - } - } - } - - return blocked; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of a spawn of this, including + // everything carried by it. + + float Deployment::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const { + float totalValue = 0; + const Actor* pFirstActor = 0; + + // Find the Loadout that this Deployment is referring to + Loadout* pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule)->Clone()); + if (pLoadout) { + // Now go through the Loadout list of items and tally the cost ofall devices that would go into inventory of the first Actor found in the list + const std::list* pMOList = pLoadout->GetCargoList(); + if (pMOList && !pMOList->empty()) { + // Go through the list of things ordered, and give any actors all the items that is present after them, + // until the next actor. Also, the first actor gets all stuff in the list above him. + const MovableObject* pInventoryObject = 0; + const Actor* pActor = 0; + std::list cargoItems; + for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) { + // Save pointer of the preset in the list + pInventoryObject = dynamic_cast(*itr); + // See if it's actually a passenger, as opposed to a regular item + pActor = dynamic_cast(pInventoryObject); + // If it's an actor, then that's the guy which will be spawned + if (pActor) { + // Add to the total cost tally + totalValue += (*itr)->GetGoldValue(nativeModule, foreignMult, nativeMult); + // If this is the first passenger, then give him all the shit found in the list before him + if (!pFirstActor) { + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); + } + // This isn't the first passenger, so give the previous guy all the stuff that was found since processing him + else { + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); + + // Also stop going through the list; we only need to count the value of ONE actor and his stuff + break; + } + // Clear out the temporary cargo list since we've assigned all the stuff in it to the return Actor + cargoItems.clear(); + + // Now set the current Actor as the one we found first + pFirstActor = pActor; + } + // If not an Actor, then add it to the temp list of items which will be added to the last passenger's inventory + else + cargoItems.push_back(pInventoryObject); + } + pActor = 0; + + // If there was a last passenger and only things after him, count the value of all the items in his inventory + if (pFirstActor) { + // Passing ownership + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); + cargoItems.clear(); + } + // If there wa NO actor in the Loadout's cargo list, then see if there's a craft we can stuff thigns into instead + else if (pLoadout->GetDeliveryCraft()) { + // The craft is now the Actor we are counting, so make an instance + pFirstActor = pLoadout->GetDeliveryCraft(); + // Add the cost of the ship + totalValue += pFirstActor->GetGoldValue(nativeModule, foreignMult); + // Count the stuff it would be filled with, passing ownership + for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) + totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); + cargoItems.clear(); + } + // If there's no Actor in this Deployment's Loadout, then we should just count the first Item or device in the Loadout + if (!pFirstActor) { + // Start over the count; we might have only had items/devices in the Loadout list, but no Actors yet + totalValue = 0; + for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) { + // If not an Actor, then we should count it and then stop + if (!dynamic_cast(*itr)) { + // Add to the total cost tally + totalValue += (*itr)->GetGoldValue(nativeModule, foreignMult); + // We're done + break; + } + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of a spawn of this, including -// everything carried by it. - -float Deployment::GetTotalValue(int nativeModule, float foreignMult, float nativeMult) const -{ - float totalValue = 0; - const Actor *pFirstActor = 0; - - // Find the Loadout that this Deployment is referring to - Loadout *pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", m_LoadoutName, nativeModule)->Clone()); - if (pLoadout) - { - // Now go through the Loadout list of items and tally the cost ofall devices that would go into inventory of the first Actor found in the list - const std::list *pMOList = pLoadout->GetCargoList(); - if (pMOList && !pMOList->empty()) - { - // Go through the list of things ordered, and give any actors all the items that is present after them, - // until the next actor. Also, the first actor gets all stuff in the list above him. - const MovableObject *pInventoryObject = 0; - const Actor *pActor = 0; - std::list cargoItems; - for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) - { - // Save pointer of the preset in the list - pInventoryObject = dynamic_cast(*itr); - // See if it's actually a passenger, as opposed to a regular item - pActor = dynamic_cast(pInventoryObject); - // If it's an actor, then that's the guy which will be spawned - if (pActor) - { - // Add to the total cost tally - totalValue += (*itr)->GetGoldValue(nativeModule, foreignMult, nativeMult); - // If this is the first passenger, then give him all the shit found in the list before him - if (!pFirstActor) - { - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); - } - // This isn't the first passenger, so give the previous guy all the stuff that was found since processing him - else - { - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); - - // Also stop going through the list; we only need to count the value of ONE actor and his stuff - break; - } - // Clear out the temporary cargo list since we've assigned all the stuff in it to the return Actor - cargoItems.clear(); - - // Now set the current Actor as the one we found first - pFirstActor = pActor; - } - // If not an Actor, then add it to the temp list of items which will be added to the last passenger's inventory - else - cargoItems.push_back(pInventoryObject); - } - pActor = 0; - - // If there was a last passenger and only things after him, count the value of all the items in his inventory - if (pFirstActor) - { - // Passing ownership - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); - cargoItems.clear(); - } - // If there wa NO actor in the Loadout's cargo list, then see if there's a craft we can stuff thigns into instead - else if (pLoadout->GetDeliveryCraft()) - { - // The craft is now the Actor we are counting, so make an instance - pFirstActor = pLoadout->GetDeliveryCraft(); - // Add the cost of the ship - totalValue += pFirstActor->GetGoldValue(nativeModule, foreignMult); - // Count the stuff it would be filled with, passing ownership - for (std::list::iterator iItr = cargoItems.begin(); iItr != cargoItems.end(); ++iItr) - totalValue += (*iItr)->GetTotalValue(nativeModule, foreignMult); - cargoItems.clear(); - } - - // If there's no Actor in this Deployment's Loadout, then we should just count the first Item or device in the Loadout - if (!pFirstActor) - { - // Start over the count; we might have only had items/devices in the Loadout list, but no Actors yet - totalValue = 0; - for (std::list::const_iterator itr = pMOList->begin(); itr != pMOList->end(); ++itr) - { - // If not an Actor, then we should count it and then stop - if (!dynamic_cast(*itr)) - { - // Add to the total cost tally - totalValue += (*itr)->GetGoldValue(nativeModule, foreignMult); - // We're done - break; - } - } - } - } - - // Delete the Loadout instance we have - delete pLoadout; - pLoadout = 0; - } - - return totalValue; -} + // Delete the Loadout instance we have + delete pLoadout; + pLoadout = 0; + } + return totalValue; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. - -bool Deployment::IsOnScenePoint(Vector &scenePoint) const -{ - if (m_Icon.GetBitmaps8().empty() || !(m_Icon.GetBitmaps8().at(0))) - return false; -// TODO: TAKE CARE OF WRAPPING -/* - // Take care of wrapping situations - bitmapPos = m_Pos + m_BitmapOffset; - Vector aScenePoint[4]; - aScenePoint[0] = scenePoint; - int passes = 1; - - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero()) - { - if (g_SceneMan.SceneWrapsX()) - { - if (bitmapPos.m_X < m_pFGColor->w) - { - aScenePoint[passes] = aScenePoint[0]; - aScenePoint[passes].m_X += g_SceneMan.GetSceneWidth(); - passes++; - } - else if (aScenePoint[0].m_X > pTargetBitmap->w - m_pFGColor->w) - { - aScenePoint[passes] = aScenePoint[0]; - aScenePoint[passes].m_X -= g_SceneMan.GetSceneWidth(); - passes++; - } - } - if (g_SceneMan.SceneWrapsY()) - { - - } - } - - // Check all the passes needed - for (int i = 0; i < passes; ++i) - { - - if (IsWithinBox(aScenePoint[i], m_Pos + m_BitmapOffset, m_pFGColor->w, m_pFGColor->h)) - { - if (getpixel(m_pFGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor || - (m_pBGColor && getpixel(m_pBGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor) || - (m_pMaterial && getpixel(m_pMaterial, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaterialAir)) - return true; - } - } -*/ - BITMAP *pBitmap = m_Icon.GetBitmaps8().at(0); - Vector bitmapPos = m_Pos - Vector(pBitmap->w / 2, pBitmap->h / 2); - if (WithinBox(scenePoint, bitmapPos, pBitmap->w, pBitmap->h)) - { - // Scene point on the bitmap - Vector bitmapPoint = scenePoint - bitmapPos; - if (getpixel(pBitmap, bitmapPoint.m_X, bitmapPoint.m_Y) != g_MaskColor) - return true; - } - - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + + bool Deployment::IsOnScenePoint(Vector& scenePoint) const { + if (m_Icon.GetBitmaps8().empty() || !(m_Icon.GetBitmaps8().at(0))) + return false; + // TODO: TAKE CARE OF WRAPPING + /* + // Take care of wrapping situations + bitmapPos = m_Pos + m_BitmapOffset; + Vector aScenePoint[4]; + aScenePoint[0] = scenePoint; + int passes = 1; + + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero()) + { + if (g_SceneMan.SceneWrapsX()) + { + if (bitmapPos.m_X < m_pFGColor->w) + { + aScenePoint[passes] = aScenePoint[0]; + aScenePoint[passes].m_X += g_SceneMan.GetSceneWidth(); + passes++; + } + else if (aScenePoint[0].m_X > pTargetBitmap->w - m_pFGColor->w) + { + aScenePoint[passes] = aScenePoint[0]; + aScenePoint[passes].m_X -= g_SceneMan.GetSceneWidth(); + passes++; + } + } + if (g_SceneMan.SceneWrapsY()) + { + + } + } + + // Check all the passes needed + for (int i = 0; i < passes; ++i) + { + + if (IsWithinBox(aScenePoint[i], m_Pos + m_BitmapOffset, m_pFGColor->w, m_pFGColor->h)) + { + if (getpixel(m_pFGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor || + (m_pBGColor && getpixel(m_pBGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor) || + (m_pMaterial && getpixel(m_pMaterial, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaterialAir)) + return true; + } + } + */ + BITMAP* pBitmap = m_Icon.GetBitmaps8().at(0); + Vector bitmapPos = m_Pos - Vector(pBitmap->w / 2, pBitmap->h / 2); + if (WithinBox(scenePoint, bitmapPos, pBitmap->w, pBitmap->h)) { + // Scene point on the bitmap + Vector bitmapPoint = scenePoint - bitmapPos; + if (getpixel(pBitmap, bitmapPoint.m_X, bitmapPoint.m_Y) != g_MaskColor) + return true; + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Deployment's current graphical representation to a -// BITMAP of choice. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Deployment's current graphical representation to a + // BITMAP of choice. -void Deployment::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const -{ - if (m_Icon.GetBitmaps8().empty() || !(m_Icon.GetBitmaps8().at(0))) - RTEAbort("Deployment's Icon bitmaps are null when drawing!"); + void Deployment::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + if (m_Icon.GetBitmaps8().empty() || !(m_Icon.GetBitmaps8().at(0))) + RTEAbort("Deployment's Icon bitmaps are null when drawing!"); - if (m_apArrowLeftBitmap.empty() || m_apArrowRightBitmap.empty()) - RTEAbort("Deployment's Arrow bitmaps are null when drawing!"); + if (m_apArrowLeftBitmap.empty() || m_apArrowRightBitmap.empty()) + RTEAbort("Deployment's Arrow bitmaps are null when drawing!"); - { - BITMAP *pBitmap = m_Icon.GetBitmaps8().at(0); + { + BITMAP* pBitmap = m_Icon.GetBitmaps8().at(0); - // Take care of wrapping situations - Vector aDrawPos[4]; - aDrawPos[0] = m_Pos - Vector(pBitmap->w / 2, pBitmap->h / 2) - targetPos; - int passes = 1; + // Take care of wrapping situations + Vector aDrawPos[4]; + aDrawPos[0] = m_Pos - Vector(pBitmap->w / 2, pBitmap->h / 2) - targetPos; + int passes = 1; - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero()) - { - if (aDrawPos[0].m_X < pBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += pTargetBitmap->w; - passes++; - } - else if (aDrawPos[0].m_X > pTargetBitmap->w - pBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= pTargetBitmap->w; - passes++; - } - } - // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam - else - { - if (g_SceneMan.SceneWrapsX()) - { - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (targetPos.m_X < 0) - { + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero()) { + if (aDrawPos[0].m_X < pBitmap->w) { aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= sceneWidth; + aDrawPos[passes].m_X += pTargetBitmap->w; passes++; - } - if (targetPos.m_X + pTargetBitmap->w > sceneWidth) - { + } else if (aDrawPos[0].m_X > pTargetBitmap->w - pBitmap->w) { aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += sceneWidth; + aDrawPos[passes].m_X -= pTargetBitmap->w; passes++; } } - } - - // Draw all the passes needed - for (int i = 0; i < passes; ++i) - { - if (mode == g_DrawColor) - { - masked_blit(pBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), pBitmap->w, pBitmap->h); - // Draw the spawn radius circle too - circle(pTargetBitmap, aDrawPos[i].GetFloorIntX() + (pBitmap->w / 2), aDrawPos[i].GetFloorIntY() + (pBitmap->h / 2), m_SpawnRadius, c_GUIColorGray); + // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam + else { + if (g_SceneMan.SceneWrapsX()) { + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (targetPos.m_X < 0) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= sceneWidth; + passes++; + } + if (targetPos.m_X + pTargetBitmap->w > sceneWidth) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += sceneWidth; + passes++; + } + } } - else if (mode == g_DrawTrans) - { - draw_trans_sprite(pTargetBitmap, pBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); - // Draw the spawn radius circle too - circle(pTargetBitmap, aDrawPos[i].GetFloorIntX() + (pBitmap->w / 2), aDrawPos[i].GetFloorIntY() + (pBitmap->h / 2), m_SpawnRadius, c_GUIColorGray); + + // Draw all the passes needed + for (int i = 0; i < passes; ++i) { + if (mode == g_DrawColor) { + masked_blit(pBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), pBitmap->w, pBitmap->h); + // Draw the spawn radius circle too + circle(pTargetBitmap, aDrawPos[i].GetFloorIntX() + (pBitmap->w / 2), aDrawPos[i].GetFloorIntY() + (pBitmap->h / 2), m_SpawnRadius, c_GUIColorGray); + } else if (mode == g_DrawTrans) { + draw_trans_sprite(pTargetBitmap, pBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); + // Draw the spawn radius circle too + circle(pTargetBitmap, aDrawPos[i].GetFloorIntX() + (pBitmap->w / 2), aDrawPos[i].GetFloorIntY() + (pBitmap->h / 2), m_SpawnRadius, c_GUIColorGray); + } } } - } - { - // Draw direction arrow - BITMAP * pBitmap = 0; - Vector offset; - if (m_HFlipped) { - pBitmap = m_apArrowLeftBitmap[0]; - offset = Vector(-14, 0); - } - else { - pBitmap = m_apArrowRightBitmap[0]; - offset = Vector(14, 0); - } + // Draw direction arrow + BITMAP* pBitmap = 0; + Vector offset; + if (m_HFlipped) { + pBitmap = m_apArrowLeftBitmap[0]; + offset = Vector(-14, 0); + } else { + pBitmap = m_apArrowRightBitmap[0]; + offset = Vector(14, 0); + } - // Take care of wrapping situations - Vector aDrawPos[4]; - aDrawPos[0] = m_Pos - Vector(pBitmap->w / 2, pBitmap->h / 2) - targetPos + offset; - int passes = 1; + // Take care of wrapping situations + Vector aDrawPos[4]; + aDrawPos[0] = m_Pos - Vector(pBitmap->w / 2, pBitmap->h / 2) - targetPos + offset; + int passes = 1; - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero()) - { - if (aDrawPos[0].m_X < pBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += pTargetBitmap->w; - passes++; - } - else if (aDrawPos[0].m_X > pTargetBitmap->w - pBitmap->w) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= pTargetBitmap->w; - passes++; - } - } - // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam - else - { - if (g_SceneMan.SceneWrapsX()) - { - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (targetPos.m_X < 0) - { + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero()) { + if (aDrawPos[0].m_X < pBitmap->w) { aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= sceneWidth; + aDrawPos[passes].m_X += pTargetBitmap->w; passes++; - } - if (targetPos.m_X + pTargetBitmap->w > sceneWidth) - { + } else if (aDrawPos[0].m_X > pTargetBitmap->w - pBitmap->w) { aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += sceneWidth; + aDrawPos[passes].m_X -= pTargetBitmap->w; passes++; } } - } - - // Draw all the passes needed - for (int i = 0; i < passes; ++i) - { - if (mode == g_DrawColor) - { - masked_blit(pBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), pBitmap->w, pBitmap->h); + // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam + else { + if (g_SceneMan.SceneWrapsX()) { + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (targetPos.m_X < 0) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= sceneWidth; + passes++; + } + if (targetPos.m_X + pTargetBitmap->w > sceneWidth) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += sceneWidth; + passes++; + } + } } - else if (mode == g_DrawTrans) - { - draw_trans_sprite(pTargetBitmap, pBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); + + // Draw all the passes needed + for (int i = 0; i < passes; ++i) { + if (mode == g_DrawColor) { + masked_blit(pBitmap, pTargetBitmap, 0, 0, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY(), pBitmap->w, pBitmap->h); + } else if (mode == g_DrawTrans) { + draw_trans_sprite(pTargetBitmap, pBitmap, aDrawPos[i].GetFloorIntX(), aDrawPos[i].GetFloorIntY()); + } } } } -} } // namespace RTE diff --git a/Source/Entities/Deployment.h b/Source/Entities/Deployment.h index 4db9f67bf..3919254a1 100644 --- a/Source/Entities/Deployment.h +++ b/Source/Entities/Deployment.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,387 +19,357 @@ #include "SceneMan.h" //#include "MovableMan.h" -namespace RTE -{ - -class ContentFile; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: Deployment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A special SceneObject that specifies a Loadout of whatever Tech is -// relevant to be placed in a specific location in a Scene. -// Parent(s): SceneObject. -// Class history: 02/27/2012 Deployment created. - -class Deployment : public SceneObject { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(Deployment); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: Deployment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a Deployment object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - Deployment() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~Deployment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a Deployment object before deletion -// from system memory. -// Arguments: None. - - ~Deployment() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Deployment object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Deployment object ready for use. -// Arguments: The name of the Loadout that this should invoke at this' position. -// Icon that represents this graphically. -// The radius around this deployment that gets checked if another -// actor/item of the same type and name already exists and will block -// re-spawning a new one by this. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(std::string loadoutName, const Icon &icon, float spawnRadius); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Deployment to be identical to another, by deep copy. -// Arguments: A reference to the Deployment to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const Deployment &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire Deployment, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); SceneObject::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the Deployment object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGraphicalIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a bitmap showing a good identifyable icon of this, for use in -// GUI lists etc. -// Arguments: None. -// Return value: A good identifyable graphical representation of this in a BITMAP, if -// available. If not, 0 is returned. Ownership is NOT TRANSFERRED! - - BITMAP * GetGraphicalIcon() const override { return !m_Icon.GetBitmaps8().empty() ? m_Icon.GetBitmaps8()[0] : nullptr; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLoadoutName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the name of the Loadout that this Deployment spawns. -// Arguments: None. -// Return value: The name of the Loadout preset that this Deployment spawns. - - const std::string & GetLoadoutName() { return m_LoadoutName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGraphicalIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a bitmap showing a good identifyable icon of this. -// Arguments: None. -// Return value: The Icon that represents this graphically. - - Icon GetIcon() { return m_Icon; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpawnRadius -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the radius around this deployment that gets checked if another -// actor/item of the same type and name already exists and will block -// re-spawning a new one by this -// Arguments: None. -// Return value: The radius this Deployment will be checking within. - - float GetSpawnRadius() const { return m_SpawnRadius; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. -// Arguments: The point in absolute scene coordinates. -// Return value: Whether this' graphical rep overlaps the scene point. - - bool IsOnScenePoint(Vector &scenePoint) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the Actor that this Deployment dictates should -// spawn here. Ownership IS transferred!! All items of the Loadout of -// this Deployment will be added to the Actor's inventory as well (and -// also owned by it) -// Arguments: Which in-game player to create the delivery for. -// A float which will be added to with the cost of the stuff returned here. -// Return value: The Actor instance, if any, that this Deployment is supposed to spawn. -// OWNERSHIP IS TRANSFERRED! - - Actor * CreateDeployedActor(int player, float &costTally); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the Actor that this Deployment dictates should -// spawn here. Ownership IS transferred!! All items of the Loadout of -// this Deployment will be added to the Actor's inventory as well (and -// also owned by it) -// Arguments: Which in-game player to create the delivery for. -// Return value: The Actor instance, if any, that this Deployment is supposed to spawn. -// OWNERSHIP IS TRANSFERRED! - - Actor * CreateDeployedActor(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Device that Deployment dictates should -// spawn here. Ownership IS transferred!! Only the first Device is created. -// Arguments: Which in-game player to create the delivery for. -// A float which will be added to with the cost of the stuff returned here. -// Return value: The Actor instance, if any, that this Deployment is supposed to spawn. -// OWNERSHIP IS TRANSFERRED! - - SceneObject * CreateDeployedObject(int player, float &costTally); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateDeployedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Device that Deployment dictates should -// spawn here. Ownership IS transferred!! Only the first Device is created. -// Arguments: Which in-game player to create the delivery for. -// Return value: The Actor instance, if any, that this Deployment is supposed to spawn. -// OWNERSHIP IS TRANSFERRED! - - SceneObject * CreateDeployedObject(); - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DeploymentBlocked -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tests whether the Object this is supposed to spawn/deploy is blocked -// by an already exiting object in the a list being positioned within the -// spawn radius of this. -// Arguments: Which in-game player to create the delivery for. -// A list of SceneObject:s that will be tested against to see if any -// sufficiently similar Object is positioned within the spawn radius of -// this. -// Return value: Whether the deployment spawning is blocked by one of the Objects in -// the list. - - bool DeploymentBlocked(int player, const std::list &existingObjects); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the cost to purchase this item, in oz's of gold. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// Return value: The cost, in oz of gold. - - float GetGoldValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override { return GetTotalValue(nativeModule, foreignMult, nativeMult); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldValueOld -////////////////////////////////////////////////////////////////////////////////////////// -// Description: DOES THE SAME THING AS GetGoldValue, USED ONLY TO PRESERVE LUA COMPATIBILITY - - float GetGoldValueOld(int nativeModule = 0, float foreignMult = 1.0) const override { return GetTotalValue(nativeModule, foreignMult, 1.0); } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of a spawn of this, including -// everything carried by it. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// Return value: The current value of this and all contained assets. - - float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return this deployment's unique ID -// Arguments: None. -// Return value: This deployment's ID - - unsigned int GetID() const { return m_ID; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CloneID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clones id from the specified deployment -// Arguments: Deployment to clone Id from. -// Return value: None - - void CloneID(Deployment * from) { if (from) m_ID = from->GetID(); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NewID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Generates new random ID for this deployment. -// Arguments: None. -// Return value: None. - - void NewID() { m_ID = RandomNum(1, 0xFFFF); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Deployment's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// like indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsHFlipped -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether this MOSprite is being drawn flipped horizontally -// (along the vertical axis), or not. -// Arguments: None. -// Return value: Whether flipped or not. - - bool IsHFlipped() const override { return m_HFlipped; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: SetHFlipped -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this should be drawn flipped horizontally (around the -// vertical axis). -// Arguments: A bool with the new value. -// Return value: None. - - void SetHFlipped(const bool flipped) override { m_HFlipped = flipped; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - - // Name of the Loadout that shuold be placed at this' location in the Scene. - std::string m_LoadoutName; - // The Icon that graphically represents this - Icon m_Icon; - // The radius around this deployment that gets checked if another actor/item of the same type and name already exists and will block re-spawning a new one by this - float m_SpawnRadius; - // The radius around this deployment that gets checked if an actor spawned by this deployment is present. If it is, deployment is blocked. - float m_WalkRadius; - // Unique deployment id, assigned to units deployed by this deployment - unsigned int m_ID; - // Whether the deployment and it's loadout is flipped - bool m_HFlipped; - // Shared HFlipped arrow bitmaps - static std::vector m_apArrowLeftBitmap; - static std::vector m_apArrowRightBitmap; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Deployment, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - Deployment(const Deployment &reference) = delete; - void operator=(const Deployment &rhs) = delete; - -}; +namespace RTE { + + class ContentFile; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: Deployment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A special SceneObject that specifies a Loadout of whatever Tech is + // relevant to be placed in a specific location in a Scene. + // Parent(s): SceneObject. + // Class history: 02/27/2012 Deployment created. + + class Deployment : public SceneObject { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(Deployment); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Deployment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Deployment object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Deployment() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~Deployment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a Deployment object before deletion + // from system memory. + // Arguments: None. + + ~Deployment() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Deployment object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Deployment object ready for use. + // Arguments: The name of the Loadout that this should invoke at this' position. + // Icon that represents this graphically. + // The radius around this deployment that gets checked if another + // actor/item of the same type and name already exists and will block + // re-spawning a new one by this. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(std::string loadoutName, const Icon& icon, float spawnRadius); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Deployment to be identical to another, by deep copy. + // Arguments: A reference to the Deployment to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Deployment& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Deployment, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + SceneObject::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the Deployment object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGraphicalIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a bitmap showing a good identifyable icon of this, for use in + // GUI lists etc. + // Arguments: None. + // Return value: A good identifyable graphical representation of this in a BITMAP, if + // available. If not, 0 is returned. Ownership is NOT TRANSFERRED! + + BITMAP* GetGraphicalIcon() const override { return !m_Icon.GetBitmaps8().empty() ? m_Icon.GetBitmaps8()[0] : nullptr; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLoadoutName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of the Loadout that this Deployment spawns. + // Arguments: None. + // Return value: The name of the Loadout preset that this Deployment spawns. + + const std::string& GetLoadoutName() { return m_LoadoutName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGraphicalIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a bitmap showing a good identifyable icon of this. + // Arguments: None. + // Return value: The Icon that represents this graphically. + + Icon GetIcon() { return m_Icon; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpawnRadius + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the radius around this deployment that gets checked if another + // actor/item of the same type and name already exists and will block + // re-spawning a new one by this + // Arguments: None. + // Return value: The radius this Deployment will be checking within. + + float GetSpawnRadius() const { return m_SpawnRadius; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + // Arguments: The point in absolute scene coordinates. + // Return value: Whether this' graphical rep overlaps the scene point. + + bool IsOnScenePoint(Vector& scenePoint) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the Actor that this Deployment dictates should + // spawn here. Ownership IS transferred!! All items of the Loadout of + // this Deployment will be added to the Actor's inventory as well (and + // also owned by it) + // Arguments: Which in-game player to create the delivery for. + // A float which will be added to with the cost of the stuff returned here. + // Return value: The Actor instance, if any, that this Deployment is supposed to spawn. + // OWNERSHIP IS TRANSFERRED! + + Actor* CreateDeployedActor(int player, float& costTally); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the Actor that this Deployment dictates should + // spawn here. Ownership IS transferred!! All items of the Loadout of + // this Deployment will be added to the Actor's inventory as well (and + // also owned by it) + // Arguments: Which in-game player to create the delivery for. + // Return value: The Actor instance, if any, that this Deployment is supposed to spawn. + // OWNERSHIP IS TRANSFERRED! + + Actor* CreateDeployedActor(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Device that Deployment dictates should + // spawn here. Ownership IS transferred!! Only the first Device is created. + // Arguments: Which in-game player to create the delivery for. + // A float which will be added to with the cost of the stuff returned here. + // Return value: The Actor instance, if any, that this Deployment is supposed to spawn. + // OWNERSHIP IS TRANSFERRED! + + SceneObject* CreateDeployedObject(int player, float& costTally); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateDeployedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Device that Deployment dictates should + // spawn here. Ownership IS transferred!! Only the first Device is created. + // Arguments: Which in-game player to create the delivery for. + // Return value: The Actor instance, if any, that this Deployment is supposed to spawn. + // OWNERSHIP IS TRANSFERRED! + + SceneObject* CreateDeployedObject(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DeploymentBlocked + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tests whether the Object this is supposed to spawn/deploy is blocked + // by an already exiting object in the a list being positioned within the + // spawn radius of this. + // Arguments: Which in-game player to create the delivery for. + // A list of SceneObject:s that will be tested against to see if any + // sufficiently similar Object is positioned within the spawn radius of + // this. + // Return value: Whether the deployment spawning is blocked by one of the Objects in + // the list. + + bool DeploymentBlocked(int player, const std::list& existingObjects); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the cost to purchase this item, in oz's of gold. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // Return value: The cost, in oz of gold. + + float GetGoldValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override { return GetTotalValue(nativeModule, foreignMult, nativeMult); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldValueOld + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: DOES THE SAME THING AS GetGoldValue, USED ONLY TO PRESERVE LUA COMPATIBILITY + + float GetGoldValueOld(int nativeModule = 0, float foreignMult = 1.0) const override { return GetTotalValue(nativeModule, foreignMult, 1.0); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of a spawn of this, including + // everything carried by it. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // Return value: The current value of this and all contained assets. + + float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return this deployment's unique ID + // Arguments: None. + // Return value: This deployment's ID + + unsigned int GetID() const { return m_ID; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CloneID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clones id from the specified deployment + // Arguments: Deployment to clone Id from. + // Return value: None + + void CloneID(Deployment* from) { + if (from) + m_ID = from->GetID(); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NewID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Generates new random ID for this deployment. + // Arguments: None. + // Return value: None. + + void NewID() { m_ID = RandomNum(1, 0xFFFF); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Deployment's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // like indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsHFlipped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether this MOSprite is being drawn flipped horizontally + // (along the vertical axis), or not. + // Arguments: None. + // Return value: Whether flipped or not. + + bool IsHFlipped() const override { return m_HFlipped; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: SetHFlipped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this should be drawn flipped horizontally (around the + // vertical axis). + // Arguments: A bool with the new value. + // Return value: None. + + void SetHFlipped(const bool flipped) override { m_HFlipped = flipped; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + + // Name of the Loadout that shuold be placed at this' location in the Scene. + std::string m_LoadoutName; + // The Icon that graphically represents this + Icon m_Icon; + // The radius around this deployment that gets checked if another actor/item of the same type and name already exists and will block re-spawning a new one by this + float m_SpawnRadius; + // The radius around this deployment that gets checked if an actor spawned by this deployment is present. If it is, deployment is blocked. + float m_WalkRadius; + // Unique deployment id, assigned to units deployed by this deployment + unsigned int m_ID; + // Whether the deployment and it's loadout is flipped + bool m_HFlipped; + // Shared HFlipped arrow bitmaps + static std::vector m_apArrowLeftBitmap; + static std::vector m_apArrowRightBitmap; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Deployment, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + Deployment(const Deployment& reference) = delete; + void operator=(const Deployment& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/Emission.cpp b/Source/Entities/Emission.cpp index 76634abf9..724bef4fe 100644 --- a/Source/Entities/Emission.cpp +++ b/Source/Entities/Emission.cpp @@ -7,165 +7,157 @@ // data@datarealms.com // http://www.datarealms.com - #include "Emission.h" #include "PresetMan.h" namespace RTE { - -//const string Emission::m_sClassName = "Emission"; - -ConcreteClassInfo(Emission, Entity, 100); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Emission, effectively -// resetting the members of this abstraction level only. - -void Emission::Clear() -{ - m_pEmission = 0; - m_PPM = 0; - m_BurstSize = 0; - m_Accumulator = 0; - m_Spread = 0; - m_MinVelocity = 0; - m_MaxVelocity = 0; - m_LifeVariation = 0.1; - m_PushesEmitter = true; - m_InheritsVel = 0; - m_StartTimer.SetSimTimeLimitMS(0); - m_StartTimer.Reset(); - m_StopTimer.SetSimTimeLimitMS(1000000); - m_StopTimer.Reset(); - m_Offset.Reset(); -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Emission object ready for use. - -int AEmitter::Emission::Create() -{ -if (Serializable::Create() < 0) -return -1; - -return 0; -} -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Emission to be identical to another, by deep copy. - -int Emission::Create(const Emission &reference) -{ - m_pEmission = reference.m_pEmission; - m_PPM = reference.m_PPM; - m_BurstSize = reference.m_BurstSize; - m_Accumulator = reference.m_Accumulator; - m_Spread = reference.m_Spread; - m_MinVelocity = reference.m_MinVelocity; - m_MaxVelocity = reference.m_MaxVelocity; - m_LifeVariation = reference.m_LifeVariation; - m_PushesEmitter = reference.m_PushesEmitter; - m_InheritsVel = reference.m_InheritsVel; - m_StartTimer = reference.m_StartTimer; - m_StopTimer = reference.m_StopTimer; - m_Offset = reference.m_Offset; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int Emission::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Serializable::ReadProperty(propName, reader)); - - MatchProperty("EmittedParticle", - { - m_pEmission = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); - RTEAssert(m_pEmission, "Stream suggests allocating an unallocatable type in AEmitter::Emission::Create!"); - }); - MatchProperty("ParticlesPerMinute", { reader >> m_PPM; }); - MatchProperty("BurstSize", { reader >> m_BurstSize; }); - MatchProperty("Spread", { reader >> m_Spread; }); - MatchProperty("MinVelocity", { reader >> m_MinVelocity; }); - MatchProperty("MaxVelocity", { reader >> m_MaxVelocity; }); - MatchProperty("LifeVariation", { reader >> m_LifeVariation; }); - MatchProperty("PushesEmitter", { reader >> m_PushesEmitter; }); - MatchProperty("Offset", { reader >> m_Offset; }); - MatchProperty("InheritsVel", - { - reader >> m_InheritsVel; - Clamp(m_InheritsVel, 1, 0); - }); - MatchProperty("StartTimeMS", + // const string Emission::m_sClassName = "Emission"; + + ConcreteClassInfo(Emission, Entity, 100); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Emission, effectively + // resetting the members of this abstraction level only. + + void Emission::Clear() { + m_pEmission = 0; + m_PPM = 0; + m_BurstSize = 0; + m_Accumulator = 0; + m_Spread = 0; + m_MinVelocity = 0; + m_MaxVelocity = 0; + m_LifeVariation = 0.1; + m_PushesEmitter = true; + m_InheritsVel = 0; + m_StartTimer.SetSimTimeLimitMS(0); + m_StartTimer.Reset(); + m_StopTimer.SetSimTimeLimitMS(1000000); + m_StopTimer.Reset(); + m_Offset.Reset(); + } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Emission object ready for use. + + int AEmitter::Emission::Create() { - double startTime; - reader >> startTime; - m_StartTimer.SetSimTimeLimitMS(startTime); - }); - MatchProperty("StopTimeMS", - { - double stopTime; - reader >> stopTime; - m_StopTimer.SetSimTimeLimitMS(stopTime); - }); - - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Emission with a Writer for -// later recreation with Create(Reader &reader); - -int Emission::Save(Writer &writer) const -{ - Serializable::Save(writer); - - writer.NewProperty("EmittedParticle"); - writer << m_pEmission; - writer.NewProperty("ParticlesPerMinute"); - writer << m_PPM; - writer.NewProperty("BurstSize"); - writer << m_BurstSize; - writer.NewProperty("Spread"); - writer << m_Spread; - writer.NewProperty("MinVelocity"); - writer << m_MinVelocity; - writer.NewProperty("MaxVelocity"); - writer << m_MaxVelocity; - writer.NewProperty("LifeVariation"); - writer << m_LifeVariation; - writer.NewProperty("PushesEmitter"); - writer << m_PushesEmitter; - writer.NewProperty("InheritsVel"); - writer << m_InheritsVel; - writer.NewProperty("Offset"); - writer << m_Offset; - writer.NewProperty("StartTimeMS"); - writer << m_StartTimer.GetSimTimeLimitMS(); - writer.NewProperty("StopTimeMS"); - writer << m_StopTimer.GetSimTimeLimitMS(); + if (Serializable::Create() < 0) + return -1; return 0; -} - -} \ No newline at end of file + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Emission to be identical to another, by deep copy. + + int Emission::Create(const Emission& reference) { + m_pEmission = reference.m_pEmission; + m_PPM = reference.m_PPM; + m_BurstSize = reference.m_BurstSize; + m_Accumulator = reference.m_Accumulator; + m_Spread = reference.m_Spread; + m_MinVelocity = reference.m_MinVelocity; + m_MaxVelocity = reference.m_MaxVelocity; + m_LifeVariation = reference.m_LifeVariation; + m_PushesEmitter = reference.m_PushesEmitter; + m_InheritsVel = reference.m_InheritsVel; + m_StartTimer = reference.m_StartTimer; + m_StopTimer = reference.m_StopTimer; + m_Offset = reference.m_Offset; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int Emission::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Serializable::ReadProperty(propName, reader)); + + MatchProperty("EmittedParticle", + { + m_pEmission = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); + RTEAssert(m_pEmission, "Stream suggests allocating an unallocatable type in AEmitter::Emission::Create!"); + }); + MatchProperty("ParticlesPerMinute", { reader >> m_PPM; }); + MatchProperty("BurstSize", { reader >> m_BurstSize; }); + MatchProperty("Spread", { reader >> m_Spread; }); + MatchProperty("MinVelocity", { reader >> m_MinVelocity; }); + MatchProperty("MaxVelocity", { reader >> m_MaxVelocity; }); + MatchProperty("LifeVariation", { reader >> m_LifeVariation; }); + MatchProperty("PushesEmitter", { reader >> m_PushesEmitter; }); + MatchProperty("Offset", { reader >> m_Offset; }); + MatchProperty("InheritsVel", + { + reader >> m_InheritsVel; + Clamp(m_InheritsVel, 1, 0); + }); + MatchProperty("StartTimeMS", + { + double startTime; + reader >> startTime; + m_StartTimer.SetSimTimeLimitMS(startTime); + }); + MatchProperty("StopTimeMS", + { + double stopTime; + reader >> stopTime; + m_StopTimer.SetSimTimeLimitMS(stopTime); + }); + + EndPropertyList; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Emission with a Writer for + // later recreation with Create(Reader &reader); + + int Emission::Save(Writer& writer) const { + Serializable::Save(writer); + + writer.NewProperty("EmittedParticle"); + writer << m_pEmission; + writer.NewProperty("ParticlesPerMinute"); + writer << m_PPM; + writer.NewProperty("BurstSize"); + writer << m_BurstSize; + writer.NewProperty("Spread"); + writer << m_Spread; + writer.NewProperty("MinVelocity"); + writer << m_MinVelocity; + writer.NewProperty("MaxVelocity"); + writer << m_MaxVelocity; + writer.NewProperty("LifeVariation"); + writer << m_LifeVariation; + writer.NewProperty("PushesEmitter"); + writer << m_PushesEmitter; + writer.NewProperty("InheritsVel"); + writer << m_InheritsVel; + writer.NewProperty("Offset"); + writer << m_Offset; + writer.NewProperty("StartTimeMS"); + writer << m_StartTimer.GetSimTimeLimitMS(); + writer.NewProperty("StopTimeMS"); + writer << m_StopTimer.GetSimTimeLimitMS(); + + return 0; + } + +} // namespace RTE diff --git a/Source/Entities/Emission.h b/Source/Entities/Emission.h index 7fa25a361..52bc01f3c 100644 --- a/Source/Entities/Emission.h +++ b/Source/Entities/Emission.h @@ -12,326 +12,302 @@ #include "Serializable.h" #include "MovableObject.h" -namespace RTE -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: Emission -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Something to bundle the properties of an emission together. -// Parent(s): Entity. - -class Emission : public Entity { - friend class AEmitter; - friend class PEmitter; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Public member variable, method and friend function declarations - -public: - - // Concrete allocation and cloning definitions - EntityAllocation(Emission); - SerializableOverrideMethods; - ClassInfoGetters; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Constructor: Emission - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Constructor method used to instantiate a Emission object in system - // memory. Create() should be called before using the object. - // Arguments: None. - - Emission() { Clear(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Creates a Emission to be identical to another, by deep copy. - // Arguments: A reference to the Emission to deep copy. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create(const Emission &reference); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Reset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Resets the entire Serializable, including its inherited members, to their - // default settings or values. - // Arguments: None. - // Return value: None. - - void Reset() override { Clear(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetEmissionParticlePreset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the reference particle to be emitted. Owenership is NOT transferred! - // Arguments: None. - // Return value: A pointer to the particle to be emitted. Not transferred! - - const MovableObject * GetEmissionParticlePreset() { return m_pEmission; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetRate - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the rate at which these emissions are made, in particles per minute. - // Arguments: None. - // Return value: The emission rate in PPM. - - float GetRate() const { return m_PPM; } - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetRate - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the rate at which these emissions are made, in particles per minute. - // Arguments: The emission rate in PPM. - // Return value: None. - - void SetRate(float newPPM) { m_PPM = newPPM; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetBurstSize - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the number of extra particles that are bursted at the beginning of - // emission. - // Arguments: None. - // Return value: The burst size. - - int GetBurstSize() const { return m_BurstSize; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetBurstSize - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the number of extra particles that are bursted at the beginning of - // emission. - // Arguments: The burst size. - // Return value: None. - - void SetBurstSize(int newSize) { m_BurstSize = newSize; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetSpread - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the angle spread of velocity of the emitted MO's to each side of - // the m_EmitAngle angle. in radians. PI/2 would mean that MO's fly out to - // one side only, with the m_Rotation defining the middle of that half circle. - // Arguments: None. - // Return value: The emission spread in radians. - - float GetSpread() const { return m_Spread; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetSpread - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the angle spread of velocity of the emitted MO's to each side of - // the m_EmitAngle angle. in radians. PI/2 would mean that MO's fly out to - // one side only, with the m_Rotation defining the middle of that half circle. - // Arguments: The emission spread in radians. - // Return value: None. - - void SetSpread(float newSpread) { m_Spread = newSpread; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetMinVelocity - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the specified minimum velocity an emitted MO can have when emitted. - // Arguments: None. - // Return value: The min emission velocity in m/s. - - float GetMinVelocity() const { return m_MinVelocity; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetMinVelocity - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the specified minimum velocity an emitted MO can have when emitted. - // Arguments: The min emission velocity in m/s. - // Return value: None. - - void SetMinVelocity(float newVel) { m_MinVelocity = newVel; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetMaxVelocity - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the specified maximum velocity an emitted MO can have when emitted. - // Arguments: None. - // Return value: The max emission velocity in m/s. - - float GetMaxVelocity() const { return m_MaxVelocity; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetMaxVelocity - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the specified maximum velocity an emitted MO can have when emitted. - // Arguments: The max emission velocity in m/s. - // Return value: None. - - void SetMaxVelocity(float newVel) { m_MaxVelocity = newVel; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetLifeVariation - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the specified variation in lifetime of the emitted particles. - // Arguments: None. - // Return value: The life variation rationally expressed.. 0.1 = up to 10% varitaion. - - float GetLifeVariation() const { return m_LifeVariation; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetLifeVariation - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the specified variation in lifetime of the emitted particles. - // Arguments: The life variation rationally expressed.. 0.1 = up to 10% varitaion. - // Return value: None. - - void SetLifeVariation(float newVariation) { m_LifeVariation = newVariation; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: PushesEmitter - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Indicates whether this emission is supposed to push its emitter back - // because of recoil. - // Arguments: None. - // Return value: Whether recoil pushing is enabled or not for this emitter. - - bool PushesEmitter() const { return m_PushesEmitter; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetPushesEmitter - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets whether this emission is supposed to push its emitter back - // because of recoil. - // Arguments: Whether recoil pushing is enabled or not for this emitter. - // Return value: None. - - void SetPushesEmitter(bool newValue) { m_PushesEmitter = newValue; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: IsEmissionTime - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Shows whether this should be emitting now or not, based on what its - // start and end timers are set to. - // Arguments: None. - // Return value: Whether this should be emitting right now. - - bool IsEmissionTime() { return m_StartTimer.IsPastSimTimeLimit() && !m_StopTimer.IsPastSimTimeLimit(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: ResetEmissionTimers - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Resets the emission timers so they start counting time as to wheter - // emissions are clearer. - // Arguments: None. - // Return value: None. - - void ResetEmissionTimers() { m_StartTimer.Reset(); m_StopTimer.Reset(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: InheritsVelocity - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: How much of the root parent's velocity this emission inherit - // Arguments: None. - // Return value: The proportion of the velocity inherited. 0.1 = 10% inheritance. - - float InheritsVelocity() { return m_InheritsVel; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetOffset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets offset of the emission point from Emitter's sprite center, which gets rotated with owner Emitter - // Arguments: None. - // Return value: Returns emission offset. - - Vector GetOffset() const { return m_Offset; } - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetOffset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets offset of the emission point from Emitter's sprite center, which gets rotated with owner Emitter - // Arguments: New offset value. - // Return value: None. - - void SetOffset(Vector offset) { m_Offset = offset; } - - ////////////////////////////////////////////////////////////////////////////////////////// - // Protected member variable and method declarations - -protected: - - // Member variables - //static const std::string m_sClassName; - // Member variables - static Entity::ClassInfo m_sClass; - - // The pointer to the preset instance, that copies of which will be emitted - const MovableObject *m_pEmission; - // Emission rate in Particles Per Minute - float m_PPM; - // The number of particles in the first initial burst of emissions - // that this AEmitter will generate upon emitting. 0 means none (duh). - int m_BurstSize; - // The accumulator for decoupling emission rate from the physics update rate. - double m_Accumulator; - // The angle spread of velocity of the emitted MO's to each - // side of the m_EmitAngle angle. in radians. - // PI/2 would mean that MO's fly out to one side only, with the - // m_Rotation defining the middle of that half circle. - float m_Spread; - // The minimum velocity an emitted MO can have when emitted - float m_MinVelocity; - // The maximum velocity an emitted MO can have when emitted - float m_MaxVelocity; - // The variation in life time of each emitted aprticle, in percentage of the existing life time of the partilcle - float m_LifeVariation; - // Whether these emissions push the emitter around with recoil or not. - bool m_PushesEmitter; - // How much of the parents velocity this emission inherits - float m_InheritsVel; - // Timers for measuring when to start and stop this emission the actual times are the set time limits of these - Timer m_StartTimer; - Timer m_StopTimer; - // Offset of the emission point from Emitter's sprite center, which gets rotated with owner Emitter - Vector m_Offset; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Private member variable and method declarations - -private: - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Clear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Clears all the member variables of this Emission, effectively - // resetting the members of this abstraction level only. - // Arguments: None. - // Return value: None. - - void Clear(); - -}; +namespace RTE { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: Emission + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Something to bundle the properties of an emission together. + // Parent(s): Entity. + + class Emission : public Entity { + friend class AEmitter; + friend class PEmitter; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(Emission); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Emission + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Emission object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Emission() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Emission to be identical to another, by deep copy. + // Arguments: A reference to the Emission to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Emission& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Serializable, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmissionParticlePreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the reference particle to be emitted. Owenership is NOT transferred! + // Arguments: None. + // Return value: A pointer to the particle to be emitted. Not transferred! + + const MovableObject* GetEmissionParticlePreset() { return m_pEmission; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rate at which these emissions are made, in particles per minute. + // Arguments: None. + // Return value: The emission rate in PPM. + + float GetRate() const { return m_PPM; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the rate at which these emissions are made, in particles per minute. + // Arguments: The emission rate in PPM. + // Return value: None. + + void SetRate(float newPPM) { m_PPM = newPPM; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBurstSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of extra particles that are bursted at the beginning of + // emission. + // Arguments: None. + // Return value: The burst size. + + int GetBurstSize() const { return m_BurstSize; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the number of extra particles that are bursted at the beginning of + // emission. + // Arguments: The burst size. + // Return value: None. + + void SetBurstSize(int newSize) { m_BurstSize = newSize; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpread + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the angle spread of velocity of the emitted MO's to each side of + // the m_EmitAngle angle. in radians. PI/2 would mean that MO's fly out to + // one side only, with the m_Rotation defining the middle of that half circle. + // Arguments: None. + // Return value: The emission spread in radians. + + float GetSpread() const { return m_Spread; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSpread + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the angle spread of velocity of the emitted MO's to each side of + // the m_EmitAngle angle. in radians. PI/2 would mean that MO's fly out to + // one side only, with the m_Rotation defining the middle of that half circle. + // Arguments: The emission spread in radians. + // Return value: None. + + void SetSpread(float newSpread) { m_Spread = newSpread; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMinVelocity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the specified minimum velocity an emitted MO can have when emitted. + // Arguments: None. + // Return value: The min emission velocity in m/s. + + float GetMinVelocity() const { return m_MinVelocity; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMinVelocity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the specified minimum velocity an emitted MO can have when emitted. + // Arguments: The min emission velocity in m/s. + // Return value: None. + + void SetMinVelocity(float newVel) { m_MinVelocity = newVel; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaxVelocity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the specified maximum velocity an emitted MO can have when emitted. + // Arguments: None. + // Return value: The max emission velocity in m/s. + + float GetMaxVelocity() const { return m_MaxVelocity; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMaxVelocity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the specified maximum velocity an emitted MO can have when emitted. + // Arguments: The max emission velocity in m/s. + // Return value: None. + + void SetMaxVelocity(float newVel) { m_MaxVelocity = newVel; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLifeVariation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the specified variation in lifetime of the emitted particles. + // Arguments: None. + // Return value: The life variation rationally expressed.. 0.1 = up to 10% varitaion. + + float GetLifeVariation() const { return m_LifeVariation; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLifeVariation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the specified variation in lifetime of the emitted particles. + // Arguments: The life variation rationally expressed.. 0.1 = up to 10% varitaion. + // Return value: None. + + void SetLifeVariation(float newVariation) { m_LifeVariation = newVariation; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PushesEmitter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this emission is supposed to push its emitter back + // because of recoil. + // Arguments: None. + // Return value: Whether recoil pushing is enabled or not for this emitter. + + bool PushesEmitter() const { return m_PushesEmitter; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPushesEmitter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this emission is supposed to push its emitter back + // because of recoil. + // Arguments: Whether recoil pushing is enabled or not for this emitter. + // Return value: None. + + void SetPushesEmitter(bool newValue) { m_PushesEmitter = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEmissionTime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this should be emitting now or not, based on what its + // start and end timers are set to. + // Arguments: None. + // Return value: Whether this should be emitting right now. + + bool IsEmissionTime() { return m_StartTimer.IsPastSimTimeLimit() && !m_StopTimer.IsPastSimTimeLimit(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResetEmissionTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the emission timers so they start counting time as to wheter + // emissions are clearer. + // Arguments: None. + // Return value: None. + + void ResetEmissionTimers() { + m_StartTimer.Reset(); + m_StopTimer.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: InheritsVelocity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: How much of the root parent's velocity this emission inherit + // Arguments: None. + // Return value: The proportion of the velocity inherited. 0.1 = 10% inheritance. + + float InheritsVelocity() { return m_InheritsVel; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets offset of the emission point from Emitter's sprite center, which gets rotated with owner Emitter + // Arguments: None. + // Return value: Returns emission offset. + + Vector GetOffset() const { return m_Offset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets offset of the emission point from Emitter's sprite center, which gets rotated with owner Emitter + // Arguments: New offset value. + // Return value: None. + + void SetOffset(Vector offset) { m_Offset = offset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + // static const std::string m_sClassName; + // Member variables + static Entity::ClassInfo m_sClass; + + // The pointer to the preset instance, that copies of which will be emitted + const MovableObject* m_pEmission; + // Emission rate in Particles Per Minute + float m_PPM; + // The number of particles in the first initial burst of emissions + // that this AEmitter will generate upon emitting. 0 means none (duh). + int m_BurstSize; + // The accumulator for decoupling emission rate from the physics update rate. + double m_Accumulator; + // The angle spread of velocity of the emitted MO's to each + // side of the m_EmitAngle angle. in radians. + // PI/2 would mean that MO's fly out to one side only, with the + // m_Rotation defining the middle of that half circle. + float m_Spread; + // The minimum velocity an emitted MO can have when emitted + float m_MinVelocity; + // The maximum velocity an emitted MO can have when emitted + float m_MaxVelocity; + // The variation in life time of each emitted aprticle, in percentage of the existing life time of the partilcle + float m_LifeVariation; + // Whether these emissions push the emitter around with recoil or not. + bool m_PushesEmitter; + // How much of the parents velocity this emission inherits + float m_InheritsVel; + // Timers for measuring when to start and stop this emission the actual times are the set time limits of these + Timer m_StartTimer; + Timer m_StopTimer; + // Offset of the emission point from Emitter's sprite center, which gets rotated with owner Emitter + Vector m_Offset; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Emission, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif \ No newline at end of file +#endif diff --git a/Source/Entities/Gib.cpp b/Source/Entities/Gib.cpp index 0b53ff151..c13697678 100644 --- a/Source/Entities/Gib.cpp +++ b/Source/Entities/Gib.cpp @@ -6,7 +6,7 @@ namespace RTE { const std::string Gib::c_ClassName = "Gib"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Gib::Clear() { m_GibParticle = nullptr; @@ -21,9 +21,9 @@ namespace RTE { m_SpreadMode = SpreadMode::SpreadRandom; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Gib::Create(const Gib &reference) { + int Gib::Create(const Gib& reference) { m_GibParticle = reference.m_GibParticle; m_Offset = reference.m_Offset; m_Count = reference.m_Count; @@ -38,13 +38,13 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Gib::ReadProperty(const std::string_view &propName, Reader &reader) { + int Gib::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("GibParticle", { - m_GibParticle = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); + m_GibParticle = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); RTEAssert(m_GibParticle, "Stream suggests allocating an unallocable type in Gib::Create!"); }); MatchProperty("Offset", { reader >> m_Offset; }); @@ -60,9 +60,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Gib::Save(Writer &writer) const { + int Gib::Save(Writer& writer) const { Serializable::Save(writer); writer.NewProperty("GibParticle"); @@ -93,4 +93,4 @@ namespace RTE { return 0; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/Gib.h b/Source/Entities/Gib.h index 23ddf10f2..505147923 100644 --- a/Source/Entities/Gib.h +++ b/Source/Entities/Gib.h @@ -15,14 +15,17 @@ namespace RTE { friend struct EntityLuaBindings; public: - SerializableClassNameGetter; SerializableOverrideMethods; /// /// Different types of logic for the Gib to use when applying velocity to its GibParticles. /// - enum SpreadMode { SpreadRandom, SpreadEven, SpreadSpiral }; + enum SpreadMode { + SpreadRandom, + SpreadEven, + SpreadSpiral + }; #pragma region Creation /// @@ -35,7 +38,7 @@ namespace RTE { /// /// A reference to the Gib to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Gib &reference); + int Create(const Gib& reference); #pragma endregion #pragma region Destruction @@ -55,13 +58,13 @@ namespace RTE { /// Gets the reference particle to be used as a Gib. Ownership is NOT transferred! /// /// A pointer to the particle to be used as a Gib. - const MovableObject * GetParticlePreset() const { return m_GibParticle; } + const MovableObject* GetParticlePreset() const { return m_GibParticle; } /// /// Sets the reference particle to be used as a Gib. Ownership is NOT transferred! /// /// A pointer to the new particle to be used as a Gib. - void SetParticlePreset(const MovableObject *newParticlePreset) { m_GibParticle = newParticlePreset; } + void SetParticlePreset(const MovableObject* newParticlePreset) { m_GibParticle = newParticlePreset; } /// /// Gets the spawn offset of this Gib from the parent's position. @@ -138,8 +141,7 @@ namespace RTE { #pragma endregion protected: - - const MovableObject *m_GibParticle; //!< The pointer to the preset instance that copies of will be created as this Gib. Not Owned. + const MovableObject* m_GibParticle; //!< The pointer to the preset instance that copies of will be created as this Gib. Not Owned. Vector m_Offset; //!< Offset spawn position from owner/parent's position. unsigned int m_Count; //!< The number of copies of the GibParticle that will be spawned. float m_Spread; //!< The angle spread of the spawned GibParticle objects to each side of the parent's angle in radians. @@ -151,7 +153,6 @@ namespace RTE { SpreadMode m_SpreadMode; //!< Determines what kind of logic is used when applying velocity to the GibParticle objects. private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. /// @@ -159,5 +160,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/GlobalScript.cpp b/Source/Entities/GlobalScript.cpp index ce18158f3..d2c9175ea 100644 --- a/Source/Entities/GlobalScript.cpp +++ b/Source/Entities/GlobalScript.cpp @@ -14,7 +14,7 @@ namespace RTE { ConcreteClassInfo(GlobalScript, Entity, 10); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GlobalScript::Clear() { m_ScriptPath.clear(); @@ -25,9 +25,9 @@ namespace RTE { m_PieSlicesToAdd.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GlobalScript::Create(const GlobalScript &reference) { + int GlobalScript::Create(const GlobalScript& reference) { Entity::Create(reference); m_ScriptPath = reference.m_ScriptPath; @@ -36,43 +36,43 @@ namespace RTE { m_HasStarted = reference.m_HasStarted; m_LateUpdate = reference.m_LateUpdate; - for (const std::unique_ptr &referencePieSliceToAdd : reference.m_PieSlicesToAdd) { - m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(referencePieSliceToAdd->Clone()))); + for (const std::unique_ptr& referencePieSliceToAdd: reference.m_PieSlicesToAdd) { + m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(referencePieSliceToAdd->Clone()))); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GlobalScript::ReadProperty(const std::string_view &propName, Reader &reader) { + int GlobalScript::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("ScriptPath", { m_ScriptPath = CorrectBackslashesInPath(reader.ReadPropValue()); }); MatchProperty("LuaClassName", { reader >> m_LuaClassName; }); MatchProperty("LateUpdate", { reader >> m_LateUpdate; }); - MatchProperty("AddPieSlice", { m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)))); }); + MatchProperty("AddPieSlice", { m_PieSlicesToAdd.emplace_back(std::unique_ptr(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)))); }); EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GlobalScript::Save(Writer &writer) const { + int GlobalScript::Save(Writer& writer) const { Entity::Save(writer); writer.NewPropertyWithValue("ScriptPath", m_ScriptPath); writer.NewPropertyWithValue("LuaClassName", m_LuaClassName); writer.NewPropertyWithValue("LateUpdate", m_LateUpdate); - for (const std::unique_ptr &pieSliceToAdd : m_PieSlicesToAdd) { + for (const std::unique_ptr& pieSliceToAdd: m_PieSlicesToAdd) { writer.NewPropertyWithValue("AddPieSlice", pieSliceToAdd.get()); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const std::vector>& GlobalScript::GetPieSlicesToAdd() const { static const std::vector> emptyVector; @@ -83,7 +83,7 @@ namespace RTE { return m_PieSlicesToAdd; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int GlobalScript::ReloadScripts() { int error = 0; @@ -93,13 +93,15 @@ namespace RTE { g_LuaMan.GetMasterScriptState().SetTempEntity(this); error = g_LuaMan.GetMasterScriptState().RunScriptString(m_LuaClassName + " = ToGlobalScript(LuaMan.TempEntity);"); } - if (error == 0) { g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath); } + if (error == 0) { + g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath); + } } return error; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int GlobalScript::Start() { if (!g_SettingsMan.IsGlobalScriptEnabled(GetModuleAndPresetName())) { @@ -111,16 +113,16 @@ namespace RTE { } int error = ReloadScripts(); - if (error == 0) { + if (error == 0) { error = g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".StartScript then " + m_LuaClassName + ":StartScript(); end"); - m_HasStarted = true; + m_HasStarted = true; } m_IsActive = error == 0; return error; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int GlobalScript::Pause(bool pause) const { if (!m_IsActive || !m_HasStarted || !g_SettingsMan.IsGlobalScriptEnabled(GetModuleAndPresetName())) { @@ -130,7 +132,7 @@ namespace RTE { return g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".PauseScript then " + m_LuaClassName + ":PauseScript(" + (pause ? "true" : "false") + "); end"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int GlobalScript::End() const { if (!m_HasStarted) { @@ -144,20 +146,20 @@ namespace RTE { return g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".EndScript then " + m_LuaClassName + ":EndScript(); end"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void GlobalScript::HandleCraftEnteringOrbit(const ACraft *orbitedCraft) { + void GlobalScript::HandleCraftEnteringOrbit(const ACraft* orbitedCraft) { if (!m_IsActive || !!m_HasStarted || orbitedCraft == nullptr || !g_MovableMan.IsActor(orbitedCraft) || !g_SettingsMan.IsGlobalScriptEnabled(GetModuleAndPresetName())) { return; } - int error = g_LuaMan.GetMasterScriptState().RunScriptFunctionString(m_LuaClassName + ".CraftEnteredOrbit", m_LuaClassName, { m_LuaClassName, m_LuaClassName + ".CraftEnteredOrbit" }, { orbitedCraft }); + int error = g_LuaMan.GetMasterScriptState().RunScriptFunctionString(m_LuaClassName + ".CraftEnteredOrbit", m_LuaClassName, {m_LuaClassName, m_LuaClassName + ".CraftEnteredOrbit"}, {orbitedCraft}); if (error) { m_IsActive = false; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GlobalScript::Update() { if (!m_IsActive) { @@ -176,8 +178,8 @@ namespace RTE { } int error = g_LuaMan.GetMasterScriptState().RunScriptString("if " + m_LuaClassName + ".UpdateScript then " + m_LuaClassName + ":UpdateScript(); end"); - if (error) { + if (error) { m_IsActive = false; } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/GlobalScript.h b/Source/Entities/GlobalScript.h index a298bb694..d3a43db7c 100644 --- a/Source/Entities/GlobalScript.h +++ b/Source/Entities/GlobalScript.h @@ -14,7 +14,6 @@ namespace RTE { friend struct EntityLuaBindings; public: - EntityAllocation(GlobalScript); SerializableOverrideMethods; ClassInfoGetters; @@ -36,7 +35,7 @@ namespace RTE { /// /// A reference to the GlobalScript to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const GlobalScript &reference); + int Create(const GlobalScript& reference); #pragma endregion #pragma region Destruction @@ -49,12 +48,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the GlobalScript object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Entity::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Entity::Destroy(); + } + Clear(); + } /// /// Resets the entire GlobalScript, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -113,7 +120,7 @@ namespace RTE { /// Handles when an ACraft has left the game scene and entered orbit by running the appropriate Lua function. Ownership is NOT transferred! /// /// The ACraft instance that entered orbit. Ownership is NOT transferred! - void HandleCraftEnteringOrbit(const ACraft *orbitedCraft); + void HandleCraftEnteringOrbit(const ACraft* orbitedCraft); /// /// Updates the state of this GlobalScript every frame. @@ -122,7 +129,6 @@ namespace RTE { #pragma endregion private: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. std::string m_ScriptPath; //!< The path to the Lua script file that defines this' behaviors in update. @@ -139,8 +145,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - GlobalScript(const GlobalScript &reference) = delete; - GlobalScript &operator=(const GlobalScript &rhs) = delete; + GlobalScript(const GlobalScript& reference) = delete; + GlobalScript& operator=(const GlobalScript& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/HDFirearm.cpp b/Source/Entities/HDFirearm.cpp index e85e0713f..72c11dda3 100644 --- a/Source/Entities/HDFirearm.cpp +++ b/Source/Entities/HDFirearm.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -26,1188 +25,1199 @@ namespace RTE { -ConcreteClassInfo(HDFirearm, HeldDevice, 50); + ConcreteClassInfo(HDFirearm, HeldDevice, 50); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this HDFirearm, effectively + // resetting the members of this abstraction level only. + + void HDFirearm::Clear() { + m_pMagazineReference = 0; + m_pMagazine = 0; + + m_pFlash = 0; + m_PreFireSound = nullptr; + m_FireSound = nullptr; + m_FireEchoSound = nullptr; + m_ActiveSound = nullptr; + m_DeactivationSound = nullptr; + m_EmptySound = nullptr; + m_ReloadStartSound = nullptr; + m_ReloadEndSound = nullptr; + m_ReloadEndOffset = -1.0F; + m_HasPlayedEndReloadSound = false; + m_RateOfFire = 0; + m_ActivationDelay = 0; + m_DeactivationDelay = 0; + m_Reloading = false; + m_DoneReloading = false; + m_BaseReloadTime = 0; + m_FullAuto = false; + m_FireIgnoresThis = true; + m_Reloadable = true; + m_DualReloadable = false; + m_OneHandedReloadTimeMultiplier = 1.5F; + m_ReloadAngle = -0.5F; + m_OneHandedReloadAngle = -1.0F; + m_ShakeRange = 0; + m_SharpShakeRange = 0; + m_NoSupportFactor = 0; + m_ParticleSpreadRange = 0; + m_ShellEjectAngle = 150; + m_ShellSpreadRange = 0; + m_ShellAngVelRange = 0; + m_ShellVelVariation = 0.1F; + m_RecoilScreenShakeAmount = 0.0F; + m_AIFireVel = -1; + m_AIBulletLifeTime = 0; + m_AIBulletAccScalar = -1; + m_LastFireTmr.Reset(); + m_ReloadTmr.Reset(); + m_MuzzleOff.Reset(); + m_EjectOff.Reset(); + m_MagOff.Reset(); + m_FiredOnce = false; + m_FireFrame = false; + m_FiredLastFrame = false; + m_AlreadyClicked = false; + m_RoundsFired = 0; + m_IsAnimatedManually = false; + + m_LegacyCompatibilityRoundsAlwaysFireUnflipped = false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Round object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this HDFirearm, effectively -// resetting the members of this abstraction level only. - -void HDFirearm::Clear() -{ - m_pMagazineReference = 0; - m_pMagazine = 0; - - m_pFlash = 0; - m_PreFireSound = nullptr; - m_FireSound = nullptr; - m_FireEchoSound = nullptr; - m_ActiveSound = nullptr; - m_DeactivationSound = nullptr; - m_EmptySound = nullptr; - m_ReloadStartSound = nullptr; - m_ReloadEndSound = nullptr; - m_ReloadEndOffset = -1.0F; - m_HasPlayedEndReloadSound = false; - m_RateOfFire = 0; - m_ActivationDelay = 0; - m_DeactivationDelay = 0; - m_Reloading = false; - m_DoneReloading = false; - m_BaseReloadTime = 0; - m_FullAuto = false; - m_FireIgnoresThis = true; - m_Reloadable = true; - m_DualReloadable = false; - m_OneHandedReloadTimeMultiplier = 1.5F; - m_ReloadAngle = -0.5F; - m_OneHandedReloadAngle = -1.0F; - m_ShakeRange = 0; - m_SharpShakeRange = 0; - m_NoSupportFactor = 0; - m_ParticleSpreadRange = 0; - m_ShellEjectAngle = 150; - m_ShellSpreadRange = 0; - m_ShellAngVelRange = 0; - m_ShellVelVariation = 0.1F; - m_RecoilScreenShakeAmount = 0.0F; - m_AIFireVel = -1; - m_AIBulletLifeTime = 0; - m_AIBulletAccScalar = -1; - m_LastFireTmr.Reset(); - m_ReloadTmr.Reset(); - m_MuzzleOff.Reset(); - m_EjectOff.Reset(); - m_MagOff.Reset(); - m_FiredOnce = false; - m_FireFrame = false; - m_FiredLastFrame = false; - m_AlreadyClicked = false; - m_RoundsFired = 0; - m_IsAnimatedManually = false; - - m_LegacyCompatibilityRoundsAlwaysFireUnflipped = false; -} + int HDFirearm::Create() { + if (HeldDevice::Create() < 0) + return -1; + if (m_pFlash) + m_pFlash->SetParentOffset(m_MuzzleOff); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Round object ready for use. + return 0; + } -int HDFirearm::Create() -{ - if (HeldDevice::Create() < 0) - return -1; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a HDFirearm to be identical to another, by deep copy. - if (m_pFlash) - m_pFlash->SetParentOffset(m_MuzzleOff); + int HDFirearm::Create(const HDFirearm& reference) { + if (reference.m_pMagazine) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pMagazine->GetUniqueID()); + } + if (reference.m_pFlash) { + m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFlash->GetUniqueID()); + } - return 0; -} + HeldDevice::Create(reference); + if (reference.m_pMagazine) { + SetMagazine(dynamic_cast(reference.m_pMagazine->Clone())); + } + if (reference.m_pFlash) { + SetFlash(dynamic_cast(reference.m_pFlash->Clone())); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a HDFirearm to be identical to another, by deep copy. - -int HDFirearm::Create(const HDFirearm &reference) { - if (reference.m_pMagazine) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pMagazine->GetUniqueID()); } - if (reference.m_pFlash) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_pFlash->GetUniqueID()); } - - HeldDevice::Create(reference); - - if (reference.m_pMagazine) { SetMagazine(dynamic_cast(reference.m_pMagazine->Clone())); } - if (reference.m_pFlash) { SetFlash(dynamic_cast(reference.m_pFlash->Clone())); } - - m_pMagazineReference = reference.m_pMagazineReference; - if (reference.m_PreFireSound) { m_PreFireSound = dynamic_cast(reference.m_PreFireSound->Clone()); } - if (reference.m_FireSound) { m_FireSound = dynamic_cast(reference.m_FireSound->Clone()); } - if (reference.m_FireEchoSound) { m_FireEchoSound = dynamic_cast(reference.m_FireEchoSound->Clone()); } - if (reference.m_ActiveSound) { m_ActiveSound = dynamic_cast(reference.m_ActiveSound->Clone()); } - if (reference.m_DeactivationSound) { m_DeactivationSound = dynamic_cast(reference.m_DeactivationSound->Clone()); } - if (reference.m_EmptySound) { m_EmptySound = dynamic_cast(reference.m_EmptySound->Clone()); } - if (reference.m_ReloadStartSound) { m_ReloadStartSound = dynamic_cast(reference.m_ReloadStartSound->Clone()); } - if (reference.m_ReloadEndSound) { m_ReloadEndSound = dynamic_cast(reference.m_ReloadEndSound->Clone()); } - m_ReloadEndOffset = reference.m_ReloadEndOffset; - m_RateOfFire = reference.m_RateOfFire; - m_ActivationDelay = reference.m_ActivationDelay; - m_DeactivationDelay = reference.m_DeactivationDelay; - m_Reloading = reference.m_Reloading; - m_DoneReloading = reference.m_DoneReloading; - m_BaseReloadTime = reference.m_BaseReloadTime; - m_LastFireTmr = reference.m_LastFireTmr; - m_ReloadTmr = reference.m_ReloadTmr; - m_FullAuto = reference.m_FullAuto; - m_FireIgnoresThis = reference.m_FireIgnoresThis; - m_Reloadable = reference.m_Reloadable; - m_DualReloadable = reference.m_DualReloadable; - m_OneHandedReloadTimeMultiplier = reference.m_OneHandedReloadTimeMultiplier; - m_ReloadAngle = reference.m_ReloadAngle; - m_OneHandedReloadAngle = reference.m_OneHandedReloadAngle; - m_ShakeRange = reference.m_ShakeRange; - m_SharpShakeRange = reference.m_SharpShakeRange; - m_NoSupportFactor = reference.m_NoSupportFactor; - m_ParticleSpreadRange = reference.m_ParticleSpreadRange; - m_ShellEjectAngle = reference.m_ShellEjectAngle; - m_ShellSpreadRange = reference.m_ShellSpreadRange; - m_ShellAngVelRange = reference.m_ShellAngVelRange; - m_ShellVelVariation = reference.m_ShellVelVariation; - m_RecoilScreenShakeAmount = reference.m_RecoilScreenShakeAmount; - m_MuzzleOff = reference.m_MuzzleOff; - m_EjectOff = reference.m_EjectOff; - m_MagOff = reference.m_MagOff; - m_RoundsFired = reference.m_RoundsFired; - m_IsAnimatedManually = reference.m_IsAnimatedManually; - - m_LegacyCompatibilityRoundsAlwaysFireUnflipped = reference.m_LegacyCompatibilityRoundsAlwaysFireUnflipped; - - return 0; -} + m_pMagazineReference = reference.m_pMagazineReference; + if (reference.m_PreFireSound) { + m_PreFireSound = dynamic_cast(reference.m_PreFireSound->Clone()); + } + if (reference.m_FireSound) { + m_FireSound = dynamic_cast(reference.m_FireSound->Clone()); + } + if (reference.m_FireEchoSound) { + m_FireEchoSound = dynamic_cast(reference.m_FireEchoSound->Clone()); + } + if (reference.m_ActiveSound) { + m_ActiveSound = dynamic_cast(reference.m_ActiveSound->Clone()); + } + if (reference.m_DeactivationSound) { + m_DeactivationSound = dynamic_cast(reference.m_DeactivationSound->Clone()); + } + if (reference.m_EmptySound) { + m_EmptySound = dynamic_cast(reference.m_EmptySound->Clone()); + } + if (reference.m_ReloadStartSound) { + m_ReloadStartSound = dynamic_cast(reference.m_ReloadStartSound->Clone()); + } + if (reference.m_ReloadEndSound) { + m_ReloadEndSound = dynamic_cast(reference.m_ReloadEndSound->Clone()); + } + m_ReloadEndOffset = reference.m_ReloadEndOffset; + m_RateOfFire = reference.m_RateOfFire; + m_ActivationDelay = reference.m_ActivationDelay; + m_DeactivationDelay = reference.m_DeactivationDelay; + m_Reloading = reference.m_Reloading; + m_DoneReloading = reference.m_DoneReloading; + m_BaseReloadTime = reference.m_BaseReloadTime; + m_LastFireTmr = reference.m_LastFireTmr; + m_ReloadTmr = reference.m_ReloadTmr; + m_FullAuto = reference.m_FullAuto; + m_FireIgnoresThis = reference.m_FireIgnoresThis; + m_Reloadable = reference.m_Reloadable; + m_DualReloadable = reference.m_DualReloadable; + m_OneHandedReloadTimeMultiplier = reference.m_OneHandedReloadTimeMultiplier; + m_ReloadAngle = reference.m_ReloadAngle; + m_OneHandedReloadAngle = reference.m_OneHandedReloadAngle; + m_ShakeRange = reference.m_ShakeRange; + m_SharpShakeRange = reference.m_SharpShakeRange; + m_NoSupportFactor = reference.m_NoSupportFactor; + m_ParticleSpreadRange = reference.m_ParticleSpreadRange; + m_ShellEjectAngle = reference.m_ShellEjectAngle; + m_ShellSpreadRange = reference.m_ShellSpreadRange; + m_ShellAngVelRange = reference.m_ShellAngVelRange; + m_ShellVelVariation = reference.m_ShellVelVariation; + m_RecoilScreenShakeAmount = reference.m_RecoilScreenShakeAmount; + m_MuzzleOff = reference.m_MuzzleOff; + m_EjectOff = reference.m_EjectOff; + m_MagOff = reference.m_MagOff; + m_RoundsFired = reference.m_RoundsFired; + m_IsAnimatedManually = reference.m_IsAnimatedManually; + + m_LegacyCompatibilityRoundsAlwaysFireUnflipped = reference.m_LegacyCompatibilityRoundsAlwaysFireUnflipped; + + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int HDFirearm::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return HeldDevice::ReadProperty(propName, reader)); + + MatchProperty("Magazine", { SetMagazine(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("Flash", { SetFlash(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("PreFireSound", { + m_PreFireSound = new SoundContainer; + reader >> m_PreFireSound; + }); + MatchProperty("FireSound", { + m_FireSound = new SoundContainer; + reader >> m_FireSound; + }); + MatchProperty("FireEchoSound", { + m_FireEchoSound = new SoundContainer; + reader >> m_FireEchoSound; + m_FireEchoSound->SetSoundOverlapMode(SoundContainer::SoundOverlapMode::RESTART); + }); + MatchProperty("ActiveSound", { + m_ActiveSound = new SoundContainer; + reader >> m_ActiveSound; + }); + MatchProperty("DeactivationSound", { + m_DeactivationSound = new SoundContainer; + reader >> m_DeactivationSound; + }); + MatchProperty("EmptySound", { + m_EmptySound = new SoundContainer; + reader >> m_EmptySound; + }); + MatchProperty("ReloadStartSound", { + m_ReloadStartSound = new SoundContainer; + reader >> m_ReloadStartSound; + }); + MatchProperty("ReloadEndSound", { + m_ReloadEndSound = new SoundContainer; + reader >> m_ReloadEndSound; + }); + MatchProperty("ReloadEndOffset", { reader >> m_ReloadEndOffset; }); + MatchProperty("RateOfFire", { reader >> m_RateOfFire; }); + MatchProperty("ActivationDelay", { reader >> m_ActivationDelay; }); + MatchProperty("DeactivationDelay", { reader >> m_DeactivationDelay; }); + MatchForwards("BaseReloadTime") MatchProperty("ReloadTime", { reader >> m_BaseReloadTime; }); + MatchProperty("FullAuto", { reader >> m_FullAuto; }); + MatchProperty("FireIgnoresThis", { reader >> m_FireIgnoresThis; }); + MatchProperty("Reloadable", { reader >> m_Reloadable; }); + MatchProperty("DualReloadable", { reader >> m_DualReloadable; }); + MatchProperty("OneHandedReloadTimeMultiplier", { reader >> m_OneHandedReloadTimeMultiplier; }); + MatchProperty("ReloadAngle", { reader >> m_ReloadAngle; }); + MatchProperty("OneHandedReloadAngle", { reader >> m_OneHandedReloadAngle; }); + MatchProperty("RecoilTransmission", { reader >> m_JointStiffness; }); + MatchProperty("IsAnimatedManually", { reader >> m_IsAnimatedManually; }); + MatchProperty("ShakeRange", { + reader >> m_ShakeRange; + m_ShakeRange /= 2; + }); + MatchProperty("SharpShakeRange", { + reader >> m_SharpShakeRange; + m_SharpShakeRange /= 2; + }); + MatchProperty("NoSupportFactor", { reader >> m_NoSupportFactor; }); + MatchProperty("ParticleSpreadRange", { + reader >> m_ParticleSpreadRange; + m_ParticleSpreadRange /= 2; + }); + MatchProperty("ShellEjectAngle", { reader >> m_ShellEjectAngle; }); + MatchProperty("ShellSpreadRange", { + reader >> m_ShellSpreadRange; + m_ShellSpreadRange /= 2; + }); + MatchProperty("ShellAngVelRange", { + reader >> m_ShellAngVelRange; + m_ShellAngVelRange /= 2; + }); + MatchProperty("ShellVelVariation", { reader >> m_ShellVelVariation; }); + MatchProperty("RecoilScreenShakeAmount", { reader >> m_RecoilScreenShakeAmount; }); + MatchProperty("MuzzleOffset", { reader >> m_MuzzleOff; }); + MatchProperty("EjectionOffset", { reader >> m_EjectOff; }); + MatchProperty("LegacyCompatibilityRoundsAlwaysFireUnflipped", { reader >> m_LegacyCompatibilityRoundsAlwaysFireUnflipped; }); + + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int HDFirearm::ReadProperty(const std::string_view &propName, Reader &reader) { - StartPropertyList(return HeldDevice::ReadProperty(propName, reader)); - - MatchProperty("Magazine", { SetMagazine(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("Flash", { SetFlash(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("PreFireSound", { - m_PreFireSound = new SoundContainer; - reader >> m_PreFireSound; - }); - MatchProperty("FireSound", { - m_FireSound = new SoundContainer; - reader >> m_FireSound; - }); - MatchProperty("FireEchoSound", { - m_FireEchoSound = new SoundContainer; - reader >> m_FireEchoSound; - m_FireEchoSound->SetSoundOverlapMode(SoundContainer::SoundOverlapMode::RESTART); - }); - MatchProperty("ActiveSound", { - m_ActiveSound = new SoundContainer; - reader >> m_ActiveSound; - }); - MatchProperty("DeactivationSound", { - m_DeactivationSound = new SoundContainer; - reader >> m_DeactivationSound; - }); - MatchProperty("EmptySound", { - m_EmptySound = new SoundContainer; - reader >> m_EmptySound; - }); - MatchProperty("ReloadStartSound", { - m_ReloadStartSound = new SoundContainer; - reader >> m_ReloadStartSound; - }); - MatchProperty("ReloadEndSound", { - m_ReloadEndSound = new SoundContainer; - reader >> m_ReloadEndSound; - }); - MatchProperty("ReloadEndOffset", { reader >> m_ReloadEndOffset; }); - MatchProperty("RateOfFire", { reader >> m_RateOfFire; }); - MatchProperty("ActivationDelay", { reader >> m_ActivationDelay; }); - MatchProperty("DeactivationDelay", { reader >> m_DeactivationDelay; }); - MatchForwards("BaseReloadTime") MatchProperty("ReloadTime", { reader >> m_BaseReloadTime; }); - MatchProperty("FullAuto", { reader >> m_FullAuto; }); - MatchProperty("FireIgnoresThis", { reader >> m_FireIgnoresThis; }); - MatchProperty("Reloadable", { reader >> m_Reloadable; }); - MatchProperty("DualReloadable", { reader >> m_DualReloadable; }); - MatchProperty("OneHandedReloadTimeMultiplier", { reader >> m_OneHandedReloadTimeMultiplier; }); - MatchProperty("ReloadAngle", { reader >> m_ReloadAngle; }); - MatchProperty("OneHandedReloadAngle", { reader >> m_OneHandedReloadAngle; }); - MatchProperty("RecoilTransmission", { reader >> m_JointStiffness; }); - MatchProperty("IsAnimatedManually", { reader >> m_IsAnimatedManually; }); - MatchProperty("ShakeRange", { - reader >> m_ShakeRange; - m_ShakeRange /= 2; - }); - MatchProperty("SharpShakeRange", { - reader >> m_SharpShakeRange; - m_SharpShakeRange /= 2; - }); - MatchProperty("NoSupportFactor", { reader >> m_NoSupportFactor; }); - MatchProperty("ParticleSpreadRange", { - reader >> m_ParticleSpreadRange; - m_ParticleSpreadRange /= 2; - }); - MatchProperty("ShellEjectAngle", { reader >> m_ShellEjectAngle; }); - MatchProperty("ShellSpreadRange", { - reader >> m_ShellSpreadRange; - m_ShellSpreadRange /= 2; - }); - MatchProperty("ShellAngVelRange", { - reader >> m_ShellAngVelRange; - m_ShellAngVelRange /= 2; - }); - MatchProperty("ShellVelVariation", { reader >> m_ShellVelVariation; }); - MatchProperty("RecoilScreenShakeAmount", { reader >> m_RecoilScreenShakeAmount; }); - MatchProperty("MuzzleOffset", { reader >> m_MuzzleOff; }); - MatchProperty("EjectionOffset", { reader >> m_EjectOff; }); - MatchProperty("LegacyCompatibilityRoundsAlwaysFireUnflipped", { reader >> m_LegacyCompatibilityRoundsAlwaysFireUnflipped; }); - - - EndPropertyList; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this HDFirearm with a Writer for + // later recreation with Create(Reader &reader); + + int HDFirearm::Save(Writer& writer) const { + HeldDevice::Save(writer); + + writer.NewProperty("Magazine"); + writer << m_pMagazine; + writer.NewProperty("Flash"); + writer << m_pFlash; + writer.NewProperty("PreFireSound"); + writer << m_PreFireSound; + writer.NewProperty("FireSound"); + writer << m_FireSound; + writer.NewProperty("FireEchoSound"); + writer << m_FireEchoSound; + writer.NewProperty("ActiveSound"); + writer << m_ActiveSound; + writer.NewProperty("DeactivationSound"); + writer << m_DeactivationSound; + writer.NewProperty("EmptySound"); + writer << m_EmptySound; + writer.NewProperty("ReloadStartSound"); + writer << m_ReloadStartSound; + writer.NewProperty("ReloadEndSound"); + writer << m_ReloadEndSound; + writer.NewPropertyWithValue("ReloadEndOffset", m_ReloadEndOffset); + writer.NewProperty("RateOfFire"); + writer << m_RateOfFire; + writer.NewProperty("ActivationDelay"); + writer << m_ActivationDelay; + writer.NewProperty("DeactivationDelay"); + writer << m_DeactivationDelay; + writer.NewProperty("ReloadTime"); + writer << m_BaseReloadTime; + writer.NewProperty("FullAuto"); + writer << m_FullAuto; + writer.NewProperty("FireIgnoresThis"); + writer << m_FireIgnoresThis; + writer.NewProperty("Reloadable"); + writer.NewPropertyWithValue("DualReloadable", m_DualReloadable); + writer.NewPropertyWithValue("OneHandedReloadTimeMultiplier", m_OneHandedReloadTimeMultiplier); + writer.NewPropertyWithValue("ReloadAngle", m_ReloadAngle); + writer.NewPropertyWithValue("OneHandedReloadAngle", m_OneHandedReloadAngle); + writer << m_Reloadable; + writer.NewProperty("RecoilTransmission"); + writer << m_JointStiffness; + writer.NewProperty("IsAnimatedManually"); + writer << m_IsAnimatedManually; + writer.NewProperty("ShakeRange"); + writer << m_ShakeRange * 2; + writer.NewProperty("SharpShakeRange"); + writer << m_SharpShakeRange * 2; + writer.NewProperty("NoSupportFactor"); + writer << m_NoSupportFactor; + writer.NewProperty("ParticleSpreadRange"); + writer << m_ParticleSpreadRange * 2; + writer.NewProperty("ShellEjectAngle"); + writer << m_ShellEjectAngle; + writer.NewProperty("ShellSpreadRange"); + writer << m_ShellSpreadRange * 2; + writer.NewProperty("ShellAngVelRange"); + writer << m_ShellAngVelRange * 2; + writer.NewProperty("ShellVelVariation"); + writer << m_ShellVelVariation; + writer.NewProperty("RecoilScreenShakeAmount"); + writer << m_RecoilScreenShakeAmount; + writer.NewProperty("MuzzleOffset"); + writer << m_MuzzleOff; + writer.NewProperty("EjectionOffset"); + writer << m_EjectOff; + + writer.NewPropertyWithValue("LegacyCompatibilityRoundsAlwaysFireUnflipped", m_LegacyCompatibilityRoundsAlwaysFireUnflipped); + + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the HDFirearm object. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this HDFirearm with a Writer for -// later recreation with Create(Reader &reader); - -int HDFirearm::Save(Writer &writer) const -{ - HeldDevice::Save(writer); - - writer.NewProperty("Magazine"); - writer << m_pMagazine; - writer.NewProperty("Flash"); - writer << m_pFlash; - writer.NewProperty("PreFireSound"); - writer << m_PreFireSound; - writer.NewProperty("FireSound"); - writer << m_FireSound; - writer.NewProperty("FireEchoSound"); - writer << m_FireEchoSound; - writer.NewProperty("ActiveSound"); - writer << m_ActiveSound; - writer.NewProperty("DeactivationSound"); - writer << m_DeactivationSound; - writer.NewProperty("EmptySound"); - writer << m_EmptySound; - writer.NewProperty("ReloadStartSound"); - writer << m_ReloadStartSound; - writer.NewProperty("ReloadEndSound"); - writer << m_ReloadEndSound; - writer.NewPropertyWithValue("ReloadEndOffset", m_ReloadEndOffset); - writer.NewProperty("RateOfFire"); - writer << m_RateOfFire; - writer.NewProperty("ActivationDelay"); - writer << m_ActivationDelay; - writer.NewProperty("DeactivationDelay"); - writer << m_DeactivationDelay; - writer.NewProperty("ReloadTime"); - writer << m_BaseReloadTime; - writer.NewProperty("FullAuto"); - writer << m_FullAuto; - writer.NewProperty("FireIgnoresThis"); - writer << m_FireIgnoresThis; - writer.NewProperty("Reloadable"); - writer.NewPropertyWithValue("DualReloadable", m_DualReloadable); - writer.NewPropertyWithValue("OneHandedReloadTimeMultiplier", m_OneHandedReloadTimeMultiplier); - writer.NewPropertyWithValue("ReloadAngle", m_ReloadAngle); - writer.NewPropertyWithValue("OneHandedReloadAngle", m_OneHandedReloadAngle); - writer << m_Reloadable; - writer.NewProperty("RecoilTransmission"); - writer << m_JointStiffness; - writer.NewProperty("IsAnimatedManually"); - writer << m_IsAnimatedManually; - writer.NewProperty("ShakeRange"); - writer << m_ShakeRange * 2; - writer.NewProperty("SharpShakeRange"); - writer << m_SharpShakeRange * 2; - writer.NewProperty("NoSupportFactor"); - writer << m_NoSupportFactor; - writer.NewProperty("ParticleSpreadRange"); - writer << m_ParticleSpreadRange * 2; - writer.NewProperty("ShellEjectAngle"); - writer << m_ShellEjectAngle; - writer.NewProperty("ShellSpreadRange"); - writer << m_ShellSpreadRange * 2; - writer.NewProperty("ShellAngVelRange"); - writer << m_ShellAngVelRange * 2; - writer.NewProperty("ShellVelVariation"); - writer << m_ShellVelVariation; - writer.NewProperty("RecoilScreenShakeAmount"); - writer << m_RecoilScreenShakeAmount; - writer.NewProperty("MuzzleOffset"); - writer << m_MuzzleOff; - writer.NewProperty("EjectionOffset"); - writer << m_EjectOff; - - writer.NewPropertyWithValue("LegacyCompatibilityRoundsAlwaysFireUnflipped", m_LegacyCompatibilityRoundsAlwaysFireUnflipped); - - return 0; -} + void HDFirearm::Destroy(bool notInherited) { + if (m_PreFireSound) { + m_PreFireSound->Stop(); + } + if (m_FireSound) { + m_FireSound->Stop(); + } + if (m_FireEchoSound) { + m_FireEchoSound->Stop(); + } + if (m_ActiveSound) { + m_ActiveSound->Stop(); + } + if (m_DeactivationSound) { + m_DeactivationSound->Stop(); + } + if (m_EmptySound) { + m_EmptySound->Stop(); + } + if (m_ReloadStartSound) { + m_ReloadStartSound->Stop(); + } + if (m_ReloadEndSound) { + m_ReloadEndSound->Stop(); + } + delete m_PreFireSound; + delete m_FireSound; + delete m_FireEchoSound; + delete m_ActiveSound; + delete m_DeactivationSound; + delete m_EmptySound; + delete m_ReloadStartSound; + delete m_ReloadEndSound; + + if (!notInherited) + HeldDevice::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the HDFirearm object. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void HDFirearm::Destroy(bool notInherited) -{ - if (m_PreFireSound) { - m_PreFireSound->Stop(); + void HDFirearm::SetMagazine(Magazine* newMagazine) { + if (m_pMagazine && m_pMagazine->IsAttached()) { + RemoveAndDeleteAttachable(m_pMagazine); + } + if (newMagazine == nullptr) { + m_pMagazine = nullptr; + } else { + m_pMagazine = newMagazine; + AddAttachable(newMagazine); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newMagazine->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + Magazine* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetMagazine"); + dynamic_cast(parent)->SetMagazine(castedAttachable); + }}); + + const Entity* newMagazineReference = g_PresetMan.GetEntityPreset(newMagazine->GetClassName(), newMagazine->GetPresetName(), newMagazine->GetModuleID()); + if (newMagazineReference) { + m_pMagazineReference = dynamic_cast(newMagazineReference); + } + } } - if (m_FireSound) { - m_FireSound->Stop(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void HDFirearm::SetFlash(Attachable* newFlash) { + if (m_pFlash && m_pFlash->IsAttached()) { + RemoveAndDeleteAttachable(m_pFlash); + } + if (newFlash == nullptr) { + m_pFlash = nullptr; + } else { + // Note - this is done here because setting mass on attached Attachables causes values to be updated on the parent (and its parent, and so on), which isn't ideal. Better to do it before the new flash is attached, so there are fewer calculations. + newFlash->SetMass(0.0F); + + m_pFlash = newFlash; + AddAttachable(newFlash); + + m_HardcodedAttachableUniqueIDsAndSetters.insert({newFlash->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + dynamic_cast(parent)->SetFlash(attachable); + }}); + + m_pFlash->SetDrawnNormallyByParent(false); + m_pFlash->SetDeleteWhenRemovedFromParent(true); + m_pFlash->SetCollidesWithTerrainWhileAttached(false); + } } - if (m_FireEchoSound) { - m_FireEchoSound->Stop(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + std::string HDFirearm::GetNextMagazineName() const { + return m_pMagazineReference->GetPresetName(); } - if (m_ActiveSound) { - m_ActiveSound->Stop(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool HDFirearm::SetNextMagazineName(std::string magName) { + const Magazine* pNewMag = dynamic_cast(g_PresetMan.GetEntityPreset("Magazine", magName)); + if (pNewMag) { + m_pMagazineReference = pNewMag; + m_AIFireVel = -1; + m_AIBulletLifeTime = 0; + m_AIBulletAccScalar = -1; + + return true; + } + return false; } - if (m_DeactivationSound) { - m_DeactivationSound->Stop(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRoundInMagCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of rounds still in the loaded magazine. + + int HDFirearm::GetRoundInMagCount() const { + return m_pMagazine ? m_pMagazine->GetRoundCount() : 0; } - if (m_EmptySound) { - m_EmptySound->Stop(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int HDFirearm::GetRoundInMagCapacity() const { + if (m_pMagazine) { + return m_pMagazine->GetCapacity(); + } else if (m_pMagazineReference) { + return m_pMagazineReference->GetCapacity(); + } + return 0; } - if (m_ReloadStartSound) { - m_ReloadStartSound->Stop(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIFireVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the velocity the AI use when aiming this weapon + + float HDFirearm::GetAIFireVel() { + if (m_AIFireVel < 0 && m_pMagazine) + m_AIFireVel = m_pMagazine->GetAIAimVel(); + + return m_AIFireVel; } - if (m_ReloadEndSound) { - m_ReloadEndSound->Stop(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIBulletLifeTime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bullet life time the AI use when aiming this weapon. + + unsigned long HDFirearm::GetAIBulletLifeTime() { + if (m_AIBulletLifeTime == 0 && m_pMagazine) { + const Round* pRound = m_pMagazine->GetNextRound(); + if (pRound) { + m_AIBulletLifeTime = pRound->GetAILifeTime(); + + // Set a default if the lifetime is zero (i.e. infinite) + if (m_AIBulletLifeTime == 0) + m_AIBulletLifeTime = 20000; + } + } + + return m_AIBulletLifeTime; } - delete m_PreFireSound; - delete m_FireSound; - delete m_FireEchoSound; - delete m_ActiveSound; - delete m_DeactivationSound; - delete m_EmptySound; - delete m_ReloadStartSound; - delete m_ReloadEndSound; - - if (!notInherited) - HeldDevice::Destroy(); - Clear(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void HDFirearm::SetMagazine(Magazine *newMagazine) { - if (m_pMagazine && m_pMagazine->IsAttached()) { RemoveAndDeleteAttachable(m_pMagazine); } - if (newMagazine == nullptr) { - m_pMagazine = nullptr; - } else { - m_pMagazine = newMagazine; - AddAttachable(newMagazine); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newMagazine->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - Magazine *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to SetMagazine"); - dynamic_cast(parent)->SetMagazine(castedAttachable); - }}); - - const Entity *newMagazineReference = g_PresetMan.GetEntityPreset(newMagazine->GetClassName(), newMagazine->GetPresetName(), newMagazine->GetModuleID()); - if (newMagazineReference) { m_pMagazineReference = dynamic_cast(newMagazineReference); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void HDFirearm::SetFlash(Attachable *newFlash) { - if (m_pFlash && m_pFlash->IsAttached()) { RemoveAndDeleteAttachable(m_pFlash); } - if (newFlash == nullptr) { - m_pFlash = nullptr; - } else { - // Note - this is done here because setting mass on attached Attachables causes values to be updated on the parent (and its parent, and so on), which isn't ideal. Better to do it before the new flash is attached, so there are fewer calculations. - newFlash->SetMass(0.0F); - - m_pFlash = newFlash; - AddAttachable(newFlash); - - m_HardcodedAttachableUniqueIDsAndSetters.insert({newFlash->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - dynamic_cast(parent)->SetFlash(attachable); - }}); - - m_pFlash->SetDrawnNormallyByParent(false); - m_pFlash->SetDeleteWhenRemovedFromParent(true); - m_pFlash->SetCollidesWithTerrainWhileAttached(false); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -std::string HDFirearm::GetNextMagazineName() const { - return m_pMagazineReference->GetPresetName(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool HDFirearm::SetNextMagazineName(std::string magName) -{ - const Magazine * pNewMag = dynamic_cast(g_PresetMan.GetEntityPreset("Magazine", magName)); - if (pNewMag) - { - m_pMagazineReference = pNewMag; - m_AIFireVel = -1; - m_AIBulletLifeTime = 0; - m_AIBulletAccScalar = -1; - - return true; - } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBulletAccScalar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. + float HDFirearm::GetBulletAccScalar() { + if (m_AIBulletAccScalar < 0 && m_pMagazine) + m_AIBulletAccScalar = m_pMagazine->GetBulletAccScalar(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRoundInMagCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of rounds still in the loaded magazine. + return m_AIBulletAccScalar; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIBlastRadius + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the blast radius the AI use when aiming this weapon + + float HDFirearm::GetAIBlastRadius() const { + int radius = -1; + if (m_pMagazine) + radius = m_pMagazine->GetAIAimBlastRadius(); + + if (radius < 0) { + // Set default value + if (m_IsExplosiveWeapon) + radius = 100; + else + radius = 0; + } + + return radius; + } -int HDFirearm::GetRoundInMagCount() const -{ - return m_pMagazine ? m_pMagazine->GetRoundCount() : 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIPenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how much material the projectiles from this weapon can destory. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float HDFirearm::GetAIPenetration() const { + if (m_pMagazine) + return m_pMagazine->GetAIAimPenetration(); -int HDFirearm::GetRoundInMagCapacity() const { - if (m_pMagazine) { - return m_pMagazine->GetCapacity(); - } else if (m_pMagazineReference) { - return m_pMagazineReference->GetCapacity(); + return 0; } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CompareTrajectories + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Estimates how close the projectiles from two weapons will land. + + float HDFirearm::CompareTrajectories(HDFirearm* pWeapon) { + if (pWeapon) { + // Get AI aim data and cap life time to one second + unsigned long LifeTime1 = GetAIBulletLifeTime(); + if (LifeTime1 == 0 || LifeTime1 > 1000) + LifeTime1 = 1000; + + unsigned long LifeTime2 = GetAIBulletLifeTime(); + if (LifeTime2 == 0 || LifeTime2 > 1000) + LifeTime2 = 1000; + + float time = std::max(std::min(LifeTime1, LifeTime2) / 1000.0f, 0.5f); + Vector Vel1 = Vector(GetAIFireVel(), 0); + Vector Vel2 = Vector(pWeapon->GetAIFireVel(), 0); + + // Estimate the hit pos according to: FuturePos=Pos+Vel+Accel*(t*t*0.5) + time = time * time * 0.5; + Vector FuturePos1 = GetMuzzlePos(); + g_SceneMan.WrapPosition(FuturePos1); + FuturePos1 = FuturePos1 * c_MPP + RotateOffset(Vel1) + g_SceneMan.GetGlobalAcc() * GetBulletAccScalar() * time; + + Vector FuturePos2 = GetMuzzlePos(); + g_SceneMan.WrapPosition(FuturePos2); + FuturePos2 = pWeapon->GetMuzzlePos() * c_MPP + RotateOffset(Vel2) + g_SceneMan.GetGlobalAcc() * pWeapon->GetBulletAccScalar() * time; + + return (FuturePos2 - FuturePos1).GetMagnitude() * c_PPM; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIFireVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the velocity the AI use when aiming this weapon + return 100000; + } -float HDFirearm::GetAIFireVel() -{ - if (m_AIFireVel < 0 && m_pMagazine) - m_AIFireVel = m_pMagazine->GetAIAimVel(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMagazinePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the magazine or other equivalent point of + // this. - return m_AIFireVel; -} + Vector HDFirearm::GetMagazinePos() const { + return m_Pos + RotateOffset(m_MagOff); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: GetMuzzlePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the muzzle or other equivalent point of + // this. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIBulletLifeTime -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bullet life time the AI use when aiming this weapon. + Vector HDFirearm::GetMuzzlePos() const { + return m_Pos + RotateOffset(m_MuzzleOff); + } -unsigned long HDFirearm::GetAIBulletLifeTime() -{ - if (m_AIBulletLifeTime == 0 && m_pMagazine) - { - const Round * pRound = m_pMagazine->GetNextRound(); - if (pRound) - { - m_AIBulletLifeTime = pRound->GetAILifeTime(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Set a default if the lifetime is zero (i.e. infinite) - if (m_AIBulletLifeTime == 0) - m_AIBulletLifeTime = 20000; - } - } + void HDFirearm::RestDetection() { + HeldDevice::RestDetection(); - return m_AIBulletLifeTime; -} + if (m_FiredOnce) { + m_RestTimer.Reset(); + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Activate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activates one of this HDFirearm's features. Analogous to 'pulling + // the trigger'. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBulletAccScalar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. + void HDFirearm::Activate() { + bool wasActivated = m_Activated; + HeldDevice::Activate(); -float HDFirearm::GetBulletAccScalar() -{ - if (m_AIBulletAccScalar < 0 && m_pMagazine) - m_AIBulletAccScalar = m_pMagazine->GetBulletAccScalar(); + if (!IsReloading()) { + if (m_DeactivationSound && m_DeactivationSound->IsBeingPlayed()) { + m_DeactivationSound->FadeOut(); + } + if (m_ActiveSound && !m_ActiveSound->IsBeingPlayed() && (m_ActiveSound->GetLoopSetting() == -1 || !wasActivated)) { + m_ActiveSound->Play(this->m_Pos); + } + if (m_PreFireSound && !wasActivated && !m_PreFireSound->IsBeingPlayed()) { + m_PreFireSound->Play(this->m_Pos); + } + } + } - return m_AIBulletAccScalar; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Deactivate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing + // the trigger'. + void HDFirearm::Deactivate() { + bool wasActivated = m_Activated; + HeldDevice::Deactivate(); + m_FiredOnce = false; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIBlastRadius -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the blast radius the AI use when aiming this weapon + if (m_PreFireSound) { + m_PreFireSound->Stop(); + } + if (m_FireSound && m_FireSound->GetLoopSetting() == -1) { + m_FireSound->Stop(); + } + if (m_DeactivationSound && wasActivated && m_FiredLastFrame) { + m_DeactivationSound->Play(m_Pos); + } + } -float HDFirearm::GetAIBlastRadius() const -{ - int radius = -1; - if (m_pMagazine) - radius = m_pMagazine->GetAIAimBlastRadius(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StopActivationSound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Aborts playing of active sound no matter what. Used to silence spinning + // weapons when weapons swapped + + void HDFirearm::StopActivationSound() { + if (m_ActiveSound && m_ActiveSound->IsBeingPlayed()) + m_ActiveSound->Stop(); + + // TODO: Also stop any animation + // Those don't work really, at least we stopped it from making noise + // m_Frame = 0; + // m_Activated = false; + // m_LastFireTmr.SetElapsedSimTimeMS(m_DeactivationDelay + 1); + } - if (radius < 0) - { - // Set default value - if (m_IsExplosiveWeapon) - radius = 100; - else - radius = 0; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return radius; -} + void HDFirearm::Reload() { + if (!m_Reloading && m_Reloadable) { + bool hadMagazineBeforeReloading = m_pMagazine != nullptr; + if (hadMagazineBeforeReloading) { + Vector constrainedMagazineOffset = g_SceneMan.ShortestDistance(m_Pos, m_pMagazine->GetPos(), g_SceneMan.SceneWrapsX()).SetMagnitude(2.0F); + Vector ejectVector = Vector(2.0F * GetFlipFactor(), 0.0F) + constrainedMagazineOffset.RadRotate(RandomNum(-0.2F, 0.2F)); + m_pMagazine->SetVel(m_Vel + ejectVector); + m_pMagazine->SetAngularVel(RandomNum(-3.0F, 3.0F)); + if (!m_pMagazine->IsDiscardable()) { + m_pMagazine->SetToDelete(); + } + RemoveAttachable(m_pMagazine, m_pMagazine->IsDiscardable(), false); + m_pMagazine = 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIPenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how much material the projectiles from this weapon can destory. + Deactivate(); + if (m_ReloadStartSound) { + m_ReloadStartSound->Play(m_Pos); + } -float HDFirearm::GetAIPenetration() const -{ - if (m_pMagazine) - return m_pMagazine->GetAIAimPenetration(); + m_ReloadTmr.Reset(); + CorrectReloadTimerForSupportAvailable(); - return 0; -} + RunScriptedFunctionInAppropriateScripts("OnReload", false, false, {}, {hadMagazineBeforeReloading ? "true" : "false"}); + m_Reloading = true; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CompareTrajectories -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Estimates how close the projectiles from two weapons will land. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -float HDFirearm::CompareTrajectories(HDFirearm * pWeapon) -{ - if (pWeapon) - { - // Get AI aim data and cap life time to one second - unsigned long LifeTime1 = GetAIBulletLifeTime(); - if (LifeTime1 == 0 || LifeTime1 > 1000) - LifeTime1 = 1000; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: NeedsReloading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently in need of being reloaded. - unsigned long LifeTime2 = GetAIBulletLifeTime(); - if (LifeTime2 == 0 || LifeTime2 > 1000) - LifeTime2 = 1000; + bool HDFirearm::NeedsReloading() const { + if (!m_Reloading && m_Reloadable) { + if (m_pMagazine) { + // If we've used over half the rounds, we can profitably go ahead and reload + return !m_pMagazine->IsOverHalfFull(); + } + return true; + } + // We're currently reloading + return false; + } - float time = std::max(std::min(LifeTime1, LifeTime2) / 1000.0f, 0.5f); - Vector Vel1 = Vector(GetAIFireVel(), 0); - Vector Vel2 = Vector(pWeapon->GetAIFireVel(), 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsFull + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently full and reloading won't have + // any effect. + + bool HDFirearm::IsFull() const { + if (!m_Reloading && m_Reloadable) { + if (m_pMagazine) { + // If we've used over half the rounds, we can profitably go ahead and reload + return m_pMagazine->GetRoundCount() == m_pMagazine->GetCapacity() || m_pMagazine->GetCapacity() < 0; + } + return false; + } + // We're currently reloading + return true; + } - // Estimate the hit pos according to: FuturePos=Pos+Vel+Accel*(t*t*0.5) - time = time * time * 0.5; - Vector FuturePos1 = GetMuzzlePos(); - g_SceneMan.WrapPosition(FuturePos1); - FuturePos1 = FuturePos1 * c_MPP + RotateOffset(Vel1) + g_SceneMan.GetGlobalAcc() * GetBulletAccScalar() * time; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Vector FuturePos2 = GetMuzzlePos(); - g_SceneMan.WrapPosition(FuturePos2); - FuturePos2 = pWeapon->GetMuzzlePos() * c_MPP + RotateOffset(Vel2) + g_SceneMan.GetGlobalAcc() * pWeapon->GetBulletAccScalar() * time; + bool HDFirearm::IsEmpty() const { + if (m_pMagazine) { + return m_pMagazine->IsEmpty(); + } + return true; + } - return (FuturePos2 - FuturePos1).GetMagnitude() * c_PPM; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return 100000; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this HDFirearm. Supposed to be done every frame. + void HDFirearm::Update() { + HeldDevice::Update(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMagazinePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the magazine or other equivalent point of -// this. + if (m_PreFireSound && m_PreFireSound->IsBeingPlayed()) { + m_PreFireSound->SetPosition(m_Pos); + } + if (m_FireSound && m_FireSound->IsBeingPlayed()) { + m_FireSound->SetPosition(m_Pos); + } + if (m_ActiveSound && m_ActiveSound->IsBeingPlayed()) { + m_ActiveSound->SetPosition(m_Pos); + } + if (m_DeactivationSound && m_DeactivationSound->IsBeingPlayed()) { + m_DeactivationSound->SetPosition(m_Pos); + } -Vector HDFirearm::GetMagazinePos() const -{ - return m_Pos + RotateOffset(m_MagOff); -} + Actor* pActor = dynamic_cast(GetRootParent()); + + ///////////////////////////////// + // Activation/firing logic + + int roundsFired = 0; + m_RoundsFired = 0; + float degAimAngle = m_Rotation.GetDegAngle(); + degAimAngle = m_HFlipped ? (180.0F + degAimAngle) : degAimAngle; + float totalFireForce = 0.0F; + m_FireFrame = false; + m_DoneReloading = false; + bool playedRoundFireSound = false; + + if (m_pMagazine && !m_pMagazine->IsEmpty()) { + if (m_Activated && !(m_PreFireSound && m_PreFireSound->IsBeingPlayed())) { + + double msPerRound = GetMSPerRound(); + if (m_FullAuto) { + // First round should fly as soon as activated and the delays are taken into account + if (!m_FiredOnce && (m_LastFireTmr.GetElapsedSimTimeMS() - m_DeactivationDelay - m_ActivationDelay) > msPerRound) { + roundsFired = 1; + // Wind back the last fire timer appropriately for the first round, but not farther back than 0 + m_LastFireTmr.SetElapsedSimTimeMS(std::max(m_LastFireTmr.GetElapsedSimTimeMS() - msPerRound, 0.0)); + } + // How many rounds are going to fly since holding down activation. Make sure gun can't be fired faster by tapping activation fast + if (m_LastFireTmr.GetElapsedSimTimeMS() > (m_ActivationTimer.GetElapsedSimTimeMS() - m_ActivationDelay)) { + roundsFired += (m_ActivationTimer.GetElapsedSimTimeMS() - m_ActivationDelay) / msPerRound; + } else { + roundsFired += m_LastFireTmr.GetElapsedSimTimeMS() / msPerRound; + } + } else { + // TODO: Confirm that the delays work properly in semi-auto! + roundsFired = !m_FiredOnce && (m_LastFireTmr.GetElapsedSimTimeMS() - m_ActivationDelay - m_DeactivationDelay) > msPerRound ? 1 : 0; + } + if (roundsFired >= 1) { + m_FiredOnce = true; + m_FireFrame = true; + m_LastFireTmr.Reset(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: GetMuzzlePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the muzzle or other equivalent point of -// this. + Vector roundVel; + Vector shellVel; -Vector HDFirearm::GetMuzzlePos() const -{ - return m_Pos + RotateOffset(m_MuzzleOff); -} + Round* pRound = 0; + Vector tempNozzle; + Vector tempEject; + MOPixel* pPixel; + float shake, particleSpread, shellSpread, lethalRange; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + lethalRange = m_MaxSharpLength * m_SharpAim + std::max(g_FrameMan.GetPlayerFrameBufferWidth(-1), g_FrameMan.GetPlayerFrameBufferHeight(-1)) * 0.51F; + if (pActor) { + lethalRange += pActor->GetAimDistance(); + } -void HDFirearm::RestDetection() { - HeldDevice::RestDetection(); + // Fire all rounds that were fired this frame. + for (int i = 0; i < roundsFired && !m_pMagazine->IsEmpty(); ++i) { + m_RoundsFired++; + + pRound = m_pMagazine->PopNextRound(); + shake = (m_ShakeRange - ((m_ShakeRange - m_SharpShakeRange) * m_SharpAim)) * + (m_Supported ? 1.0F : m_NoSupportFactor) * RandomNormalNum(); + tempNozzle = m_MuzzleOff.GetYFlipped(m_HFlipped); + tempNozzle.DegRotate(degAimAngle + shake); + roundVel.SetXY(pRound->GetFireVel(), 0); + roundVel.DegRotate(degAimAngle + shake); + + Vector particlePos; + Vector particleVel; + int particleCountMax = pRound->ParticleCount(); + float lifeVariation = pRound->GetLifeVariation(); + + // Launch all particles in round + MovableObject* pParticle = 0; + while (!pRound->IsEmpty()) { + pParticle = pRound->PopNextParticle(); + + // Only make the particles separate back behind the nozzle, not in front. This is to avoid silly penetration firings + particlePos = tempNozzle + (roundVel.GetNormalized() * (-RandomNum()) * pRound->GetSeparation()); + pParticle->SetPos(m_Pos + particlePos); + + particleVel = roundVel; + particleSpread = m_ParticleSpreadRange * RandomNormalNum(); + particleVel.DegRotate(particleSpread); + pParticle->SetVel(pRound->GetInheritsFirerVelocity() ? (m_Vel + particleVel) : particleVel); + if (m_LegacyCompatibilityRoundsAlwaysFireUnflipped) { + pParticle->SetRotAngle(particleVel.GetAbsRadAngle()); + } else { + pParticle->SetRotAngle(particleVel.GetAbsRadAngle() + (m_HFlipped ? -c_PI : 0)); + pParticle->SetHFlipped(m_HFlipped); + } + if (lifeVariation != 0 && pParticle->GetLifetime() != 0) { + pParticle->SetLifetime(std::max(static_cast(pParticle->GetLifetime() * (1.0F + (particleCountMax > 1 ? lifeVariation - (lifeVariation * 2.0F * (static_cast(pRound->ParticleCount()) / static_cast(particleCountMax - 1))) : lifeVariation * RandomNormalNum()))), 1)); + } + // F = m * a + totalFireForce += pParticle->GetMass() * pParticle->GetVel().GetMagnitude(); + + // Remove from parent if it's an attachable + Attachable* pAttachable = dynamic_cast(pParticle); + if (pAttachable) { + if (pAttachable->IsAttached()) { + pAttachable->GetParent()->RemoveAttachable(pAttachable); + } + + // Activate if it is some kind of grenade or whatnot. + ThrownDevice* pTD = dynamic_cast(pAttachable); + if (pTD) { + pTD->Activate(); + } + } + + // Set the fired particle to not hit this HeldDevice's parent, if applicable + if (m_FireIgnoresThis) + pParticle->SetWhichMOToNotHit(this, 1.0f); + + // Set the team so alarm events that happen if these gib won't freak out the guy firing + pParticle->SetTeam(m_Team); + + // Also make this not hit team members + // TODO: Don't hardcode this??? + pParticle->SetIgnoresTeamHits(true); + + // Decide for how long until the bullet tumble and start to lose lethality + pPixel = dynamic_cast(pParticle); + if (pPixel) { + // Stray bullets heavily affected by bullet shake lose lethality quicker, as if missing on an imaginary "Z" axis + lethalRange *= std::max(1.0F - std::abs(shake) / 20.0F, 0.1F); + pPixel->SetLethalRange(lethalRange); + } + g_MovableMan.AddParticle(pParticle); + } + pParticle = 0; + + // Launch shell, if there is one. + MovableObject* pShell = pRound->GetShell() ? dynamic_cast(pRound->GetShell()->Clone()) : 0; + if (pShell) { + tempEject = m_EjectOff.GetYFlipped(m_HFlipped); + shellSpread = m_ShellSpreadRange * RandomNormalNum(); + tempEject.DegRotate(degAimAngle + shellSpread); + pShell->SetPos(m_Pos + tempEject); + + // ##@#@@$ TEMP + shellVel.SetXY(pRound->GetShellVel() * (1.0F - RandomNum(0.0F, m_ShellVelVariation)), 0); + shellVel.DegRotate(degAimAngle + m_ShellEjectAngle * (m_HFlipped ? -1 : 1) + shellSpread); + pShell->SetVel(m_Vel + shellVel); + pShell->SetRotAngle(m_Rotation.GetRadAngle()); + pShell->SetAngularVel(pShell->GetAngularVel() + (m_ShellAngVelRange * RandomNormalNum())); + pShell->SetHFlipped(m_HFlipped); + // Set the ejected shell to not hit this HeldDevice's parent, if applicable + if (m_FireIgnoresThis) + pShell->SetWhichMOToNotHit(this, 1.0f); + // Set the team so alarm events that happen if these gib won't freak out the guy firing + pShell->SetTeam(m_Team); + // Set this to ignore team hits in case it's lethal + // TODO: Don't hardcode this??? + pShell->SetIgnoresTeamHits(true); + g_MovableMan.AddParticle(pShell); + pShell = 0; + } - if (m_FiredOnce) { m_RestTimer.Reset(); } -} + // Sound the extra Round firing sound, if any is defined + if (!playedRoundFireSound && pRound->HasFireSound()) { + pRound->GetFireSound()->Play(m_Pos); + playedRoundFireSound = true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Activate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activates one of this HDFirearm's features. Analogous to 'pulling -// the trigger'. + delete pRound; + } + pRound = 0; -void HDFirearm::Activate() { - bool wasActivated = m_Activated; - HeldDevice::Activate(); + if (m_FireFrame) { + RunScriptedFunctionInAppropriateScripts("OnFire", false, false); + } + } else { + m_ActivationTimer.Reset(); + } + } else if (m_Activated && !m_AlreadyClicked) { + // Play empty pin click sound. + if (m_EmptySound) { + m_EmptySound->Play(m_Pos); + } + // Indicate that we have clicked once during the current activation. + m_AlreadyClicked = true; + } - if (!IsReloading()) { - if (m_DeactivationSound && m_DeactivationSound->IsBeingPlayed()) { m_DeactivationSound->FadeOut(); } - if (m_ActiveSound && !m_ActiveSound->IsBeingPlayed() && (m_ActiveSound->GetLoopSetting() == -1 || !wasActivated)) { m_ActiveSound->Play(this->m_Pos); } - if (m_PreFireSound && !wasActivated && !m_PreFireSound->IsBeingPlayed()) { m_PreFireSound->Play(this->m_Pos); } - } -} + if (m_Reloading && m_ReloadEndSound) { + // x0.5 the sound length generally just lines up better and leaves less dead air assuming a normal attempt at a ReloadEnd sound + float offsetMilliseconds = m_ReloadEndOffset == -1.0F ? m_ReloadEndSound->GetLength(SoundContainer::LengthOfSoundType::NextPlayed) * 0.5f : m_ReloadEndOffset; + bool shouldPlay = !m_HasPlayedEndReloadSound && m_ReloadTmr.LeftTillSimTimeLimitMS() <= offsetMilliseconds; + if (shouldPlay) { + m_ReloadEndSound->Play(m_Pos); + m_HasPlayedEndReloadSound = true; + } + } + if (m_Reloading && !m_pMagazine && m_pMagazineReference && m_ReloadTmr.IsPastSimTimeLimit()) { + SetMagazine(dynamic_cast(m_pMagazineReference->Clone())); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Deactivate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing -// the trigger'. + m_ActivationTimer.Reset(); + m_LastFireTmr.Reset(); -void HDFirearm::Deactivate() { - bool wasActivated = m_Activated; - HeldDevice::Deactivate(); - m_FiredOnce = false; + if (m_PreFireSound && m_Activated) { + m_PreFireSound->Play(); + } - if (m_PreFireSound) { m_PreFireSound->Stop(); } - if (m_FireSound && m_FireSound->GetLoopSetting() == -1) { m_FireSound->Stop(); } - if (m_DeactivationSound && wasActivated && m_FiredLastFrame) { m_DeactivationSound->Play(m_Pos); } -} + m_HasPlayedEndReloadSound = false; + m_Reloading = false; + m_DoneReloading = true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StopActivationSound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Aborts playing of active sound no matter what. Used to silence spinning -// weapons when weapons swapped - -void HDFirearm::StopActivationSound() -{ - if (m_ActiveSound && m_ActiveSound->IsBeingPlayed()) - m_ActiveSound->Stop(); - - //TODO: Also stop any animation - //Those don't work really, at least we stopped it from making noise - //m_Frame = 0; - //m_Activated = false; - //m_LastFireTmr.SetElapsedSimTimeMS(m_DeactivationDelay + 1); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void HDFirearm::Reload() { - if (!m_Reloading && m_Reloadable) { - bool hadMagazineBeforeReloading = m_pMagazine != nullptr; - if (hadMagazineBeforeReloading) { - Vector constrainedMagazineOffset = g_SceneMan.ShortestDistance(m_Pos, m_pMagazine->GetPos(), g_SceneMan.SceneWrapsX()).SetMagnitude(2.0F); - Vector ejectVector = Vector(2.0F * GetFlipFactor(), 0.0F) + constrainedMagazineOffset.RadRotate(RandomNum(-0.2F, 0.2F)); - m_pMagazine->SetVel(m_Vel + ejectVector); - m_pMagazine->SetAngularVel(RandomNum(-3.0F, 3.0F)); - - if (!m_pMagazine->IsDiscardable()) { m_pMagazine->SetToDelete(); } - RemoveAttachable(m_pMagazine, m_pMagazine->IsDiscardable(), false); - m_pMagazine = 0; - } - - Deactivate(); - if (m_ReloadStartSound) { m_ReloadStartSound->Play(m_Pos); } + // Do stuff to deactivate after being activated + if (!m_Activated) { + // Reset the click indicator. + m_AlreadyClicked = false; - m_ReloadTmr.Reset(); - CorrectReloadTimerForSupportAvailable(); + // Stop any looping activation sounds + if (m_FireSound && m_FireSound->GetLoopSetting() == -1) // && m_FireSound->IsBeingPlayed()) + m_FireSound->Stop(); + } - RunScriptedFunctionInAppropriateScripts("OnReload", false, false, {}, { hadMagazineBeforeReloading ? "true" : "false" }); + ////////////////////////////////////////////// + // Recoil and other activation effects logic. - m_Reloading = true; - } -} + // TODO: don't use arbitrary numbers? + m_RecoilForce.SetMagnitude(std::max(m_RecoilForce.GetMagnitude() * 0.7F - 1.0F, 0.0F)); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (roundsFired > 0) { + // Alternate to get that shake effect! + m_Recoiled = !m_Recoiled; + // Set up the recoil force and shake offsets + if (m_Recoiled) { + m_RecoilForce.SetXY(totalFireForce * m_JointStiffness, 0); + m_RecoilForce = RotateOffset(m_RecoilForce); + m_RecoilForce = -m_RecoilForce; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: NeedsReloading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently in need of being reloaded. - -bool HDFirearm::NeedsReloading() const -{ - if (!m_Reloading && m_Reloadable) { - if (m_pMagazine) - { - // If we've used over half the rounds, we can profitably go ahead and reload - return !m_pMagazine->IsOverHalfFull(); - } - return true; - } - // We're currently reloading - return false; -} + // Set up the recoil shake offset + m_RecoilOffset = m_RecoilForce; + m_RecoilOffset.SetMagnitude(std::min(m_RecoilOffset.GetMagnitude(), 1.0F)); + } + // Screen shake + if (pActor) { + int controllingPlayer = pActor->GetController()->GetPlayer(); + int screenId = g_ActivityMan.GetActivity()->ScreenOfPlayer(controllingPlayer); + if (screenId != -1) { + const float shakiness = g_CameraMan.GetDefaultShakePerUnitOfRecoilEnergy(); + const float maxShakiness = g_CameraMan.GetDefaultShakeFromRecoilMaximum(); // Some weapons fire huge rounds, so restrict the amount + float screenShakeAmount = m_RecoilScreenShakeAmount == -1.0F ? std::min(totalFireForce * m_JointStiffness * shakiness, maxShakiness) : m_RecoilScreenShakeAmount; + g_CameraMan.ApplyScreenShake(screenShakeAmount, screenId); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsFull -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently full and reloading won't have -// any effect. - -bool HDFirearm::IsFull() const -{ - if (!m_Reloading && m_Reloadable) { - if (m_pMagazine) - { - // If we've used over half the rounds, we can profitably go ahead and reload - return m_pMagazine->GetRoundCount() == m_pMagazine->GetCapacity() || m_pMagazine->GetCapacity() < 0; - } - return false; - } - // We're currently reloading - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool HDFirearm::IsEmpty() const { - if (m_pMagazine) { - return m_pMagazine->IsEmpty(); - } - return true; -} + AddImpulseForce(m_RecoilForce, m_RecoilOffset); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Display gun animation + if (!m_IsAnimatedManually && m_FrameCount > 1) { + m_Frame = 1; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this HDFirearm. Supposed to be done every frame. - -void HDFirearm::Update() -{ - HeldDevice::Update(); - - if (m_PreFireSound && m_PreFireSound->IsBeingPlayed()) { m_PreFireSound->SetPosition(m_Pos); } - if (m_FireSound && m_FireSound->IsBeingPlayed()) { m_FireSound->SetPosition(m_Pos); } - if (m_ActiveSound && m_ActiveSound->IsBeingPlayed()) { m_ActiveSound->SetPosition(m_Pos); } - if (m_DeactivationSound && m_DeactivationSound->IsBeingPlayed()) { m_DeactivationSound->SetPosition(m_Pos); } - - Actor *pActor = dynamic_cast(GetRootParent()); - - ///////////////////////////////// - // Activation/firing logic - - int roundsFired = 0; - m_RoundsFired = 0; - float degAimAngle = m_Rotation.GetDegAngle(); - degAimAngle = m_HFlipped ? (180.0F + degAimAngle) : degAimAngle; - float totalFireForce = 0.0F; - m_FireFrame = false; - m_DoneReloading = false; - bool playedRoundFireSound = false; - - if (m_pMagazine && !m_pMagazine->IsEmpty()) - { - if (m_Activated && !(m_PreFireSound && m_PreFireSound->IsBeingPlayed())) { - - double msPerRound = GetMSPerRound(); - if (m_FullAuto) { - // First round should fly as soon as activated and the delays are taken into account - if (!m_FiredOnce && (m_LastFireTmr.GetElapsedSimTimeMS() - m_DeactivationDelay - m_ActivationDelay) > msPerRound) { - roundsFired = 1; - // Wind back the last fire timer appropriately for the first round, but not farther back than 0 - m_LastFireTmr.SetElapsedSimTimeMS(std::max(m_LastFireTmr.GetElapsedSimTimeMS() - msPerRound, 0.0)); + // Display gun flame frame. + if (m_pFlash) { + m_pFlash->SetParentOffset(m_MuzzleOff); + m_pFlash->SetFrame(RandomNum(0, m_pFlash->GetFrameCount() - 1)); + } + + // Play firing sound + // Only start playing if it's not a looping fire sound that is already playing, and if there's a mag + if (m_pMagazine) { + if (m_FireSound && !(m_FireSound->GetLoopSetting() == -1 && m_FireSound->IsBeingPlayed())) { + m_FireSound->Play(m_Pos); } - // How many rounds are going to fly since holding down activation. Make sure gun can't be fired faster by tapping activation fast - if (m_LastFireTmr.GetElapsedSimTimeMS() > (m_ActivationTimer.GetElapsedSimTimeMS() - m_ActivationDelay)) { - roundsFired += (m_ActivationTimer.GetElapsedSimTimeMS() - m_ActivationDelay) / msPerRound; - } else { - roundsFired += m_LastFireTmr.GetElapsedSimTimeMS() / msPerRound; + if (m_FireEchoSound) { + Scene::Area* noEchoArea = g_SceneMan.GetScene()->GetOptionalArea("IndoorArea"); + if (noEchoArea == nullptr || !noEchoArea->IsInside(m_Pos)) { + m_FireEchoSound->Play(m_Pos); + } } - } else { - // TODO: Confirm that the delays work properly in semi-auto! - roundsFired = !m_FiredOnce && (m_LastFireTmr.GetElapsedSimTimeMS() - m_ActivationDelay - m_DeactivationDelay) > msPerRound ? 1 : 0; } - if (roundsFired >= 1) - { - m_FiredOnce = true; - m_FireFrame = true; - m_LastFireTmr.Reset(); - } - - Vector roundVel; - Vector shellVel; - - Round *pRound = 0; - Vector tempNozzle; - Vector tempEject; - MOPixel *pPixel; - float shake, particleSpread, shellSpread, lethalRange; - - lethalRange = m_MaxSharpLength * m_SharpAim + std::max(g_FrameMan.GetPlayerFrameBufferWidth(-1), g_FrameMan.GetPlayerFrameBufferHeight(-1)) * 0.51F; - if (pActor) { - lethalRange += pActor->GetAimDistance(); - } - - // Fire all rounds that were fired this frame. - for (int i = 0; i < roundsFired && !m_pMagazine->IsEmpty(); ++i) - { - m_RoundsFired++; - - pRound = m_pMagazine->PopNextRound(); - shake = (m_ShakeRange - ((m_ShakeRange - m_SharpShakeRange) * m_SharpAim)) * - (m_Supported ? 1.0F : m_NoSupportFactor) * RandomNormalNum(); - tempNozzle = m_MuzzleOff.GetYFlipped(m_HFlipped); - tempNozzle.DegRotate(degAimAngle + shake); - roundVel.SetXY(pRound->GetFireVel(), 0); - roundVel.DegRotate(degAimAngle + shake); - - Vector particlePos; - Vector particleVel; - int particleCountMax = pRound->ParticleCount(); - float lifeVariation = pRound->GetLifeVariation(); - - // Launch all particles in round - MovableObject *pParticle = 0; - while (!pRound->IsEmpty()) - { - pParticle = pRound->PopNextParticle(); - - // Only make the particles separate back behind the nozzle, not in front. This is to avoid silly penetration firings - particlePos = tempNozzle + (roundVel.GetNormalized() * (-RandomNum()) * pRound->GetSeparation()); - pParticle->SetPos(m_Pos + particlePos); - - particleVel = roundVel; - particleSpread = m_ParticleSpreadRange * RandomNormalNum(); - particleVel.DegRotate(particleSpread); - pParticle->SetVel(pRound->GetInheritsFirerVelocity() ? (m_Vel + particleVel) : particleVel); - if (m_LegacyCompatibilityRoundsAlwaysFireUnflipped) { - pParticle->SetRotAngle(particleVel.GetAbsRadAngle()); - } else { - pParticle->SetRotAngle(particleVel.GetAbsRadAngle() + (m_HFlipped ? -c_PI : 0)); - pParticle->SetHFlipped(m_HFlipped); - } - if (lifeVariation != 0 && pParticle->GetLifetime() != 0) { - pParticle->SetLifetime(std::max(static_cast(pParticle->GetLifetime() * (1.0F + (particleCountMax > 1 ? lifeVariation - (lifeVariation * 2.0F * (static_cast(pRound->ParticleCount()) / static_cast(particleCountMax - 1))) : lifeVariation * RandomNormalNum()))), 1)); - } - // F = m * a - totalFireForce += pParticle->GetMass() * pParticle->GetVel().GetMagnitude(); - - // Remove from parent if it's an attachable - Attachable *pAttachable = dynamic_cast(pParticle); - if (pAttachable) { - if (pAttachable->IsAttached()) { - pAttachable->GetParent()->RemoveAttachable(pAttachable); - } - - // Activate if it is some kind of grenade or whatnot. - ThrownDevice *pTD = dynamic_cast(pAttachable); - if (pTD) { - pTD->Activate(); - } - } - - // Set the fired particle to not hit this HeldDevice's parent, if applicable - if (m_FireIgnoresThis) - pParticle->SetWhichMOToNotHit(this, 1.0f); - - // Set the team so alarm events that happen if these gib won't freak out the guy firing - pParticle->SetTeam(m_Team); - - // Also make this not hit team members - // TODO: Don't hardcode this??? - pParticle->SetIgnoresTeamHits(true); - - // Decide for how long until the bullet tumble and start to lose lethality - pPixel = dynamic_cast(pParticle); - if (pPixel) { - // Stray bullets heavily affected by bullet shake lose lethality quicker, as if missing on an imaginary "Z" axis - lethalRange *= std::max(1.0F - std::abs(shake) / 20.0F, 0.1F); - pPixel->SetLethalRange(lethalRange); - } - g_MovableMan.AddParticle(pParticle); - } - pParticle = 0; - - // Launch shell, if there is one. - MovableObject *pShell = pRound->GetShell() ? dynamic_cast(pRound->GetShell()->Clone()) : 0; - if (pShell) - { - tempEject = m_EjectOff.GetYFlipped(m_HFlipped); - shellSpread = m_ShellSpreadRange * RandomNormalNum(); - tempEject.DegRotate(degAimAngle + shellSpread); - pShell->SetPos(m_Pos + tempEject); - - // ##@#@@$ TEMP - shellVel.SetXY(pRound->GetShellVel() * (1.0F - RandomNum(0.0F, m_ShellVelVariation)), 0); - shellVel.DegRotate(degAimAngle + m_ShellEjectAngle * (m_HFlipped ? -1 : 1) + shellSpread); - pShell->SetVel(m_Vel + shellVel); - pShell->SetRotAngle(m_Rotation.GetRadAngle()); - pShell->SetAngularVel(pShell->GetAngularVel() + (m_ShellAngVelRange * RandomNormalNum())); - pShell->SetHFlipped(m_HFlipped); - // Set the ejected shell to not hit this HeldDevice's parent, if applicable - if (m_FireIgnoresThis) - pShell->SetWhichMOToNotHit(this, 1.0f); - // Set the team so alarm events that happen if these gib won't freak out the guy firing - pShell->SetTeam(m_Team); - // Set this to ignore team hits in case it's lethal - // TODO: Don't hardcode this??? - pShell->SetIgnoresTeamHits(true); - g_MovableMan.AddParticle(pShell); - pShell = 0; - } - - // Sound the extra Round firing sound, if any is defined - if (!playedRoundFireSound && pRound->HasFireSound()) - { - pRound->GetFireSound()->Play(m_Pos); - playedRoundFireSound = true; - } - - delete pRound; - } - pRound = 0; - - if (m_FireFrame) { RunScriptedFunctionInAppropriateScripts("OnFire", false, false); } + if (m_Loudness > 0) { + g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, m_Loudness)); + } } else { - m_ActivationTimer.Reset(); + m_Recoiled = false; + if (!m_IsAnimatedManually) { + m_Frame = 0; + } } - } else if (m_Activated && !m_AlreadyClicked) { - // Play empty pin click sound. - if (m_EmptySound) { m_EmptySound->Play(m_Pos); } - // Indicate that we have clicked once during the current activation. - m_AlreadyClicked = true; - } - - if (m_Reloading && m_ReloadEndSound) { - // x0.5 the sound length generally just lines up better and leaves less dead air assuming a normal attempt at a ReloadEnd sound - float offsetMilliseconds = m_ReloadEndOffset == -1.0F ? m_ReloadEndSound->GetLength(SoundContainer::LengthOfSoundType::NextPlayed) * 0.5f : m_ReloadEndOffset; - bool shouldPlay = !m_HasPlayedEndReloadSound && m_ReloadTmr.LeftTillSimTimeLimitMS() <= offsetMilliseconds; - if (shouldPlay) { - m_ReloadEndSound->Play(m_Pos); - m_HasPlayedEndReloadSound = true; - } - } - - if (m_Reloading && !m_pMagazine && m_pMagazineReference && m_ReloadTmr.IsPastSimTimeLimit()) { - SetMagazine(dynamic_cast(m_pMagazineReference->Clone())); - - m_ActivationTimer.Reset(); - m_LastFireTmr.Reset(); - - if (m_PreFireSound && m_Activated) { - m_PreFireSound->Play(); - } - m_HasPlayedEndReloadSound = false; - m_Reloading = false; - m_DoneReloading = true; - } + // Display and override gun animation if there's a special one + if (m_FrameCount > 1) { + if (m_SpriteAnimMode == LOOPWHENACTIVE) { + if (m_Activated || m_LastFireTmr.GetElapsedSimTimeMS() < m_DeactivationDelay) { + // Max rate of the animation when fully activated and firing + int animDuration = m_SpriteAnimDuration; + // Spin up - can only spin up if mag is inserted + if (m_Activated && !m_Reloading && m_ActivationTimer.GetElapsedSimTimeMS() < m_ActivationDelay) { + animDuration = (int)LERP(0, m_ActivationDelay, (float)(m_SpriteAnimDuration * 10), (float)m_SpriteAnimDuration, m_ActivationTimer.GetElapsedSimTimeMS()); + if (m_ActiveSound) { + m_ActiveSound->SetPitch(LERP(0, m_ActivationDelay, 0, 1.0, m_ActivationTimer.GetElapsedSimTimeMS())); + } + } + // Spin down + if ((!m_Activated || m_Reloading) && m_LastFireTmr.GetElapsedSimTimeMS() < m_DeactivationDelay) { + animDuration = (int)LERP(0, m_DeactivationDelay, (float)m_SpriteAnimDuration, (float)(m_SpriteAnimDuration * 10), m_LastFireTmr.GetElapsedSimTimeMS()); + if (m_ActiveSound) { + m_ActiveSound->SetPitch(LERP(0, m_DeactivationDelay, 1.0, 0, m_LastFireTmr.GetElapsedSimTimeMS())); + } + } - // Do stuff to deactivate after being activated - if (!m_Activated) - { - // Reset the click indicator. - m_AlreadyClicked = false; - - // Stop any looping activation sounds - if (m_FireSound && m_FireSound->GetLoopSetting() == -1)// && m_FireSound->IsBeingPlayed()) - m_FireSound->Stop(); - } - - ////////////////////////////////////////////// - // Recoil and other activation effects logic. - - // TODO: don't use arbitrary numbers? - m_RecoilForce.SetMagnitude(std::max(m_RecoilForce.GetMagnitude() * 0.7F - 1.0F, 0.0F)); - - if (roundsFired > 0) { - // Alternate to get that shake effect! - m_Recoiled = !m_Recoiled; - - // Set up the recoil force and shake offsets - if (m_Recoiled) - { - m_RecoilForce.SetXY(totalFireForce * m_JointStiffness, 0); - m_RecoilForce = RotateOffset(m_RecoilForce); - m_RecoilForce = -m_RecoilForce; - - // Set up the recoil shake offset - m_RecoilOffset = m_RecoilForce; - m_RecoilOffset.SetMagnitude(std::min(m_RecoilOffset.GetMagnitude(), 1.0F)); - } - - // Screen shake - if (pActor) { - int controllingPlayer = pActor->GetController()->GetPlayer(); - int screenId = g_ActivityMan.GetActivity()->ScreenOfPlayer(controllingPlayer); - if (screenId != -1) { - const float shakiness = g_CameraMan.GetDefaultShakePerUnitOfRecoilEnergy(); - const float maxShakiness = g_CameraMan.GetDefaultShakeFromRecoilMaximum(); // Some weapons fire huge rounds, so restrict the amount - float screenShakeAmount = m_RecoilScreenShakeAmount == -1.0F ? std::min(totalFireForce * m_JointStiffness * shakiness, maxShakiness) : m_RecoilScreenShakeAmount; - g_CameraMan.ApplyScreenShake(screenShakeAmount, screenId); - } - } - - AddImpulseForce(m_RecoilForce, m_RecoilOffset); - - // Display gun animation - if (!m_IsAnimatedManually && m_FrameCount > 1) { m_Frame = 1; } - - // Display gun flame frame. - if (m_pFlash) { - m_pFlash->SetParentOffset(m_MuzzleOff); - m_pFlash->SetFrame(RandomNum(0, m_pFlash->GetFrameCount() - 1)); - } - - // Play firing sound - // Only start playing if it's not a looping fire sound that is already playing, and if there's a mag - if (m_pMagazine) { - if (m_FireSound && !(m_FireSound->GetLoopSetting() == -1 && m_FireSound->IsBeingPlayed())) { - m_FireSound->Play(m_Pos); - } - if (m_FireEchoSound) { - Scene::Area* noEchoArea = g_SceneMan.GetScene()->GetOptionalArea("IndoorArea"); - if (noEchoArea == nullptr || !noEchoArea->IsInside(m_Pos)) { - m_FireEchoSound->Play(m_Pos); - } - } - } - - if (m_Loudness > 0) { g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, m_Loudness)); } - } else { - m_Recoiled = false; - if (!m_IsAnimatedManually) { m_Frame = 0; } - } - - // Display and override gun animation if there's a special one - if (m_FrameCount > 1) - { - if (m_SpriteAnimMode == LOOPWHENACTIVE) - { - if (m_Activated || m_LastFireTmr.GetElapsedSimTimeMS() < m_DeactivationDelay) { - // Max rate of the animation when fully activated and firing - int animDuration = m_SpriteAnimDuration; - // Spin up - can only spin up if mag is inserted - if (m_Activated && !m_Reloading && m_ActivationTimer.GetElapsedSimTimeMS() < m_ActivationDelay) - { - animDuration = (int)LERP(0, m_ActivationDelay, (float)(m_SpriteAnimDuration * 10), (float)m_SpriteAnimDuration, m_ActivationTimer.GetElapsedSimTimeMS()); - if (m_ActiveSound) { m_ActiveSound->SetPitch(LERP(0, m_ActivationDelay, 0, 1.0, m_ActivationTimer.GetElapsedSimTimeMS())); } - } - // Spin down - if ((!m_Activated || m_Reloading) && m_LastFireTmr.GetElapsedSimTimeMS() < m_DeactivationDelay) - { - animDuration = (int)LERP(0, m_DeactivationDelay, (float)m_SpriteAnimDuration, (float)(m_SpriteAnimDuration * 10), m_LastFireTmr.GetElapsedSimTimeMS()); - if (m_ActiveSound) { m_ActiveSound->SetPitch(LERP(0, m_DeactivationDelay, 1.0, 0, m_LastFireTmr.GetElapsedSimTimeMS())); } - } - - if (animDuration > 0 && !(m_Reloading && m_LastFireTmr.GetElapsedSimTimeMS() >= m_DeactivationDelay)) { - float cycleTime = ((long)m_SpriteAnimTimer.GetElapsedSimTimeMS()) % animDuration; - if (!m_IsAnimatedManually) - m_Frame = std::floor((cycleTime / (float)animDuration) * (float)m_FrameCount); + if (animDuration > 0 && !(m_Reloading && m_LastFireTmr.GetElapsedSimTimeMS() >= m_DeactivationDelay)) { + float cycleTime = ((long)m_SpriteAnimTimer.GetElapsedSimTimeMS()) % animDuration; + if (!m_IsAnimatedManually) + m_Frame = std::floor((cycleTime / (float)animDuration) * (float)m_FrameCount); + } else { + StopActivationSound(); + } } else { + if (!m_IsAnimatedManually) { + m_Frame = 0; + } StopActivationSound(); } - } else { - if (!m_IsAnimatedManually) { m_Frame = 0; } - StopActivationSound(); - } - } - } - - ///////////////////////////////// - // Update fitted Magazine. - - if (m_pMagazine) { - // Recoil offset has to be applied after the Update or it'll get reset within the update - m_pMagazine->SetRecoil(m_RecoilForce, m_RecoilOffset, m_Recoiled); - } + } + } - m_FiredLastFrame = m_FireFrame; + ///////////////////////////////// + // Update fitted Magazine. - // Set the screen flash effect to draw at the final post processing stage - if (m_FireFrame && m_pFlash && m_pFlash->GetScreenEffect()) { - Vector muzzlePos = m_Pos + RotateOffset(m_MuzzleOff + Vector(m_pFlash->GetSpriteWidth() * 0.3F, 0)); - if (m_EffectAlwaysShows || !g_SceneMan.ObscuredPoint(muzzlePos)) { - g_PostProcessMan.RegisterPostEffect(muzzlePos, m_pFlash->GetScreenEffect(), m_pFlash->GetScreenEffectHash(), RandomNum(m_pFlash->GetEffectStopStrength(), m_pFlash->GetEffectStartStrength()), m_pFlash->GetEffectRotAngle()); - } - } -} + if (m_pMagazine) { + // Recoil offset has to be applied after the Update or it'll get reset within the update + m_pMagazine->SetRecoil(m_RecoilForce, m_RecoilOffset, m_Recoiled); + } + m_FiredLastFrame = m_FireFrame; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EstimateDigStrength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Estimates what material strength the rounds in the magazine can destroy. - -float HDFirearm::EstimateDigStrength() const { - return m_pMagazine ? m_pMagazine->EstimateDigStrength() : m_pMagazineReference->EstimateDigStrength(); -} + // Set the screen flash effect to draw at the final post processing stage + if (m_FireFrame && m_pFlash && m_pFlash->GetScreenEffect()) { + Vector muzzlePos = m_Pos + RotateOffset(m_MuzzleOff + Vector(m_pFlash->GetSpriteWidth() * 0.3F, 0)); + if (m_EffectAlwaysShows || !g_SceneMan.ObscuredPoint(muzzlePos)) { + g_PostProcessMan.RegisterPostEffect(muzzlePos, m_pFlash->GetScreenEffect(), m_pFlash->GetScreenEffectHash(), RandomNum(m_pFlash->GetEffectStopStrength(), m_pFlash->GetEffectStartStrength()), m_pFlash->GetEffectRotAngle()); + } + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EstimateDigStrength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Estimates what material strength the rounds in the magazine can destroy. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this HDFirearm's current graphical representation to a -// BITMAP of choice. + float HDFirearm::EstimateDigStrength() const { + return m_pMagazine ? m_pMagazine->EstimateDigStrength() : m_pMagazineReference->EstimateDigStrength(); + } -void HDFirearm::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { - if (m_pFlash && m_FireFrame && !m_pFlash->IsDrawnAfterParent() && mode == g_DrawColor && !onlyPhysical) { - m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this HDFirearm's current graphical representation to a + // BITMAP of choice. - HeldDevice::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + void HDFirearm::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + if (m_pFlash && m_FireFrame && !m_pFlash->IsDrawnAfterParent() && mode == g_DrawColor && !onlyPhysical) { + m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } - if (m_pFlash && m_FireFrame && m_pFlash->IsDrawnAfterParent() && mode == g_DrawColor && !onlyPhysical) { - m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - } -} + HeldDevice::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + if (m_pFlash && m_FireFrame && m_pFlash->IsDrawnAfterParent() && mode == g_DrawColor && !onlyPhysical) { + m_pFlash->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws an aiming aid in front of this HeldDevice. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws an aiming aid in front of this HeldDevice. -void HDFirearm::DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) -{ - if (!m_HUDVisible) - return; + void HDFirearm::DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { + if (!m_HUDVisible) + return; - // Only draw if the team viewing this is on the same team OR has seen the space where this is located - int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); - if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam) - { - if (g_SceneMan.IsUnseen(m_Pos.m_X, m_Pos.m_Y, viewingTeam)) - return; - } + // Only draw if the team viewing this is on the same team OR has seen the space where this is located + int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen)); + if (viewingTeam != m_Team && viewingTeam != Activity::NoTeam) { + if (g_SceneMan.IsUnseen(m_Pos.m_X, m_Pos.m_Y, viewingTeam)) + return; + } - HeldDevice::DrawHUD(pTargetBitmap, targetPos, whichScreen); + HeldDevice::DrawHUD(pTargetBitmap, targetPos, whichScreen); - if (!m_Parent || IsReloading() || m_MaxSharpLength == 0) { - return; - } + if (!m_Parent || IsReloading() || m_MaxSharpLength == 0) { + return; + } - float sharpLength = std::max(m_MaxSharpLength * m_SharpAim, 20.0F); - int glowStrength = RandomNum(95, 159); - int pointCount; - if (playerControlled && sharpLength > 20.0F) { - pointCount = m_SharpAim > 0.5F ? 4 : 3; - } else { - pointCount = 2; - } - int pointSpacing = 10 - pointCount; - sharpLength -= static_cast(pointSpacing * pointCount) * 0.5F; - Vector muzzleOffset(std::max(m_MuzzleOff.m_X, m_SpriteRadius), m_MuzzleOff.m_Y); - - //acquire_bitmap(pTargetBitmap); - for (int i = 0; i < pointCount; ++i) { - Vector aimPoint(sharpLength + static_cast(pointSpacing * i), 0); - aimPoint = RotateOffset(aimPoint + muzzleOffset) + m_Pos; - - g_PostProcessMan.RegisterGlowDotEffect(aimPoint, YellowDot, glowStrength); - aimPoint -= targetPos; - g_SceneMan.WrapPosition(aimPoint); - putpixel(pTargetBitmap, aimPoint.GetFloorIntX(), aimPoint.GetFloorIntY(), g_YellowGlowColor); + float sharpLength = std::max(m_MaxSharpLength * m_SharpAim, 20.0F); + int glowStrength = RandomNum(95, 159); + int pointCount; + if (playerControlled && sharpLength > 20.0F) { + pointCount = m_SharpAim > 0.5F ? 4 : 3; + } else { + pointCount = 2; + } + int pointSpacing = 10 - pointCount; + sharpLength -= static_cast(pointSpacing * pointCount) * 0.5F; + Vector muzzleOffset(std::max(m_MuzzleOff.m_X, m_SpriteRadius), m_MuzzleOff.m_Y); + + // acquire_bitmap(pTargetBitmap); + for (int i = 0; i < pointCount; ++i) { + Vector aimPoint(sharpLength + static_cast(pointSpacing * i), 0); + aimPoint = RotateOffset(aimPoint + muzzleOffset) + m_Pos; + + g_PostProcessMan.RegisterGlowDotEffect(aimPoint, YellowDot, glowStrength); + aimPoint -= targetPos; + g_SceneMan.WrapPosition(aimPoint); + putpixel(pTargetBitmap, aimPoint.GetFloorIntX(), aimPoint.GetFloorIntY(), g_YellowGlowColor); + } + // release_bitmap(pTargetBitmap); } - //release_bitmap(pTargetBitmap); -} } // namespace RTE diff --git a/Source/Entities/HDFirearm.h b/Source/Entities/HDFirearm.h index 4bfa67256..127a60b28 100644 --- a/Source/Entities/HDFirearm.h +++ b/Source/Entities/HDFirearm.h @@ -10,1031 +10,989 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "HeldDevice.h" -namespace RTE -{ - -class Magazine; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: HDFirearm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A firearm device that fires projectile MO's and discharges shell MO's. -// Parent(s): HeldDevice. -// Class history: 07/1/2002 HDFirearm created. - -class HDFirearm : public HeldDevice { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(HDFirearm); -SerializableOverrideMethods; -ClassInfoGetters; -AddScriptFunctionNames(HeldDevice, "OnFire", "OnReload"); - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: HDFirearm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a HDFirearm object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - HDFirearm() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~HDFirearm -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a HDFirearm object before deletion -// from system memory. -// Arguments: None. - - ~HDFirearm() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the HDFirearm object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a HDFirearm to be identical to another, by deep copy. -// Arguments: A reference to the HDFirearm to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const HDFirearm &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire HDFirearm, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); HeldDevice::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetReloadEndOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets reload end offset, in ms. This is how early the ReloadEnd -// sound is played compared to actual end of reload. -// Arguments: None. -// Return value: The reload end offset, in ms. - - int GetReloadEndOffset() const { return m_ReloadEndOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetReloadEndOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets reload end offset, in ms. This is how early the ReloadEnd -// sound is played compared to actual end of reload. -// Arguments: The new reload end offset, in ms. -// Return value: None. - - void SetReloadEndOffset(int newRate) { m_ReloadEndOffset = newRate; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRateOfFire -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rate of fire of this. This applies even if semi-auto. it -// limits how quickly a new round can be fired after the last. -// Arguments: None. -// Return value: The rate of fire, in rounds per min. - - int GetRateOfFire() const { return m_RateOfFire; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetRateOfFire -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the rate of fire of this. This applies even if semi-auto. it -// limits how quickly a new round can be fired after the last. -// Arguments: The new rate of fire, in rounds per min. -// Return value: None. - - void SetRateOfFire(int newRate) { m_RateOfFire = newRate; } - - - /// - /// Gets the minimum time in between shots, in MS. - /// - /// The minimum time in between shots, in MS. - double GetMSPerRound() const { return 60000.0 / static_cast(m_RateOfFire); } - - /// - /// Gets the Magazine of this HDFirearm. - /// - /// A pointer to Magazine of this HDFirearm. Ownership is NOT transferred! - Magazine * GetMagazine() const { return m_pMagazine; } - - /// - /// Sets the Magazine for this HDFirearm. Ownership IS transferred! - /// - /// The new Magazine to use. - void SetMagazine(Magazine *newMagazine); - - /// - /// Gets the flash of this HDFirearm. - /// - /// A pointer to flash of this HDFirearm. Ownership is NOT transferred! - Attachable * GetFlash() const { return m_pFlash; } - - /// - /// Sets the flash for this HDFirearm. Ownership IS transferred! - /// - /// The new flash to use. - void SetFlash(Attachable *newFlash); - - /// - /// Gets the preset name of the next Magazine that will be loaded into this gun. - /// - /// The preset name of the next Magazine that will be loaded into this gun. - std::string GetNextMagazineName() const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetNextMagazineName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the Preset name of the next Magazine that will be loaded into -// this gun. This changes all future mags that will be reloaded. -// Arguments: The preset name of the new Magazine to load into this from now on. -// Return value: Whether the specified magazine was found and successfully prepared. - - bool SetNextMagazineName(std::string magName); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRoundInMagCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of rounds still in the loaded magazine. Negative value -// means infinite ammo. -// Arguments: None. -// Return value: An int with the number of rounds in the magazine currently in this -// HDFirearm. Negative means infinite ammo. - - int GetRoundInMagCount() const; - - /// - /// Gets the maximum RoundCount a Magazine of this HDFirearm can hold. - /// If there is no Magazine, it gets the RoundCount of the reference Magazine. - /// - /// An int with the maximum RoundCount the magazine or magazine reference of this HDFirearm can hold. - int GetRoundInMagCapacity() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the delay before firing. -// Arguments: None. -// Return value: An int with the activation delay in ms. - - int GetActivationDelay() const { return m_ActivationDelay; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetActivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the delay before firing. -// Arguments: An int with the activation delay in ms. -// Return value: None. - - void SetActivationDelay(int delay) { m_ActivationDelay = delay; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeactivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the delay between release of activation and another can be started. -// Arguments: None. -// Return value: An int with the delay in ms. - - int GetDeactivationDelay() const { return m_DeactivationDelay; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDeactivationDelay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the delay between release of activation and another can be started. -// Arguments: An int with the delay in ms. -// Return value: None. - - void SetDeactivationDelay(int delay) { m_DeactivationDelay = delay; }; - - /// - /// Gets the base time this HDFirearm takes to reload, in milliseconds. - /// - /// The base time this HeldDevice takes to reload, in milliseconds. - int GetBaseReloadTime() const { return m_BaseReloadTime; }; - - /// - /// Sets the base time this HDFirearm takes to reload, in milliseconds. - /// - /// The base time this HDFirearm should take to reload, in milliseconds. - void SetBaseReloadTime(int newReloadTime) { m_BaseReloadTime = newReloadTime; CorrectReloadTimerForSupportAvailable(); }; - - /// - /// Gets how long this HDFirearm currently takes to reload, in milliseconds. - /// - /// How long this HDFirearm currently takes to reload, in milliseconds. - int GetReloadTime() const { return m_ReloadTmr.GetSimTimeLimitMS() <= 0 ? m_BaseReloadTime : static_cast(std::floor(m_ReloadTmr.GetSimTimeLimitMS())); }; - - /// - /// Gets whether or not this HDFirearm allows dual-reload, i.e. if it's one-handed and dual-wieldable, it can reload at the same time as another weapon that also allows dual-reload. - /// - /// Whether or not this HDFirearm allows dual-reload. - bool IsDualReloadable() const { return m_DualReloadable; } - - /// - /// Sets whether or not this HDFirearm allows dual-reloading. - /// - /// The new value for whether or not this HDFirearm should allow dual-reloading. - void SetDualReloadable(bool newDualReloadable) { m_DualReloadable = newDualReloadable; } - - /// - /// Gets the multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. - /// - /// The multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. - float GetOneHandedReloadTimeMultiplier() const { return m_OneHandedReloadTimeMultiplier; } - - /// - /// Sets the multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. - /// - /// The new multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. - void SetOneHandedReloadTimeMultiplier(float newOneHandedReloadTimeMultiplier) { m_OneHandedReloadTimeMultiplier = newOneHandedReloadTimeMultiplier; } - - /// - /// Gets the reload angle this HDFirearm will use when support is available. - /// - /// The reload angle this HDFirearm will use when support is available, in radians. - float GetReloadAngle() const { return m_ReloadAngle; } - - /// - /// Sets the reload angle this HDFirearm should use when support is available. - /// - /// The new reload angle this HDFirearm should use when support is available. - void SetReloadAngle(float newReloadAngle) { m_ReloadAngle = newReloadAngle; } - - /// - /// Gets the reload angle this HDFirearm will use when support is not available. - /// - /// The reload angle this HDFirearm will use when support is not available, in radians. - float GetOneHandedReloadAngle() const { return m_OneHandedReloadAngle; } - - /// - /// Sets the reload angle this HDFirearm should use when support is not available. - /// - /// The new reload angle this HDFirearm should use when support is not available. - void SetOneHandedReloadAngle(float newOneHandedReloadAngle) { m_OneHandedReloadAngle = newOneHandedReloadAngle; } - - /// - /// Gets the reload angle this HDFirearm is currently using, based on whether or not support is available. - /// - /// The current reload angle of this HDFirearm, in radians. - float GetCurrentReloadAngle() const { return m_SupportAvailable ? m_ReloadAngle : m_OneHandedReloadAngle; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetShakeRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the range of normal shaking of entire weapon. -// Arguments: None. -// Return value: A float with the range in degrees. - - float GetShakeRange() const { return m_ShakeRange; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetShakeRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the range of normal shaking of entire weapon. -// Arguments: A float with the range in degrees. -// Return value: None. - - void SetShakeRange(float range) { m_ShakeRange = range; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSharpShakeRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the range of shaking of entire weapon during sharp aiming. -// Arguments: None. -// Return value: A float with the range in degrees. - - float GetSharpShakeRange() const { return m_SharpShakeRange; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSharpShakeRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the range of shaking of entire weapon during sharp aiming. -// Arguments: A float with the range in degrees. -// Return value: None. - - void SetSharpShakeRange(float range) { m_SharpShakeRange = range; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNoSupportFactor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the factor for how much more weapon shakes if it isn't supported -// by a second hand. -// Arguments: None. -// Return value: A float with the factor. - - float GetNoSupportFactor() const { return m_NoSupportFactor; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetNoSupportFactor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the factor for how much more weapon shakes if it isn't supported -// by a second hand. -// Arguments: A float with the factor. -// Return value: None. - - void SetNoSupportFactor(float factor) { m_NoSupportFactor = factor; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetParticleSpreadRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the range of spread angle of fired particles, in one direction. -// Arguments: None. -// Return value: A float with the range in degrees. - - float GetParticleSpreadRange() const { return m_ParticleSpreadRange; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetParticleSpreadRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the range of spread angle of fired particles, in one direction. -// Arguments: A float with the range in degrees. -// Return value: None. - - void SetParticleSpreadRange(float range) { m_ParticleSpreadRange = range; }; - - /// - /// Gets the random velocity variation scalar at which this HDFirearm's shell is to be ejected. - /// - /// A float with the scalar value. - float GetShellVelVariation() const { return m_ShellVelVariation; } - - /// - /// Sets the random velocity variation scalar at which this HDFirearm's shell is to be ejected. - /// - /// The new velocity variation scalar. - void SetShellVelVariation(float newVariation) { m_ShellVelVariation = newVariation; } - - /// - /// Sets the stiffness scalar of the joint of this HDFirearm. Unlike Attachable::SetJointStiffness, there are no limitations on this value. - /// 1.0 means impulse forces on this attachable will be transferred to the parent with 100% strength, 0 means they will not transfer at all, negative values will apply negative force, which may behave oddly. - /// - /// A float describing the normalized stiffness scalar of this Attachable's joint. - void SetJointStiffness(float jointStiffness) override { m_JointStiffness = jointStiffness; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIFireVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the velocity the AI use when aiming this weapon. -// Arguments: None. -// Return value: A float with the velocity in m/s. - - float GetAIFireVel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIBulletLifeTime -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bullet life time the AI use when aiming this weapon. -// Arguments: None. -// Return value: A float with the life time in ms. - - unsigned long GetAIBulletLifeTime(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBulletAccScalar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. -// Arguments: None. -// Return value: A float with the scalar. - - float GetBulletAccScalar(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIBlastRadius -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the blast radius the AI use when aiming this weapon. -// Arguments: None. -// Return value: A float with the blast radius in pixels. - - float GetAIBlastRadius() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIPenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how much material the projectiles from this weapon can destory. -// Arguments: None. -// Return value: A float with the material strength. - - float GetAIPenetration() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CompareTrajectories -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Estimates how close the projectiles from two weapons will land. -// Arguments: A HDFirearm pointer to compare with. -// Return value: A float with the distance in pixels. - - float CompareTrajectories(HDFirearm * pWeapon); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMagazinePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the magazine or other equivalent point of -// this. -// Arguments: None. -// Return value: A vector describing the absolute world coordinates for the magazine -// attachment point of this - - Vector GetMagazinePos() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMuzzlePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the muzzle or other equivalent point of -// this. -// Arguments: None. -// Return value: A vector describing the absolute world coordinates for the muzzle point -// of this - - Vector GetMuzzlePos() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMuzzleOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the unrotated relative offset from the position to the muzzle or -// other equivalent point of this. -// Arguments: None. -// Return value: A unrotated vector describing the relative for the muzzle point of -// this from this' position. - - Vector GetMuzzleOffset() const override { return m_MuzzleOff; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetMuzzleOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the unrotated relative offset from the position to the muzzle or -// other equivalent point of this. -// Arguments: Bew ofsset value. -// Return value: None. - - void SetMuzzleOffset(Vector newOffset) override { m_MuzzleOff = newOffset; } - - /// - /// Gets this HDFirearm's pre fire sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's pre fire sound. - SoundContainer * GetPreFireSound() const { return m_PreFireSound; } - - /// - /// Sets this HDFirearm's pre fire sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's pre fire sound. - void SetPreFireSound(SoundContainer *newSound) { m_PreFireSound = newSound; } - - /// - /// Gets this HDFirearm's fire sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's fire sound. - SoundContainer * GetFireSound() const { return m_FireSound; } - - /// - /// Sets this HDFirearm's fire sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's fire sound. - void SetFireSound(SoundContainer *newSound) { m_FireSound = newSound; } - - /// - /// Gets this HDFirearm's fire echo sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's fire echo sound. - SoundContainer * GetFireEchoSound() const { return m_FireEchoSound; } - - /// - /// Sets this HDFirearm's fire echo sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's fire echo sound. - void SetFireEchoSound(SoundContainer *newSound) { m_FireEchoSound = newSound; } - - /// - /// Gets this HDFirearm's active sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's active sound. - SoundContainer * GetActiveSound() const { return m_ActiveSound; } - - /// - /// Sets this HDFirearm's active sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's active sound. - void SetActiveSound(SoundContainer *newSound) { m_ActiveSound = newSound; } - - /// - /// Gets this HDFirearm's deactivation sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's deactivation sound. - SoundContainer * GetDeactivationSound() const { return m_DeactivationSound; } - - /// - /// Sets this HDFirearm's deactivation sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's deactivation sound. - void SetDeactivationSound(SoundContainer *newSound) { m_DeactivationSound = newSound; } - - /// - /// Gets this HDFirearm's empty sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's empty sound. - SoundContainer * GetEmptySound() const { return m_EmptySound; } - - /// - /// Sets this HDFirearm's empty sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's empty sound. - void SetEmptySound(SoundContainer *newSound) { m_EmptySound = newSound; } - - /// - /// Gets this HDFirearm's reload start sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's reload start sound. - SoundContainer * GetReloadStartSound() const { return m_ReloadStartSound; } - - /// - /// Sets this HDFirearm's reload start sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's reload start sound. - void SetReloadStartSound(SoundContainer *newSound) { m_ReloadStartSound = newSound; } - - /// - /// Gets this HDFirearm's reload end sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this HDFirearm's reload end sound. - SoundContainer * GetReloadEndSound() const { return m_ReloadEndSound; } - - /// - /// Sets this HDFirearm's reload end sound. Ownership IS transferred! - /// - /// The new SoundContainer for this HDFirearm's reload end sound. - void SetReloadEndSound(SoundContainer *newSound) { m_ReloadEndSound = newSound; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ResetAllTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resest all the timers used by this. Can be emitters, etc. This is to -// prevent backed up emissions to come out all at once while this has been -// held dormant in an inventory. -// Arguments: None. -// Return value: None. - - void ResetAllTimers() override { HeldDevice::ResetAllTimers(); m_LastFireTmr.Reset(); m_ReloadTmr.Reset(); } - - /// - /// Gets this HDFirearm's reload progress as a scalar from 0 to 1. - /// - /// The reload progress as a scalar from 0 to 1. - float GetReloadProgress() const { return IsReloading() && m_BaseReloadTime > 0 ? static_cast(m_ReloadTmr.SimTimeLimitProgress()) : 1.0F; } - - /// - /// Does the calculations necessary to detect whether this HDFirearm is at rest or not. IsAtRest() retrieves the answer. - /// - void RestDetection() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Activate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activates one of this HDFirearm's features. Analogous to 'pulling -// the trigger'. -// Arguments: None. -// Return value: None. - - void Activate() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Deactivate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing -// the trigger'. -// Arguments: None. -// Return value: None. - - void Deactivate() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StopActivationSound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Aborts playing of active sound no matter what. Used to silence spinning -// weapons when weapons swapped -// Arguments: None. -// Return value: None. - - void StopActivationSound(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reload -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Throws out the currently used Magazine, if any, and puts in a new one -// after the reload delay is up. -// Arguments: None. -// Return value: None. - - void Reload() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsReloading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently being reloaded. -// Arguments: None. -// Return value: Whetehr being reloaded. - - bool IsReloading() const override { return m_Reloading; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DoneReloading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device just finished reloading this frame. -// Arguments: None. -// Return value: Whether just done reloading this frame. - - bool DoneReloading() const override { return m_DoneReloading; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: NeedsReloading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently in need of being reloaded. -// Arguments: None. -// Return value: Whetehr in need of reloading (ie not full). - - bool NeedsReloading() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsFull -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently full and reloading won't have -// any effect. -// Arguments: None. -// Return value: Whetehr magazine is full or not. - - bool IsFull() const override; - - bool IsEmpty() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsFullAuto -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is fully automatic or not. -// Arguments: None. -// Return value: Whether the player can hold down fire and this will fire repeatedly. - - bool IsFullAuto() const { return m_FullAuto; } - - /// - /// Gets whether this HDFirearm is set to be reloadable or not. - /// - /// Whether this HDFirearm is reloadable. - bool IsReloadable() const { return m_Reloadable; } - - /// - /// Sets whether this HDFirearm is reloadable or not and halts the reloading process. - /// - /// Whether this HDFirearm is reloadable. - void SetReloadable(bool isReloadable) { m_Reloadable = isReloadable; m_Reloading = m_Reloading && m_Reloadable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFullAuto -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether the device is fully automatic or not. -// Arguments: New value. -// Return value: None. - - void SetFullAuto(bool newValue) { m_FullAuto = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this HDFirearm's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws an aiming aid in front of this HeldDevice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// Which player's screen this is being drawn to. May affect what HUD elements -// get drawn etc. -// Return value: None. - - void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EstimateDigStrength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Estimates what material strength one round in the magazine can destroy. -// Arguments: None. -// Return value: The maximum material strength the regular or the tracer round can destroy. - - float EstimateDigStrength() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FiredOnce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Whether at least one round has already been fired during the current activation. -// Arguments: None. -// Return value: Returns true if at least one round has already been fired during the current activation. - - bool FiredOnce() const { return m_FiredOnce; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FiredFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Whether at least one round has already been fired during the current frame. -// Arguments: None. -// Return value: Returns true at least one round has already been fired during the current frame. - - bool FiredFrame() const { return m_FireFrame; } - - /// - /// Gets whether this HDFirearm is ready to be fired. - /// - /// Whether this HDFirearm is ready to pop another Round. - bool CanFire() const { return m_LastFireTmr.IsPastSimMS(GetMSPerRound()); } - - /// - /// Gets whether this HDFirearm is halfway to be fired. Used for evenly spacing out dual-wielded fire. - /// - /// Whether this HDFirearm is halfway to pop another Round. - bool HalfwayToNextRound() const { return m_LastFireTmr.IsPastSimMS(GetMSPerRound() / 2.0); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RoundsFired -////////////////////////////////////////////////////////////////////////////////////////// -// Description: How many rounds were fired during this frame. -// Arguments: None. -// Return value: Returns the number of rounds fired during this frame. - - int RoundsFired() const { return m_RoundsFired; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsAnimatedManually -////////////////////////////////////////////////////////////////////////////////////////// -// Description: If true then the m_Frame property is not changed bye the Update function -// Arguments: None. -// Return value: Whether this HDFirearm is animated manually. - - bool IsAnimatedManually() const { return m_IsAnimatedManually; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAnimatedManually -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets Whether this HDFirearm is animated manually. -// Arguments: Manual animation flag value. -// Return value: None. - - void SetAnimatedManually(bool newValue) { m_IsAnimatedManually = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Sets this Attachable's parent MOSRotating, and also sets its Team based on its parent and, if the Attachable is set to collide, adds/removes Atoms to its new/old parent. - /// Additionally, sets this HDFirearm as not firing or reloading, and resets its reload timer. - /// - /// A pointer to the MOSRotating to set as the new parent. Ownership is NOT transferred! - void SetParent(MOSRotating *newParent) override { HeldDevice::SetParent(newParent); Deactivate(); m_Reloading = false; m_ReloadTmr.Reset(); } - - // Member variables. - static Entity::ClassInfo m_sClass; - - // The mag reference which all current mags are generated from. - // NOT owned by this, owned by PresetMan - const Magazine *m_pMagazineReference; - // Magazine MovableObject. Owned - Magazine *m_pMagazine; - // Muzzle Flash Attachable. Owned - Attachable *m_pFlash; - - SoundContainer *m_PreFireSound; //!< The sound this HDFirearm should play before it starts firing. Distinct from activation sound in that it will play exactly once per trigger pull and not pitch up. - // The audio of this FireArm being fired. - SoundContainer *m_FireSound; - SoundContainer *m_FireEchoSound; //!< The audio that is played as the echo for the gun. Each shot will restart this sound, so it doesn't ever overlap. - // The audio that is played immediately upon activation, but perhaps before actual first firing, if there's a pre-delay - SoundContainer *m_ActiveSound; - // The audio that is played immediately upon cease of activation - SoundContainer *m_DeactivationSound; - // The audio of this FireArm being fired empty. - SoundContainer *m_EmptySound; - // The audio of this FireArm being reloaded. - SoundContainer *m_ReloadStartSound; - SoundContainer *m_ReloadEndSound; - // The offset of how long before the reload finishes the sound plays - float m_ReloadEndOffset; - // Whether or not the end-of-relaod sound has already been played or not. - bool m_HasPlayedEndReloadSound; - - // Rate of fire, in rounds per min. - // If 0, firearm is semi-automatic (ie only one discharge per activation). - int m_RateOfFire; - // Delay between activation and full round output is achieved, in ms - int m_ActivationDelay; - // Delay between release of activation and another can be started, in ms - int m_DeactivationDelay; - // Reloading or not - bool m_Reloading; - // Just done reloading this frame - bool m_DoneReloading; - // Base reload time in millisecs. - int m_BaseReloadTime; - // Whether this HDFirearm is full or semi-auto. - bool m_FullAuto; - // Whether particles fired from this HDFirearm will ignore hits with itself, - // and the root parent of this HDFirearm, regardless if they are set to hit MOs. - bool m_FireIgnoresThis; - bool m_Reloadable; //!< Whether this HDFirearm is reloadable by normal means. - float m_OneHandedReloadTimeMultiplier; //!< The multiplier for how long this weapon takes to reload when being used one-handed. Only relevant for one-handed weapons. - bool m_DualReloadable; //!< Whether or not this weapon can be dual-reloaded, i.e. both guns can reload at once instead of having to wait til the other dual-wielded gun isn't being reloaded. Only relevant for one-handed weapons. - float m_ReloadAngle; //!< The angle offset for the default reload animation, in radians. - float m_OneHandedReloadAngle; //!< The angle offset for one-handed reload animation, in radians. - - // Timer for timing how long ago the last round was fired. - Timer m_LastFireTmr; - // Timer for timing reload times. - Timer m_ReloadTmr; - - // The point from where the projectiles appear. - Vector m_MuzzleOff; - // The point from where the discharged shells appear. - Vector m_EjectOff; - // Offset to magazine. - Vector m_MagOff; - // Range of normal shaking of entire weapon. - float m_ShakeRange; - // Range of shaking of entire weapon during sharp aiming. - float m_SharpShakeRange; - // Factor for how much more weapon shakes if it isn't supported by a second hand. - float m_NoSupportFactor; - // Range of spread angle of fired particles, in one direction - float m_ParticleSpreadRange; - // Angle in which shells are ejected relative to this weapon - float m_ShellEjectAngle; - // Range of spread angle of ejected shells, in one direction - float m_ShellSpreadRange; - // Range of spread in ang vel of ejected shells, in one direction - float m_ShellAngVelRange; - float m_ShellVelVariation; //!< The velocity variation scalar of ejected shells. - // The amount of screenshake that recoil causes - float m_RecoilScreenShakeAmount; - // The muzzle velocity the AI use when aiming this weapon - float m_AIFireVel; - // The bullet life time the AI use when aiming this weapon - unsigned long m_AIBulletLifeTime; - // The bullet acc scalar the AI use when aiming this weapon - float m_AIBulletAccScalar; - - // Whether at least one round has already been - // fired during the current activation. - bool m_FiredOnce; - // Whether at least one round has already been - // fired during the current frame. - bool m_FireFrame; - // Whether at least one round was fired during the last frame - bool m_FiredLastFrame; - // Whether, if this HDFireArm is empty, pin has already clicked once during - // current acticvation. - bool m_AlreadyClicked; - // How many rounds were fired during this frame - int m_RoundsFired; - // If true m_Frame is not changed during an update hence the animation - // is done by external Lua code - bool m_IsAnimatedManually; - - - bool m_LegacyCompatibilityRoundsAlwaysFireUnflipped; // - /// Ensures the reload Timer's time limit is set accordingly, based on whether the HDFirearm has support available. - /// - void CorrectReloadTimerForSupportAvailable() { m_ReloadTmr.SetSimTimeLimitMS(static_cast(static_cast(m_BaseReloadTime) * (m_SupportAvailable ? 1.0F : m_OneHandedReloadTimeMultiplier))); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this HDFirearm, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - HDFirearm(const HDFirearm &reference) = delete; - HDFirearm & operator=(const HDFirearm &rhs) = delete; - -}; +namespace RTE { + + class Magazine; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: HDFirearm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A firearm device that fires projectile MO's and discharges shell MO's. + // Parent(s): HeldDevice. + // Class history: 07/1/2002 HDFirearm created. + + class HDFirearm : public HeldDevice { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(HDFirearm); + SerializableOverrideMethods; + ClassInfoGetters; + AddScriptFunctionNames(HeldDevice, "OnFire", "OnReload"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: HDFirearm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a HDFirearm object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + HDFirearm() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~HDFirearm + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a HDFirearm object before deletion + // from system memory. + // Arguments: None. + + ~HDFirearm() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the HDFirearm object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a HDFirearm to be identical to another, by deep copy. + // Arguments: A reference to the HDFirearm to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const HDFirearm& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire HDFirearm, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + HeldDevice::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetReloadEndOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets reload end offset, in ms. This is how early the ReloadEnd + // sound is played compared to actual end of reload. + // Arguments: None. + // Return value: The reload end offset, in ms. + + int GetReloadEndOffset() const { return m_ReloadEndOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetReloadEndOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets reload end offset, in ms. This is how early the ReloadEnd + // sound is played compared to actual end of reload. + // Arguments: The new reload end offset, in ms. + // Return value: None. + + void SetReloadEndOffset(int newRate) { m_ReloadEndOffset = newRate; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRateOfFire + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rate of fire of this. This applies even if semi-auto. it + // limits how quickly a new round can be fired after the last. + // Arguments: None. + // Return value: The rate of fire, in rounds per min. + + int GetRateOfFire() const { return m_RateOfFire; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRateOfFire + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the rate of fire of this. This applies even if semi-auto. it + // limits how quickly a new round can be fired after the last. + // Arguments: The new rate of fire, in rounds per min. + // Return value: None. + + void SetRateOfFire(int newRate) { m_RateOfFire = newRate; } + + /// + /// Gets the minimum time in between shots, in MS. + /// + /// The minimum time in between shots, in MS. + double GetMSPerRound() const { return 60000.0 / static_cast(m_RateOfFire); } + + /// + /// Gets the Magazine of this HDFirearm. + /// + /// A pointer to Magazine of this HDFirearm. Ownership is NOT transferred! + Magazine* GetMagazine() const { return m_pMagazine; } + + /// + /// Sets the Magazine for this HDFirearm. Ownership IS transferred! + /// + /// The new Magazine to use. + void SetMagazine(Magazine* newMagazine); + + /// + /// Gets the flash of this HDFirearm. + /// + /// A pointer to flash of this HDFirearm. Ownership is NOT transferred! + Attachable* GetFlash() const { return m_pFlash; } + + /// + /// Sets the flash for this HDFirearm. Ownership IS transferred! + /// + /// The new flash to use. + void SetFlash(Attachable* newFlash); + + /// + /// Gets the preset name of the next Magazine that will be loaded into this gun. + /// + /// The preset name of the next Magazine that will be loaded into this gun. + std::string GetNextMagazineName() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetNextMagazineName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the Preset name of the next Magazine that will be loaded into + // this gun. This changes all future mags that will be reloaded. + // Arguments: The preset name of the new Magazine to load into this from now on. + // Return value: Whether the specified magazine was found and successfully prepared. + + bool SetNextMagazineName(std::string magName); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRoundInMagCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of rounds still in the loaded magazine. Negative value + // means infinite ammo. + // Arguments: None. + // Return value: An int with the number of rounds in the magazine currently in this + // HDFirearm. Negative means infinite ammo. + + int GetRoundInMagCount() const; + + /// + /// Gets the maximum RoundCount a Magazine of this HDFirearm can hold. + /// If there is no Magazine, it gets the RoundCount of the reference Magazine. + /// + /// An int with the maximum RoundCount the magazine or magazine reference of this HDFirearm can hold. + int GetRoundInMagCapacity() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the delay before firing. + // Arguments: None. + // Return value: An int with the activation delay in ms. + + int GetActivationDelay() const { return m_ActivationDelay; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetActivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the delay before firing. + // Arguments: An int with the activation delay in ms. + // Return value: None. + + void SetActivationDelay(int delay) { m_ActivationDelay = delay; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeactivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the delay between release of activation and another can be started. + // Arguments: None. + // Return value: An int with the delay in ms. + + int GetDeactivationDelay() const { return m_DeactivationDelay; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDeactivationDelay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the delay between release of activation and another can be started. + // Arguments: An int with the delay in ms. + // Return value: None. + + void SetDeactivationDelay(int delay) { m_DeactivationDelay = delay; }; + + /// + /// Gets the base time this HDFirearm takes to reload, in milliseconds. + /// + /// The base time this HeldDevice takes to reload, in milliseconds. + int GetBaseReloadTime() const { return m_BaseReloadTime; }; + + /// + /// Sets the base time this HDFirearm takes to reload, in milliseconds. + /// + /// The base time this HDFirearm should take to reload, in milliseconds. + void SetBaseReloadTime(int newReloadTime) { + m_BaseReloadTime = newReloadTime; + CorrectReloadTimerForSupportAvailable(); + }; + + /// + /// Gets how long this HDFirearm currently takes to reload, in milliseconds. + /// + /// How long this HDFirearm currently takes to reload, in milliseconds. + int GetReloadTime() const { return m_ReloadTmr.GetSimTimeLimitMS() <= 0 ? m_BaseReloadTime : static_cast(std::floor(m_ReloadTmr.GetSimTimeLimitMS())); }; + + /// + /// Gets whether or not this HDFirearm allows dual-reload, i.e. if it's one-handed and dual-wieldable, it can reload at the same time as another weapon that also allows dual-reload. + /// + /// Whether or not this HDFirearm allows dual-reload. + bool IsDualReloadable() const { return m_DualReloadable; } + + /// + /// Sets whether or not this HDFirearm allows dual-reloading. + /// + /// The new value for whether or not this HDFirearm should allow dual-reloading. + void SetDualReloadable(bool newDualReloadable) { m_DualReloadable = newDualReloadable; } + + /// + /// Gets the multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. + /// + /// The multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. + float GetOneHandedReloadTimeMultiplier() const { return m_OneHandedReloadTimeMultiplier; } + + /// + /// Sets the multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. + /// + /// The new multiplier to be applied to reload time when this HDFirearm is being reloaded one-handed. + void SetOneHandedReloadTimeMultiplier(float newOneHandedReloadTimeMultiplier) { m_OneHandedReloadTimeMultiplier = newOneHandedReloadTimeMultiplier; } + + /// + /// Gets the reload angle this HDFirearm will use when support is available. + /// + /// The reload angle this HDFirearm will use when support is available, in radians. + float GetReloadAngle() const { return m_ReloadAngle; } + + /// + /// Sets the reload angle this HDFirearm should use when support is available. + /// + /// The new reload angle this HDFirearm should use when support is available. + void SetReloadAngle(float newReloadAngle) { m_ReloadAngle = newReloadAngle; } + + /// + /// Gets the reload angle this HDFirearm will use when support is not available. + /// + /// The reload angle this HDFirearm will use when support is not available, in radians. + float GetOneHandedReloadAngle() const { return m_OneHandedReloadAngle; } + + /// + /// Sets the reload angle this HDFirearm should use when support is not available. + /// + /// The new reload angle this HDFirearm should use when support is not available. + void SetOneHandedReloadAngle(float newOneHandedReloadAngle) { m_OneHandedReloadAngle = newOneHandedReloadAngle; } + + /// + /// Gets the reload angle this HDFirearm is currently using, based on whether or not support is available. + /// + /// The current reload angle of this HDFirearm, in radians. + float GetCurrentReloadAngle() const { return m_SupportAvailable ? m_ReloadAngle : m_OneHandedReloadAngle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetShakeRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the range of normal shaking of entire weapon. + // Arguments: None. + // Return value: A float with the range in degrees. + + float GetShakeRange() const { return m_ShakeRange; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetShakeRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the range of normal shaking of entire weapon. + // Arguments: A float with the range in degrees. + // Return value: None. + + void SetShakeRange(float range) { m_ShakeRange = range; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSharpShakeRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the range of shaking of entire weapon during sharp aiming. + // Arguments: None. + // Return value: A float with the range in degrees. + + float GetSharpShakeRange() const { return m_SharpShakeRange; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSharpShakeRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the range of shaking of entire weapon during sharp aiming. + // Arguments: A float with the range in degrees. + // Return value: None. + + void SetSharpShakeRange(float range) { m_SharpShakeRange = range; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNoSupportFactor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the factor for how much more weapon shakes if it isn't supported + // by a second hand. + // Arguments: None. + // Return value: A float with the factor. + + float GetNoSupportFactor() const { return m_NoSupportFactor; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetNoSupportFactor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the factor for how much more weapon shakes if it isn't supported + // by a second hand. + // Arguments: A float with the factor. + // Return value: None. + + void SetNoSupportFactor(float factor) { m_NoSupportFactor = factor; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetParticleSpreadRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the range of spread angle of fired particles, in one direction. + // Arguments: None. + // Return value: A float with the range in degrees. + + float GetParticleSpreadRange() const { return m_ParticleSpreadRange; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetParticleSpreadRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the range of spread angle of fired particles, in one direction. + // Arguments: A float with the range in degrees. + // Return value: None. + + void SetParticleSpreadRange(float range) { m_ParticleSpreadRange = range; }; + + /// + /// Gets the random velocity variation scalar at which this HDFirearm's shell is to be ejected. + /// + /// A float with the scalar value. + float GetShellVelVariation() const { return m_ShellVelVariation; } + + /// + /// Sets the random velocity variation scalar at which this HDFirearm's shell is to be ejected. + /// + /// The new velocity variation scalar. + void SetShellVelVariation(float newVariation) { m_ShellVelVariation = newVariation; } + + /// + /// Sets the stiffness scalar of the joint of this HDFirearm. Unlike Attachable::SetJointStiffness, there are no limitations on this value. + /// 1.0 means impulse forces on this attachable will be transferred to the parent with 100% strength, 0 means they will not transfer at all, negative values will apply negative force, which may behave oddly. + /// + /// A float describing the normalized stiffness scalar of this Attachable's joint. + void SetJointStiffness(float jointStiffness) override { m_JointStiffness = jointStiffness; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIFireVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the velocity the AI use when aiming this weapon. + // Arguments: None. + // Return value: A float with the velocity in m/s. + + float GetAIFireVel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIBulletLifeTime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bullet life time the AI use when aiming this weapon. + // Arguments: None. + // Return value: A float with the life time in ms. + + unsigned long GetAIBulletLifeTime(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBulletAccScalar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. + // Arguments: None. + // Return value: A float with the scalar. + + float GetBulletAccScalar(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIBlastRadius + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the blast radius the AI use when aiming this weapon. + // Arguments: None. + // Return value: A float with the blast radius in pixels. + + float GetAIBlastRadius() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIPenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how much material the projectiles from this weapon can destory. + // Arguments: None. + // Return value: A float with the material strength. + + float GetAIPenetration() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CompareTrajectories + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Estimates how close the projectiles from two weapons will land. + // Arguments: A HDFirearm pointer to compare with. + // Return value: A float with the distance in pixels. + + float CompareTrajectories(HDFirearm* pWeapon); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMagazinePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the magazine or other equivalent point of + // this. + // Arguments: None. + // Return value: A vector describing the absolute world coordinates for the magazine + // attachment point of this + + Vector GetMagazinePos() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMuzzlePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the muzzle or other equivalent point of + // this. + // Arguments: None. + // Return value: A vector describing the absolute world coordinates for the muzzle point + // of this + + Vector GetMuzzlePos() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMuzzleOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the unrotated relative offset from the position to the muzzle or + // other equivalent point of this. + // Arguments: None. + // Return value: A unrotated vector describing the relative for the muzzle point of + // this from this' position. + + Vector GetMuzzleOffset() const override { return m_MuzzleOff; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetMuzzleOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the unrotated relative offset from the position to the muzzle or + // other equivalent point of this. + // Arguments: Bew ofsset value. + // Return value: None. + + void SetMuzzleOffset(Vector newOffset) override { m_MuzzleOff = newOffset; } + + /// + /// Gets this HDFirearm's pre fire sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's pre fire sound. + SoundContainer* GetPreFireSound() const { return m_PreFireSound; } + + /// + /// Sets this HDFirearm's pre fire sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's pre fire sound. + void SetPreFireSound(SoundContainer* newSound) { m_PreFireSound = newSound; } + + /// + /// Gets this HDFirearm's fire sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's fire sound. + SoundContainer* GetFireSound() const { return m_FireSound; } + + /// + /// Sets this HDFirearm's fire sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's fire sound. + void SetFireSound(SoundContainer* newSound) { m_FireSound = newSound; } + + /// + /// Gets this HDFirearm's fire echo sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's fire echo sound. + SoundContainer* GetFireEchoSound() const { return m_FireEchoSound; } + + /// + /// Sets this HDFirearm's fire echo sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's fire echo sound. + void SetFireEchoSound(SoundContainer* newSound) { m_FireEchoSound = newSound; } + + /// + /// Gets this HDFirearm's active sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's active sound. + SoundContainer* GetActiveSound() const { return m_ActiveSound; } + + /// + /// Sets this HDFirearm's active sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's active sound. + void SetActiveSound(SoundContainer* newSound) { m_ActiveSound = newSound; } + + /// + /// Gets this HDFirearm's deactivation sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's deactivation sound. + SoundContainer* GetDeactivationSound() const { return m_DeactivationSound; } + + /// + /// Sets this HDFirearm's deactivation sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's deactivation sound. + void SetDeactivationSound(SoundContainer* newSound) { m_DeactivationSound = newSound; } + + /// + /// Gets this HDFirearm's empty sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's empty sound. + SoundContainer* GetEmptySound() const { return m_EmptySound; } + + /// + /// Sets this HDFirearm's empty sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's empty sound. + void SetEmptySound(SoundContainer* newSound) { m_EmptySound = newSound; } + + /// + /// Gets this HDFirearm's reload start sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's reload start sound. + SoundContainer* GetReloadStartSound() const { return m_ReloadStartSound; } + + /// + /// Sets this HDFirearm's reload start sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's reload start sound. + void SetReloadStartSound(SoundContainer* newSound) { m_ReloadStartSound = newSound; } + + /// + /// Gets this HDFirearm's reload end sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this HDFirearm's reload end sound. + SoundContainer* GetReloadEndSound() const { return m_ReloadEndSound; } + + /// + /// Sets this HDFirearm's reload end sound. Ownership IS transferred! + /// + /// The new SoundContainer for this HDFirearm's reload end sound. + void SetReloadEndSound(SoundContainer* newSound) { m_ReloadEndSound = newSound; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. + // Arguments: None. + // Return value: None. + + void ResetAllTimers() override { + HeldDevice::ResetAllTimers(); + m_LastFireTmr.Reset(); + m_ReloadTmr.Reset(); + } + + /// + /// Gets this HDFirearm's reload progress as a scalar from 0 to 1. + /// + /// The reload progress as a scalar from 0 to 1. + float GetReloadProgress() const { return IsReloading() && m_BaseReloadTime > 0 ? static_cast(m_ReloadTmr.SimTimeLimitProgress()) : 1.0F; } + + /// + /// Does the calculations necessary to detect whether this HDFirearm is at rest or not. IsAtRest() retrieves the answer. + /// + void RestDetection() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Activate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activates one of this HDFirearm's features. Analogous to 'pulling + // the trigger'. + // Arguments: None. + // Return value: None. + + void Activate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Deactivate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing + // the trigger'. + // Arguments: None. + // Return value: None. + + void Deactivate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StopActivationSound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Aborts playing of active sound no matter what. Used to silence spinning + // weapons when weapons swapped + // Arguments: None. + // Return value: None. + + void StopActivationSound(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reload + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Throws out the currently used Magazine, if any, and puts in a new one + // after the reload delay is up. + // Arguments: None. + // Return value: None. + + void Reload() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsReloading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently being reloaded. + // Arguments: None. + // Return value: Whetehr being reloaded. + + bool IsReloading() const override { return m_Reloading; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DoneReloading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device just finished reloading this frame. + // Arguments: None. + // Return value: Whether just done reloading this frame. + + bool DoneReloading() const override { return m_DoneReloading; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: NeedsReloading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently in need of being reloaded. + // Arguments: None. + // Return value: Whetehr in need of reloading (ie not full). + + bool NeedsReloading() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsFull + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently full and reloading won't have + // any effect. + // Arguments: None. + // Return value: Whetehr magazine is full or not. + + bool IsFull() const override; + + bool IsEmpty() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsFullAuto + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is fully automatic or not. + // Arguments: None. + // Return value: Whether the player can hold down fire and this will fire repeatedly. + + bool IsFullAuto() const { return m_FullAuto; } + + /// + /// Gets whether this HDFirearm is set to be reloadable or not. + /// + /// Whether this HDFirearm is reloadable. + bool IsReloadable() const { return m_Reloadable; } + + /// + /// Sets whether this HDFirearm is reloadable or not and halts the reloading process. + /// + /// Whether this HDFirearm is reloadable. + void SetReloadable(bool isReloadable) { + m_Reloadable = isReloadable; + m_Reloading = m_Reloading && m_Reloadable; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFullAuto + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether the device is fully automatic or not. + // Arguments: New value. + // Return value: None. + + void SetFullAuto(bool newValue) { m_FullAuto = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this HDFirearm's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws an aiming aid in front of this HeldDevice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // Which player's screen this is being drawn to. May affect what HUD elements + // get drawn etc. + // Return value: None. + + void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EstimateDigStrength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Estimates what material strength one round in the magazine can destroy. + // Arguments: None. + // Return value: The maximum material strength the regular or the tracer round can destroy. + + float EstimateDigStrength() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FiredOnce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Whether at least one round has already been fired during the current activation. + // Arguments: None. + // Return value: Returns true if at least one round has already been fired during the current activation. + + bool FiredOnce() const { return m_FiredOnce; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FiredFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Whether at least one round has already been fired during the current frame. + // Arguments: None. + // Return value: Returns true at least one round has already been fired during the current frame. + + bool FiredFrame() const { return m_FireFrame; } + + /// + /// Gets whether this HDFirearm is ready to be fired. + /// + /// Whether this HDFirearm is ready to pop another Round. + bool CanFire() const { return m_LastFireTmr.IsPastSimMS(GetMSPerRound()); } + + /// + /// Gets whether this HDFirearm is halfway to be fired. Used for evenly spacing out dual-wielded fire. + /// + /// Whether this HDFirearm is halfway to pop another Round. + bool HalfwayToNextRound() const { return m_LastFireTmr.IsPastSimMS(GetMSPerRound() / 2.0); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RoundsFired + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: How many rounds were fired during this frame. + // Arguments: None. + // Return value: Returns the number of rounds fired during this frame. + + int RoundsFired() const { return m_RoundsFired; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsAnimatedManually + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: If true then the m_Frame property is not changed bye the Update function + // Arguments: None. + // Return value: Whether this HDFirearm is animated manually. + + bool IsAnimatedManually() const { return m_IsAnimatedManually; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAnimatedManually + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets Whether this HDFirearm is animated manually. + // Arguments: Manual animation flag value. + // Return value: None. + + void SetAnimatedManually(bool newValue) { m_IsAnimatedManually = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Sets this Attachable's parent MOSRotating, and also sets its Team based on its parent and, if the Attachable is set to collide, adds/removes Atoms to its new/old parent. + /// Additionally, sets this HDFirearm as not firing or reloading, and resets its reload timer. + /// + /// A pointer to the MOSRotating to set as the new parent. Ownership is NOT transferred! + void SetParent(MOSRotating* newParent) override { + HeldDevice::SetParent(newParent); + Deactivate(); + m_Reloading = false; + m_ReloadTmr.Reset(); + } + + // Member variables. + static Entity::ClassInfo m_sClass; + + // The mag reference which all current mags are generated from. + // NOT owned by this, owned by PresetMan + const Magazine* m_pMagazineReference; + // Magazine MovableObject. Owned + Magazine* m_pMagazine; + // Muzzle Flash Attachable. Owned + Attachable* m_pFlash; + + SoundContainer* m_PreFireSound; //!< The sound this HDFirearm should play before it starts firing. Distinct from activation sound in that it will play exactly once per trigger pull and not pitch up. + // The audio of this FireArm being fired. + SoundContainer* m_FireSound; + SoundContainer* m_FireEchoSound; //!< The audio that is played as the echo for the gun. Each shot will restart this sound, so it doesn't ever overlap. + // The audio that is played immediately upon activation, but perhaps before actual first firing, if there's a pre-delay + SoundContainer* m_ActiveSound; + // The audio that is played immediately upon cease of activation + SoundContainer* m_DeactivationSound; + // The audio of this FireArm being fired empty. + SoundContainer* m_EmptySound; + // The audio of this FireArm being reloaded. + SoundContainer* m_ReloadStartSound; + SoundContainer* m_ReloadEndSound; + // The offset of how long before the reload finishes the sound plays + float m_ReloadEndOffset; + // Whether or not the end-of-relaod sound has already been played or not. + bool m_HasPlayedEndReloadSound; + + // Rate of fire, in rounds per min. + // If 0, firearm is semi-automatic (ie only one discharge per activation). + int m_RateOfFire; + // Delay between activation and full round output is achieved, in ms + int m_ActivationDelay; + // Delay between release of activation and another can be started, in ms + int m_DeactivationDelay; + // Reloading or not + bool m_Reloading; + // Just done reloading this frame + bool m_DoneReloading; + // Base reload time in millisecs. + int m_BaseReloadTime; + // Whether this HDFirearm is full or semi-auto. + bool m_FullAuto; + // Whether particles fired from this HDFirearm will ignore hits with itself, + // and the root parent of this HDFirearm, regardless if they are set to hit MOs. + bool m_FireIgnoresThis; + bool m_Reloadable; //!< Whether this HDFirearm is reloadable by normal means. + float m_OneHandedReloadTimeMultiplier; //!< The multiplier for how long this weapon takes to reload when being used one-handed. Only relevant for one-handed weapons. + bool m_DualReloadable; //!< Whether or not this weapon can be dual-reloaded, i.e. both guns can reload at once instead of having to wait til the other dual-wielded gun isn't being reloaded. Only relevant for one-handed weapons. + float m_ReloadAngle; //!< The angle offset for the default reload animation, in radians. + float m_OneHandedReloadAngle; //!< The angle offset for one-handed reload animation, in radians. + + // Timer for timing how long ago the last round was fired. + Timer m_LastFireTmr; + // Timer for timing reload times. + Timer m_ReloadTmr; + + // The point from where the projectiles appear. + Vector m_MuzzleOff; + // The point from where the discharged shells appear. + Vector m_EjectOff; + // Offset to magazine. + Vector m_MagOff; + // Range of normal shaking of entire weapon. + float m_ShakeRange; + // Range of shaking of entire weapon during sharp aiming. + float m_SharpShakeRange; + // Factor for how much more weapon shakes if it isn't supported by a second hand. + float m_NoSupportFactor; + // Range of spread angle of fired particles, in one direction + float m_ParticleSpreadRange; + // Angle in which shells are ejected relative to this weapon + float m_ShellEjectAngle; + // Range of spread angle of ejected shells, in one direction + float m_ShellSpreadRange; + // Range of spread in ang vel of ejected shells, in one direction + float m_ShellAngVelRange; + float m_ShellVelVariation; //!< The velocity variation scalar of ejected shells. + // The amount of screenshake that recoil causes + float m_RecoilScreenShakeAmount; + // The muzzle velocity the AI use when aiming this weapon + float m_AIFireVel; + // The bullet life time the AI use when aiming this weapon + unsigned long m_AIBulletLifeTime; + // The bullet acc scalar the AI use when aiming this weapon + float m_AIBulletAccScalar; + + // Whether at least one round has already been + // fired during the current activation. + bool m_FiredOnce; + // Whether at least one round has already been + // fired during the current frame. + bool m_FireFrame; + // Whether at least one round was fired during the last frame + bool m_FiredLastFrame; + // Whether, if this HDFireArm is empty, pin has already clicked once during + // current acticvation. + bool m_AlreadyClicked; + // How many rounds were fired during this frame + int m_RoundsFired; + // If true m_Frame is not changed during an update hence the animation + // is done by external Lua code + bool m_IsAnimatedManually; + + bool m_LegacyCompatibilityRoundsAlwaysFireUnflipped; // + /// Ensures the reload Timer's time limit is set accordingly, based on whether the HDFirearm has support available. + /// + void CorrectReloadTimerForSupportAvailable() { m_ReloadTmr.SetSimTimeLimitMS(static_cast(static_cast(m_BaseReloadTime) * (m_SupportAvailable ? 1.0F : m_OneHandedReloadTimeMultiplier))); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this HDFirearm, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + HDFirearm(const HDFirearm& reference) = delete; + HDFirearm& operator=(const HDFirearm& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/HeldDevice.cpp b/Source/Entities/HeldDevice.cpp index 4e3aa73d8..ce460701c 100644 --- a/Source/Entities/HeldDevice.cpp +++ b/Source/Entities/HeldDevice.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -29,577 +28,559 @@ namespace RTE { -ConcreteClassInfo(HeldDevice, Attachable, 50); + ConcreteClassInfo(HeldDevice, Attachable, 50); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this HeldDevice, effectively + // resetting the members of this abstraction level only. + + void HeldDevice::Clear() { + m_HeldDeviceType = WEAPON; + m_Activated = false; + m_ActivationTimer.Reset(); + m_OneHanded = false; + m_DualWieldable = false; + m_StanceOffset.Reset(); + m_SharpStanceOffset.Reset(); + m_SharpAim = 0.0F; + m_MaxSharpLength = 0; + m_Supportable = true; + m_Supported = false; + m_SupportAvailable = false; + m_SupportOffset.Reset(); + m_UseSupportOffsetWhileReloading = true; + m_SeenByPlayer.fill(false); + m_IsUnPickupable = false; + m_PickupableByPresetNames.clear(); + m_GripStrengthMultiplier = 1.0F; + m_BlinkTimer.Reset(); + m_BlinkTimer.SetSimTimeLimitMS(1000); + m_Loudness = -1; + m_IsExplosiveWeapon = false; + m_GetsHitByMOsWhenHeld = false; + m_VisualRecoilMultiplier = 1.0F; + + // NOTE: This special override of a parent class member variable avoids needing an extra variable to avoid overwriting INI values. + m_CollidesWithTerrainWhileAttached = false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this HeldDevice, effectively -// resetting the members of this abstraction level only. - -void HeldDevice::Clear() -{ - m_HeldDeviceType = WEAPON; - m_Activated = false; - m_ActivationTimer.Reset(); - m_OneHanded = false; - m_DualWieldable = false; - m_StanceOffset.Reset(); - m_SharpStanceOffset.Reset(); - m_SharpAim = 0.0F; - m_MaxSharpLength = 0; - m_Supportable = true; - m_Supported = false; - m_SupportAvailable = false; - m_SupportOffset.Reset(); - m_UseSupportOffsetWhileReloading = true; - m_SeenByPlayer.fill(false); - m_IsUnPickupable = false; - m_PickupableByPresetNames.clear(); - m_GripStrengthMultiplier = 1.0F; - m_BlinkTimer.Reset(); - m_BlinkTimer.SetSimTimeLimitMS(1000); - m_Loudness = -1; - m_IsExplosiveWeapon = false; - m_GetsHitByMOsWhenHeld = false; - m_VisualRecoilMultiplier = 1.0F; - - // NOTE: This special override of a parent class member variable avoids needing an extra variable to avoid overwriting INI values. - m_CollidesWithTerrainWhileAttached = false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Round object ready for use. + + int HeldDevice::Create() { + if (Attachable::Create() < 0) + return -1; + + // Set MO Type. + m_MOType = MovableObject::TypeHeldDevice; + + // Set HeldDeviceType based on tags + if (IsInGroup("Weapons")) + m_HeldDeviceType = WEAPON; + else if (IsInGroup("Tools")) + m_HeldDeviceType = TOOL; + else if (IsInGroup("Shields")) + m_HeldDeviceType = SHIELD; + + if (IsInGroup("Weapons - Explosive")) + m_IsExplosiveWeapon = true; + else + m_IsExplosiveWeapon = false; + + // Backwards compatibility so that the tag is added for sure + if (m_HeldDeviceType == WEAPON) + AddToGroup("Weapons"); + else if (m_HeldDeviceType == TOOL) + AddToGroup("Tools"); + else if (m_HeldDeviceType == SHIELD) + AddToGroup("Shields"); + + // No Loudness set in the ini-file + if (m_Loudness < 0) { + if (m_HeldDeviceType == TOOL) + m_Loudness = 0.5; // Force tools to make less noise + else + m_Loudness = 1.0; + } + // Make it so held devices are dropped gently when their parent gibs + m_ParentGibBlastStrengthMultiplier = 0.0F; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Round object ready for use. - -int HeldDevice::Create() -{ - if (Attachable::Create() < 0) - return -1; - - // Set MO Type. - m_MOType = MovableObject::TypeHeldDevice; - - // Set HeldDeviceType based on tags - if (IsInGroup("Weapons")) - m_HeldDeviceType = WEAPON; - else if (IsInGroup("Tools")) - m_HeldDeviceType = TOOL; - else if (IsInGroup("Shields")) - m_HeldDeviceType = SHIELD; - - if (IsInGroup("Weapons - Explosive")) - m_IsExplosiveWeapon = true; - else - m_IsExplosiveWeapon = false; - - // Backwards compatibility so that the tag is added for sure - if (m_HeldDeviceType == WEAPON) - AddToGroup("Weapons"); - else if (m_HeldDeviceType == TOOL) - AddToGroup("Tools"); - else if (m_HeldDeviceType == SHIELD) - AddToGroup("Shields"); - - // No Loudness set in the ini-file - if (m_Loudness < 0) - { - if (m_HeldDeviceType == TOOL) - m_Loudness = 0.5; // Force tools to make less noise - else - m_Loudness = 1.0; - } - - // Make it so held devices are dropped gently when their parent gibs - m_ParentGibBlastStrengthMultiplier = 0.0F; - - // Make it so users can't accidentally set this to true for HeldDevices, since it'll cause crashes when swapping inventory items around. - m_DeleteWhenRemovedFromParent = false; - - // All HeldDevice:s by default avoid hitting and getting physically hit by AtomGoups when they are at rest - m_IgnoresAGHitsWhenSlowerThan = 1.0; - - // By default, held items should not be able to be squished and destroyed into the ground at all - m_CanBeSquished = false; - - return 0; -} + // Make it so users can't accidentally set this to true for HeldDevices, since it'll cause crashes when swapping inventory items around. + m_DeleteWhenRemovedFromParent = false; + // All HeldDevice:s by default avoid hitting and getting physically hit by AtomGoups when they are at rest + m_IgnoresAGHitsWhenSlowerThan = 1.0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a HeldDevice to be identical to another, by deep copy. - -int HeldDevice::Create(const HeldDevice &reference) -{ - Attachable::Create(reference); - - // Set MO Type. - m_MOType = MovableObject::TypeHeldDevice; - - m_HeldDeviceType = reference.m_HeldDeviceType; - - m_Activated = reference.m_Activated; - m_ActivationTimer = reference.m_ActivationTimer; - - m_OneHanded = reference.m_OneHanded; - m_DualWieldable = reference.m_DualWieldable; - m_StanceOffset = reference.m_StanceOffset; - m_SharpStanceOffset = reference.m_SharpStanceOffset; - m_SupportOffset = reference.m_SupportOffset; - m_UseSupportOffsetWhileReloading = reference.m_UseSupportOffsetWhileReloading; - m_Supportable = reference.m_Supportable; - m_IsUnPickupable = reference.m_IsUnPickupable; - for (std::string referenceActorWhoCanPickThisUp : reference.m_PickupableByPresetNames) { - m_PickupableByPresetNames.insert(referenceActorWhoCanPickThisUp); - } - m_GripStrengthMultiplier = reference.m_GripStrengthMultiplier; - - m_SharpAim = reference.m_SharpAim; - m_MaxSharpLength = reference.m_MaxSharpLength; - m_Supportable = reference.m_Supportable; - m_Supported = reference.m_Supported; - m_SupportAvailable = reference.m_SupportAvailable; - m_Loudness = reference.m_Loudness; - m_IsExplosiveWeapon = reference.m_IsExplosiveWeapon; - m_GetsHitByMOsWhenHeld = reference.m_GetsHitByMOsWhenHeld; - m_VisualRecoilMultiplier = reference.m_VisualRecoilMultiplier; - - return 0; -} + // By default, held items should not be able to be squished and destroyed into the ground at all + m_CanBeSquished = false; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int HeldDevice::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Attachable::ReadProperty(propName, reader)); - - MatchProperty("HeldDeviceType", { reader >> m_HeldDeviceType; }); - MatchProperty("OneHanded", { reader >> m_OneHanded; }); - MatchProperty("DualWieldable", { reader >> m_DualWieldable; }); - MatchProperty("StanceOffset", { reader >> m_StanceOffset; }); - MatchProperty("SharpStanceOffset", { reader >> m_SharpStanceOffset; }); - MatchProperty("Supportable", { reader >> m_Supportable; }); - MatchProperty("SupportOffset", { reader >> m_SupportOffset; }); - MatchProperty("UseSupportOffsetWhileReloading", { reader >> m_UseSupportOffsetWhileReloading; }); - MatchProperty("PickupableBy", { - std::string pickupableByValue = reader.ReadPropValue(); - if (pickupableByValue == "PickupableByEntries") { - while (reader.NextProperty()) { - std::string pickupableByEntryType = reader.ReadPropName(); - if (pickupableByEntryType == "AddPresetNameEntry") { - m_PickupableByPresetNames.insert(reader.ReadPropValue()); - } else if (pickupableByEntryType == "AddClassNameEntry ") { - reader.ReportError("AddClassNameEntry is not yet supported."); - } else if (pickupableByEntryType == "AddGroupEntry") { - reader.ReportError("AddGroupEntry is not yet supported."); - } else if (pickupableByEntryType == "AddDataModuleEntry ") { - reader.ReportError("AddDataModuleEntry is not yet supported."); - } else { - break; - } - } - } else if (pickupableByValue == "None") { - SetUnPickupable(true); - } - }); - MatchProperty("GripStrengthMultiplier", { reader >> m_GripStrengthMultiplier; }); - MatchProperty("SharpLength", { reader >> m_MaxSharpLength; }); - MatchProperty("Loudness", { reader >> m_Loudness; }); - MatchProperty("GetsHitByMOsWhenHeld", { reader >> m_GetsHitByMOsWhenHeld; }); - MatchProperty("VisualRecoilMultiplier", { reader >> m_VisualRecoilMultiplier; }); - MatchProperty("SpecialBehaviour_Activated", { reader >> m_Activated; }); - MatchProperty("SpecialBehaviour_ActivationTimerElapsedSimTimeMS", { - double elapsedSimTimeMS; - reader >> elapsedSimTimeMS; - m_ActivationTimer.SetElapsedSimTimeMS(elapsedSimTimeMS); - }); - - EndPropertyList; -} - + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a HeldDevice to be identical to another, by deep copy. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this HeldDevice with a Writer for -// later recreation with Create(Reader &reader); - -int HeldDevice::Save(Writer &writer) const -{ - Attachable::Save(writer); -/* - writer.NewLine(); - writer << "// 0 = Offensive Weapon, 1 = Tool, 2 = Shield"; - writer.NewProperty("HeldDeviceType"); - writer << m_HeldDeviceType; -*/ - writer.NewProperty("OneHanded"); - writer << m_OneHanded; - writer.NewProperty("StanceOffset"); - writer << m_StanceOffset; - writer.NewProperty("SharpStanceOffset"); - writer << m_SharpStanceOffset; - writer.NewPropertyWithValue("Supportable", m_Supportable); - writer.NewProperty("SupportOffset"); - writer << m_SupportOffset; - writer.NewPropertyWithValue("UseSupportOffsetWhileReloading", m_UseSupportOffsetWhileReloading); - writer.NewProperty("GripStrengthMultiplier"); - writer << m_GripStrengthMultiplier; - writer.NewProperty("SharpLength"); - writer << m_MaxSharpLength; - writer.NewProperty("Loudness"); - writer << m_Loudness; - writer.NewProperty("GetsHitByMOsWhenHeld"); - writer << m_GetsHitByMOsWhenHeld; - writer.NewProperty("VisualRecoilMultiplier"); - writer << m_VisualRecoilMultiplier; - - return 0; -} + int HeldDevice::Create(const HeldDevice& reference) { + Attachable::Create(reference); + // Set MO Type. + m_MOType = MovableObject::TypeHeldDevice; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the HeldDevice object. + m_HeldDeviceType = reference.m_HeldDeviceType; -void HeldDevice::Destroy(bool notInherited) -{ + m_Activated = reference.m_Activated; + m_ActivationTimer = reference.m_ActivationTimer; - if (!notInherited) - Attachable::Destroy(); - Clear(); -} + m_OneHanded = reference.m_OneHanded; + m_DualWieldable = reference.m_DualWieldable; + m_StanceOffset = reference.m_StanceOffset; + m_SharpStanceOffset = reference.m_SharpStanceOffset; + m_SupportOffset = reference.m_SupportOffset; + m_UseSupportOffsetWhileReloading = reference.m_UseSupportOffsetWhileReloading; + m_Supportable = reference.m_Supportable; + m_IsUnPickupable = reference.m_IsUnPickupable; + for (std::string referenceActorWhoCanPickThisUp: reference.m_PickupableByPresetNames) { + m_PickupableByPresetNames.insert(referenceActorWhoCanPickThisUp); + } + m_GripStrengthMultiplier = reference.m_GripStrengthMultiplier; + + m_SharpAim = reference.m_SharpAim; + m_MaxSharpLength = reference.m_MaxSharpLength; + m_Supportable = reference.m_Supportable; + m_Supported = reference.m_Supported; + m_SupportAvailable = reference.m_SupportAvailable; + m_Loudness = reference.m_Loudness; + m_IsExplosiveWeapon = reference.m_IsExplosiveWeapon; + m_GetsHitByMOsWhenHeld = reference.m_GetsHitByMOsWhenHeld; + m_VisualRecoilMultiplier = reference.m_VisualRecoilMultiplier; + + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int HeldDevice::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Attachable::ReadProperty(propName, reader)); + + MatchProperty("HeldDeviceType", { reader >> m_HeldDeviceType; }); + MatchProperty("OneHanded", { reader >> m_OneHanded; }); + MatchProperty("DualWieldable", { reader >> m_DualWieldable; }); + MatchProperty("StanceOffset", { reader >> m_StanceOffset; }); + MatchProperty("SharpStanceOffset", { reader >> m_SharpStanceOffset; }); + MatchProperty("Supportable", { reader >> m_Supportable; }); + MatchProperty("SupportOffset", { reader >> m_SupportOffset; }); + MatchProperty("UseSupportOffsetWhileReloading", { reader >> m_UseSupportOffsetWhileReloading; }); + MatchProperty("PickupableBy", { + std::string pickupableByValue = reader.ReadPropValue(); + if (pickupableByValue == "PickupableByEntries") { + while (reader.NextProperty()) { + std::string pickupableByEntryType = reader.ReadPropName(); + if (pickupableByEntryType == "AddPresetNameEntry") { + m_PickupableByPresetNames.insert(reader.ReadPropValue()); + } else if (pickupableByEntryType == "AddClassNameEntry ") { + reader.ReportError("AddClassNameEntry is not yet supported."); + } else if (pickupableByEntryType == "AddGroupEntry") { + reader.ReportError("AddGroupEntry is not yet supported."); + } else if (pickupableByEntryType == "AddDataModuleEntry ") { + reader.ReportError("AddDataModuleEntry is not yet supported."); + } else { + break; + } + } + } else if (pickupableByValue == "None") { + SetUnPickupable(true); + } + }); + MatchProperty("GripStrengthMultiplier", { reader >> m_GripStrengthMultiplier; }); + MatchProperty("SharpLength", { reader >> m_MaxSharpLength; }); + MatchProperty("Loudness", { reader >> m_Loudness; }); + MatchProperty("GetsHitByMOsWhenHeld", { reader >> m_GetsHitByMOsWhenHeld; }); + MatchProperty("VisualRecoilMultiplier", { reader >> m_VisualRecoilMultiplier; }); + MatchProperty("SpecialBehaviour_Activated", { reader >> m_Activated; }); + MatchProperty("SpecialBehaviour_ActivationTimerElapsedSimTimeMS", { + double elapsedSimTimeMS; + reader >> elapsedSimTimeMS; + m_ActivationTimer.SetElapsedSimTimeMS(elapsedSimTimeMS); + }); + + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetStanceOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current position offset of this HeldDevice's joint relative -// from the parent Actor's position, if attached. -// Arguments: None. -// Return value: A const reference to the current stance parent offset. - -Vector HeldDevice::GetStanceOffset() const -{ - if (m_SharpAim > 0) { - float rotAngleScalar = std::abs(std::sin(GetRootParent()->GetRotAngle())); - // Deviate the vertical axis towards regular StanceOffset based on the user's rotation so that sharp aiming doesn't look awkward when prone - return Vector(m_SharpStanceOffset.GetX(), m_SharpStanceOffset.GetY() * (1.0F - rotAngleScalar) + m_StanceOffset.GetY() * rotAngleScalar).GetXFlipped(m_HFlipped); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this HeldDevice with a Writer for + // later recreation with Create(Reader &reader); + + int HeldDevice::Save(Writer& writer) const { + Attachable::Save(writer); + /* + writer.NewLine(); + writer << "// 0 = Offensive Weapon, 1 = Tool, 2 = Shield"; + writer.NewProperty("HeldDeviceType"); + writer << m_HeldDeviceType; + */ + writer.NewProperty("OneHanded"); + writer << m_OneHanded; + writer.NewProperty("StanceOffset"); + writer << m_StanceOffset; + writer.NewProperty("SharpStanceOffset"); + writer << m_SharpStanceOffset; + writer.NewPropertyWithValue("Supportable", m_Supportable); + writer.NewProperty("SupportOffset"); + writer << m_SupportOffset; + writer.NewPropertyWithValue("UseSupportOffsetWhileReloading", m_UseSupportOffsetWhileReloading); + writer.NewProperty("GripStrengthMultiplier"); + writer << m_GripStrengthMultiplier; + writer.NewProperty("SharpLength"); + writer << m_MaxSharpLength; + writer.NewProperty("Loudness"); + writer << m_Loudness; + writer.NewProperty("GetsHitByMOsWhenHeld"); + writer << m_GetsHitByMOsWhenHeld; + writer.NewProperty("VisualRecoilMultiplier"); + writer << m_VisualRecoilMultiplier; + + return 0; } - else - return m_StanceOffset.GetXFlipped(m_HFlipped); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the HeldDevice object. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSupportPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the support handhold that this HeldDevice -// offers. + void HeldDevice::Destroy(bool notInherited) { -Vector HeldDevice::GetSupportPos() const -{ -/* - Vector rotOff(m_SupportOffset.GetYFlipped(m_HFlipped)); - rotOff.RadRotate(m_HFlipped ? (c_PI + m_Rotation) : m_Rotation); - return m_Pos + rotOff; -*/ - return m_Pos + RotateOffset(m_SupportOffset); -} + if (!notInherited) + Attachable::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetStanceOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current position offset of this HeldDevice's joint relative + // from the parent Actor's position, if attached. + // Arguments: None. + // Return value: A const reference to the current stance parent offset. + + Vector HeldDevice::GetStanceOffset() const { + if (m_SharpAim > 0) { + float rotAngleScalar = std::abs(std::sin(GetRootParent()->GetRotAngle())); + // Deviate the vertical axis towards regular StanceOffset based on the user's rotation so that sharp aiming doesn't look awkward when prone + return Vector(m_SharpStanceOffset.GetX(), m_SharpStanceOffset.GetY() * (1.0F - rotAngleScalar) + m_StanceOffset.GetY() * rotAngleScalar).GetXFlipped(m_HFlipped); + } else + return m_StanceOffset.GetXFlipped(m_HFlipped); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMagazinePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the magazine or other equivalent point of -// this. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSupportPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the support handhold that this HeldDevice + // offers. + + Vector HeldDevice::GetSupportPos() const { + /* + Vector rotOff(m_SupportOffset.GetYFlipped(m_HFlipped)); + rotOff.RadRotate(m_HFlipped ? (c_PI + m_Rotation) : m_Rotation); + return m_Pos + rotOff; + */ + return m_Pos + RotateOffset(m_SupportOffset); + } -Vector HeldDevice::GetMagazinePos() const -{ - return m_Pos; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMagazinePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the magazine or other equivalent point of + // this. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Vector HeldDevice::GetMagazinePos() const { + return m_Pos; + } -bool HeldDevice::IsBeingHeld() const { - return dynamic_cast(m_Parent); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool HeldDevice::IsBeingHeld() const { + return dynamic_cast(m_Parent); + } -void HeldDevice::RemovePickupableByPresetName(const std::string &actorPresetName) { - std::unordered_set::iterator pickupableByPresetNameEntry = m_PickupableByPresetNames.find(actorPresetName); - if (pickupableByPresetNameEntry != m_PickupableByPresetNames.end()) { m_PickupableByPresetNames.erase(pickupableByPresetNameEntry); } -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void HeldDevice::RemovePickupableByPresetName(const std::string& actorPresetName) { + std::unordered_set::iterator pickupableByPresetNameEntry = m_PickupableByPresetNames.find(actorPresetName); + if (pickupableByPresetNameEntry != m_PickupableByPresetNames.end()) { + m_PickupableByPresetNames.erase(pickupableByPresetNameEntry); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. -bool HeldDevice::CollideAtPoint(HitData &hd) -{ - if (!m_GetsHitByMOsWhenHeld && IsBeingHeld()) { - return false; - } + bool HeldDevice::CollideAtPoint(HitData& hd) { + if (!m_GetsHitByMOsWhenHeld && IsBeingHeld()) { + return false; + } - return Attachable::CollideAtPoint(hd); -} + return Attachable::CollideAtPoint(hd); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Activate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activates this HDFirearm. Analogous to 'pulling the trigger'. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Activate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activates this HDFirearm. Analogous to 'pulling the trigger'. + void HeldDevice::Activate() { + if (!m_Activated) { + m_ActivationTimer.Reset(); + } + m_Activated = true; + } -void HeldDevice::Activate() -{ - if (!m_Activated) { m_ActivationTimer.Reset(); } - m_Activated = true; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Deactivate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing + // the trigger'. + void HeldDevice::Deactivate() { + m_Activated = false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Deactivate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing -// the trigger'. - -void HeldDevice::Deactivate() -{ - m_Activated = false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool HeldDevice::TransferJointImpulses(Vector &jointImpulses, float jointStiffnessValueToUse, float jointStrengthValueToUse, float gibImpulseLimitValueToUse) { - MovableObject *parent = m_Parent; - if (!parent) { - return false; - } - if (m_ImpulseForces.empty()) { - return true; - } - const Arm *parentAsArm = dynamic_cast(parent); - if (parentAsArm && parentAsArm->GetGripStrength() > 0 && jointStrengthValueToUse < 0) { - jointStrengthValueToUse = parentAsArm->GetGripStrength() * m_GripStrengthMultiplier; - if (m_Supported) { - if (const AHuman *rootParentAsAHuman = dynamic_cast(GetRootParent())) { jointStrengthValueToUse += rootParentAsAHuman->GetBGArm() ? rootParentAsAHuman->GetBGArm()->GetGripStrength() * m_GripStrengthMultiplier : 0.0F; } - } - } - bool intact = Attachable::TransferJointImpulses(jointImpulses, jointStiffnessValueToUse, jointStrengthValueToUse, gibImpulseLimitValueToUse); - if (!intact) { - Actor *rootParentAsActor = dynamic_cast(parent->GetRootParent()); - if (rootParentAsActor && rootParentAsActor->GetStatus() == Actor::STABLE) { rootParentAsActor->SetStatus(Actor::UNSTABLE); } - } - return intact; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Travel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Travels this, using its physical representation. -// Arguments: None. -// Return value: None. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void HeldDevice::Travel() -{ - Attachable::Travel(); -} -*/ + bool HeldDevice::TransferJointImpulses(Vector& jointImpulses, float jointStiffnessValueToUse, float jointStrengthValueToUse, float gibImpulseLimitValueToUse) { + MovableObject* parent = m_Parent; + if (!parent) { + return false; + } + if (m_ImpulseForces.empty()) { + return true; + } + const Arm* parentAsArm = dynamic_cast(parent); + if (parentAsArm && parentAsArm->GetGripStrength() > 0 && jointStrengthValueToUse < 0) { + jointStrengthValueToUse = parentAsArm->GetGripStrength() * m_GripStrengthMultiplier; + if (m_Supported) { + if (const AHuman* rootParentAsAHuman = dynamic_cast(GetRootParent())) { + jointStrengthValueToUse += rootParentAsAHuman->GetBGArm() ? rootParentAsAHuman->GetBGArm()->GetGripStrength() * m_GripStrengthMultiplier : 0.0F; + } + } + } + bool intact = Attachable::TransferJointImpulses(jointImpulses, jointStiffnessValueToUse, jointStrengthValueToUse, gibImpulseLimitValueToUse); + if (!intact) { + Actor* rootParentAsActor = dynamic_cast(parent->GetRootParent()); + if (rootParentAsActor && rootParentAsActor->GetStatus() == Actor::STABLE) { + rootParentAsActor->SetStatus(Actor::UNSTABLE); + } + } + return intact; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this HeldDevice. Supposed to be done every frame. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void HeldDevice::Update() -{ - Attachable::Update(); + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Travel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Travels this, using its physical representation. + // Arguments: None. + // Return value: None. - // Remove loose items that have completely disappeared into the terrain, unless they're pinned - if (!m_Parent && m_PinStrength <= 0 && m_RestTimer.IsPastSimMS(20000) && m_CanBeSquished && m_pAtomGroup->RatioInTerrain() > 0.9) - GibThis(); + void HeldDevice::Travel() + { + Attachable::Travel(); + } + */ - if (m_Activated) - m_RestTimer.Reset(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this HeldDevice. Supposed to be done every frame. - //////////////////////////////////////// - // Animate the sprite, if applicable + void HeldDevice::Update() { + Attachable::Update(); - if (m_FrameCount > 1) - { - if (m_SpriteAnimMode == LOOPWHENACTIVE && m_Activated) - { - float cycleTime = ((long)m_SpriteAnimTimer.GetElapsedSimTimeMS()) % m_SpriteAnimDuration; - m_Frame = std::floor((cycleTime / (float)m_SpriteAnimDuration) * (float)m_FrameCount); - } - } + // Remove loose items that have completely disappeared into the terrain, unless they're pinned + if (!m_Parent && m_PinStrength <= 0 && m_RestTimer.IsPastSimMS(20000) && m_CanBeSquished && m_pAtomGroup->RatioInTerrain() > 0.9) + GibThis(); - if (!m_Parent) { + if (m_Activated) + m_RestTimer.Reset(); - } - else { - ///////////////////////////////// - // Update and apply rotations and scale + //////////////////////////////////////// + // Animate the sprite, if applicable - // Taken care of by holder/owner Arm. -// m_Pos += m_ParentOffset; -// Don't apply state changes to BITMAP anywhere else than Draw(). -// m_aSprite->SetAngle(m_Rotation); -// m_aSprite->SetScale(m_Scale); - } + if (m_FrameCount > 1) { + if (m_SpriteAnimMode == LOOPWHENACTIVE && m_Activated) { + float cycleTime = ((long)m_SpriteAnimTimer.GetElapsedSimTimeMS()) % m_SpriteAnimDuration; + m_Frame = std::floor((cycleTime / (float)m_SpriteAnimDuration) * (float)m_FrameCount); + } + } - if (m_BlinkTimer.IsPastSimTimeLimit()) { m_BlinkTimer.Reset(); } -} + if (!m_Parent) { + } else { + ///////////////////////////////// + // Update and apply rotations and scale + + // Taken care of by holder/owner Arm. + // m_Pos += m_ParentOffset; + // Don't apply state changes to BITMAP anywhere else than Draw(). + // m_aSprite->SetAngle(m_Rotation); + // m_aSprite->SetScale(m_Scale); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this HeldDevice's current graphical representation to a -// BITMAP of choice. - -void HeldDevice::Draw(BITMAP *pTargetBitmap, - const Vector &targetPos, - DrawMode mode, - bool onlyPhysical) const -{ - Attachable::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); -/* - // Draw suporting hand if applicable. - if (m_Supported) { - Vector handPos(m_Pos.GetFloored() + - RotateOffset(m_SupportOffset) + - (m_Recoiled ? m_RecoilOffset : Vector()) - - targetPos); - handPos.m_X -= m_pSupportHand->GetWidth() >> 1; - handPos.m_Y -= m_pSupportHand->GetHeight() >> 1; - if (!m_HFlipped) - m_pSupportHand->DrawTrans(pTargetBitmap, handPos.m_X, handPos.m_Y); - else - m_pSupportHand->DrawTransHFlip(pTargetBitmap, handPos.m_X, handPos.m_Y); - } -*/ -/* -#ifdef DEBUG_BUILD - if (mode == g_DrawColor && !onlyPhysical) - { - m_pAtomGroup->Draw(pTargetBitmap, targetPos, false, 122); - m_pDeepGroup->Draw(pTargetBitmap, targetPos, false, 13); - } -#endif -*/ -} + if (m_BlinkTimer.IsPastSimTimeLimit()) { + m_BlinkTimer.Reset(); + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this HeldDevice's current graphical representation to a + // BITMAP of choice. + + void HeldDevice::Draw(BITMAP* pTargetBitmap, + const Vector& targetPos, + DrawMode mode, + bool onlyPhysical) const { + Attachable::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + /* + // Draw suporting hand if applicable. + if (m_Supported) { + Vector handPos(m_Pos.GetFloored() + + RotateOffset(m_SupportOffset) + + (m_Recoiled ? m_RecoilOffset : Vector()) - + targetPos); + handPos.m_X -= m_pSupportHand->GetWidth() >> 1; + handPos.m_Y -= m_pSupportHand->GetHeight() >> 1; + if (!m_HFlipped) + m_pSupportHand->DrawTrans(pTargetBitmap, handPos.m_X, handPos.m_Y); + else + m_pSupportHand->DrawTransHFlip(pTargetBitmap, handPos.m_X, handPos.m_Y); + } + */ + /* + #ifdef DEBUG_BUILD + if (mode == g_DrawColor && !onlyPhysical) + { + m_pAtomGroup->Draw(pTargetBitmap, targetPos, false, 122); + m_pDeepGroup->Draw(pTargetBitmap, targetPos, false, 13); + } + #endif + */ + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Actor's current graphical HUD overlay representation to a -// BITMAP of choice. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Actor's current graphical HUD overlay representation to a + // BITMAP of choice. -void HeldDevice::DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) { - if (!m_HUDVisible) { - return; - } + void HeldDevice::DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { + if (!m_HUDVisible) { + return; + } - Attachable::DrawHUD(pTargetBitmap, targetPos, whichScreen); + Attachable::DrawHUD(pTargetBitmap, targetPos, whichScreen); - if (!IsUnPickupable()) { - if (m_Parent) { - m_SeenByPlayer.fill(false); - m_BlinkTimer.Reset(); - } else { - int viewingPlayer = g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen); - if (viewingPlayer == -1) { - return; - } - // Only draw if the team viewing this has seen the space where this is located. - int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(viewingPlayer); - if (viewingTeam == Activity::NoTeam || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam)) { - return; - } + if (!IsUnPickupable()) { + if (m_Parent) { + m_SeenByPlayer.fill(false); + m_BlinkTimer.Reset(); + } else { + int viewingPlayer = g_ActivityMan.GetActivity()->PlayerOfScreen(whichScreen); + if (viewingPlayer == -1) { + return; + } + // Only draw if the team viewing this has seen the space where this is located. + int viewingTeam = g_ActivityMan.GetActivity()->GetTeamOfPlayer(viewingPlayer); + if (viewingTeam == Activity::NoTeam || g_SceneMan.IsUnseen(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), viewingTeam)) { + return; + } - Vector drawPos = m_Pos - targetPos; - // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam. - if (!targetPos.IsZero()) { - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { - if ((targetPos.GetFloorIntX() < 0) && (m_Pos.GetFloorIntX() > (sceneWidth - pTargetBitmap->w))) { - drawPos.m_X -= static_cast(sceneWidth); - } else if ((targetPos.GetFloorIntX() + pTargetBitmap->w > sceneWidth) && (m_Pos.GetFloorIntX() < pTargetBitmap->w)) { - drawPos.m_X += static_cast(sceneWidth); + Vector drawPos = m_Pos - targetPos; + // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam. + if (!targetPos.IsZero()) { + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.GetFloorIntX() < 0) && (m_Pos.GetFloorIntX() > (sceneWidth - pTargetBitmap->w))) { + drawPos.m_X -= static_cast(sceneWidth); + } else if ((targetPos.GetFloorIntX() + pTargetBitmap->w > sceneWidth) && (m_Pos.GetFloorIntX() < pTargetBitmap->w)) { + drawPos.m_X += static_cast(sceneWidth); + } } - } - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { - if ((targetPos.GetFloorIntY() < 0) && (m_Pos.GetFloorIntY() > (sceneHeight - pTargetBitmap->h))) { - drawPos.m_Y -= static_cast(sceneHeight); - } else if ((targetPos.GetFloorIntY() + pTargetBitmap->h > sceneHeight) && (m_Pos.GetFloorIntY() < pTargetBitmap->h)) { - drawPos.m_Y += static_cast(sceneHeight); + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.GetFloorIntY() < 0) && (m_Pos.GetFloorIntY() > (sceneHeight - pTargetBitmap->h))) { + drawPos.m_Y -= static_cast(sceneHeight); + } else if ((targetPos.GetFloorIntY() + pTargetBitmap->h > sceneHeight) && (m_Pos.GetFloorIntY() < pTargetBitmap->h)) { + drawPos.m_Y += static_cast(sceneHeight); + } } } - } - GUIFont *pSymbolFont = g_FrameMan.GetLargeFont(); - GUIFont *pTextFont = g_FrameMan.GetSmallFont(); - if (pSymbolFont && pTextFont) { - const Activity *activity = g_ActivityMan.GetActivity(); - float unheldItemDisplayRange = activity->GetActivityState() == Activity::ActivityState::Running ? g_SettingsMan.GetUnheldItemsHUDDisplayRange() : -1.0F; - if (g_SettingsMan.AlwaysDisplayUnheldItemsInStrategicMode()) { - const GameActivity *gameActivity = dynamic_cast(activity); - if (gameActivity && gameActivity->GetViewState(viewingPlayer) == GameActivity::ViewState::ActorSelect) { unheldItemDisplayRange = -1.0F; } - } - if (!m_SeenByPlayer[viewingPlayer]) { - m_SeenByPlayer[viewingPlayer] = unheldItemDisplayRange < 0 || (unheldItemDisplayRange > 0 && m_Vel.MagnitudeIsLessThan(2.0F) && g_SceneMan.ShortestDistance(m_Pos, g_CameraMan.GetScrollTarget(whichScreen), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(unheldItemDisplayRange)); - } else { - // Note - to avoid item HUDs flickering in and out, we need to add a little leeway when hiding them if they're already displayed. - if (unheldItemDisplayRange > 0) { unheldItemDisplayRange += 4.0F; } - m_SeenByPlayer.at(viewingPlayer) = unheldItemDisplayRange < 0 || (unheldItemDisplayRange > 0 && g_SceneMan.ShortestDistance(m_Pos, g_CameraMan.GetScrollTarget(whichScreen), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(unheldItemDisplayRange)); - - char pickupArrowString[64]; - pickupArrowString[0] = 0; - if (m_BlinkTimer.GetElapsedSimTimeMS() < 250) { + GUIFont* pSymbolFont = g_FrameMan.GetLargeFont(); + GUIFont* pTextFont = g_FrameMan.GetSmallFont(); + if (pSymbolFont && pTextFont) { + const Activity* activity = g_ActivityMan.GetActivity(); + float unheldItemDisplayRange = activity->GetActivityState() == Activity::ActivityState::Running ? g_SettingsMan.GetUnheldItemsHUDDisplayRange() : -1.0F; + if (g_SettingsMan.AlwaysDisplayUnheldItemsInStrategicMode()) { + const GameActivity* gameActivity = dynamic_cast(activity); + if (gameActivity && gameActivity->GetViewState(viewingPlayer) == GameActivity::ViewState::ActorSelect) { + unheldItemDisplayRange = -1.0F; + } + } + if (!m_SeenByPlayer[viewingPlayer]) { + m_SeenByPlayer[viewingPlayer] = unheldItemDisplayRange < 0 || (unheldItemDisplayRange > 0 && m_Vel.MagnitudeIsLessThan(2.0F) && g_SceneMan.ShortestDistance(m_Pos, g_CameraMan.GetScrollTarget(whichScreen), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(unheldItemDisplayRange)); + } else { + // Note - to avoid item HUDs flickering in and out, we need to add a little leeway when hiding them if they're already displayed. + if (unheldItemDisplayRange > 0) { + unheldItemDisplayRange += 4.0F; + } + m_SeenByPlayer.at(viewingPlayer) = unheldItemDisplayRange < 0 || (unheldItemDisplayRange > 0 && g_SceneMan.ShortestDistance(m_Pos, g_CameraMan.GetScrollTarget(whichScreen), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(unheldItemDisplayRange)); + + char pickupArrowString[64]; pickupArrowString[0] = 0; - } else if (m_BlinkTimer.GetElapsedSimTimeMS() < 500) { - pickupArrowString[0] = -42; - pickupArrowString[1] = 0; - } else if (m_BlinkTimer.GetElapsedSimTimeMS() < 750) { - pickupArrowString[0] = -41; - pickupArrowString[1] = 0; - } else if (m_BlinkTimer.GetElapsedSimTimeMS() < 1000) { - pickupArrowString[0] = -40; - pickupArrowString[1] = 0; + if (m_BlinkTimer.GetElapsedSimTimeMS() < 250) { + pickupArrowString[0] = 0; + } else if (m_BlinkTimer.GetElapsedSimTimeMS() < 500) { + pickupArrowString[0] = -42; + pickupArrowString[1] = 0; + } else if (m_BlinkTimer.GetElapsedSimTimeMS() < 750) { + pickupArrowString[0] = -41; + pickupArrowString[1] = 0; + } else if (m_BlinkTimer.GetElapsedSimTimeMS() < 1000) { + pickupArrowString[0] = -40; + pickupArrowString[1] = 0; + } + + AllegroBitmap targetAllegroBitmap(pTargetBitmap); + pSymbolFont->DrawAligned(&targetAllegroBitmap, drawPos.GetFloorIntX() - 1, drawPos.GetFloorIntY() - 20, pickupArrowString, GUIFont::Centre); + pTextFont->DrawAligned(&targetAllegroBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() - 29, m_PresetName, GUIFont::Centre); } - - AllegroBitmap targetAllegroBitmap(pTargetBitmap); - pSymbolFont->DrawAligned(&targetAllegroBitmap, drawPos.GetFloorIntX() - 1, drawPos.GetFloorIntY() - 20, pickupArrowString, GUIFont::Centre); - pTextFont->DrawAligned(&targetAllegroBitmap, drawPos.GetFloorIntX(), drawPos.GetFloorIntY() - 29, m_PresetName, GUIFont::Centre); } } } } -} } // namespace RTE diff --git a/Source/Entities/HeldDevice.h b/Source/Entities/HeldDevice.h index 79e572707..4312b9f81 100644 --- a/Source/Entities/HeldDevice.h +++ b/Source/Entities/HeldDevice.h @@ -10,715 +10,677 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "Attachable.h" #include "Actor.h" -namespace RTE -{ - -enum HeldDeviceType -{ - WEAPON = 0, - TOOL, - SHIELD, - BOMB, -}; - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: HeldDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: An articulated device that can be weilded by an Actor. -// Parent(s): Attachable. -// Class history: 06/2/2002 HeldDevice created. -// 01/31/2007 Made concrete so Shields can be jsut HeldDevice:s - -class HeldDevice : public Attachable { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(HeldDevice); -SerializableOverrideMethods; -ClassInfoGetters; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: HeldDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a HeldDevice object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - HeldDevice() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~HeldDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a HeldDevice object before deletion -// from system memory. -// Arguments: None. - - ~HeldDevice() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the HeldDevice object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a HeldDevice to be identical to another, by deep copy. -// Arguments: A reference to the HeldDevice to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const HeldDevice &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire HeldDevice, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Attachable::Reset(); m_MOType = MovableObject::TypeHeldDevice; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAboveHUDPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of the top of this' HUD stack. -// Arguments: None. -// Return value: A Vector with the absolute position of this' HUD stack top point. - - Vector GetAboveHUDPos() const override { return m_Pos + Vector(0, -32); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSupportPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the support handhold that this HeldDevice -// offers. -// Arguments: None. -// Return value: A vector describing the absolute world coordinates for the support -// position of this HeldDevice. - - Vector GetSupportPos() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMagazinePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the magazine or other equivalent point of -// this. -// Arguments: None. -// Return value: A vector describing the absolute world coordinates for the magazine -// attachment point of this - - virtual Vector GetMagazinePos() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMuzzlePos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of the muzzle or other equivalent point of -// this. -// Arguments: None. -// Return value: A vector describing the absolute world coordinates for the muzzle point -// of this - - virtual Vector GetMuzzlePos() const { return m_Pos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMuzzleOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the unrotated relative offset from the position to the muzzle or -// other equivalent point of this. -// Arguments: None. -// Return value: A unrotated vector describing the relative for the muzzle point of -// this from this' position. - - virtual Vector GetMuzzleOffset() const { return Vector(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetMuzzleOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the unrotated relative offset from the position to the muzzle or -// other equivalent point of this. -// Arguments: Bew ofsset value. -// Return value: None. - - virtual void SetMuzzleOffset(Vector newOffset) { /* Actually does something in inherited classes */ } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetStanceOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current position offset of this HeldDevice's joint relative -// from the parent Actor's position, if attached. -// Arguments: None. -// Return value: A const reference to the current stance parent offset. - - virtual Vector GetStanceOffset() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetStanceOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current position offset of this HeldDevice's joint relative -// from the parent Actor's position, if attached. -// Arguments: New value. -// Return value: None. - - void SetStanceOffset(Vector newValue) { m_StanceOffset = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetSharpStanceOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current position offset of this HeldDevice's joint relative -// from the parent Actor's position, if attached. -// Arguments: New value. -// Return value: None. - - Vector GetSharpStanceOffset() const { return m_SharpStanceOffset; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetSharpStanceOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current position offset of this HeldDevice's joint relative -// from the parent Actor's position, if attached. -// Arguments: New value. -// Return value: None. - - void SetSharpStanceOffset(Vector newValue) { m_SharpStanceOffset = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetSharpLength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how much farther an Actor which holds this device can see when -// aiming this HeldDevice sharply. -// Arguments: None. -// Return value: The length in world pixel units. - - float GetSharpLength() const { return m_MaxSharpLength; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetSharpLength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets how much farther an Actor which holds this device can see when -// aiming this HeldDevice sharply. -// Arguments: The length in world pixel units. -// Return value: None. - - void SetSharpLength(float newLength) { m_MaxSharpLength = newLength; } - - /// - /// Gets whether this HeldDevice can be supported when held. - /// - /// Whether this HeldDevice can be supported when held. - bool IsSupportable() const { return m_Supportable; } - - /// - /// Sets whether this HeldDevice can be supported when held. - /// - /// Whether this HeldDevice can be supported when held. - void SetSupportable(bool shouldBeSupportable) { m_Supportable = shouldBeSupportable; } - - /// - /// Gets whether this HeldDevice is currently supported by a second Arm. - /// - /// Whether this HeldDevice is supported or not. - bool GetSupported() const { return m_Supportable && m_Supported; } - - /// - /// Sets whether this HeldDevice is currently supported by a second Arm. - /// - /// Whether this HeldDevice is being supported. - void SetSupported(bool supported) { m_Supported = m_Supportable && supported; } - - /// - /// Gets whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). - /// - /// Whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). - bool GetSupportAvailable() const { return m_Supportable && m_SupportAvailable; } - - /// - /// Sets whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). - /// - /// Whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). - void SetSupportAvailable(bool supportAvailable) { m_SupportAvailable = m_Supportable && supportAvailable; } - - /// - /// Gets whether this HeldDevice while be held at the support offset with the off-hand when reloading. - /// - /// Whether this HeldDevice while be held at the support offset with the off-hand when reloading. - bool GetUseSupportOffsetWhileReloading() const { return m_UseSupportOffsetWhileReloading; } - - /// - /// Sets whether this HeldDevice while be held at the support offset with the off-hand when reloading. - /// - /// Whether this HeldDevice while be held at the support offset with the off-hand when reloading. - void SetUseSupportOffsetWhileReloading(bool value) { m_UseSupportOffsetWhileReloading = value; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetSupportOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns support offset. -// Arguments: None. -// Return value: Support offset value. - - Vector GetSupportOffset() const { return m_SupportOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetSupportOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets support offset. -// Arguments: New support offset value. -// Return value: None. - - void SetSupportOffset(Vector newOffset) { m_SupportOffset = newOffset; } - - /// - /// Gets whether this HeldDevice has any limitations on what can pick it up. - /// - /// Whether this HeldDevice has any limitations on what can pick it up. - bool HasPickupLimitations() const { return IsUnPickupable() || !m_PickupableByPresetNames.empty(); } - - /// - /// Gets whether this HeldDevice cannot be picked up at all. - /// - /// Whether this HeldDevice cannot be picked up at all. - bool IsUnPickupable() const { return m_IsUnPickupable; } - - /// - /// Sets whether this HeldDevice cannot be picked up at all. - /// - /// Whether this HeldDevice cannot be picked up at all. True means it cannot, false means any other limitations will apply normally. - void SetUnPickupable(bool shouldBeUnPickupable) { m_IsUnPickupable = shouldBeUnPickupable; } - - /// - /// Checks whether the given Actor can pick up this HeldDevice. - /// - /// The Actor to check. Ownership is NOT transferred. - /// Whether the given Actor can pick up this HeldDevice. - bool IsPickupableBy(const Actor *actor) const { return !HasPickupLimitations() || m_PickupableByPresetNames.find(actor->GetPresetName()) != m_PickupableByPresetNames.end(); } - - /// - /// Specify that objects with the given PresetName can pick up this HeldDevice. - /// - /// The PresetName of an object that should be able to pick up this HeldDevice. - void AddPickupableByPresetName(const std::string &presetName) { SetUnPickupable(false); m_PickupableByPresetNames.insert(presetName); } - - /// - /// Remove allowance for objects with the given PresetName to pick up this HeldDevice. - /// Note that if the last allowance is removed, the HeldDevice will no longer have pickup limitations, rather than setting itself as unpickupable. - /// - /// The PresetName of an object that should no longer be able to pick up this HeldDevice. - void RemovePickupableByPresetName(const std::string &actorPresetName); - - /// - /// Gets the multiplier for how well this HeldDevice can be gripped by Arms. - /// - /// The grip strength multiplier for this HeldDevice. - float GetGripStrengthMultiplier() const { return m_GripStrengthMultiplier; } - - /// - /// Sets the multiplier for how well this HeldDevice can be gripped by Arms. - /// - /// The new grip strength multiplier for this HeldDevice. - void SetGripStrengthMultiplier(float gripStrengthMultiplier) { m_GripStrengthMultiplier = gripStrengthMultiplier; } - - /// - /// Gets whether this can get hit by MOs when held. - /// - /// Whether this can get hit by MOs when held. - bool GetsHitByMOsWhenHeld() const { return m_GetsHitByMOsWhenHeld; } - - /// - /// Sets whether this can get hit by MOs when held. - /// - /// Whether this can get hit by MOs when held. - void SetGetsHitByMOsWhenHeld(bool value) { m_GetsHitByMOsWhenHeld = value; } - - /// - /// Gets whether this HeldDevice is currently being held or not. - /// - /// Whether this HeldDevice is currently being held or not. - bool IsBeingHeld() const; - - /// - /// Gets the visual recoil multiplier. - /// - /// A float with the scalar value. - float GetVisualRecoilMultiplier() const { return m_VisualRecoilMultiplier; } - - /// - /// Sets the visual recoil multiplier. - /// - /// The new recoil multiplier scalar. - void SetVisualRecoilMultiplier(float value) { m_VisualRecoilMultiplier = value; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSharpAim -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the degree to which this is being aimed sharp. This will -// affect the accuracy and what GetParentOffset returns. -// Arguments: A normalized scalar between 0 (no sharp aim) to 1.0 (best aim). -// Return value: None. - - void SetSharpAim(float sharpAim) { m_SharpAim = sharpAim; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsWeapon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this is an offensive weapon or not. -// Arguments: None. -// Return value: Offensive weapon or not. - - bool IsWeapon() { return m_HeldDeviceType == WEAPON; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsTool -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this is a tool or not. -// Arguments: None. -// Return value: Tool or not. - - bool IsTool() { return m_HeldDeviceType == TOOL; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsShield -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this is a shield or not. -// Arguments: None. -// Return value: Shield or not. - - bool IsShield() { return m_HeldDeviceType == SHIELD; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDualWieldable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this is a dual wieldable weapon or not. -// Arguments: None. -// Return value: Dual wieldable or not. - - bool IsDualWieldable() const { return m_DualWieldable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDualWieldable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this is a dual wieldable weapon or not. -// Arguments: Dual wieldable or not. -// Return value: None. - - void SetDualWieldable(bool isDualWieldable) { m_DualWieldable = isDualWieldable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsOneHanded -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this can be held and operated effectively with one -// hand or not. -// Arguments: None. -// Return value: One handed device or not. - - bool IsOneHanded() const { return m_OneHanded; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOneHanded -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this can be held and operated effectively with one -// hand or not. -// Arguments: New value. -// Return value: None. - - void SetOneHanded(bool newValue) { m_OneHanded = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. -// Arguments: Reference to the HitData struct which describes the collision. This -// will be modified to represent the results of the collision. -// Return value: Whether the collision has been deemed valid. If false, then disregard -// any impulses in the Hitdata. - - bool CollideAtPoint(HitData &hitData) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Activate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Activates one of this HDFirearm's features. Analogous to 'pulling -// the trigger'. -// Arguments: None. -// Return value: None. - - virtual void Activate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Deactivate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing -// the trigger'. -// Arguments: None. -// Return value: None. - - virtual void Deactivate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reload -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Throws out the currently used Magazine, if any, and puts in a new one -// after the reload delay is up. -// Arguments: None. -// Return value: None. - - virtual void Reload() {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsActivated -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently being activated. -// Arguments: None. -// Return value: Whether being activated. - - virtual bool IsActivated() const { return m_Activated; } - - /// - /// Gets the activation Timer for this HeldDevice. - /// - /// The activation Timer for this HeldDevice. - const Timer & GetActivationTimer() const { return m_ActivationTimer;} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsReloading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently being reloaded. -// Arguments: None. -// Return value: Whetehr being reloaded. - - virtual bool IsReloading() const { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DoneReloading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device just finished reloading this frame. -// Arguments: None. -// Return value: Whether just done reloading this frame. - - virtual bool DoneReloading() const { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: NeedsReloading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently in need of being reloaded. -// Arguments: None. -// Return value: Whetehr in need of reloading (ie not full). - - virtual bool NeedsReloading() const { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsFull -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the device is curtrently full and reloading won't have -// any effect. -// Arguments: None. -// Return value: Whetehr magazine is full or not. - - virtual bool IsFull() const { return true; } - - /// - /// Tells whether this HeldDevice is currently empty of ammo. - /// - /// Whether this HeldDevice is empty. - virtual bool IsEmpty() const { return false; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this HeldDevice's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this' current graphical HUD overlay representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// Which player's screen this is being drawn to. May affect what HUD elements -// get drawn etc. -// Return value: None. - - void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; - - /// - /// Resest all the timers used by this. Can be emitters, etc. This is to prevent backed up emissions to come out all at once while this has been held dormant in an inventory. - /// - void ResetAllTimers() override { Attachable::ResetAllTimers(); m_ActivationTimer.Reset(); } +namespace RTE { + + enum HeldDeviceType { + WEAPON = 0, + TOOL, + SHIELD, + BOMB, + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: HeldDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: An articulated device that can be weilded by an Actor. + // Parent(s): Attachable. + // Class history: 06/2/2002 HeldDevice created. + // 01/31/2007 Made concrete so Shields can be jsut HeldDevice:s + + class HeldDevice : public Attachable { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(HeldDevice); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: HeldDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a HeldDevice object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + HeldDevice() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~HeldDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a HeldDevice object before deletion + // from system memory. + // Arguments: None. + + ~HeldDevice() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the HeldDevice object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a HeldDevice to be identical to another, by deep copy. + // Arguments: A reference to the HeldDevice to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const HeldDevice& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire HeldDevice, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Attachable::Reset(); + m_MOType = MovableObject::TypeHeldDevice; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAboveHUDPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of the top of this' HUD stack. + // Arguments: None. + // Return value: A Vector with the absolute position of this' HUD stack top point. + + Vector GetAboveHUDPos() const override { return m_Pos + Vector(0, -32); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSupportPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the support handhold that this HeldDevice + // offers. + // Arguments: None. + // Return value: A vector describing the absolute world coordinates for the support + // position of this HeldDevice. + + Vector GetSupportPos() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMagazinePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the magazine or other equivalent point of + // this. + // Arguments: None. + // Return value: A vector describing the absolute world coordinates for the magazine + // attachment point of this + + virtual Vector GetMagazinePos() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMuzzlePos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of the muzzle or other equivalent point of + // this. + // Arguments: None. + // Return value: A vector describing the absolute world coordinates for the muzzle point + // of this + + virtual Vector GetMuzzlePos() const { return m_Pos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMuzzleOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the unrotated relative offset from the position to the muzzle or + // other equivalent point of this. + // Arguments: None. + // Return value: A unrotated vector describing the relative for the muzzle point of + // this from this' position. + + virtual Vector GetMuzzleOffset() const { return Vector(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetMuzzleOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the unrotated relative offset from the position to the muzzle or + // other equivalent point of this. + // Arguments: Bew ofsset value. + // Return value: None. + + virtual void SetMuzzleOffset(Vector newOffset) { /* Actually does something in inherited classes */ + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetStanceOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current position offset of this HeldDevice's joint relative + // from the parent Actor's position, if attached. + // Arguments: None. + // Return value: A const reference to the current stance parent offset. + + virtual Vector GetStanceOffset() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetStanceOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current position offset of this HeldDevice's joint relative + // from the parent Actor's position, if attached. + // Arguments: New value. + // Return value: None. + + void SetStanceOffset(Vector newValue) { m_StanceOffset = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetSharpStanceOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current position offset of this HeldDevice's joint relative + // from the parent Actor's position, if attached. + // Arguments: New value. + // Return value: None. + + Vector GetSharpStanceOffset() const { return m_SharpStanceOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetSharpStanceOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current position offset of this HeldDevice's joint relative + // from the parent Actor's position, if attached. + // Arguments: New value. + // Return value: None. + + void SetSharpStanceOffset(Vector newValue) { m_SharpStanceOffset = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetSharpLength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how much farther an Actor which holds this device can see when + // aiming this HeldDevice sharply. + // Arguments: None. + // Return value: The length in world pixel units. + + float GetSharpLength() const { return m_MaxSharpLength; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetSharpLength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets how much farther an Actor which holds this device can see when + // aiming this HeldDevice sharply. + // Arguments: The length in world pixel units. + // Return value: None. + + void SetSharpLength(float newLength) { m_MaxSharpLength = newLength; } + + /// + /// Gets whether this HeldDevice can be supported when held. + /// + /// Whether this HeldDevice can be supported when held. + bool IsSupportable() const { return m_Supportable; } + + /// + /// Sets whether this HeldDevice can be supported when held. + /// + /// Whether this HeldDevice can be supported when held. + void SetSupportable(bool shouldBeSupportable) { m_Supportable = shouldBeSupportable; } + + /// + /// Gets whether this HeldDevice is currently supported by a second Arm. + /// + /// Whether this HeldDevice is supported or not. + bool GetSupported() const { return m_Supportable && m_Supported; } + + /// + /// Sets whether this HeldDevice is currently supported by a second Arm. + /// + /// Whether this HeldDevice is being supported. + void SetSupported(bool supported) { m_Supported = m_Supportable && supported; } + + /// + /// Gets whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). + /// + /// Whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). + bool GetSupportAvailable() const { return m_Supportable && m_SupportAvailable; } + + /// + /// Sets whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). + /// + /// Whether this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). + void SetSupportAvailable(bool supportAvailable) { m_SupportAvailable = m_Supportable && supportAvailable; } + + /// + /// Gets whether this HeldDevice while be held at the support offset with the off-hand when reloading. + /// + /// Whether this HeldDevice while be held at the support offset with the off-hand when reloading. + bool GetUseSupportOffsetWhileReloading() const { return m_UseSupportOffsetWhileReloading; } + + /// + /// Sets whether this HeldDevice while be held at the support offset with the off-hand when reloading. + /// + /// Whether this HeldDevice while be held at the support offset with the off-hand when reloading. + void SetUseSupportOffsetWhileReloading(bool value) { m_UseSupportOffsetWhileReloading = value; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetSupportOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns support offset. + // Arguments: None. + // Return value: Support offset value. + + Vector GetSupportOffset() const { return m_SupportOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetSupportOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets support offset. + // Arguments: New support offset value. + // Return value: None. + + void SetSupportOffset(Vector newOffset) { m_SupportOffset = newOffset; } + + /// + /// Gets whether this HeldDevice has any limitations on what can pick it up. + /// + /// Whether this HeldDevice has any limitations on what can pick it up. + bool HasPickupLimitations() const { return IsUnPickupable() || !m_PickupableByPresetNames.empty(); } + + /// + /// Gets whether this HeldDevice cannot be picked up at all. + /// + /// Whether this HeldDevice cannot be picked up at all. + bool IsUnPickupable() const { return m_IsUnPickupable; } + + /// + /// Sets whether this HeldDevice cannot be picked up at all. + /// + /// Whether this HeldDevice cannot be picked up at all. True means it cannot, false means any other limitations will apply normally. + void SetUnPickupable(bool shouldBeUnPickupable) { m_IsUnPickupable = shouldBeUnPickupable; } + + /// + /// Checks whether the given Actor can pick up this HeldDevice. + /// + /// The Actor to check. Ownership is NOT transferred. + /// Whether the given Actor can pick up this HeldDevice. + bool IsPickupableBy(const Actor* actor) const { return !HasPickupLimitations() || m_PickupableByPresetNames.find(actor->GetPresetName()) != m_PickupableByPresetNames.end(); } + + /// + /// Specify that objects with the given PresetName can pick up this HeldDevice. + /// + /// The PresetName of an object that should be able to pick up this HeldDevice. + void AddPickupableByPresetName(const std::string& presetName) { + SetUnPickupable(false); + m_PickupableByPresetNames.insert(presetName); + } + + /// + /// Remove allowance for objects with the given PresetName to pick up this HeldDevice. + /// Note that if the last allowance is removed, the HeldDevice will no longer have pickup limitations, rather than setting itself as unpickupable. + /// + /// The PresetName of an object that should no longer be able to pick up this HeldDevice. + void RemovePickupableByPresetName(const std::string& actorPresetName); + + /// + /// Gets the multiplier for how well this HeldDevice can be gripped by Arms. + /// + /// The grip strength multiplier for this HeldDevice. + float GetGripStrengthMultiplier() const { return m_GripStrengthMultiplier; } + + /// + /// Sets the multiplier for how well this HeldDevice can be gripped by Arms. + /// + /// The new grip strength multiplier for this HeldDevice. + void SetGripStrengthMultiplier(float gripStrengthMultiplier) { m_GripStrengthMultiplier = gripStrengthMultiplier; } + + /// + /// Gets whether this can get hit by MOs when held. + /// + /// Whether this can get hit by MOs when held. + bool GetsHitByMOsWhenHeld() const { return m_GetsHitByMOsWhenHeld; } + + /// + /// Sets whether this can get hit by MOs when held. + /// + /// Whether this can get hit by MOs when held. + void SetGetsHitByMOsWhenHeld(bool value) { m_GetsHitByMOsWhenHeld = value; } + + /// + /// Gets whether this HeldDevice is currently being held or not. + /// + /// Whether this HeldDevice is currently being held or not. + bool IsBeingHeld() const; + + /// + /// Gets the visual recoil multiplier. + /// + /// A float with the scalar value. + float GetVisualRecoilMultiplier() const { return m_VisualRecoilMultiplier; } + + /// + /// Sets the visual recoil multiplier. + /// + /// The new recoil multiplier scalar. + void SetVisualRecoilMultiplier(float value) { m_VisualRecoilMultiplier = value; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSharpAim + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the degree to which this is being aimed sharp. This will + // affect the accuracy and what GetParentOffset returns. + // Arguments: A normalized scalar between 0 (no sharp aim) to 1.0 (best aim). + // Return value: None. + + void SetSharpAim(float sharpAim) { m_SharpAim = sharpAim; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsWeapon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this is an offensive weapon or not. + // Arguments: None. + // Return value: Offensive weapon or not. + + bool IsWeapon() { return m_HeldDeviceType == WEAPON; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsTool + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this is a tool or not. + // Arguments: None. + // Return value: Tool or not. + + bool IsTool() { return m_HeldDeviceType == TOOL; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsShield + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this is a shield or not. + // Arguments: None. + // Return value: Shield or not. + + bool IsShield() { return m_HeldDeviceType == SHIELD; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDualWieldable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this is a dual wieldable weapon or not. + // Arguments: None. + // Return value: Dual wieldable or not. + + bool IsDualWieldable() const { return m_DualWieldable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDualWieldable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this is a dual wieldable weapon or not. + // Arguments: Dual wieldable or not. + // Return value: None. + + void SetDualWieldable(bool isDualWieldable) { m_DualWieldable = isDualWieldable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsOneHanded + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this can be held and operated effectively with one + // hand or not. + // Arguments: None. + // Return value: One handed device or not. + + bool IsOneHanded() const { return m_OneHanded; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOneHanded + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this can be held and operated effectively with one + // hand or not. + // Arguments: New value. + // Return value: None. + + void SetOneHanded(bool newValue) { m_OneHanded = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + // Arguments: Reference to the HitData struct which describes the collision. This + // will be modified to represent the results of the collision. + // Return value: Whether the collision has been deemed valid. If false, then disregard + // any impulses in the Hitdata. + + bool CollideAtPoint(HitData& hitData) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Activate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Activates one of this HDFirearm's features. Analogous to 'pulling + // the trigger'. + // Arguments: None. + // Return value: None. + + virtual void Activate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Deactivate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Deactivates one of this HDFirearm's features. Analogous to 'releasing + // the trigger'. + // Arguments: None. + // Return value: None. + + virtual void Deactivate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reload + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Throws out the currently used Magazine, if any, and puts in a new one + // after the reload delay is up. + // Arguments: None. + // Return value: None. + + virtual void Reload() {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsActivated + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently being activated. + // Arguments: None. + // Return value: Whether being activated. + + virtual bool IsActivated() const { return m_Activated; } + + /// + /// Gets the activation Timer for this HeldDevice. + /// + /// The activation Timer for this HeldDevice. + const Timer& GetActivationTimer() const { return m_ActivationTimer; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsReloading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently being reloaded. + // Arguments: None. + // Return value: Whetehr being reloaded. + + virtual bool IsReloading() const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DoneReloading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device just finished reloading this frame. + // Arguments: None. + // Return value: Whether just done reloading this frame. + + virtual bool DoneReloading() const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: NeedsReloading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently in need of being reloaded. + // Arguments: None. + // Return value: Whetehr in need of reloading (ie not full). + + virtual bool NeedsReloading() const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsFull + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the device is curtrently full and reloading won't have + // any effect. + // Arguments: None. + // Return value: Whetehr magazine is full or not. + + virtual bool IsFull() const { return true; } + + /// + /// Tells whether this HeldDevice is currently empty of ammo. + /// + /// Whether this HeldDevice is empty. + virtual bool IsEmpty() const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this HeldDevice's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this' current graphical HUD overlay representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // Which player's screen this is being drawn to. May affect what HUD elements + // get drawn etc. + // Return value: None. + + void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + + /// + /// Resest all the timers used by this. Can be emitters, etc. This is to prevent backed up emissions to come out all at once while this has been held dormant in an inventory. + /// + void ResetAllTimers() override { + Attachable::ResetAllTimers(); + m_ActivationTimer.Reset(); + } #pragma region Force Transferral - /// - /// Bundles up all the accumulated impulse forces of this HeldDevice and calculates how they transfer to the joint, and therefore to the parent. - /// If the accumulated impulse forces exceed the joint strength or gib impulse limit of this HeldDevice, the jointImpulses Vector will be filled up to that limit and false will be returned. - /// Additionally, in this case, the HeldDevice will remove itself from its parent, destabilizing said parent if it's an Actor, and gib itself if appropriate. - /// - /// A vector that will have the impulse forces affecting the joint ADDED to it. - /// An optional override for the HeldDevice's joint stiffness for this function call. Primarily used to allow subclasses to perform special behavior. - /// An optional override for the HeldDevice's joint strength for this function call. Primarily used to allow subclasses to perform special behavior. - /// An optional override for the HeldDevice's gib impulse limit for this function call. Primarily used to allow subclasses to perform special behavior. - /// False if the HeldDevice has no parent or its accumulated forces are greater than its joint strength or gib impulse limit, otherwise true. - bool TransferJointImpulses(Vector &jointImpulses, float jointStiffnessValueToUse = -1, float jointStrengthValueToUse = -1, float gibImpulseLimitValueToUse = -1) override; + /// + /// Bundles up all the accumulated impulse forces of this HeldDevice and calculates how they transfer to the joint, and therefore to the parent. + /// If the accumulated impulse forces exceed the joint strength or gib impulse limit of this HeldDevice, the jointImpulses Vector will be filled up to that limit and false will be returned. + /// Additionally, in this case, the HeldDevice will remove itself from its parent, destabilizing said parent if it's an Actor, and gib itself if appropriate. + /// + /// A vector that will have the impulse forces affecting the joint ADDED to it. + /// An optional override for the HeldDevice's joint stiffness for this function call. Primarily used to allow subclasses to perform special behavior. + /// An optional override for the HeldDevice's joint strength for this function call. Primarily used to allow subclasses to perform special behavior. + /// An optional override for the HeldDevice's gib impulse limit for this function call. Primarily used to allow subclasses to perform special behavior. + /// False if the HeldDevice has no parent or its accumulated forces are greater than its joint strength or gib impulse limit, otherwise true. + bool TransferJointImpulses(Vector& jointImpulses, float jointStiffnessValueToUse = -1, float jointStrengthValueToUse = -1, float gibImpulseLimitValueToUse = -1) override; #pragma endregion - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - // Indicates what kind of held device this is, see the HeldDeviceType enum - int m_HeldDeviceType; - // Is this HeldDevice that are currently activated? - bool m_Activated; - // Timer for timing how long a feature has been activated. - Timer m_ActivationTimer; - // Can be weilded well with one hand or not - bool m_OneHanded; - // Can be weilded with bg hand or not - bool m_DualWieldable; - // Position offset from the parent's own position to this HeldDevice's joint, which - // defines the normal stance that an arm that is holding this device should have. - Vector m_StanceOffset; - // The alternative parent offset stance that is used when the device is carefully aimed. - Vector m_SharpStanceOffset; - // The point at which the other arm of the holder can support this HeldDevice. - // Relative to the m_Pos. This is like a seconday handle position. - Vector m_SupportOffset; - // Whether the actor using this gun should keep hold of the support offset when reloading, instead of using their ReloadOffset/HolsterOffset - bool m_UseSupportOffsetWhileReloading; - // The degree as to this is being aimed carefully. 0 means no sharp aim, and 1.0 means best aim. - float m_SharpAim; - // How much farther the player can see when aiming this sharply. - float m_MaxSharpLength; - bool m_Supportable; //!< Whether or not this HeldDevice can be supported. - bool m_Supported; //!< Whether or not this HeldDevice is currently being supported by another Arm. - bool m_SupportAvailable; //!< Whether or not this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). - bool m_IsUnPickupable; //!< Whether or not this HeldDevice should be able to be picked up at all. - //TODO: move this smelly thing elsewhere - std::array m_SeenByPlayer; //!< An array of players that can currently see the pickup HUD of this HeldDevice. - std::unordered_set m_PickupableByPresetNames; //!< The unordered set of PresetNames that can pick up this HeldDevice if it's dropped. An empty set means there are no PresetName limitations. - float m_GripStrengthMultiplier; //!< The multiplier for how well this HeldDevice can be gripped by Arms. - // Blink timer for the icon - Timer m_BlinkTimer; - // How loud this device is when activated. 0 means perfectly quiet 0.5 means half of normal (normal equals audiable from ~half a screen) - float m_Loudness; - // If this weapon belongs to the "Explosive Weapons" group or not - bool m_IsExplosiveWeapon; - // If this device can be hit by MOs whenever it's held - bool m_GetsHitByMOsWhenHeld; - /// The multiplier for visual recoil - float m_VisualRecoilMultiplier; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this HeldDevice, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - HeldDevice(const HeldDevice &reference) = delete; - HeldDevice & operator=(const HeldDevice &rhs) = delete; - -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + // Indicates what kind of held device this is, see the HeldDeviceType enum + int m_HeldDeviceType; + // Is this HeldDevice that are currently activated? + bool m_Activated; + // Timer for timing how long a feature has been activated. + Timer m_ActivationTimer; + // Can be weilded well with one hand or not + bool m_OneHanded; + // Can be weilded with bg hand or not + bool m_DualWieldable; + // Position offset from the parent's own position to this HeldDevice's joint, which + // defines the normal stance that an arm that is holding this device should have. + Vector m_StanceOffset; + // The alternative parent offset stance that is used when the device is carefully aimed. + Vector m_SharpStanceOffset; + // The point at which the other arm of the holder can support this HeldDevice. + // Relative to the m_Pos. This is like a seconday handle position. + Vector m_SupportOffset; + // Whether the actor using this gun should keep hold of the support offset when reloading, instead of using their ReloadOffset/HolsterOffset + bool m_UseSupportOffsetWhileReloading; + // The degree as to this is being aimed carefully. 0 means no sharp aim, and 1.0 means best aim. + float m_SharpAim; + // How much farther the player can see when aiming this sharply. + float m_MaxSharpLength; + bool m_Supportable; //!< Whether or not this HeldDevice can be supported. + bool m_Supported; //!< Whether or not this HeldDevice is currently being supported by another Arm. + bool m_SupportAvailable; //!< Whether or not this HeldDevice's parent has a second Arm available to provide support (or this is on a Turret). + bool m_IsUnPickupable; //!< Whether or not this HeldDevice should be able to be picked up at all. + // TODO: move this smelly thing elsewhere + std::array m_SeenByPlayer; //!< An array of players that can currently see the pickup HUD of this HeldDevice. + std::unordered_set m_PickupableByPresetNames; //!< The unordered set of PresetNames that can pick up this HeldDevice if it's dropped. An empty set means there are no PresetName limitations. + float m_GripStrengthMultiplier; //!< The multiplier for how well this HeldDevice can be gripped by Arms. + // Blink timer for the icon + Timer m_BlinkTimer; + // How loud this device is when activated. 0 means perfectly quiet 0.5 means half of normal (normal equals audiable from ~half a screen) + float m_Loudness; + // If this weapon belongs to the "Explosive Weapons" group or not + bool m_IsExplosiveWeapon; + // If this device can be hit by MOs whenever it's held + bool m_GetsHitByMOsWhenHeld; + /// The multiplier for visual recoil + float m_VisualRecoilMultiplier; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this HeldDevice, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + HeldDevice(const HeldDevice& reference) = delete; + HeldDevice& operator=(const HeldDevice& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/Icon.cpp b/Source/Entities/Icon.cpp index 2bae7cab1..466884be6 100644 --- a/Source/Entities/Icon.cpp +++ b/Source/Entities/Icon.cpp @@ -4,7 +4,7 @@ namespace RTE { ConcreteClassInfo(Icon, Entity, 80); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Icon::Clear() { m_BitmapFile.Reset(); @@ -13,11 +13,13 @@ namespace RTE { m_BitmapsTrueColor.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Icon::Create() { if (m_BitmapsIndexed.empty() || m_BitmapsTrueColor.empty()) { - if (m_BitmapFile.GetDataPath().empty()) { m_BitmapFile.SetDataPath("Base.rte/GUIs/DefaultIcon.png"); } + if (m_BitmapFile.GetDataPath().empty()) { + m_BitmapFile.SetDataPath("Base.rte/GUIs/DefaultIcon.png"); + } m_BitmapFile.GetAsAnimation(m_BitmapsIndexed, m_FrameCount, COLORCONV_REDUCE_TO_256); m_BitmapFile.GetAsAnimation(m_BitmapsTrueColor, m_FrameCount, COLORCONV_8_TO_32); @@ -25,9 +27,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Icon::Create(const Icon &reference) { + int Icon::Create(const Icon& reference) { Entity::Create(reference); m_BitmapFile = reference.m_BitmapFile; @@ -38,20 +40,20 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Icon::ReadProperty(const std::string_view &propName, Reader &reader) { + int Icon::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("BitmapFile", { reader >> m_BitmapFile; }); MatchProperty("FrameCount", { reader >> m_FrameCount; }); EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Icon::Save(Writer &writer) const { + int Icon::Save(Writer& writer) const { Entity::Save(writer); writer.NewProperty("BitmapFile"); writer << m_BitmapFile; @@ -61,10 +63,12 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Icon::Destroy(bool notInherited) { - if (!notInherited) { Entity::Destroy(); } + if (!notInherited) { + Entity::Destroy(); + } Clear(); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/Icon.h b/Source/Entities/Icon.h index 118d50010..364bf73b1 100644 --- a/Source/Entities/Icon.h +++ b/Source/Entities/Icon.h @@ -12,7 +12,6 @@ namespace RTE { class Icon : public Entity { public: - EntityAllocation(Icon); SerializableOverrideMethods; ClassInfoGetters; @@ -27,7 +26,12 @@ namespace RTE { /// Copy constructor method used to instantiate an Icon object identical to an already existing one. /// /// An Icon object which is passed in by reference. - Icon(const Icon &reference) { if (this != &reference) { Clear(); Create(reference); } } + Icon(const Icon& reference) { + if (this != &reference) { + Clear(); + Create(reference); + } + } /// /// Makes the Icon object ready for use. @@ -40,7 +44,7 @@ namespace RTE { /// /// A reference to the Icon to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Icon &reference); + int Create(const Icon& reference); #pragma endregion #pragma region Destruction @@ -58,7 +62,10 @@ namespace RTE { /// /// Resets the entire Icon, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -72,13 +79,13 @@ namespace RTE { /// Gets the array of 8-bit bitmaps of this Icon, as many as GetFrameCount says. Neither the array nor the BITMAPs are transferred ownership! /// /// The BITMAPs in 8bpp of this Icon. - std::vector GetBitmaps8() const { return m_BitmapsIndexed; } + std::vector GetBitmaps8() const { return m_BitmapsIndexed; } /// /// Gets the array of 32-bit bitmaps of this Icon, as many as GetFrameCount says. Neither the array nor the BITMAPs are transferred ownership! /// /// The BITMAPs in 32bpp of this Icon. - std::vector GetBitmaps32() const { return m_BitmapsTrueColor; } + std::vector GetBitmaps32() const { return m_BitmapsTrueColor; } #pragma endregion #pragma region Operator Overloads @@ -87,25 +94,29 @@ namespace RTE { /// /// An Icon reference. /// A reference to the changed Icon. - Icon & operator=(const Icon &rhs) { if (this != &rhs) { Destroy(); Create(rhs); } return *this; } + Icon& operator=(const Icon& rhs) { + if (this != &rhs) { + Destroy(); + Create(rhs); + } + return *this; + } #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. ContentFile m_BitmapFile; //!< ContentFile containing the bitmap file of this Icon. unsigned int m_FrameCount; //!< Number of frames in this Icon's animation. - std::vector m_BitmapsIndexed; //!< Vector containing the 8bpp BITMAPs of this Icon. BITMAPs are NOT owned! - std::vector m_BitmapsTrueColor; //!< Vector containing the 32bpp BITMAPs of this Icon. BITMAPs are NOT owned! + std::vector m_BitmapsIndexed; //!< Vector containing the 8bpp BITMAPs of this Icon. BITMAPs are NOT owned! + std::vector m_BitmapsTrueColor; //!< Vector containing the 32bpp BITMAPs of this Icon. BITMAPs are NOT owned! private: - /// /// Clears all the member variables of this Icon, effectively resetting the members of this abstraction level only. /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/Leg.cpp b/Source/Entities/Leg.cpp index 8b693d513..370a2a46e 100644 --- a/Source/Entities/Leg.cpp +++ b/Source/Entities/Leg.cpp @@ -6,7 +6,7 @@ namespace RTE { ConcreteClassInfo(Leg, Attachable, 50); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Leg::Clear() { m_Foot = nullptr; @@ -27,7 +27,7 @@ namespace RTE { m_MoveSpeed = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Leg::Create() { if (Attachable::Create() < 0) { @@ -40,7 +40,9 @@ namespace RTE { // Ensure Legs don't collide with terrain when attached since their expansion/contraction is frame based so atom group doesn't know how to account for it. SetCollidesWithTerrainWhileAttached(false); - if (m_ContractedOffset.GetSqrMagnitude() > m_ExtendedOffset.GetSqrMagnitude()) { std::swap(m_ContractedOffset, m_ExtendedOffset); } + if (m_ContractedOffset.GetSqrMagnitude() > m_ExtendedOffset.GetSqrMagnitude()) { + std::swap(m_ContractedOffset, m_ExtendedOffset); + } m_MinExtension = m_ContractedOffset.GetMagnitude(); m_MaxExtension = m_ExtendedOffset.GetMagnitude(); @@ -48,12 +50,12 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Leg::Create(const Leg &reference) { + int Leg::Create(const Leg& reference) { if (reference.m_Foot) { m_ReferenceHardcodedAttachableUniqueIDs.insert(reference.m_Foot->GetUniqueID()); - SetFoot(dynamic_cast(reference.m_Foot->Clone())); + SetFoot(dynamic_cast(reference.m_Foot->Clone())); } Attachable::Create(reference); @@ -75,12 +77,12 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Leg::ReadProperty(const std::string_view &propName, Reader &reader) { + int Leg::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Attachable::ReadProperty(propName, reader)); - - MatchProperty("Foot", { SetFoot(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + + MatchProperty("Foot", { SetFoot(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); MatchProperty("ContractedOffset", { reader >> m_ContractedOffset; m_MinExtension = m_ContractedOffset.GetMagnitude(); @@ -96,9 +98,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Leg::Save(Writer &writer) const { + int Leg::Save(Writer& writer) const { Attachable::Save(writer); writer.NewProperty("Foot"); @@ -117,41 +119,45 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Leg::SetFoot(Attachable *newFoot) { - if (m_Foot && m_Foot->IsAttached()) { RemoveAndDeleteAttachable(m_Foot); } + void Leg::SetFoot(Attachable* newFoot) { + if (m_Foot && m_Foot->IsAttached()) { + RemoveAndDeleteAttachable(m_Foot); + } if (newFoot == nullptr) { m_Foot = nullptr; } else { m_Foot = newFoot; AddAttachable(newFoot); - m_HardcodedAttachableUniqueIDsAndSetters.insert({newFoot->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - dynamic_cast(parent)->SetFoot(attachable); - }}); + m_HardcodedAttachableUniqueIDsAndSetters.insert({newFoot->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + dynamic_cast(parent)->SetFoot(attachable); + }}); - if (m_Foot->HasNoSetDamageMultiplier()) { m_Foot->SetDamageMultiplier(1.0F); } + if (m_Foot->HasNoSetDamageMultiplier()) { + m_Foot->SetDamageMultiplier(1.0F); + } m_Foot->SetInheritsRotAngle(false); m_Foot->SetParentGibBlastStrengthMultiplier(0.0F); m_Foot->SetCollidesWithTerrainWhileAttached(false); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - AtomGroup * Leg::GetFootGroupFromFootAtomGroup() { + AtomGroup* Leg::GetFootGroupFromFootAtomGroup() { if (!m_Foot) { return nullptr; } - AtomGroup *footGroup = dynamic_cast(m_Foot->GetAtomGroup()->Clone()); + AtomGroup* footGroup = dynamic_cast(m_Foot->GetAtomGroup()->Clone()); int atomLeftMostOffset = m_Foot->GetSpriteWidth(); int atomTopMostOffset = m_Foot->GetSpriteHeight(); int atomBottomMostOffset = 0; - for (const Atom *atom : footGroup->GetAtomList()) { + for (const Atom* atom: footGroup->GetAtomList()) { int atomOffsetX = atom->GetOriginalOffset().GetFloorIntX(); int atomOffsetY = atom->GetOriginalOffset().GetFloorIntY(); // Auto-generated AtomGroups are created empty so a single Atom is added at 0,0. Ignore it and any others to not screw up detecting the left-most and top-most offsets. @@ -163,7 +169,7 @@ namespace RTE { } int groupCenterOffsetY = (atomTopMostOffset + atomBottomMostOffset) / 2; - std::vector filteredAtomList; + std::vector filteredAtomList; // We want the FootGroup to end up with an "L" shape, so filter all the top and right Atoms while taking into account the heel might be slant and the sole might not be flat. The extra Atoms are not necessary and might (further) screw up some walking physics. // Start from the bottom so we can filter any Atom that might be above the bottom-most one on the same X offset. @@ -172,7 +178,7 @@ namespace RTE { int atomOffsetY = (*atomItr)->GetOriginalOffset().GetFloorIntY(); bool haveBottomMostAtomOnThisXOffset = false; - for (const Atom *filteredAtom : filteredAtomList) { + for (const Atom* filteredAtom: filteredAtomList) { haveBottomMostAtomOnThisXOffset = (filteredAtom->GetOriginalOffset().GetFloorIntX() == atomOffsetX) && (filteredAtom->GetOriginalOffset().GetFloorIntY() > atomOffsetY); if (haveBottomMostAtomOnThisXOffset) { break; @@ -180,7 +186,7 @@ namespace RTE { } if (atomOffsetX == atomLeftMostOffset || atomOffsetY == atomBottomMostOffset || (!haveBottomMostAtomOnThisXOffset && atomOffsetX > atomLeftMostOffset && atomOffsetY >= groupCenterOffsetY)) { - Atom *newAtom = new Atom(*(*atomItr)); + Atom* newAtom = new Atom(*(*atomItr)); newAtom->SetMaterial(g_SceneMan.GetMaterialFromID(MaterialColorKeys::g_MaterialRubber)); filteredAtomList.emplace_back(newAtom); @@ -192,7 +198,7 @@ namespace RTE { return footGroup; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Leg::Update() { Attachable::PreUpdate(); @@ -219,13 +225,15 @@ namespace RTE { UpdateFootFrameAndRotation(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Leg::UpdateCurrentAnkleOffset() { if (IsAttached()) { Vector targetOffset = g_SceneMan.ShortestDistance(m_JointPos, m_TargetPosition, g_SceneMan.SceneWrapsX()); Vector rotatedTargetOffset = targetOffset.GetRadRotatedCopy(m_Parent->GetRotAngle()); - if (m_WillIdle && rotatedTargetOffset.m_Y < -std::abs(rotatedTargetOffset.m_X)) { targetOffset = m_Parent->RotateOffset(m_IdleOffset); } + if (m_WillIdle && rotatedTargetOffset.m_Y < -std::abs(rotatedTargetOffset.m_X)) { + targetOffset = m_Parent->RotateOffset(m_IdleOffset); + } Vector distanceFromTargetOffsetToAnkleOffset(targetOffset - m_AnkleOffset); m_AnkleOffset += distanceFromTargetOffsetToAnkleOffset * m_MoveSpeed; @@ -236,7 +244,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Leg::UpdateLegRotation() { if (IsAttached()) { @@ -257,7 +265,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Leg::UpdateFootFrameAndRotation() { if (m_Foot) { @@ -278,4 +286,4 @@ namespace RTE { } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/Leg.h b/Source/Entities/Leg.h index 8db84f1ce..7d2ab1dd7 100644 --- a/Source/Entities/Leg.h +++ b/Source/Entities/Leg.h @@ -13,7 +13,6 @@ namespace RTE { class Leg : public Attachable { public: - EntityAllocation(Leg); SerializableOverrideMethods; ClassInfoGetters; @@ -35,7 +34,7 @@ namespace RTE { /// /// A reference to the Leg to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Leg &reference); + int Create(const Leg& reference); #pragma endregion #pragma region Destruction @@ -48,12 +47,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the Leg object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Attachable::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Attachable::Destroy(); + } + Clear(); + } /// /// Resets the entire Leg, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Attachable::Reset(); } + void Reset() override { + Clear(); + Attachable::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -61,13 +68,13 @@ namespace RTE { /// Gets the foot of this Leg. /// /// A pointer to foot of this Leg. Ownership is NOT transferred! - Attachable * GetFoot() const { return m_Foot; } + Attachable* GetFoot() const { return m_Foot; } /// /// Sets the foot for this Leg. Ownership IS transferred! /// /// The new foot to use. - void SetFoot(Attachable *newFoot); + void SetFoot(Attachable* newFoot); /// /// Gets the min length this of Leg, the minimum allowed length from its joint to its ankle's position. @@ -97,7 +104,7 @@ namespace RTE { /// Sets the position this Leg should move towards, in absolute coordinates. /// /// The position the Leg should move towards. - void SetTargetPosition(const Vector &targetPosition) { m_TargetPosition = targetPosition; } + void SetTargetPosition(const Vector& targetPosition) { m_TargetPosition = targetPosition; } /// /// Sets whether this Leg will go into idle offset mode if the target appears to be above the joint of the Leg. @@ -111,7 +118,7 @@ namespace RTE { /// Gets a copy of this Leg's foot AtomGroup to be used as an Actor's FootGroup. /// /// A copy of this Leg's foot AtomGroup to be used as an Actor's FootGroup. OWNERSHIP IS TRANSFERRED! - AtomGroup * GetFootGroupFromFootAtomGroup(); + AtomGroup* GetFootGroupFromFootAtomGroup(); #pragma endregion #pragma region Override Methods @@ -122,28 +129,26 @@ namespace RTE { #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - Attachable *m_Foot; //!< Pointer to the foot attachable of this Leg. - + Attachable* m_Foot; //!< Pointer to the foot attachable of this Leg. + Vector m_ContractedOffset; //!< The offset from the joint where the ankle contracts to in the sprite. Vector m_ExtendedOffset; //!< The offset from the joint where the ankle extends to in the sprite. float m_MinExtension; //!< Precalculated min extension of the Leg (from the joint) based on the contracted offset. float m_MaxExtension; //!< Precalculated max extension of the Leg (from the joint) based on the extended offset. float m_NormalizedExtension; //!< Normalized scalar of where the ankle offset's magnitude is between the min and max extensions. - + Vector m_TargetPosition; //!< The absolute position that this Leg's foot is moving towards. Vector m_IdleOffset; //!< The target offset from m_Pos that this Leg's foot is moving towards when allowed to idle and the target position is not acceptable. Vector m_AnkleOffset; //!< Current offset from the joint to the ankle where the foot should be. - + bool m_WillIdle; //!< Whether the Leg will go to idle position if the target position is above the Leg's joint position. float m_MoveSpeed; //!< How fast the Leg moves to a reach target, 0 means it doesn't and 1 means it moves instantly. private: - #pragma region Update Breakdown /// /// Updates the current ankle offset for this Leg. Should only be called from Update. @@ -170,8 +175,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - Leg(const Leg &reference) = delete; - Leg & operator=(const Leg &rhs) = delete; + Leg(const Leg& reference) = delete; + Leg& operator=(const Leg& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/LimbPath.cpp b/Source/Entities/LimbPath.cpp index 599185403..1ab6b095e 100644 --- a/Source/Entities/LimbPath.cpp +++ b/Source/Entities/LimbPath.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,691 +19,628 @@ namespace RTE { -ConcreteClassInfo(LimbPath, Entity, 20); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this LimbPath, effectively -// resetting the members of this abstraction level only. - -void LimbPath::Clear() -{ - m_Start.Reset(); - m_StartSegCount = 0; - m_Segments.clear(); -// m_CurrentSegment = 0; - m_FootCollisionsDisabledSegment = -1; - m_SegProgress = 0.0; - for (int i = 0; i < SPEEDCOUNT; ++i) { - m_TravelSpeed[i] = 0.0; - } - m_TravelSpeedMultiplier = 1.0F; - m_WhichSpeed = NORMAL; - m_PushForce = 0.0; - m_JointPos.Reset(); - m_JointVel.Reset(); - m_Rotation.Reset(); - m_RotationOffset.Reset(); - m_PositionOffset.Reset(); - m_TimeLeft = 0.0; - m_PathTimer.Reset(); - m_SegTimer.Reset(); - m_TotalLength = 0.0; - m_RegularLength = 0.0; - m_SegmentDone = false; - m_Ended = true; - m_HFlipped = false; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the LimbPath object ready for use. - -int LimbPath::Create() -{ - // Read all the properties - if (Entity::Create() < 0) - return -1; - - if (m_Segments.size() > 0) - m_CurrentSegment = m_Segments.begin(); - else - m_CurrentSegment = m_Segments.end(); - - Terminate(); - - return 0; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the LimbPath object ready for use. - -int LimbPath::Create(const Vector &startPoint, - const unsigned int segCount, - const Vector *aSegArray, - const float travelSpeed) -{ - m_StartPoint = startPoint; - m_SegCount = segCount; - m_TravelSpeed = travelSpeed; - - m_Segments = new Vector[m_SegCount]; - - if (aSegArray) - { - for (int i = 0; i < m_SegCount; ++i) - m_Segments[i] = aSegArray[i]; - } - - return 0; -} -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a LimbPath to be identical to another, by deep copy. - -int LimbPath::Create(const LimbPath &reference) -{ - Entity::Create(reference); - - m_Start = reference.m_Start; - m_StartSegCount = reference.m_StartSegCount; - - std::deque::const_iterator itr; - for (itr = reference.m_Segments.begin(); itr != reference.m_Segments.end(); ++itr) - m_Segments.push_back(*itr); - - if (m_Segments.size() > 0) - m_CurrentSegment = m_Segments.begin(); - else - m_CurrentSegment = m_Segments.end(); - - m_FootCollisionsDisabledSegment = reference.m_FootCollisionsDisabledSegment; - - m_SegProgress = reference.m_SegProgress; - for (int i = 0; i < SPEEDCOUNT; ++i) { - m_TravelSpeed[i] = reference.m_TravelSpeed[i]; - } - m_TravelSpeedMultiplier = reference.m_TravelSpeedMultiplier; - m_PushForce = reference.m_PushForce; - m_TimeLeft = reference.m_TimeLeft; - m_TotalLength = reference.m_TotalLength; - m_RegularLength = reference.m_RegularLength; - m_SegmentDone = reference.m_SegmentDone; - m_HFlipped = reference.m_HFlipped; - - Terminate(); - - return 0; -} + ConcreteClassInfo(LimbPath, Entity, 20); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this LimbPath, effectively + // resetting the members of this abstraction level only. + + void LimbPath::Clear() { + m_Start.Reset(); + m_StartSegCount = 0; + m_Segments.clear(); + // m_CurrentSegment = 0; + m_FootCollisionsDisabledSegment = -1; + m_SegProgress = 0.0; + for (int i = 0; i < SPEEDCOUNT; ++i) { + m_TravelSpeed[i] = 0.0; + } + m_TravelSpeedMultiplier = 1.0F; + m_WhichSpeed = NORMAL; + m_PushForce = 0.0; + m_JointPos.Reset(); + m_JointVel.Reset(); + m_Rotation.Reset(); + m_RotationOffset.Reset(); + m_PositionOffset.Reset(); + m_TimeLeft = 0.0; + m_PathTimer.Reset(); + m_SegTimer.Reset(); + m_TotalLength = 0.0; + m_RegularLength = 0.0; + m_SegmentDone = false; + m_Ended = true; + m_HFlipped = false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the LimbPath object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int LimbPath::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(Entity::ReadProperty(propName, reader)); - - MatchProperty("StartOffset", { reader >> m_Start; }); - MatchProperty("StartSegCount", { reader >> m_StartSegCount; }); - MatchProperty("AddSegment", - { - Vector segment; - reader >> segment; - m_Segments.push_back(segment); - m_TotalLength += segment.GetMagnitude(); - if (m_Segments.size() >= m_StartSegCount) { - m_RegularLength += segment.GetMagnitude(); - } - }); - MatchProperty("EndSegCount", { reader >> m_FootCollisionsDisabledSegment; }); - - MatchProperty("SlowTravelSpeed", { - reader >> m_TravelSpeed[SLOW]; - //m_TravelSpeed[SLOW] = m_TravelSpeed[SLOW] * 2; - }); - MatchProperty("NormalTravelSpeed", { - reader >> m_TravelSpeed[NORMAL]; - //m_TravelSpeed[NORMAL] = m_TravelSpeed[NORMAL] * 2; - }); - MatchProperty("FastTravelSpeed", { - reader >> m_TravelSpeed[FAST]; - //m_TravelSpeed[FAST] = m_TravelSpeed[FAST] * 2; - }); - MatchProperty("TravelSpeedMultiplier", { reader >> m_TravelSpeedMultiplier; }); - MatchProperty("PushForce", { - reader >> m_PushForce; - //m_PushForce = m_PushForce / 1.5; - }); - - EndPropertyList; -} - - -Vector LimbPath::RotatePoint(const Vector &point) const { - Vector offset = (m_RotationOffset).GetXFlipped(m_HFlipped); - return (((point - offset) * m_Rotation) + offset) + m_PositionOffset; -} + int LimbPath::Create() { + // Read all the properties + if (Entity::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this LimbPath with a Writer for -// later recreation with Create(Reader &reader); - -int LimbPath::Save(Writer &writer) const -{ - Entity::Save(writer); - - writer.NewProperty("StartOffset"); - writer << m_Start; - writer.NewProperty("StartSegCount"); - writer << m_StartSegCount; - for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) - { - writer.NewProperty("AddSegment"); - writer << *itr; - } - writer.NewProperty("SlowTravelSpeed"); - writer << m_TravelSpeed[SLOW]; - writer.NewProperty("NormalTravelSpeed"); - writer << m_TravelSpeed[NORMAL]; - writer.NewProperty("FastTravelSpeed"); - writer << m_TravelSpeed[FAST]; - writer.NewProperty("TravelSpeedMultiplier"); - writer << m_TravelSpeedMultiplier; - writer.NewProperty("PushForce"); - writer << m_PushForce; - - return 0; -} + if (m_Segments.size() > 0) + m_CurrentSegment = m_Segments.begin(); + else + m_CurrentSegment = m_Segments.end(); + Terminate(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the LimbPath object. - -void LimbPath::Destroy(bool notInherited) -{ - - if (!notInherited) - Entity::Destroy(); - Clear(); -} + return 0; + } + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the LimbPath object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetProgressPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the APPROXIMATE scene position that the limb was reported to be -// last frame. - -Vector LimbPath::GetProgressPos() -{ - Vector returnVec(m_Start); - if (IsStaticPoint()) { - return m_JointPos + RotatePoint(returnVec); - } + int LimbPath::Create(const Vector &startPoint, + const unsigned int segCount, + const Vector *aSegArray, + const float travelSpeed) + { + m_StartPoint = startPoint; + m_SegCount = segCount; + m_TravelSpeed = travelSpeed; - // Add all the segments before the current one - std::deque::const_iterator itr; - for (itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) { - returnVec += *itr; - } + m_Segments = new Vector[m_SegCount]; - // Add any from the progress made on the current one - if (itr != m_Segments.end()) { - returnVec += *m_CurrentSegment * m_SegProgress; - } + if (aSegArray) + { + for (int i = 0; i < m_SegCount; ++i) + m_Segments[i] = aSegArray[i]; + } - return m_JointPos + RotatePoint(returnVec); -} + return 0; + } + */ + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a LimbPath to be identical to another, by deep copy. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentSegTarget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the scene/world position target that the current segment represents. + int LimbPath::Create(const LimbPath& reference) { + Entity::Create(reference); -Vector LimbPath::GetCurrentSegTarget() -{ - Vector returnVec(m_Start); - if (IsStaticPoint()) { - return m_JointPos + RotatePoint(returnVec); - } + m_Start = reference.m_Start; + m_StartSegCount = reference.m_StartSegCount; - std::deque::const_iterator itr; + std::deque::const_iterator itr; + for (itr = reference.m_Segments.begin(); itr != reference.m_Segments.end(); ++itr) + m_Segments.push_back(*itr); - for (itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) { - returnVec += *itr; - } + if (m_Segments.size() > 0) + m_CurrentSegment = m_Segments.begin(); + else + m_CurrentSegment = m_Segments.end(); - if (itr != m_Segments.end()) { - returnVec += *m_CurrentSegment; - } + m_FootCollisionsDisabledSegment = reference.m_FootCollisionsDisabledSegment; - return m_JointPos + RotatePoint(returnVec); -} + m_SegProgress = reference.m_SegProgress; + for (int i = 0; i < SPEEDCOUNT; ++i) { + m_TravelSpeed[i] = reference.m_TravelSpeed[i]; + } + m_TravelSpeedMultiplier = reference.m_TravelSpeedMultiplier; + m_PushForce = reference.m_PushForce; + m_TimeLeft = reference.m_TimeLeft; + m_TotalLength = reference.m_TotalLength; + m_RegularLength = reference.m_RegularLength; + m_SegmentDone = reference.m_SegmentDone; + m_HFlipped = reference.m_HFlipped; + Terminate(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the velocity of the current position on the path. -// Note that this should be called BEFORE GetNextVec() if the -// appropriate matching velocity is to be returned here. If the limb -// doesn't hit the end of a segment before the time chunk runs out, -// the returned move vector is limited by the time chunk. + return 0; + } -Vector LimbPath::GetCurrentVel(const Vector &limbPos) -{ - Vector returnVel; - Vector distVect = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()); - float adjustedTravelSpeed = (m_TravelSpeed[m_WhichSpeed] / (1.0F + std::abs(m_JointVel.GetY()) * 0.1F)) * m_TravelSpeedMultiplier; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int LimbPath::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(Entity::ReadProperty(propName, reader)); + + MatchProperty("StartOffset", { reader >> m_Start; }); + MatchProperty("StartSegCount", { reader >> m_StartSegCount; }); + MatchProperty("AddSegment", + { + Vector segment; + reader >> segment; + m_Segments.push_back(segment); + m_TotalLength += segment.GetMagnitude(); + if (m_Segments.size() >= m_StartSegCount) { + m_RegularLength += segment.GetMagnitude(); + } + }); + MatchProperty("EndSegCount", { reader >> m_FootCollisionsDisabledSegment; }); + + MatchProperty("SlowTravelSpeed", { + reader >> m_TravelSpeed[SLOW]; + // m_TravelSpeed[SLOW] = m_TravelSpeed[SLOW] * 2; + }); + MatchProperty("NormalTravelSpeed", { + reader >> m_TravelSpeed[NORMAL]; + // m_TravelSpeed[NORMAL] = m_TravelSpeed[NORMAL] * 2; + }); + MatchProperty("FastTravelSpeed", { + reader >> m_TravelSpeed[FAST]; + // m_TravelSpeed[FAST] = m_TravelSpeed[FAST] * 2; + }); + MatchProperty("TravelSpeedMultiplier", { reader >> m_TravelSpeedMultiplier; }); + MatchProperty("PushForce", { + reader >> m_PushForce; + // m_PushForce = m_PushForce / 1.5; + }); + + EndPropertyList; + } - if (IsStaticPoint()) - { - returnVel = distVect * c_MPP / 0.020/* + m_JointVel*/; - returnVel.CapMagnitude(adjustedTravelSpeed); - returnVel += m_JointVel; + Vector LimbPath::RotatePoint(const Vector& point) const { + Vector offset = (m_RotationOffset).GetXFlipped(m_HFlipped); + return (((point - offset) * m_Rotation) + offset) + m_PositionOffset; + } -// if (distVect.MagnitudeIsLessThan(0.5F)) -// returnVel *= 0.1; - } - else - { - returnVel.SetXY(adjustedTravelSpeed, 0); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this LimbPath with a Writer for + // later recreation with Create(Reader &reader); + + int LimbPath::Save(Writer& writer) const { + Entity::Save(writer); + + writer.NewProperty("StartOffset"); + writer << m_Start; + writer.NewProperty("StartSegCount"); + writer << m_StartSegCount; + for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) { + writer.NewProperty("AddSegment"); + writer << *itr; + } + writer.NewProperty("SlowTravelSpeed"); + writer << m_TravelSpeed[SLOW]; + writer.NewProperty("NormalTravelSpeed"); + writer << m_TravelSpeed[NORMAL]; + writer.NewProperty("FastTravelSpeed"); + writer << m_TravelSpeed[FAST]; + writer.NewProperty("TravelSpeedMultiplier"); + writer << m_TravelSpeedMultiplier; + writer.NewProperty("PushForce"); + writer << m_PushForce; + + return 0; + } - if (!distVect.IsZero()) - returnVel.AbsRotateTo(distVect); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the LimbPath object. - returnVel += m_JointVel; - } + void LimbPath::Destroy(bool notInherited) { - return returnVel; -} + if (!notInherited) + Entity::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetProgressPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the APPROXIMATE scene position that the limb was reported to be + // last frame. + + Vector LimbPath::GetProgressPos() { + Vector returnVec(m_Start); + if (IsStaticPoint()) { + return m_JointPos + RotatePoint(returnVec); + } + + // Add all the segments before the current one + std::deque::const_iterator itr; + for (itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) { + returnVec += *itr; + } + + // Add any from the progress made on the current one + if (itr != m_Segments.end()) { + returnVec += *m_CurrentSegment * m_SegProgress; + } + + return m_JointPos + RotatePoint(returnVec); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextTimeChunk -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the time needed to get to the target waypoint of the current -// segment at the current speed, if there are no obstacles. The chunk -// will not exceed the remaining time left on the frame, and will deduct -// itself from the remaining frame time tally (originally set by -// SetFrameTime()). - -float LimbPath::GetNextTimeChunk(const Vector &limbPos) -{ - float timeChunk; - - if (IsStaticPoint()) - { - // Use all the time to get to the target point. - timeChunk = m_TimeLeft; - m_TimeLeft = 0.0; - } - else - { - Vector distance; - // Figure out the distance, in meters, between the limb position and the target. - distance = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()) * c_MPP; - // Add the distance needed to be traveled due to the joint velocity. -// distance += m_JointVel * m_TimeLeft; - - // Figure out the time needed to get to the target at the current speed, if - // there are no obstacles. - timeChunk = distance.GetMagnitude() / (GetSpeed() + m_JointVel.GetMagnitude()); - // Cap the time segment off to what we have left, if needed. - timeChunk = timeChunk > m_TimeLeft ? m_TimeLeft : timeChunk; - // Deduct the time used to pushtravel from the total time left. - m_TimeLeft -= timeChunk; - } - - return timeChunk; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentSegTarget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the scene/world position target that the current segment represents. + Vector LimbPath::GetCurrentSegTarget() { + Vector returnVec(m_Start); + if (IsStaticPoint()) { + return m_JointPos + RotatePoint(returnVec); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReportProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Used to report how much progress was made to getting the limb close to -// the target (the next segment start). - -void LimbPath::ReportProgress(const Vector &limbPos) -{ - if (IsStaticPoint()) { - const float staticPointEndedThreshold = 1.0F; - m_Ended = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()).MagnitudeIsLessThan(staticPointEndedThreshold); - } else { - // Check if we are sufficiently close to the target to start going after the next one. - Vector distVec = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()); - float distance = distVec.GetMagnitude(); - float segMag = (*(m_CurrentSegment)).GetMagnitude(); - - // TODO: Don't hardcode this!") - const float segmentEndedThreshold = 1.5F; - if (distance < segmentEndedThreshold) - { - if (++(m_CurrentSegment) == m_Segments.end()) - { - --(m_CurrentSegment); - // Get normalized progress measure toward the target. - m_SegProgress = distance > segMag ? 0.0F : (1.0F - (distance / segMag)); - m_Ended = true; - } - // Next segment! - else - { - m_SegProgress = 0.0; - m_SegTimer.Reset(); - m_Ended = false; - } - } - else - { - m_SegProgress = distance > segMag ? 0.0F : (1.0F - (distance / segMag)); - m_Ended = false; - } - } -} + std::deque::const_iterator itr; + for (itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) { + returnVec += *itr; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a value representing the total progress that has been made on -// this entire path. If the path has ended, 0.0 is returned. - -float LimbPath::GetTotalProgress() const -{ - if (m_Ended || IsStaticPoint()) - return 0.0; + if (itr != m_Segments.end()) { + returnVec += *m_CurrentSegment; + } - float prog = 0; - for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) - prog += itr->GetMagnitude(); + return m_JointPos + RotatePoint(returnVec); + } - prog += (*(m_CurrentSegment)).GetMagnitude() * m_SegProgress; - return prog / m_TotalLength; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the velocity of the current position on the path. + // Note that this should be called BEFORE GetNextVec() if the + // appropriate matching velocity is to be returned here. If the limb + // doesn't hit the end of a segment before the time chunk runs out, + // the returned move vector is limited by the time chunk. + + Vector LimbPath::GetCurrentVel(const Vector& limbPos) { + Vector returnVel; + Vector distVect = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()); + float adjustedTravelSpeed = (m_TravelSpeed[m_WhichSpeed] / (1.0F + std::abs(m_JointVel.GetY()) * 0.1F)) * m_TravelSpeedMultiplier; + + if (IsStaticPoint()) { + returnVel = distVect * c_MPP / 0.020 /* + m_JointVel*/; + returnVel.CapMagnitude(adjustedTravelSpeed); + returnVel += m_JointVel; + + // if (distVect.MagnitudeIsLessThan(0.5F)) + // returnVel *= 0.1; + } else { + returnVel.SetXY(adjustedTravelSpeed, 0); + + if (!distVect.IsZero()) + returnVel.AbsRotateTo(distVect); + + returnVel += m_JointVel; + } + + return returnVel; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextTimeChunk + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the time needed to get to the target waypoint of the current + // segment at the current speed, if there are no obstacles. The chunk + // will not exceed the remaining time left on the frame, and will deduct + // itself from the remaining frame time tally (originally set by + // SetFrameTime()). + + float LimbPath::GetNextTimeChunk(const Vector& limbPos) { + float timeChunk; + + if (IsStaticPoint()) { + // Use all the time to get to the target point. + timeChunk = m_TimeLeft; + m_TimeLeft = 0.0; + } else { + Vector distance; + // Figure out the distance, in meters, between the limb position and the target. + distance = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()) * c_MPP; + // Add the distance needed to be traveled due to the joint velocity. + // distance += m_JointVel * m_TimeLeft; + + // Figure out the time needed to get to the target at the current speed, if + // there are no obstacles. + timeChunk = distance.GetMagnitude() / (GetSpeed() + m_JointVel.GetMagnitude()); + // Cap the time segment off to what we have left, if needed. + timeChunk = timeChunk > m_TimeLeft ? m_TimeLeft : timeChunk; + // Deduct the time used to pushtravel from the total time left. + m_TimeLeft -= timeChunk; + } + + return timeChunk; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRegularProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a value representing the progress that has been made on the -// regular part of this path, ie everything except the starting segments. -// If progress has not been made past the starting segments, < 0 will -// be returned. If the path has ended, 0.0 is returned. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReportProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Used to report how much progress was made to getting the limb close to + // the target (the next segment start). + + void LimbPath::ReportProgress(const Vector& limbPos) { + if (IsStaticPoint()) { + const float staticPointEndedThreshold = 1.0F; + m_Ended = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()).MagnitudeIsLessThan(staticPointEndedThreshold); + } else { + // Check if we are sufficiently close to the target to start going after the next one. + Vector distVec = g_SceneMan.ShortestDistance(limbPos, GetCurrentSegTarget()); + float distance = distVec.GetMagnitude(); + float segMag = (*(m_CurrentSegment)).GetMagnitude(); + + // TODO: Don't hardcode this!") + const float segmentEndedThreshold = 1.5F; + if (distance < segmentEndedThreshold) { + if (++(m_CurrentSegment) == m_Segments.end()) { + --(m_CurrentSegment); + // Get normalized progress measure toward the target. + m_SegProgress = distance > segMag ? 0.0F : (1.0F - (distance / segMag)); + m_Ended = true; + } + // Next segment! + else { + m_SegProgress = 0.0; + m_SegTimer.Reset(); + m_Ended = false; + } + } else { + m_SegProgress = distance > segMag ? 0.0F : (1.0F - (distance / segMag)); + m_Ended = false; + } + } + } -float LimbPath::GetRegularProgress() const -{ - if (m_Ended || IsStaticPoint()) - return 0.0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a value representing the total progress that has been made on + // this entire path. If the path has ended, 0.0 is returned. - float prog = m_RegularLength - m_TotalLength; - for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) - prog += itr->GetMagnitude(); - prog += (*(m_CurrentSegment)).GetMagnitude() * m_SegProgress; + float LimbPath::GetTotalProgress() const { + if (m_Ended || IsStaticPoint()) + return 0.0; - return prog / m_RegularLength; -} + float prog = 0; + for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) + prog += itr->GetMagnitude(); + prog += (*(m_CurrentSegment)).GetMagnitude() * m_SegProgress; + return prog / m_TotalLength; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRegularProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a value representing the progress that has been made on the + // regular part of this path, ie everything except the starting segments. + // If progress has not been made past the starting segments, < 0 will + // be returned. If the path has ended, 0.0 is returned. -int LimbPath::GetCurrentSegmentNumber() const { - int progress = 0; - if (!m_Ended && !IsStaticPoint()) { - for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) { - progress++; - } - } - return progress; -} + float LimbPath::GetRegularProgress() const { + if (m_Ended || IsStaticPoint()) + return 0.0; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float prog = m_RegularLength - m_TotalLength; + for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) + prog += itr->GetMagnitude(); + prog += (*(m_CurrentSegment)).GetMagnitude() * m_SegProgress; + return prog / m_RegularLength; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the speed that a limb traveling this LimbPath should have to one -// of the three predefined speed settings. - -void LimbPath::SetSpeed(int newSpeed) -{ - if (newSpeed <= SLOW) - m_WhichSpeed = SLOW; - else if (newSpeed >= FAST) - m_WhichSpeed = FAST; - else - m_WhichSpeed = NORMAL; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OverrideSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the speed that a limb traveling this LimbPath with the specified preset should have. + int LimbPath::GetCurrentSegmentNumber() const { + int progress = 0; + if (!m_Ended && !IsStaticPoint()) { + for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_CurrentSegment; ++itr) { + progress++; + } + } + return progress; + } -void LimbPath::OverrideSpeed(int speedPreset, float newSpeed) -{ - if (speedPreset == SLOW || speedPreset == FAST || speedPreset == NORMAL) - { - m_TravelSpeed[m_WhichSpeed] = newSpeed; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the speed that a limb traveling this LimbPath should have to one + // of the three predefined speed settings. + + void LimbPath::SetSpeed(int newSpeed) { + if (newSpeed <= SLOW) + m_WhichSpeed = SLOW; + else if (newSpeed >= FAST) + m_WhichSpeed = FAST; + else + m_WhichSpeed = NORMAL; } -} -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Terminate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this LimbPath's progress to its end. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OverrideSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the speed that a limb traveling this LimbPath with the specified preset should have. -void LimbPath::Terminate() -{ - if (IsStaticPoint()) { - m_Ended = true; - } - else { - m_CurrentSegment = --(m_Segments.end()); - m_SegProgress = 1.0; - m_Ended = true; - } -} + void LimbPath::OverrideSpeed(int speedPreset, float newSpeed) { + if (speedPreset == SLOW || speedPreset == FAST || speedPreset == NORMAL) { + m_TravelSpeed[m_WhichSpeed] = newSpeed; + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Terminate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this LimbPath's progress to its end. + + void LimbPath::Terminate() { + if (IsStaticPoint()) { + m_Ended = true; + } else { + m_CurrentSegment = --(m_Segments.end()); + m_SegProgress = 1.0; + m_Ended = true; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Restart -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Restarts the position tracking of the limb that travels along this -// LimbPath. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Restart + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Restarts the position tracking of the limb that travels along this + // LimbPath. + + void LimbPath::Restart() { + m_CurrentSegment = m_Segments.begin(); + m_PathTimer.Reset(); + m_SegTimer.Reset(); + m_SegProgress = 0; + m_Ended = false; + } -void LimbPath::Restart() -{ - m_CurrentSegment = m_Segments.begin(); - m_PathTimer.Reset(); - m_SegTimer.Reset(); - m_SegProgress = 0; - m_Ended = false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RestartFree + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Restarts the position tracking of the limb that travels along this + // LimbPath at a point which does not contain terrain. In doing this, + // a list of potential starting segments are checked and the first to + // yield a starting position that is not in terrain will be picked. + // If none of the candidate starting segments are free of terrain, + // the last one in the list will be picked and false will be returned + // here. The passed in limbPos Vector will be set to the new position of + // the restarted path, if a free spot is found. + + bool LimbPath::RestartFree(Vector& limbPos, MOID MOIDToIgnore, int ignoreTeam) { + std::deque::iterator prevSeg = m_CurrentSegment; + float prevProg = m_SegProgress; + m_SegProgress = 0; + bool found = false; + float result = 0; + + if (IsStaticPoint()) { + Vector notUsed; + Vector targetPos = m_JointPos + RotatePoint(m_Start); + Vector beginPos = targetPos; + // TODO: don't hardcode the beginpos + beginPos.m_Y -= 24; + + result = g_SceneMan.CastObstacleRay(beginPos, targetPos - beginPos, notUsed, limbPos, MOIDToIgnore, ignoreTeam, g_MaterialGrass); + + // Only indicate that we found free position if there were any free pixels encountered + if (result < 0 || result > 0) + found = true; + } else { + Vector notUsed; + + // Start at the very beginning of the path + m_CurrentSegment = m_Segments.begin(); + + // Find the first start segment that has an obstacle on it + int i = 0; + for (; i < m_StartSegCount; ++i) { + Vector offsetSegment = (*m_CurrentSegment); + result = g_SceneMan.CastObstacleRay(GetProgressPos(), RotatePoint(offsetSegment), notUsed, limbPos, MOIDToIgnore, ignoreTeam, g_MaterialGrass); + + // If we found an obstacle after the first pixel, report the current segment as the starting one and that there is free space here + if (result > 0) { + // Set accurate segment progress + // TODO: See if this is a good idea, or if we should just set it to 0 and set limbPos to the start of current segment + m_SegProgress = g_SceneMan.ShortestDistance(GetProgressPos(), limbPos).GetMagnitude() / offsetSegment.GetMagnitude(); + limbPos = GetProgressPos(); + // m_SegProgress = 0; + m_Ended = false; + found = true; + break; + } + // If obstacle was found on first pixel, report last segment as restarting pos, if there was a last segment + else if (result == 0 && m_CurrentSegment != m_Segments.begin()) { + // Use last segment + --(m_CurrentSegment); + limbPos = GetProgressPos(); + m_SegProgress = 0; + m_Ended = false; + found = true; + break; + } + // If obstacle was found on the first pixel of the first segment, then just report that we couldn't find any free space + else if (result == 0 && m_CurrentSegment == m_Segments.begin()) { + found = false; + break; + } + + // Check next segment, and quit if it's the end + if (++(m_CurrentSegment) == m_Segments.end()) { + found = false; + break; + } + } + + // If we couldn't find any obstacles on the starting segments, then set it to the first non-starting seg and report success + if (!found && i == m_StartSegCount && m_CurrentSegment != m_Segments.end()) { + limbPos = GetProgressPos(); + m_SegProgress = 0; + m_Ended = false; + found = true; + } + } + + if (found) { + m_PathTimer.Reset(); + m_SegTimer.Reset(); + return true; + } + + // Failed to find free space, so set back to old state + m_CurrentSegment = prevSeg; + m_SegProgress = prevProg; + return false; + } + // Todo - cache this instead of recalculating each time! + float LimbPath::GetLowestY() const { + float lowestY = m_Start.GetY(); + for (auto itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) { + lowestY = std::max(itr->GetY(), lowestY); + } + return lowestY; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RestartFree -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Restarts the position tracking of the limb that travels along this -// LimbPath at a point which does not contain terrain. In doing this, -// a list of potential starting segments are checked and the first to -// yield a starting position that is not in terrain will be picked. -// If none of the candidate starting segments are free of terrain, -// the last one in the list will be picked and false will be returned -// here. The passed in limbPos Vector will be set to the new position of -// the restarted path, if a free spot is found. - -bool LimbPath::RestartFree(Vector &limbPos, MOID MOIDToIgnore, int ignoreTeam) -{ - std::deque::iterator prevSeg = m_CurrentSegment; - float prevProg = m_SegProgress; - m_SegProgress = 0; - bool found = false; - float result = 0; - - if (IsStaticPoint()) - { - Vector notUsed; - Vector targetPos = m_JointPos + RotatePoint(m_Start); - Vector beginPos = targetPos; -// TODO: don't hardcode the beginpos - beginPos.m_Y -= 24; - - result = g_SceneMan.CastObstacleRay(beginPos, targetPos - beginPos, notUsed, limbPos, MOIDToIgnore, ignoreTeam, g_MaterialGrass); - - // Only indicate that we found free position if there were any free pixels encountered - if (result < 0 || result > 0) - found = true; - } - else - { - Vector notUsed; - - // Start at the very beginning of the path - m_CurrentSegment = m_Segments.begin(); - - // Find the first start segment that has an obstacle on it - int i = 0; - for (; i < m_StartSegCount; ++i) - { - Vector offsetSegment = (*m_CurrentSegment); - result = g_SceneMan.CastObstacleRay(GetProgressPos(), RotatePoint(offsetSegment), notUsed, limbPos, MOIDToIgnore, ignoreTeam, g_MaterialGrass); - - // If we found an obstacle after the first pixel, report the current segment as the starting one and that there is free space here - if (result > 0) - { - // Set accurate segment progress -// TODO: See if this is a good idea, or if we should just set it to 0 and set limbPos to the start of current segment - m_SegProgress = g_SceneMan.ShortestDistance(GetProgressPos(), limbPos).GetMagnitude() / offsetSegment.GetMagnitude(); - limbPos = GetProgressPos(); -// m_SegProgress = 0; - m_Ended = false; - found = true; - break; - } - // If obstacle was found on first pixel, report last segment as restarting pos, if there was a last segment - else if (result == 0 && m_CurrentSegment != m_Segments.begin()) - { - // Use last segment - --(m_CurrentSegment); - limbPos = GetProgressPos(); - m_SegProgress = 0; - m_Ended = false; - found = true; - break; - } - // If obstacle was found on the first pixel of the first segment, then just report that we couldn't find any free space - else if (result == 0 && m_CurrentSegment == m_Segments.begin()) - { - found = false; - break; - } - - // Check next segment, and quit if it's the end - if (++(m_CurrentSegment) == m_Segments.end()) - { - found = false; - break; - } - } - - // If we couldn't find any obstacles on the starting segments, then set it to the first non-starting seg and report success - if (!found && i == m_StartSegCount && m_CurrentSegment != m_Segments.end()) - { - limbPos = GetProgressPos(); - m_SegProgress = 0; - m_Ended = false; - found = true; - } - } - - if (found) - { - m_PathTimer.Reset(); - m_SegTimer.Reset(); - return true; - } - - // Failed to find free space, so set back to old state - m_CurrentSegment = prevSeg; - m_SegProgress = prevProg; - return false; -} - -// Todo - cache this instead of recalculating each time! -float LimbPath::GetLowestY() const -{ - float lowestY = m_Start.GetY(); - for (auto itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) { - lowestY = std::max(itr->GetY(), lowestY); - } - return lowestY; -} - -// Todo - cache this instead of recalculating each time! -float LimbPath::GetMiddleX() const -{ - float lowestX = m_Start.GetX(); - float highestX = m_Start.GetX(); - for (auto itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) { - lowestX = std::min(itr->GetX(), lowestX); - highestX = std::max(itr->GetX(), highestX); - } - float result = (lowestX + highestX) * 0.5F; - return m_HFlipped ? -result : result; -} + // Todo - cache this instead of recalculating each time! + float LimbPath::GetMiddleX() const { + float lowestX = m_Start.GetX(); + float highestX = m_Start.GetX(); + for (auto itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) { + lowestX = std::min(itr->GetX(), lowestX); + highestX = std::max(itr->GetX(), highestX); + } + float result = (lowestX + highestX) * 0.5F; + return m_HFlipped ? -result : result; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this LimbPath's current graphical debug representation to a + // BITMAP of choice. + + void LimbPath::Draw(BITMAP* pTargetBitmap, + const Vector& targetPos, + unsigned char color) const { + Vector prevPoint = m_Start; + Vector nextPoint = prevPoint; + for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) { + nextPoint += *itr; + + Vector prevWorldPosition = m_JointPos + RotatePoint(prevPoint); + Vector nextWorldPosition = m_JointPos + RotatePoint(nextPoint); + line(pTargetBitmap, prevWorldPosition.m_X, prevWorldPosition.m_Y, nextWorldPosition.m_X, nextWorldPosition.m_Y, color); + + Vector min(std::min(prevWorldPosition.m_X, nextWorldPosition.m_X), std::min(prevWorldPosition.m_Y, nextWorldPosition.m_Y)); + Vector max(std::max(prevWorldPosition.m_X, nextWorldPosition.m_X), std::max(prevWorldPosition.m_Y, nextWorldPosition.m_Y)); + g_SceneMan.RegisterDrawing(pTargetBitmap, g_NoMOID, min.m_X, max.m_Y, max.m_X, min.m_Y); + + prevPoint += *itr; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this LimbPath's current graphical debug representation to a -// BITMAP of choice. - -void LimbPath::Draw(BITMAP *pTargetBitmap, - const Vector &targetPos, - unsigned char color) const -{ - Vector prevPoint = m_Start; - Vector nextPoint = prevPoint; - for (std::deque::const_iterator itr = m_Segments.begin(); itr != m_Segments.end(); ++itr) - { - nextPoint += *itr; - - Vector prevWorldPosition = m_JointPos + RotatePoint(prevPoint); - Vector nextWorldPosition = m_JointPos + RotatePoint(nextPoint); - line(pTargetBitmap, prevWorldPosition.m_X, prevWorldPosition.m_Y, nextWorldPosition.m_X, nextWorldPosition.m_Y, color); - - Vector min(std::min(prevWorldPosition.m_X, nextWorldPosition.m_X), std::min(prevWorldPosition.m_Y, nextWorldPosition.m_Y)); - Vector max(std::max(prevWorldPosition.m_X, nextWorldPosition.m_X), std::max(prevWorldPosition.m_Y, nextWorldPosition.m_Y)); - g_SceneMan.RegisterDrawing(pTargetBitmap, g_NoMOID, min.m_X, max.m_Y, max.m_X, min.m_Y); - - prevPoint += *itr; - } -} - -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/LimbPath.h b/Source/Entities/LimbPath.h index c84e409ab..e7739347a 100644 --- a/Source/Entities/LimbPath.h +++ b/Source/Entities/LimbPath.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,721 +18,685 @@ #include "ActivityMan.h" #include "Atom.h" -namespace RTE -{ +namespace RTE { #define SPEEDCOUNT 3 -enum Speed -{ - SLOW = 0, - NORMAL, - FAST -}; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: LimbPath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A set of Vector:s making up a motion path for a AtomGroup's limb. The -// path is continuous. -// Parent(s): Entity. -// Class history: 05/25/2001 LimbPath created. - -class LimbPath : public Entity { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(LimbPath); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: LimbPath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a LimbPath object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - LimbPath() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~LimbPath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a LimbPath object before deletion -// from system memory. -// Arguments: None. - - ~LimbPath() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the LimbPath object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the LimbPath object ready for use. -// Arguments: A Vector specifying starting point of this LimbPath, relative -// to the owning RTEActor's origin. -// An int specifying how many segments there are in the following -// segment array. This MUST match the actual size of the array! -// An array of Vectors that hold the desired path segments to use. -// A float specifying the constant travel speed the limb traveling this -// LimbPath should have, in m/s. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const Vector &startPoint, - const unsigned int segCount = 1, - const Vector *aSegArray = new Vector, - const float travelSpeed = 1.0); -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a LimbPath to be identical to another, by deep copy. -// Arguments: A reference to the LimbPath to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const LimbPath &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire LimbPath, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Entity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the LimbPath object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - /// - /// Gets the coordinates where the limb should start at the start of the LimbPath cycle, relative to the owning AtomGroup's local origin. - /// - /// A Vector with the start position. - const Vector & GetStartOffset() const { return m_Start; } - - /// - /// Sets the coordinates where the limb should start at the start of the LimbPath cycle, relative to the owning AtomGroup's local origin. - /// - /// A Vector with the new start offset. - void SetStartOffset(const Vector &newStartOffset) { m_Start = newStartOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSegCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of Vector:s the internal array of 'waypoints' or -// segments of this LimbPath. -// Arguments: None. -// Return value: An int with he count. - - unsigned int GetSegCount() const { return m_Segments.size(); } - - - /// - /// Gets a pointer to the segment at the given index. Ownership is NOT transferred. - /// - /// The index of the segment to get. - /// A pointer to the segment at the given index. Ownership is NOT transferred. - Vector *GetSegment(int segmentIndex) { if (segmentIndex >= 0 && segmentIndex < m_Segments.size()) { return &m_Segments.at(segmentIndex); } return nullptr;} - - /// - /// Gets whether or not foot collisions should be disabled, i.e. the limbpath's progress is greater than the FootCollisionsDisabledSegment value. - /// - /// Whether or not foot collisions should be disabled for this limbpath at its current progress. - bool FootCollisionsShouldBeDisabled() const { return m_FootCollisionsDisabledSegment >= 0 && GetSegCount() - GetCurrentSegmentNumber() <= m_FootCollisionsDisabledSegment; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSegProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how far the limb was last reported to be away form the current -// segment target/waypoint. -// Arguments: None. -// Return value: A normalized float describing the progress made toward the current -// segment last frame. 0.5 means it was half the length of the current -// segment away from it. - - float GetSegProgress() const { return m_SegProgress; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetProgressPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the APPROXIMATE scene position that the limb was reported to be -// last frame. This really shouldn't be used by external clients. -// Arguments: None. -// Return value: A Vector with the APPROXIAMTE scene/world coordinates of the limb as -// reported last. - - Vector GetProgressPos(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentSegTarget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the scene/world position target that the current segment represents. -// Arguments: None. -// Return value: A vector with the scene position of the current segment target. - - Vector GetCurrentSegTarget(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the velocity of the current position on the path. -// Arguments: The current world coordinate position of the Limb. -// Return value: A Vector with the current move velocity. - - Vector GetCurrentVel(const Vector &limbPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the speed that a limb traveling this LimbPath should have. -// Arguments: None. -// Return value: A float describing the speed in m/s. - - float GetSpeed() const { return m_TravelSpeed[m_WhichSpeed] * m_TravelSpeedMultiplier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the speed that a limb traveling this LimbPath should have for the specified preset. -// Arguments: Predefined speed preset to set the value for. -// Return value: A float describing the speed in m/s. - - float GetSpeed(int speedPreset) const { if (speedPreset == SLOW || speedPreset == NORMAL || speedPreset == FAST) return m_TravelSpeed[speedPreset]; else return 0; } - - /// - /// Sets the current travel speed multiplier. - /// - /// The new travel speed multiplier. - void SetTravelSpeedMultiplier(float newValue) { m_TravelSpeedMultiplier = newValue; } - - /// - /// Gets the current travel speed multiplier. - /// - /// The current travel speed multiplier. - float GetTravelSpeedMultiplier() const { return m_TravelSpeedMultiplier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the force that a limb traveling this LimbPath can push against -// stuff in the scene with. It will increase to the double if progress -// isn't made on the segment. -// Arguments: None. -// Return value: The currently set force maximum, in kg * m/s^2. - - float GetPushForce() const { return m_PushForce + (m_PushForce * (m_SegTimer.GetElapsedSimTimeMS() / 500)); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets thedefault, unaltered force that a limb traveling this LimbPath can push against -// stuff in the scene with. -// Arguments: None. -// Return value: The default set force maximum, in kg * m/s^2. - - float GetDefaultPushForce() const { return m_PushForce; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextTimeChunk -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the time needed to get to the target waypoint of the current -// segment at the current speed, if there are no obstacles. The chunk -// will not exceed the remaining time left on the frame, and will deduct -// itself from the remaining frame time tally (originally set by -// SetFrameTime()). -// Arguments: The current world coordinate position of the Limb. -// Return value: A float describing the time chunk in seconds. - - float GetNextTimeChunk(const Vector &limbPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalPathTime -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total time that this entire path should take to travel along -// with the current speed setting, including the start segments. -// Arguments: None. -// Return value: The total time (ms) this should take to travel along, if unobstructed. - - float GetTotalPathTime() const { return ((m_TotalLength * c_MPP) / (m_TravelSpeed[m_WhichSpeed] * m_TravelSpeedMultiplier)) * 1000; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRegularPathTime -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total time that this path should take to travel along -// with the current speed setting, NOT including the start segments. -// Arguments: None. -// Return value: The total time (ms) this should take to travel along, if unobstructed. - - float GetRegularPathTime() const { return ((m_RegularLength * c_MPP) / (m_TravelSpeed[m_WhichSpeed] * m_TravelSpeedMultiplier)) * 1000; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalTimeProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ratio of time since the path was restarted and the total time -// it should take to travel along the path with the current speed setting, -// including the start segments. -// Arguments: None. -// Return value: A positive scalar ratio showing the progress. 0 - 1.0 and beyond. -// If the path has ended, but not been reset, 0 is returned. - - float GetTotalTimeProgress() const { return m_Ended ? 0 : (m_PathTimer.GetElapsedSimTimeMS() / GetTotalPathTime()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRegularTimeProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ratio of time since the path was restarted and the total time -// it should take to travel along the path with the current speed setting, -// NOT including the start segments. -// Arguments: None. -// Return value: A positive scalar ratio showing the progress. 0 - 1.0 and beyond. -// If the path has ended, but not been reset, 0 is returned. - - float GetRegularTimeProgress() const { return m_Ended ? 0 : (m_PathTimer.GetElapsedSimTimeMS() / GetRegularPathTime()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReportProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Used to report how much progress was made to getting the limb close to -// the target (the current segment waypoint). -// Arguments: The new limb position in world coords. -// Return value: None. - - void ReportProgress(const Vector &limbPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a value representing the total progress that has been made on -// this entire path. If the path has ended, 0.0 is returned. -// Arguments: None. -// Return value: A float indicating the total progress made on the entire path, from -// 0.0 to 1.0. If the path has ended, 0.0 is returned. - - float GetTotalProgress() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRegularProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a value representing the progress that has been made on the -// regular part of this path, ie averythign except the starting segments. -// If progress has not been made past the starting segments, < 0 will -// be returned. If the path has ended, 0.0 is returned. -// Arguments: None. -// Return value: A float indicating the total progress made on the regular path, from -// 0.0 to 1.0. If the path has ended, 0.0 is returned. - - float GetRegularProgress() const; - - /// - /// Gets the current segment as a number, rather than an iterator. - /// - /// The current segment as a number. - int GetCurrentSegmentNumber() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSegments -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets a new array of 'waypoints' or segments of this LimbPath. -// Arguments: An int specifying how many segments there are in the following -// segment array. This MUST match the actual size of the array! -// A pointer to the new Vector array. -// Return value: None. - -// void SetSegments(const unsigned int segCount, const Vector *newSegments); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCurrentSeg -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current seg pointer to whichever segment in the segment deque. -// Arguments: An int that is an index to a valid element of the internal segment array. -// Return value: None. - -// void SetCurrentSeg(unsigned int currentSeg) { m_CurrentSegment = currentSeg; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the speed that a limb traveling this LimbPath should have to one -// of the three predefined speed settings. -// Arguments: An int specifying which discrete speed setting to use from the Speed -// enumeration. -// Return value: None. - - void SetSpeed(int newSpeed); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OverrideSpeed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the speed that a limb traveling this LimbPath with the specified preset should have. -// Arguments: An int specifying which discrete speed setting to use from the Speed -// enumeration. New limb travel speed value. -// Return value: None. - - void OverrideSpeed(int speedPreset, float newSpeed); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OverridePushForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the force that a limb traveling this LimbPath can push against -// stuff in the scene with. -// Arguments: The new push force maximum, in kg * m/s^2. -// Return value: None. - - void OverridePushForce(float newForce) { m_PushForce = newForce; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFrameTime -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the amount of time that will be used by the limb to travel every -// frame. Defined in seconds. -// Arguments: A float describing the time in s. -// Return value: None. - - void SetFrameTime(float newFrameTime) { m_TimeLeft = newFrameTime; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetHFlip -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this path is flipped horizontally or not. If being -// flipped the path automatically restarts. -// Arguments: A bool telling this path to be flipped or not. -// Return value: None. - - void SetHFlip(bool hflipped) { m_HFlipped = hflipped; } - - /// - /// Gets the h flip. - /// - /// The h flip. - bool GetHFlip() { return m_HFlipped; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetJointPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Informs this LimbPath of the absolute world coordinates of its owning -// Actor's limb's joint for this frame. Needs to be done before -// travelling anyhting along this path each frame. -// Arguments: A Vector with the updated joint position info. -// Return value: None. - - void SetJointPos(const Vector &jointPos) { m_JointPos = jointPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetJointVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Informs this LimbPath of the current velocity of its owning Actor's -// limb's joint for this frame. Needs to be done before travelling -// anyhting along this path each frame. -// Arguments: A Vector with the updated joint velocity info. -// Return value: None. - - void SetJointVel(const Vector &jointVel) { m_JointVel = jointVel; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetRotation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Informs this LimbPath of the current rotation of its owning Actor's -// for this frame. Needs to be done before travelling -// anything along this path each frame. -// Arguments: A Matrix with the updated rotation info. -// Return value: None. - - void SetRotation(const Matrix &rotation) { m_Rotation = rotation; m_Rotation.SetXFlipped(m_HFlipped); } - - /// - /// Sets the new rotation offset. - /// - /// The new rotation offset, in local space. - void SetRotationOffset(const Vector& rotationOffset) { m_RotationOffset = rotationOffset; } - - /// - /// Sets the new position offset. - /// - /// The new position offset, in local space. - void SetPositionOffset(const Vector& positionOffset) { m_PositionOffset = positionOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FrameDone -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns if GetNextMoveVec() have to be called again or not on this -// frame. If the last call didn't use up all the time moving on the -// current segment because it ended, this will return false. Then -// GetNextMoveVec() needs to be called at least one more time this frame. -// Arguments: None. -// Return value: A bool with the answer. - - bool FrameDone() const { return m_TimeLeft <= 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PathEnded -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the last call to ProgressMade() completed the -// entire path. Use Restart() to start the path over. -// Arguments: None. -// Return value: A bool with the answer. - - bool PathEnded() const { return m_Ended; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PathIsAtStart -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the path has been restarted without making any -// progress yet. -// Arguments: None. -// Return value: A bool with the answer. - - bool PathIsAtStart() const { return m_CurrentSegment == m_Segments.begin() && m_SegProgress == 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Terminate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this LimbPath's progress to its end. -// Arguments: None. -// Return value: None. - - void Terminate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Restart -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Restarts the position tracking of the limb that travels along this -// LimbPath. -// Arguments: None. -// Return value: None. - - void Restart(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RestartFree -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Restarts the position tracking of the limb that travels along this -// LimbPath at a point which does not contain terrain. In doing this, -// a list of potential starting segments are checked and the first to -// yield a starting position that is not in terrain will be picked. -// If none of the candidate starting segments are free of terrain, -// the last one in the list will be picked and false will be returned -// here. The passed in limbPos Vector will be set to teh new position of -// the restarted path, if a free spot is found. -// Arguments: Limb scene pos which will be set to the new reset position if a free -// spot was found. -// The root MOID to ignore when looking for a free position. -// To enable ignoring of all MOIDs associated with an object of a specific -// team which also has team ignoring enabled itself. -// Return value: Whether a starting segment that yielded a starting pos free of terrain -// was found or not. - - bool RestartFree(Vector &limbPos, MOID MOIDToIgnore = g_NoMOID, int ignoreTeam = Activity::NoTeam); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsInitialized -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicated whether this path is has been created and had some data set -// yet. -// Arguments: None. -// Return value: Whether this has been Create:ed yet. - - bool IsInitialized() const { return !m_Start.IsZero() || !m_Segments.empty(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsStaticPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicated whether this path is in fact just a single point to where -// the limb will always be ordered to move toward. IE a standing still -// type limb movement. -// Arguments: None. -// Return value: None. - - bool IsStaticPoint() const { return m_Segments.empty(); } - - /// - /// Returns the lowest y position of this LimbPath. - /// - /// The lowest y position of this LimbPath. - float GetLowestY() const; - - /// - /// Returns the middle x position of this LimbPath. - /// - /// The middle x position of this LimbPath. - float GetMiddleX() const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this LimbPath's current graphical debug representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// The color to draw the path's pixels as. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), unsigned char color = 34) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - static Entity::ClassInfo m_sClass; - - // The starting point of the path. - Vector m_Start; - - // The number of starting segments, counting into the path from its beginning, - // that upon restart of this path will be tried in reverse order till one which - // yields a starting position that is clear of terrain is found. - int m_StartSegCount; - - // Array containing the actual 'waypoints' or segments for the path. - std::deque m_Segments; - - // The iterator to the segment of the path that the limb ended up on the end of - std::deque::iterator m_CurrentSegment; - - int m_FootCollisionsDisabledSegment; //!< The segment after which foot collisions will be disabled for this limbpath, if it's for legs. - - // Normalized measure of how far the limb has progressed toward the - // current segment's target. 0.0 means its farther away than the - // magnitude of the entire segment. 0.5 means it's half the mag of the segment - // away from the target. - float m_SegProgress; - - // The constant speed that the limb traveling this path has in m/s. - float m_TravelSpeed[SPEEDCOUNT]; - - // The current travel speed multiplier - float m_TravelSpeedMultiplier; - - // The current speed setting. - int m_WhichSpeed; - - // The max force that a limb travelling along this path can push. - // In kg * m/(s^2) - float m_PushForce; - - // The latest known position of the owning actor's joint in world coordinates. - Vector m_JointPos; - // The latest known velocity of the owning actor's joint in world coordinates. - Vector m_JointVel; - // The rotation applied to this walkpath. - Matrix m_Rotation; - // The point we should be rotated around, in local space. - Vector m_RotationOffset; - // The offset to apply to our walkpath position, in local space. - Vector m_PositionOffset; - - // If GetNextTimeSeg() couldn't use up all frame time because the current segment - // ended,this var stores the remainder of time that should be used to progress - // on the next segment during the same frame. - float m_TimeLeft; - - // Times the amount of sim time spent since the last path traversal was started - Timer m_PathTimer; - // Times the amount of sim time spent pursuing the current segment's target. - Timer m_SegTimer; - - // Total length of this LimbPath, including the alternative starting segments, in pixel units - float m_TotalLength; - // Length of this LimbPath, excluding the alternative starting segments. - float m_RegularLength; - bool m_SegmentDone; - bool m_Ended; - bool m_HFlipped; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this LimbPath, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - /// - /// Rotates a point to match our rotation and rotation offset. - /// - /// The point to rotate. - /// The rotated point. - Vector RotatePoint(const Vector &point) const; - -}; + enum Speed { + SLOW = 0, + NORMAL, + FAST + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: LimbPath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A set of Vector:s making up a motion path for a AtomGroup's limb. The + // path is continuous. + // Parent(s): Entity. + // Class history: 05/25/2001 LimbPath created. + + class LimbPath : public Entity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(LimbPath); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: LimbPath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a LimbPath object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + LimbPath() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~LimbPath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a LimbPath object before deletion + // from system memory. + // Arguments: None. + + ~LimbPath() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the LimbPath object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the LimbPath object ready for use. + // Arguments: A Vector specifying starting point of this LimbPath, relative + // to the owning RTEActor's origin. + // An int specifying how many segments there are in the following + // segment array. This MUST match the actual size of the array! + // An array of Vectors that hold the desired path segments to use. + // A float specifying the constant travel speed the limb traveling this + // LimbPath should have, in m/s. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Vector &startPoint, + const unsigned int segCount = 1, + const Vector *aSegArray = new Vector, + const float travelSpeed = 1.0); + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a LimbPath to be identical to another, by deep copy. + // Arguments: A reference to the LimbPath to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const LimbPath& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire LimbPath, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Entity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the LimbPath object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + /// + /// Gets the coordinates where the limb should start at the start of the LimbPath cycle, relative to the owning AtomGroup's local origin. + /// + /// A Vector with the start position. + const Vector& GetStartOffset() const { return m_Start; } + + /// + /// Sets the coordinates where the limb should start at the start of the LimbPath cycle, relative to the owning AtomGroup's local origin. + /// + /// A Vector with the new start offset. + void SetStartOffset(const Vector& newStartOffset) { m_Start = newStartOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSegCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of Vector:s the internal array of 'waypoints' or + // segments of this LimbPath. + // Arguments: None. + // Return value: An int with he count. + + unsigned int GetSegCount() const { return m_Segments.size(); } + + /// + /// Gets a pointer to the segment at the given index. Ownership is NOT transferred. + /// + /// The index of the segment to get. + /// A pointer to the segment at the given index. Ownership is NOT transferred. + Vector* GetSegment(int segmentIndex) { + if (segmentIndex >= 0 && segmentIndex < m_Segments.size()) { + return &m_Segments.at(segmentIndex); + } + return nullptr; + } + + /// + /// Gets whether or not foot collisions should be disabled, i.e. the limbpath's progress is greater than the FootCollisionsDisabledSegment value. + /// + /// Whether or not foot collisions should be disabled for this limbpath at its current progress. + bool FootCollisionsShouldBeDisabled() const { return m_FootCollisionsDisabledSegment >= 0 && GetSegCount() - GetCurrentSegmentNumber() <= m_FootCollisionsDisabledSegment; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSegProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how far the limb was last reported to be away form the current + // segment target/waypoint. + // Arguments: None. + // Return value: A normalized float describing the progress made toward the current + // segment last frame. 0.5 means it was half the length of the current + // segment away from it. + + float GetSegProgress() const { return m_SegProgress; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetProgressPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the APPROXIMATE scene position that the limb was reported to be + // last frame. This really shouldn't be used by external clients. + // Arguments: None. + // Return value: A Vector with the APPROXIAMTE scene/world coordinates of the limb as + // reported last. + + Vector GetProgressPos(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentSegTarget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the scene/world position target that the current segment represents. + // Arguments: None. + // Return value: A vector with the scene position of the current segment target. + + Vector GetCurrentSegTarget(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the velocity of the current position on the path. + // Arguments: The current world coordinate position of the Limb. + // Return value: A Vector with the current move velocity. + + Vector GetCurrentVel(const Vector& limbPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the speed that a limb traveling this LimbPath should have. + // Arguments: None. + // Return value: A float describing the speed in m/s. + + float GetSpeed() const { return m_TravelSpeed[m_WhichSpeed] * m_TravelSpeedMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the speed that a limb traveling this LimbPath should have for the specified preset. + // Arguments: Predefined speed preset to set the value for. + // Return value: A float describing the speed in m/s. + + float GetSpeed(int speedPreset) const { + if (speedPreset == SLOW || speedPreset == NORMAL || speedPreset == FAST) + return m_TravelSpeed[speedPreset]; + else + return 0; + } + + /// + /// Sets the current travel speed multiplier. + /// + /// The new travel speed multiplier. + void SetTravelSpeedMultiplier(float newValue) { m_TravelSpeedMultiplier = newValue; } + + /// + /// Gets the current travel speed multiplier. + /// + /// The current travel speed multiplier. + float GetTravelSpeedMultiplier() const { return m_TravelSpeedMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the force that a limb traveling this LimbPath can push against + // stuff in the scene with. It will increase to the double if progress + // isn't made on the segment. + // Arguments: None. + // Return value: The currently set force maximum, in kg * m/s^2. + + float GetPushForce() const { return m_PushForce + (m_PushForce * (m_SegTimer.GetElapsedSimTimeMS() / 500)); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets thedefault, unaltered force that a limb traveling this LimbPath can push against + // stuff in the scene with. + // Arguments: None. + // Return value: The default set force maximum, in kg * m/s^2. + + float GetDefaultPushForce() const { return m_PushForce; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextTimeChunk + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the time needed to get to the target waypoint of the current + // segment at the current speed, if there are no obstacles. The chunk + // will not exceed the remaining time left on the frame, and will deduct + // itself from the remaining frame time tally (originally set by + // SetFrameTime()). + // Arguments: The current world coordinate position of the Limb. + // Return value: A float describing the time chunk in seconds. + + float GetNextTimeChunk(const Vector& limbPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalPathTime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total time that this entire path should take to travel along + // with the current speed setting, including the start segments. + // Arguments: None. + // Return value: The total time (ms) this should take to travel along, if unobstructed. + + float GetTotalPathTime() const { return ((m_TotalLength * c_MPP) / (m_TravelSpeed[m_WhichSpeed] * m_TravelSpeedMultiplier)) * 1000; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRegularPathTime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total time that this path should take to travel along + // with the current speed setting, NOT including the start segments. + // Arguments: None. + // Return value: The total time (ms) this should take to travel along, if unobstructed. + + float GetRegularPathTime() const { return ((m_RegularLength * c_MPP) / (m_TravelSpeed[m_WhichSpeed] * m_TravelSpeedMultiplier)) * 1000; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalTimeProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ratio of time since the path was restarted and the total time + // it should take to travel along the path with the current speed setting, + // including the start segments. + // Arguments: None. + // Return value: A positive scalar ratio showing the progress. 0 - 1.0 and beyond. + // If the path has ended, but not been reset, 0 is returned. + + float GetTotalTimeProgress() const { return m_Ended ? 0 : (m_PathTimer.GetElapsedSimTimeMS() / GetTotalPathTime()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRegularTimeProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ratio of time since the path was restarted and the total time + // it should take to travel along the path with the current speed setting, + // NOT including the start segments. + // Arguments: None. + // Return value: A positive scalar ratio showing the progress. 0 - 1.0 and beyond. + // If the path has ended, but not been reset, 0 is returned. + + float GetRegularTimeProgress() const { return m_Ended ? 0 : (m_PathTimer.GetElapsedSimTimeMS() / GetRegularPathTime()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReportProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Used to report how much progress was made to getting the limb close to + // the target (the current segment waypoint). + // Arguments: The new limb position in world coords. + // Return value: None. + + void ReportProgress(const Vector& limbPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a value representing the total progress that has been made on + // this entire path. If the path has ended, 0.0 is returned. + // Arguments: None. + // Return value: A float indicating the total progress made on the entire path, from + // 0.0 to 1.0. If the path has ended, 0.0 is returned. + + float GetTotalProgress() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRegularProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a value representing the progress that has been made on the + // regular part of this path, ie averythign except the starting segments. + // If progress has not been made past the starting segments, < 0 will + // be returned. If the path has ended, 0.0 is returned. + // Arguments: None. + // Return value: A float indicating the total progress made on the regular path, from + // 0.0 to 1.0. If the path has ended, 0.0 is returned. + + float GetRegularProgress() const; + + /// + /// Gets the current segment as a number, rather than an iterator. + /// + /// The current segment as a number. + int GetCurrentSegmentNumber() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSegments + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets a new array of 'waypoints' or segments of this LimbPath. + // Arguments: An int specifying how many segments there are in the following + // segment array. This MUST match the actual size of the array! + // A pointer to the new Vector array. + // Return value: None. + + // void SetSegments(const unsigned int segCount, const Vector *newSegments); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCurrentSeg + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current seg pointer to whichever segment in the segment deque. + // Arguments: An int that is an index to a valid element of the internal segment array. + // Return value: None. + + // void SetCurrentSeg(unsigned int currentSeg) { m_CurrentSegment = currentSeg; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the speed that a limb traveling this LimbPath should have to one + // of the three predefined speed settings. + // Arguments: An int specifying which discrete speed setting to use from the Speed + // enumeration. + // Return value: None. + + void SetSpeed(int newSpeed); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OverrideSpeed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the speed that a limb traveling this LimbPath with the specified preset should have. + // Arguments: An int specifying which discrete speed setting to use from the Speed + // enumeration. New limb travel speed value. + // Return value: None. + + void OverrideSpeed(int speedPreset, float newSpeed); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OverridePushForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the force that a limb traveling this LimbPath can push against + // stuff in the scene with. + // Arguments: The new push force maximum, in kg * m/s^2. + // Return value: None. + + void OverridePushForce(float newForce) { m_PushForce = newForce; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFrameTime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the amount of time that will be used by the limb to travel every + // frame. Defined in seconds. + // Arguments: A float describing the time in s. + // Return value: None. + + void SetFrameTime(float newFrameTime) { m_TimeLeft = newFrameTime; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetHFlip + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this path is flipped horizontally or not. If being + // flipped the path automatically restarts. + // Arguments: A bool telling this path to be flipped or not. + // Return value: None. + + void SetHFlip(bool hflipped) { m_HFlipped = hflipped; } + + /// + /// Gets the h flip. + /// + /// The h flip. + bool GetHFlip() { return m_HFlipped; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetJointPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Informs this LimbPath of the absolute world coordinates of its owning + // Actor's limb's joint for this frame. Needs to be done before + // travelling anyhting along this path each frame. + // Arguments: A Vector with the updated joint position info. + // Return value: None. + + void SetJointPos(const Vector& jointPos) { m_JointPos = jointPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetJointVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Informs this LimbPath of the current velocity of its owning Actor's + // limb's joint for this frame. Needs to be done before travelling + // anyhting along this path each frame. + // Arguments: A Vector with the updated joint velocity info. + // Return value: None. + + void SetJointVel(const Vector& jointVel) { m_JointVel = jointVel; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRotation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Informs this LimbPath of the current rotation of its owning Actor's + // for this frame. Needs to be done before travelling + // anything along this path each frame. + // Arguments: A Matrix with the updated rotation info. + // Return value: None. + + void SetRotation(const Matrix& rotation) { + m_Rotation = rotation; + m_Rotation.SetXFlipped(m_HFlipped); + } + + /// + /// Sets the new rotation offset. + /// + /// The new rotation offset, in local space. + void SetRotationOffset(const Vector& rotationOffset) { m_RotationOffset = rotationOffset; } + + /// + /// Sets the new position offset. + /// + /// The new position offset, in local space. + void SetPositionOffset(const Vector& positionOffset) { m_PositionOffset = positionOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FrameDone + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns if GetNextMoveVec() have to be called again or not on this + // frame. If the last call didn't use up all the time moving on the + // current segment because it ended, this will return false. Then + // GetNextMoveVec() needs to be called at least one more time this frame. + // Arguments: None. + // Return value: A bool with the answer. + + bool FrameDone() const { return m_TimeLeft <= 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PathEnded + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the last call to ProgressMade() completed the + // entire path. Use Restart() to start the path over. + // Arguments: None. + // Return value: A bool with the answer. + + bool PathEnded() const { return m_Ended; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PathIsAtStart + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the path has been restarted without making any + // progress yet. + // Arguments: None. + // Return value: A bool with the answer. + + bool PathIsAtStart() const { return m_CurrentSegment == m_Segments.begin() && m_SegProgress == 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Terminate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this LimbPath's progress to its end. + // Arguments: None. + // Return value: None. + + void Terminate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Restart + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Restarts the position tracking of the limb that travels along this + // LimbPath. + // Arguments: None. + // Return value: None. + + void Restart(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RestartFree + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Restarts the position tracking of the limb that travels along this + // LimbPath at a point which does not contain terrain. In doing this, + // a list of potential starting segments are checked and the first to + // yield a starting position that is not in terrain will be picked. + // If none of the candidate starting segments are free of terrain, + // the last one in the list will be picked and false will be returned + // here. The passed in limbPos Vector will be set to teh new position of + // the restarted path, if a free spot is found. + // Arguments: Limb scene pos which will be set to the new reset position if a free + // spot was found. + // The root MOID to ignore when looking for a free position. + // To enable ignoring of all MOIDs associated with an object of a specific + // team which also has team ignoring enabled itself. + // Return value: Whether a starting segment that yielded a starting pos free of terrain + // was found or not. + + bool RestartFree(Vector& limbPos, MOID MOIDToIgnore = g_NoMOID, int ignoreTeam = Activity::NoTeam); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsInitialized + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicated whether this path is has been created and had some data set + // yet. + // Arguments: None. + // Return value: Whether this has been Create:ed yet. + + bool IsInitialized() const { return !m_Start.IsZero() || !m_Segments.empty(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsStaticPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicated whether this path is in fact just a single point to where + // the limb will always be ordered to move toward. IE a standing still + // type limb movement. + // Arguments: None. + // Return value: None. + + bool IsStaticPoint() const { return m_Segments.empty(); } + + /// + /// Returns the lowest y position of this LimbPath. + /// + /// The lowest y position of this LimbPath. + float GetLowestY() const; + + /// + /// Returns the middle x position of this LimbPath. + /// + /// The middle x position of this LimbPath. + float GetMiddleX() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this LimbPath's current graphical debug representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // The color to draw the path's pixels as. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), unsigned char color = 34) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + static Entity::ClassInfo m_sClass; + + // The starting point of the path. + Vector m_Start; + + // The number of starting segments, counting into the path from its beginning, + // that upon restart of this path will be tried in reverse order till one which + // yields a starting position that is clear of terrain is found. + int m_StartSegCount; + + // Array containing the actual 'waypoints' or segments for the path. + std::deque m_Segments; + + // The iterator to the segment of the path that the limb ended up on the end of + std::deque::iterator m_CurrentSegment; + + int m_FootCollisionsDisabledSegment; //!< The segment after which foot collisions will be disabled for this limbpath, if it's for legs. + + // Normalized measure of how far the limb has progressed toward the + // current segment's target. 0.0 means its farther away than the + // magnitude of the entire segment. 0.5 means it's half the mag of the segment + // away from the target. + float m_SegProgress; + + // The constant speed that the limb traveling this path has in m/s. + float m_TravelSpeed[SPEEDCOUNT]; + + // The current travel speed multiplier + float m_TravelSpeedMultiplier; + + // The current speed setting. + int m_WhichSpeed; + + // The max force that a limb travelling along this path can push. + // In kg * m/(s^2) + float m_PushForce; + + // The latest known position of the owning actor's joint in world coordinates. + Vector m_JointPos; + // The latest known velocity of the owning actor's joint in world coordinates. + Vector m_JointVel; + // The rotation applied to this walkpath. + Matrix m_Rotation; + // The point we should be rotated around, in local space. + Vector m_RotationOffset; + // The offset to apply to our walkpath position, in local space. + Vector m_PositionOffset; + + // If GetNextTimeSeg() couldn't use up all frame time because the current segment + // ended,this var stores the remainder of time that should be used to progress + // on the next segment during the same frame. + float m_TimeLeft; + + // Times the amount of sim time spent since the last path traversal was started + Timer m_PathTimer; + // Times the amount of sim time spent pursuing the current segment's target. + Timer m_SegTimer; + + // Total length of this LimbPath, including the alternative starting segments, in pixel units + float m_TotalLength; + // Length of this LimbPath, excluding the alternative starting segments. + float m_RegularLength; + bool m_SegmentDone; + bool m_Ended; + bool m_HFlipped; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this LimbPath, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + /// + /// Rotates a point to match our rotation and rotation offset. + /// + /// The point to rotate. + /// The rotated point. + Vector RotatePoint(const Vector& point) const; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/Loadout.cpp b/Source/Entities/Loadout.cpp index 7acbb61f2..18604cc71 100644 --- a/Source/Entities/Loadout.cpp +++ b/Source/Entities/Loadout.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -18,290 +17,268 @@ namespace RTE { -ConcreteClassInfo(Loadout, Entity, 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Loadout, effectively -// resetting the members of this abstraction level only. - -void Loadout::Clear() -{ - m_Complete = true; - m_pDeliveryCraft = 0; - m_CargoItems.clear(); -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Loadout object ready for use. - -int Loadout::Create() -{ - if (Entity::Create() < 0) - return -1; - - return 0; -} -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Loadout to be identical to another, by deep copy. - -int Loadout::Create(const Loadout &reference) -{ - Entity::Create(reference); - - m_Complete = reference.m_Complete; - // These are preset instances, not owned by the reference or this. - m_pDeliveryCraft = reference.m_pDeliveryCraft; - for (std::list::const_iterator itr = reference.m_CargoItems.begin(); itr != reference.m_CargoItems.end(); ++itr) - m_CargoItems.push_back(*itr); - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int Loadout::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Entity::ReadProperty(propName, reader)); - - // Need to load all this stuff without the assumption that it all is available. Mods might have changed etc so things might still not be around, and that's ok. - MatchProperty("DeliveryCraft", - { - std::string className; - std::string presetName; - // Load class name and then preset instance name - reader >> className; - // Ignore the property name, just interested in the value - if (reader.ReadPropName() != "PresetName") - reader.ReportError("Expected property \"PresetName\" not found when reading BuyMenu Loadout settings!"); - // Read the preset's name and try to find it - presetName = reader.ReadPropValue(); - // It's OK if we can't find it.. just means we aren't a complete loadout - m_pDeliveryCraft = dynamic_cast(g_PresetMan.GetEntityPreset(className, presetName, -1)); - if (!m_pDeliveryCraft) - m_Complete = false; - // Artificially end reading this property since we got all we needed - reader.NextProperty(); - }); - MatchProperty("AddCargoItem", - { - std::string className; - std::string presetName; - // Load class name and then preset instance name - reader >> className; - // Ignore the property name, just interested in the value - if (reader.ReadPropName() != "PresetName") - reader.ReportError("Expected property \"PresetName\" not found when reading BuyMenu Loadout settings!"); - // Read the preset's name and try to find it - presetName = reader.ReadPropValue(); - // It's OK if we can't find it.. just means we aren't a complete loadout - const MovableObject *pCargo = dynamic_cast(g_PresetMan.GetEntityPreset(className, presetName, -1)); - if (!pCargo) - m_Complete = false; - // Add the found cargo item to the list - else - m_CargoItems.push_back(pCargo); - - // Artificially end reading this property since we got all we needed - reader.NextProperty(); - - pCargo = 0; - }); - - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Loadout with a Writer for -// later recreation with Create(Reader &reader); - -int Loadout::Save(Writer &writer) const -{ - Entity::Save(writer); - - if (m_pDeliveryCraft) - { - writer.NewProperty("DeliveryCraft"); - writer.ObjectStart(m_pDeliveryCraft->GetClassName()); - writer.NewProperty("PresetName"); - writer << m_pDeliveryCraft->GetModuleAndPresetName(); - writer.ObjectEnd(); - } - for (std::list::const_iterator itr = m_CargoItems.begin(); itr != m_CargoItems.end(); ++itr) - { - writer.NewProperty("AddCargoItem"); - writer.ObjectStart((*itr)->GetClassName()); - writer.NewProperty("PresetName"); - writer << (*itr)->GetModuleAndPresetName(); - writer.ObjectEnd(); - } - - return 0; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the Icon object. - -void Loadout::Destroy(bool notInherited) -{ -// delete; - - if (!notInherited) - Entity::Destroy(); - Clear(); -} -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateFirstActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Actor that this Loadout has and equips. -// Ownership IS transferred!! All items of the Loadout of this Deployment -// will be added to the Actor's inventory as well (and also owned by it) - -Actor * Loadout::CreateFirstActor(int nativeModule, float foreignMult, float nativeMult, float &costTally) const -{ - // The Actor instance we return and pass ownership of - Actor *pReturnActor = 0; - - // Now go through the cargo list of items and load new instances of all - // Devices into inventory of an instance of the first Actor found in the list - if (!m_CargoItems.empty()) - { - // Go through the list of things ordered, and give any actors all the items that is present after them, - // until the next actor. Also, the first actor gets all stuff in the list above him. - MovableObject *pInventoryObject = 0; - Actor *pActor = nullptr; - std::list tempCargo; - for (std::list::const_iterator itr = m_CargoItems.begin(); itr != m_CargoItems.end(); ++itr) - { - // Add to the total cost tally - costTally += (*itr)->GetGoldValue(nativeModule, foreignMult, nativeMult); - // Make copy of the preset instance in the list - pInventoryObject = dynamic_cast((*itr)->Clone()); - // See if it's actually a passenger, as opposed to a regular item - pActor = dynamic_cast(pInventoryObject); - // If it's an actor, then set its team and add it to the Craft's inventory! - if (pActor) - { - // If this is the first passenger, then give him all the shit found in the list before him - if (!pReturnActor) - { - for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) - pActor->AddInventoryItem(*iItr); - } - // This isn't the first passenger, so give the previous guy all the stuff that was found since processing him - else - { - // Go through the temporary list and give the previous, real first actor all the stuff - for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) - pReturnActor->AddInventoryItem(*iItr); - // Clear out the temporary cargo list since we've assigned all the stuff in it to the return Actor - tempCargo.clear(); - - // REMOVE the value of this bookend actor from the total cost tally - he is not included! - costTally -= pActor->GetGoldValue(nativeModule, foreignMult, nativeMult); - // Also stop going through the list; we only need ONE Actor.. so destroy the instance we jsut created of a second one. - delete pActor; - pActor = nullptr; - // STOP! - break; - } - // Clear out the temporary cargo list since we've assigned all the stuff in it to the return Actor - tempCargo.clear(); - - // Now set the current Actor as the one we return; he'll eventually get everything found after him as well - pReturnActor = pActor; - // Set the position and team etc for the Actor we are prepping to spawn - pReturnActor->SetControllerMode(Controller::CIM_AI); - pReturnActor->SetAIMode(Actor::AIMODE_SENTRY); - } - // If not an Actor, then add it to the temp list of items which will be added to the last passenger's inventory - else - tempCargo.push_back(pInventoryObject); - } - pActor = 0; - - // If there was a last passenger and only things after him, stuff all the items into his inventory - if (pReturnActor) - { - // Passing ownership - for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) - pReturnActor->AddInventoryItem(*iItr); - tempCargo.clear(); - } - // If there wa NO actor in the Loadout's cargo list, then see if there's a craft we can stuff thigns into instead - else if (m_pDeliveryCraft) - { - // The craft is now the Actor we are spawning, so make an instance - pReturnActor = dynamic_cast(m_pDeliveryCraft->Clone()); - // Add the cost of the ship - costTally += pReturnActor->GetGoldValue(nativeModule, foreignMult, nativeMult); - // Fill it with the stuff, passing ownership - for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) - pReturnActor->AddInventoryItem(*iItr); - tempCargo.clear(); - } - } - - // PASSING OWNERSHIP - return pReturnActor; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CreateFirstDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Device that is defined in this Loadout. -// Ownership IS transferred!! Only the first Device is created. - -SceneObject * Loadout::CreateFirstDevice(int nativeModule, float foreignMult, float nativeMult, float &costTally) const -{ - // The Actor instance we return and pass ownership of - SceneObject *pReturnObject = 0; - - // Now go through the Loadout list of items and load new instances of all - // Devices into inventory of an instance of the first Actor found in the list - if (!m_CargoItems.empty()) - { - for (std::list::const_iterator itr = m_CargoItems.begin(); itr != m_CargoItems.end(); ++itr) - { - // If not an Actor, then we should create and return it. - if (!dynamic_cast(*itr)) - { - pReturnObject = dynamic_cast((*itr)->Clone()); - // Add to the total cost tally - costTally += pReturnObject->GetGoldValue(nativeModule, foreignMult, nativeMult); - // We're done - break; - } - } - } - - // PASSING OWNERSHIP - return pReturnObject; -} - -} // namespace RTE \ No newline at end of file + ConcreteClassInfo(Loadout, Entity, 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Loadout, effectively + // resetting the members of this abstraction level only. + + void Loadout::Clear() { + m_Complete = true; + m_pDeliveryCraft = 0; + m_CargoItems.clear(); + } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Loadout object ready for use. + + int Loadout::Create() + { + if (Entity::Create() < 0) + return -1; + + return 0; + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Loadout to be identical to another, by deep copy. + + int Loadout::Create(const Loadout& reference) { + Entity::Create(reference); + + m_Complete = reference.m_Complete; + // These are preset instances, not owned by the reference or this. + m_pDeliveryCraft = reference.m_pDeliveryCraft; + for (std::list::const_iterator itr = reference.m_CargoItems.begin(); itr != reference.m_CargoItems.end(); ++itr) + m_CargoItems.push_back(*itr); + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int Loadout::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Entity::ReadProperty(propName, reader)); + + // Need to load all this stuff without the assumption that it all is available. Mods might have changed etc so things might still not be around, and that's ok. + MatchProperty("DeliveryCraft", + { + std::string className; + std::string presetName; + // Load class name and then preset instance name + reader >> className; + // Ignore the property name, just interested in the value + if (reader.ReadPropName() != "PresetName") + reader.ReportError("Expected property \"PresetName\" not found when reading BuyMenu Loadout settings!"); + // Read the preset's name and try to find it + presetName = reader.ReadPropValue(); + // It's OK if we can't find it.. just means we aren't a complete loadout + m_pDeliveryCraft = dynamic_cast(g_PresetMan.GetEntityPreset(className, presetName, -1)); + if (!m_pDeliveryCraft) + m_Complete = false; + // Artificially end reading this property since we got all we needed + reader.NextProperty(); + }); + MatchProperty("AddCargoItem", + { + std::string className; + std::string presetName; + // Load class name and then preset instance name + reader >> className; + // Ignore the property name, just interested in the value + if (reader.ReadPropName() != "PresetName") + reader.ReportError("Expected property \"PresetName\" not found when reading BuyMenu Loadout settings!"); + // Read the preset's name and try to find it + presetName = reader.ReadPropValue(); + // It's OK if we can't find it.. just means we aren't a complete loadout + const MovableObject* pCargo = dynamic_cast(g_PresetMan.GetEntityPreset(className, presetName, -1)); + if (!pCargo) + m_Complete = false; + // Add the found cargo item to the list + else + m_CargoItems.push_back(pCargo); + + // Artificially end reading this property since we got all we needed + reader.NextProperty(); + + pCargo = 0; + }); + + EndPropertyList; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Loadout with a Writer for + // later recreation with Create(Reader &reader); + + int Loadout::Save(Writer& writer) const { + Entity::Save(writer); + + if (m_pDeliveryCraft) { + writer.NewProperty("DeliveryCraft"); + writer.ObjectStart(m_pDeliveryCraft->GetClassName()); + writer.NewProperty("PresetName"); + writer << m_pDeliveryCraft->GetModuleAndPresetName(); + writer.ObjectEnd(); + } + for (std::list::const_iterator itr = m_CargoItems.begin(); itr != m_CargoItems.end(); ++itr) { + writer.NewProperty("AddCargoItem"); + writer.ObjectStart((*itr)->GetClassName()); + writer.NewProperty("PresetName"); + writer << (*itr)->GetModuleAndPresetName(); + writer.ObjectEnd(); + } + + return 0; + } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the Icon object. + + void Loadout::Destroy(bool notInherited) + { + // delete; + + if (!notInherited) + Entity::Destroy(); + Clear(); + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateFirstActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Actor that this Loadout has and equips. + // Ownership IS transferred!! All items of the Loadout of this Deployment + // will be added to the Actor's inventory as well (and also owned by it) + + Actor* Loadout::CreateFirstActor(int nativeModule, float foreignMult, float nativeMult, float& costTally) const { + // The Actor instance we return and pass ownership of + Actor* pReturnActor = 0; + + // Now go through the cargo list of items and load new instances of all + // Devices into inventory of an instance of the first Actor found in the list + if (!m_CargoItems.empty()) { + // Go through the list of things ordered, and give any actors all the items that is present after them, + // until the next actor. Also, the first actor gets all stuff in the list above him. + MovableObject* pInventoryObject = 0; + Actor* pActor = nullptr; + std::list tempCargo; + for (std::list::const_iterator itr = m_CargoItems.begin(); itr != m_CargoItems.end(); ++itr) { + // Add to the total cost tally + costTally += (*itr)->GetGoldValue(nativeModule, foreignMult, nativeMult); + // Make copy of the preset instance in the list + pInventoryObject = dynamic_cast((*itr)->Clone()); + // See if it's actually a passenger, as opposed to a regular item + pActor = dynamic_cast(pInventoryObject); + // If it's an actor, then set its team and add it to the Craft's inventory! + if (pActor) { + // If this is the first passenger, then give him all the shit found in the list before him + if (!pReturnActor) { + for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) + pActor->AddInventoryItem(*iItr); + } + // This isn't the first passenger, so give the previous guy all the stuff that was found since processing him + else { + // Go through the temporary list and give the previous, real first actor all the stuff + for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) + pReturnActor->AddInventoryItem(*iItr); + // Clear out the temporary cargo list since we've assigned all the stuff in it to the return Actor + tempCargo.clear(); + + // REMOVE the value of this bookend actor from the total cost tally - he is not included! + costTally -= pActor->GetGoldValue(nativeModule, foreignMult, nativeMult); + // Also stop going through the list; we only need ONE Actor.. so destroy the instance we jsut created of a second one. + delete pActor; + pActor = nullptr; + // STOP! + break; + } + // Clear out the temporary cargo list since we've assigned all the stuff in it to the return Actor + tempCargo.clear(); + + // Now set the current Actor as the one we return; he'll eventually get everything found after him as well + pReturnActor = pActor; + // Set the position and team etc for the Actor we are prepping to spawn + pReturnActor->SetControllerMode(Controller::CIM_AI); + pReturnActor->SetAIMode(Actor::AIMODE_SENTRY); + } + // If not an Actor, then add it to the temp list of items which will be added to the last passenger's inventory + else + tempCargo.push_back(pInventoryObject); + } + pActor = 0; + + // If there was a last passenger and only things after him, stuff all the items into his inventory + if (pReturnActor) { + // Passing ownership + for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) + pReturnActor->AddInventoryItem(*iItr); + tempCargo.clear(); + } + // If there wa NO actor in the Loadout's cargo list, then see if there's a craft we can stuff thigns into instead + else if (m_pDeliveryCraft) { + // The craft is now the Actor we are spawning, so make an instance + pReturnActor = dynamic_cast(m_pDeliveryCraft->Clone()); + // Add the cost of the ship + costTally += pReturnActor->GetGoldValue(nativeModule, foreignMult, nativeMult); + // Fill it with the stuff, passing ownership + for (std::list::iterator iItr = tempCargo.begin(); iItr != tempCargo.end(); ++iItr) + pReturnActor->AddInventoryItem(*iItr); + tempCargo.clear(); + } + } + + // PASSING OWNERSHIP + return pReturnActor; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CreateFirstDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Device that is defined in this Loadout. + // Ownership IS transferred!! Only the first Device is created. + + SceneObject* Loadout::CreateFirstDevice(int nativeModule, float foreignMult, float nativeMult, float& costTally) const { + // The Actor instance we return and pass ownership of + SceneObject* pReturnObject = 0; + + // Now go through the Loadout list of items and load new instances of all + // Devices into inventory of an instance of the first Actor found in the list + if (!m_CargoItems.empty()) { + for (std::list::const_iterator itr = m_CargoItems.begin(); itr != m_CargoItems.end(); ++itr) { + // If not an Actor, then we should create and return it. + if (!dynamic_cast(*itr)) { + pReturnObject = dynamic_cast((*itr)->Clone()); + // Add to the total cost tally + costTally += pReturnObject->GetGoldValue(nativeModule, foreignMult, nativeMult); + // We're done + break; + } + } + } + + // PASSING OWNERSHIP + return pReturnObject; + } + +} // namespace RTE diff --git a/Source/Entities/Loadout.h b/Source/Entities/Loadout.h index 709694f8e..2f66f335d 100644 --- a/Source/Entities/Loadout.h +++ b/Source/Entities/Loadout.h @@ -10,208 +10,205 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files //#include "FrameMan.h" #include "Entity.h" -namespace RTE -{ - -class SceneObject; -class MovableObject; -class ACraft; -class Actor; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Nested class: Loadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines a delivery of Actors, with all their equipment etc. -// Parent(s): Entity. -// Class history: 2/21/2012 Loadout created. - -class Loadout : public Entity { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(Loadout); -SerializableOverrideMethods; -ClassInfoGetters; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: Loadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a Loadout object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - Loadout() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: Loadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Copy constructor method used to instantiate a Loadout object -// identical to an already existing one. -// Arguments: A Loadout object which is passed in by reference. - - Loadout(const Loadout &reference) { if (this != &reference) { Clear(); Create(reference); } } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Operator: Loadout assignment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: An assignment operator for setting one Loadout equal to another. -// Arguments: A Loadout reference. -// Return value: A reference to the changed Loadout. - - Loadout & operator=(const Loadout &rhs) { if (this != &rhs) { Destroy(); Create(rhs); } return *this; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Loadout to be identical to another, by deep copy. -// Arguments: A reference to the Loadout to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const Loadout &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire Entity, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Entity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsComplete -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this loadout is complete, or some Entity within could -// not be found on load. -// Arguments: None. -// Return value: Complete or not. - - bool IsComplete() { return m_Complete; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateFirstActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Actor that this Loadout has and equips. -// Ownership IS transferred!! All items of the Loadout of this Deployment -// will be added to the Actor's inventory as well (and also owned by it) -// Arguments: Which in-game player to create the Actor for. -// A float which will be added to with the cost of the stuff returned here. -// Return value: The Actor instance, if any, that is first defined in this Loadout. -// OWNERSHIP IS TRANSFERRED! - - Actor * CreateFirstActor(int nativeModule, float foreignMult, float nativeMult, float &costTally) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateFirstDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns the first Device that is defined in this Loadout. -// Ownership IS transferred!! Only the first Device is created. -// Arguments: Which in-game player to create the device for. -// A float which will be added to with the cost of the stuff returned here. -// Return value: The SceneObject instance, if any, that this Loadout defines first. -// OWNERSHIP IS TRANSFERRED! - - SceneObject * CreateFirstDevice(int nativeModule, float foreignMult, float nativeMult, float &costTally) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeliveryCraft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the preset of the delivery craft set for this loadout. Owenership -// is NOT transferred! -// Arguments: None. -// Return value: A pointer to the ACraft preset instance. OWNERSHIP IS NOT TRANSFERRED! - - const ACraft * GetDeliveryCraft() const { return m_pDeliveryCraft; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDeliveryCraft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the preset of the delivery craft set for this loadout. Owenership -// is NOT transferred! -// Arguments: A pointer to the ACraft preset instance. OWNERSHIP IS NOT TRANSFERRED! -// Return value: None. - - void SetDeliveryCraft(const ACraft *pCraft) { m_pDeliveryCraft = pCraft; m_Complete = m_Complete && m_pDeliveryCraft; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCargoList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of cargo Entity items this Loadout represents. -// Arguments: None. -// Return value: A pointer to the list of cargo Entity items. OWNERSHIP IS NOT TRANSFERRED! - - std::list * GetCargoList() { return &m_CargoItems; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddToCargoList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a new Preset to the list of cargo items to be included in this. -// Arguments: A const pointer to the ScneObject preset we want to add to this loadout. -// Return value: None. - - void AddToCargoList(const SceneObject *pNewItem) { if (pNewItem) m_CargoItems.push_back(pNewItem); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - // Whether this Loadout is the full thing, or something is missing due to unavailable entities on load - bool m_Complete; - // Preset instance of the delivery craft, not owned by this. - const ACraft *m_pDeliveryCraft; - // The cargo of this loadout, all preset instances not owned by this - std::list m_CargoItems; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Loadout, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; +namespace RTE { + + class SceneObject; + class MovableObject; + class ACraft; + class Actor; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Nested class: Loadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines a delivery of Actors, with all their equipment etc. + // Parent(s): Entity. + // Class history: 2/21/2012 Loadout created. + + class Loadout : public Entity { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(Loadout); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Loadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Loadout object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Loadout() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Loadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Copy constructor method used to instantiate a Loadout object + // identical to an already existing one. + // Arguments: A Loadout object which is passed in by reference. + + Loadout(const Loadout& reference) { + if (this != &reference) { + Clear(); + Create(reference); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Operator: Loadout assignment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: An assignment operator for setting one Loadout equal to another. + // Arguments: A Loadout reference. + // Return value: A reference to the changed Loadout. + + Loadout& operator=(const Loadout& rhs) { + if (this != &rhs) { + Destroy(); + Create(rhs); + } + return *this; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Loadout to be identical to another, by deep copy. + // Arguments: A reference to the Loadout to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Loadout& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Entity, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Entity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsComplete + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this loadout is complete, or some Entity within could + // not be found on load. + // Arguments: None. + // Return value: Complete or not. + + bool IsComplete() { return m_Complete; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateFirstActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Actor that this Loadout has and equips. + // Ownership IS transferred!! All items of the Loadout of this Deployment + // will be added to the Actor's inventory as well (and also owned by it) + // Arguments: Which in-game player to create the Actor for. + // A float which will be added to with the cost of the stuff returned here. + // Return value: The Actor instance, if any, that is first defined in this Loadout. + // OWNERSHIP IS TRANSFERRED! + + Actor* CreateFirstActor(int nativeModule, float foreignMult, float nativeMult, float& costTally) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateFirstDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns the first Device that is defined in this Loadout. + // Ownership IS transferred!! Only the first Device is created. + // Arguments: Which in-game player to create the device for. + // A float which will be added to with the cost of the stuff returned here. + // Return value: The SceneObject instance, if any, that this Loadout defines first. + // OWNERSHIP IS TRANSFERRED! + + SceneObject* CreateFirstDevice(int nativeModule, float foreignMult, float nativeMult, float& costTally) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeliveryCraft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the preset of the delivery craft set for this loadout. Owenership + // is NOT transferred! + // Arguments: None. + // Return value: A pointer to the ACraft preset instance. OWNERSHIP IS NOT TRANSFERRED! + + const ACraft* GetDeliveryCraft() const { return m_pDeliveryCraft; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDeliveryCraft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the preset of the delivery craft set for this loadout. Owenership + // is NOT transferred! + // Arguments: A pointer to the ACraft preset instance. OWNERSHIP IS NOT TRANSFERRED! + // Return value: None. + + void SetDeliveryCraft(const ACraft* pCraft) { + m_pDeliveryCraft = pCraft; + m_Complete = m_Complete && m_pDeliveryCraft; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCargoList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of cargo Entity items this Loadout represents. + // Arguments: None. + // Return value: A pointer to the list of cargo Entity items. OWNERSHIP IS NOT TRANSFERRED! + + std::list* GetCargoList() { return &m_CargoItems; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddToCargoList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a new Preset to the list of cargo items to be included in this. + // Arguments: A const pointer to the ScneObject preset we want to add to this loadout. + // Return value: None. + + void AddToCargoList(const SceneObject* pNewItem) { + if (pNewItem) + m_CargoItems.push_back(pNewItem); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + // Whether this Loadout is the full thing, or something is missing due to unavailable entities on load + bool m_Complete; + // Preset instance of the delivery craft, not owned by this. + const ACraft* m_pDeliveryCraft; + // The cargo of this loadout, all preset instances not owned by this + std::list m_CargoItems; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Loadout, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/MOPixel.cpp b/Source/Entities/MOPixel.cpp index 27371996c..1feefb8c0 100644 --- a/Source/Entities/MOPixel.cpp +++ b/Source/Entities/MOPixel.cpp @@ -8,7 +8,7 @@ namespace RTE { ConcreteClassInfo(MOPixel, MovableObject, 2000); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::Clear() { m_Atom = 0; @@ -20,36 +20,42 @@ namespace RTE { m_Staininess = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int MOPixel::Create() { if (MovableObject::Create() < 0) { return -1; } - if (!m_Atom) { m_Atom = new Atom; } + if (!m_Atom) { + m_Atom = new Atom; + } - if (m_MinLethalRange < m_MaxLethalRange) { m_LethalRange *= RandomNum(m_MinLethalRange, m_MaxLethalRange); } + if (m_MinLethalRange < m_MaxLethalRange) { + m_LethalRange *= RandomNum(m_MinLethalRange, m_MaxLethalRange); + } m_LethalSharpness = m_Sharpness * 0.5F; return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MOPixel::Create(Color color, const float mass, const Vector &position, const Vector &velocity, Atom *atom, const unsigned long lifetime) { + int MOPixel::Create(Color color, const float mass, const Vector& position, const Vector& velocity, Atom* atom, const unsigned long lifetime) { m_Color = color; m_Atom = atom; m_Atom->SetOwner(this); - if (m_MinLethalRange < m_MaxLethalRange) { m_LethalRange *= RandomNum(m_MinLethalRange, m_MaxLethalRange); } + if (m_MinLethalRange < m_MaxLethalRange) { + m_LethalRange *= RandomNum(m_MinLethalRange, m_MaxLethalRange); + } m_LethalSharpness = m_Sharpness * 0.5F; return MovableObject::Create(mass, position, velocity, lifetime); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MOPixel::Create(const MOPixel &reference) { + int MOPixel::Create(const MOPixel& reference) { MovableObject::Create(reference); m_Atom = new Atom(*(reference.m_Atom)); @@ -64,13 +70,15 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MOPixel::ReadProperty(const std::string_view &propName, Reader &reader) { + int MOPixel::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return MovableObject::ReadProperty(propName, reader)); - + MatchProperty("Atom", { - if (!m_Atom) { m_Atom = new Atom; } + if (!m_Atom) { + m_Atom = new Atom; + } reader >> m_Atom; m_Atom->SetOwner(this); }); @@ -82,9 +90,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MOPixel::Save(Writer &writer) const { + int MOPixel::Save(Writer& writer) const { MovableObject::Save(writer); writer.NewProperty("Atom"); @@ -101,51 +109,55 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::Destroy(bool notInherited) { delete m_Atom; - if (!notInherited) { MovableObject::Destroy(); } + if (!notInherited) { + MovableObject::Destroy(); + } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int MOPixel::GetDrawPriority() const { return m_Atom->GetMaterial()->GetPriority(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Material * MOPixel::GetMaterial() const { return m_Atom->GetMaterial(); } + const Material* MOPixel::GetMaterial() const { return m_Atom->GetMaterial(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MOPixel::SetAtom(Atom *newAtom) { + void MOPixel::SetAtom(Atom* newAtom) { delete m_Atom; m_Atom = newAtom; m_Atom->SetOwner(this); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::SetLethalRange(float range) { m_LethalRange = range; - if (m_MinLethalRange < m_MaxLethalRange) { m_LethalRange *= RandomNum(m_MinLethalRange, m_MaxLethalRange); } + if (m_MinLethalRange < m_MaxLethalRange) { + m_LethalRange *= RandomNum(m_MinLethalRange, m_MaxLethalRange); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int MOPixel::GetTrailLength() const { return m_Atom->GetTrailLength(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::SetTrailLength(int trailLength) { m_Atom->SetTrailLength(trailLength); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MOPixel::HitTestAtPixel(int pixelX, int pixelY) const { if (!GetsHitByMOs() || GetRootParent()->GetTraveling()) { @@ -155,7 +167,7 @@ namespace RTE { return m_Pos.GetFloorIntX() == pixelX && m_Pos.GetFloorIntY() == pixelY; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::Travel() { MovableObject::Travel(); @@ -168,20 +180,22 @@ namespace RTE { if (m_HitsMOs && m_pMOToNotHit && g_MovableMan.ValidMO(m_pMOToNotHit) && !m_MOIgnoreTimer.IsPastSimTimeLimit()) { std::vector MOIDsNotToHit; m_pMOToNotHit->GetMOIDs(MOIDsNotToHit); - for (const MOID &MOIDNotToHit : MOIDsNotToHit) { + for (const MOID& MOIDNotToHit: MOIDsNotToHit) { m_Atom->AddMOIDToIgnore(MOIDNotToHit); } } // Do static particle bounce calculations. int hitCount = 0; - if (!IsTooFast()) { hitCount = m_Atom->Travel(g_TimerMan.GetDeltaTimeSecs(), true, g_SceneMan.SceneIsLocked()); } + if (!IsTooFast()) { + hitCount = m_Atom->Travel(g_TimerMan.GetDeltaTimeSecs(), true, g_SceneMan.SceneIsLocked()); + } m_Atom->ClearMOIDIgnoreList(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool MOPixel::CollideAtPoint(HitData &hd) { + bool MOPixel::CollideAtPoint(HitData& hd) { RTEAssert(hd.HitPoint.GetFloored() == m_Pos.GetFloored(), "Collision mismatch in MOPixel::CollideAtPoint!"); RTEAssert(hd.Body[HITOR], "Valid MO not passed into MOPixel::CollideAtPoint!"); @@ -197,7 +211,7 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::RestDetection() { MovableObject::RestDetection(); @@ -210,7 +224,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::Update() { MovableObject::Update(); @@ -237,9 +251,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MOPixel::Draw(BITMAP *targetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { + void MOPixel::Draw(BITMAP* targetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { // Don't draw color if this isn't a drawing frame if (!g_TimerMan.DrawnSimUpdate() && mode == g_DrawColor) { return; @@ -277,7 +291,7 @@ namespace RTE { g_SceneMan.RegisterDrawing(targetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, pixelPos, 1.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOPixel::SetPostScreenEffectToDraw() const { if (m_AgeTimer.GetElapsedSimTimeMS() >= m_EffectStartTime && (m_EffectStopTime == 0 || !m_AgeTimer.IsPastSimMS(m_EffectStopTime))) { @@ -286,4 +300,4 @@ namespace RTE { } } } -} +} // namespace RTE diff --git a/Source/Entities/MOPixel.h b/Source/Entities/MOPixel.h index 402fdc9ba..2e8d7c6c6 100644 --- a/Source/Entities/MOPixel.h +++ b/Source/Entities/MOPixel.h @@ -13,7 +13,6 @@ namespace RTE { class MOPixel : public MovableObject { public: - EntityAllocation(MOPixel); ClassInfoGetters; SerializableOverrideMethods; @@ -33,7 +32,10 @@ namespace RTE { /// A Vector specifying the initial velocity. /// An Atom that will collide with the terrain. Ownership IS transferred! /// The amount of time in ms this MOPixel will exist. 0 means unlimited. - MOPixel(Color color, const float mass, const Vector &position, const Vector &velocity, Atom *atom, const unsigned long lifetime = 0) { Clear(); Create(color, mass, position, velocity, atom, lifetime); } + MOPixel(Color color, const float mass, const Vector& position, const Vector& velocity, Atom* atom, const unsigned long lifetime = 0) { + Clear(); + Create(color, mass, position, velocity, atom, lifetime); + } /// /// Makes the MOPixel object ready for use. @@ -51,21 +53,21 @@ namespace RTE { /// An Atom that will collide with the terrain. /// The amount of time in ms this MOPixel will exist. 0 means unlimited. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(Color color, const float mass, const Vector &position, const Vector &velocity, Atom *atom, const unsigned long lifetime = 0); + int Create(Color color, const float mass, const Vector& position, const Vector& velocity, Atom* atom, const unsigned long lifetime = 0); /// /// Creates a MOPixel to be identical to another, by deep copy. /// /// A reference to the MOPixel to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const MOPixel &reference); + int Create(const MOPixel& reference); #pragma endregion #pragma region Destruction /// /// Destructor method used to clean up a MOPixel object before deletion from system memory. /// - ~MOPixel() override { Destroy(true); } + ~MOPixel() override { Destroy(true); } /// /// Destroys and resets (through Clear()) the MOPixel object. @@ -76,7 +78,10 @@ namespace RTE { /// /// Resets the entire MOPixel, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); MovableObject::Reset(); } + void Reset() override { + Clear(); + MovableObject::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -90,19 +95,19 @@ namespace RTE { /// Gets the main Material of this MOPixel. /// /// The Material of this MOPixel. - const Material * GetMaterial() const override; + const Material* GetMaterial() const override; /// /// Gets the current Atom of this MOPixel. /// /// A const reference to the current Atom. - const Atom * GetAtom() const { return m_Atom; } + const Atom* GetAtom() const { return m_Atom; } /// /// Replaces the current Atom of this MOPixel with a new one. /// /// A reference to the new Atom. Ownership IS transferred! - void SetAtom(Atom *newAtom); + void SetAtom(Atom* newAtom); /// /// Gets the color of this MOPixel. @@ -141,13 +146,13 @@ namespace RTE { void SetTrailLength(int trailLength); /// - /// Gets this MOPixel's staininess, which defines how likely a pixel is to stain a surface when it collides with it. + /// Gets this MOPixel's staininess, which defines how likely a pixel is to stain a surface when it collides with it. /// /// This MOPixel's current staininess value. float GetStaininess() const { return m_Staininess; } /// - /// Sets this MOPixel's staininess, which defines how likely a pixel is to stain a surface when it collides with it. + /// Sets this MOPixel's staininess, which defines how likely a pixel is to stain a surface when it collides with it. /// /// The new staininess value. void SetStaininess(float staininess) { m_Staininess = staininess; } @@ -173,7 +178,7 @@ namespace RTE { /// /// Reference to the HitData struct which describes the collision. This will be modified to represent the results of the collision. /// Whether the collision has been deemed valid. If false, then disregard any impulses in the HitData. - bool CollideAtPoint(HitData &hitData) override; + bool CollideAtPoint(HitData& hitData) override; /// /// Does the calculations necessary to detect whether this MOPixel is at rest or not. IsAtRest() retrieves the answer. @@ -185,14 +190,14 @@ namespace RTE { /// /// The HitData describing the collision in detail. /// Whether the MOPixel should immediately halt any travel going on after this bounce. - bool OnBounce(HitData &hd) override { return false; } + bool OnBounce(HitData& hd) override { return false; } /// /// Defines what should happen when this MOPixel hits and then sink into something. This is called by the owned Atom/AtomGroup of this MOPixel during travel. /// /// The HitData describing the collision in detail. /// Whether the MOPixel should immediately halt any travel going on after this sinkage. - bool OnSink(HitData &hd) override { return false; } + bool OnSink(HitData& hd) override { return false; } /// /// Updates this MOPixel. Supposed to be done every frame. @@ -206,15 +211,14 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// In which mode to draw in. See the DrawMode enumeration for the modes. /// Whether to not draw any extra 'ghost' items of this MOPixel, indicator arrows or hovering HUD text and so on. - void Draw(BITMAP *targetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + void Draw(BITMAP* targetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - Atom *m_Atom; //!< The single Atom that is responsible for collisions of this MOPixel. - Color m_Color; //!< Color representation of this MOPixel. + Atom* m_Atom; //!< The single Atom that is responsible for collisions of this MOPixel. + Color m_Color; //!< Color representation of this MOPixel. float m_LethalRange; //!< After this distance in meters, the MO has a chance to no longer hit MOs, and its Lifetime decreases. Defaults to the length of a player's screen. float m_MinLethalRange; //!< Lower bound multiplier for setting LethalRange at random. By default, 1.0 equals one screen. @@ -223,7 +227,6 @@ namespace RTE { float m_Staininess; //!< How likely a pixel is to stain a surface when it collides with it. Defaults to 0 (never stain). private: - /// /// Sets the screen effect to draw at the final post-processing stage. /// @@ -234,5 +237,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/MOSParticle.cpp b/Source/Entities/MOSParticle.cpp index 7ab18f68a..16bf67304 100644 --- a/Source/Entities/MOSParticle.cpp +++ b/Source/Entities/MOSParticle.cpp @@ -7,26 +7,28 @@ namespace RTE { ConcreteClassInfo(MOSParticle, MovableObject, 1000); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOSParticle::Clear() { m_Atom = nullptr; m_SpriteAnimMode = OVERLIFETIME; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int MOSParticle::Create() { if (MOSprite::Create() < 0) { return -1; } - if (!m_Atom) { m_Atom = new Atom(); } + if (!m_Atom) { + m_Atom = new Atom(); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MOSParticle::Create(const MOSParticle &reference) { + int MOSParticle::Create(const MOSParticle& reference) { MOSprite::Create(reference); m_Atom = new Atom(*(reference.m_Atom)); @@ -35,23 +37,25 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MOSParticle::ReadProperty(const std::string_view &propName, Reader &reader) { + int MOSParticle::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return MOSprite::ReadProperty(propName, reader)); - + MatchProperty("Atom", { - if (!m_Atom) { m_Atom = new Atom; } + if (!m_Atom) { + m_Atom = new Atom; + } reader >> *m_Atom; m_Atom->SetOwner(this); - }); - + }); + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MOSParticle::Save(Writer &writer) const { + int MOSParticle::Save(Writer& writer) const { MOSprite::Save(writer); // TODO: Make proper save system that knows not to save redundant data! @@ -63,32 +67,34 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOSParticle::Destroy(bool notInherited) { delete m_Atom; - if (!notInherited) { MOSprite::Destroy(); } + if (!notInherited) { + MOSprite::Destroy(); + } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int MOSParticle::GetDrawPriority() const { return m_Atom->GetMaterial()->GetPriority(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Material * MOSParticle::GetMaterial() const { return m_Atom->GetMaterial(); } + const Material* MOSParticle::GetMaterial() const { return m_Atom->GetMaterial(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MOSParticle::SetAtom(Atom *newAtom) { + void MOSParticle::SetAtom(Atom* newAtom) { delete m_Atom; m_Atom = newAtom; m_Atom->SetOwner(this); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOSParticle::RestDetection() { MOSprite::RestDetection(); @@ -101,7 +107,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOSParticle::Travel() { MOSprite::Travel(); @@ -117,14 +123,14 @@ namespace RTE { if (m_HitsMOs && m_pMOToNotHit && g_MovableMan.ValidMO(m_pMOToNotHit) && !m_MOIgnoreTimer.IsPastSimTimeLimit()) { std::vector MOIDsNotToHit; m_pMOToNotHit->GetMOIDs(MOIDsNotToHit); - for (const MOID &MOIDNotToHit : MOIDsNotToHit) { + for (const MOID& MOIDNotToHit: MOIDsNotToHit) { m_Atom->AddMOIDToIgnore(MOIDNotToHit); } } // Do static particle bounce calculations. int hitCount = 0; - if (!IsTooFast()) { - m_Atom->Travel(g_TimerMan.GetDeltaTimeSecs(), true, g_SceneMan.SceneIsLocked()); + if (!IsTooFast()) { + m_Atom->Travel(g_TimerMan.GetDeltaTimeSecs(), true, g_SceneMan.SceneIsLocked()); } m_Atom->ClearMOIDIgnoreList(); @@ -145,21 +151,25 @@ namespace RTE { m_Frame = std::floor(newFrame); m_Rotation += m_AngularVel * deltaTime; - if (m_Frame >= m_FrameCount) { m_Frame = m_FrameCount - 1; } + if (m_Frame >= m_FrameCount) { + m_Frame = m_FrameCount - 1; + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOSParticle::Update() { MOSprite::Update(); - if (m_pScreenEffect) { SetPostScreenEffectToDraw(); } + if (m_pScreenEffect) { + SetPostScreenEffectToDraw(); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MOSParticle::Draw(BITMAP *targetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { + void MOSParticle::Draw(BITMAP* targetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { RTEAssert(!m_aSprite.empty(), "No sprite bitmaps loaded to draw " + GetPresetName()); RTEAssert(m_Frame >= 0 && m_Frame < m_FrameCount, "Frame is out of bounds for " + GetPresetName()); @@ -169,8 +179,8 @@ namespace RTE { Vector spritePos(m_Pos + m_SpriteOffset - targetPos); - //TODO I think this is an array with 4 elements to account for Y wrapping. Y wrapping is not really handled in this game, so this can probably be knocked down to 2 elements. Also, I'm sure this code can be simplified. - std::array drawPositions = { spritePos }; + // TODO I think this is an array with 4 elements to account for Y wrapping. Y wrapping is not really handled in this game, so this can probably be knocked down to 2 elements. Also, I'm sure this code can be simplified. + std::array drawPositions = {spritePos}; int drawPasses = 1; if (g_SceneMan.SceneWrapsX()) { if (targetPos.IsZero() && m_WrapDoubleDraw) { @@ -231,7 +241,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MOSParticle::SetPostScreenEffectToDraw() const { if (m_AgeTimer.GetElapsedSimTimeMS() >= m_EffectStartTime && (m_EffectStopTime == 0 || !m_AgeTimer.IsPastSimMS(m_EffectStopTime))) { @@ -240,4 +250,4 @@ namespace RTE { } } } -} +} // namespace RTE diff --git a/Source/Entities/MOSParticle.h b/Source/Entities/MOSParticle.h index 3d40c7dbb..703feeb56 100644 --- a/Source/Entities/MOSParticle.h +++ b/Source/Entities/MOSParticle.h @@ -13,7 +13,6 @@ namespace RTE { class MOSParticle : public MOSprite { public: - EntityAllocation(MOSParticle); ClassInfoGetters; SerializableOverrideMethods; @@ -40,7 +39,7 @@ namespace RTE { /// A Vector specifying the initial velocity. /// The amount of time in ms this MOSParticle will exist. 0 means unlimited. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(ContentFile spriteFile, const int frameCount = 1, const float mass = 1, const Vector &position = Vector(0, 0), const Vector &velocity = Vector(0, 0), const unsigned long lifetime = 0) { + int Create(ContentFile spriteFile, const int frameCount = 1, const float mass = 1, const Vector& position = Vector(0, 0), const Vector& velocity = Vector(0, 0), const unsigned long lifetime = 0) { MOSprite::Create(spriteFile, frameCount, mass, position, velocity, lifetime); return 0; } @@ -50,7 +49,7 @@ namespace RTE { /// /// A reference to the MOSParticle to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const MOSParticle &reference); + int Create(const MOSParticle& reference); #pragma endregion #pragma region Destruction @@ -68,7 +67,10 @@ namespace RTE { /// /// Resets the entire MOSParticle, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); MOSprite::Reset(); } + void Reset() override { + Clear(); + MOSprite::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -82,19 +84,19 @@ namespace RTE { /// Gets the main material of this MOSParticle. /// /// The material of this MOSParticle. - const Material * GetMaterial() const override; + const Material* GetMaterial() const override; /// /// Gets the current Atom of this MOSParticle. /// /// A const reference to the current Atom. - const Atom * GetAtom() const { return m_Atom; } + const Atom* GetAtom() const { return m_Atom; } /// /// Replaces the current Atom of this MOSParticle with a new one. /// /// A reference to the new Atom. - void SetAtom(Atom *newAtom); + void SetAtom(Atom* newAtom); #pragma endregion #pragma region Virtual Override Methods @@ -104,12 +106,12 @@ namespace RTE { void Travel() override; /// - /// Calculates the collision response when another MO's Atom collides with this MO's physical representation. + /// Calculates the collision response when another MO's Atom collides with this MO's physical representation. /// The effects will be applied directly to this MO, and also represented in the passed in HitData. /// /// Reference to the HitData struct which describes the collision. This will be modified to represent the results of the collision. /// Whether the collision has been deemed valid. If false, then disregard any impulses in the HitData. - bool CollideAtPoint(HitData &hitData) override { return true; } + bool CollideAtPoint(HitData& hitData) override { return true; } /// /// Does the calculations necessary to detect whether this MOSParticle is at rest or not. IsAtRest() retrieves the answer. @@ -121,14 +123,14 @@ namespace RTE { /// /// The HitData describing the collision in detail. /// Whether the MOSParticle should immediately halt any travel going on after this bounce. - bool OnBounce(HitData &hd) override { return false; } + bool OnBounce(HitData& hd) override { return false; } /// /// Defines what should happen when this MOSParticle hits and then sink into something. This is called by the owned Atom/AtomGroup of this MOSParticle during travel. /// /// The HitData describing the collision in detail. /// Whether the MOSParticle should immediately halt any travel going on after this sinkage. - bool OnSink(HitData &hd) override { return false; } + bool OnSink(HitData& hd) override { return false; } /// /// Updates this MOParticle. Supposed to be done every frame. @@ -142,18 +144,16 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// In which mode to draw in. See the DrawMode enumeration for the modes. /// Whether to not draw any extra 'ghost' items of this MOSParticle, indicator arrows or hovering HUD text and so on. - void Draw(BITMAP *targetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + void Draw(BITMAP* targetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - Atom *m_Atom; //!< The Atom that will be the physical representation of this MOSParticle. + Atom* m_Atom; //!< The Atom that will be the physical representation of this MOSParticle. float m_TimeRest; //!< Accumulated time in seconds that did not cause a frame change. private: - /// /// Sets the screen effect to draw at the final post-processing stage. /// @@ -165,8 +165,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - MOSParticle(const MOSParticle &reference) = delete; - MOSParticle & operator=(const MOSParticle &rhs) = delete; + MOSParticle(const MOSParticle& reference) = delete; + MOSParticle& operator=(const MOSParticle& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/MOSRotating.cpp b/Source/Entities/MOSRotating.cpp index f67f999f5..5c6e28996 100644 --- a/Source/Entities/MOSRotating.cpp +++ b/Source/Entities/MOSRotating.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -28,2069 +27,2071 @@ namespace RTE { -ConcreteClassInfo(MOSRotating, MOSprite, 500); + ConcreteClassInfo(MOSRotating, MOSprite, 500); + + BITMAP* MOSRotating::m_spTempBitmap16 = 0; + BITMAP* MOSRotating::m_spTempBitmap32 = 0; + BITMAP* MOSRotating::m_spTempBitmap64 = 0; + BITMAP* MOSRotating::m_spTempBitmap128 = 0; + BITMAP* MOSRotating::m_spTempBitmap256 = 0; + BITMAP* MOSRotating::m_spTempBitmap512 = 0; + + BITMAP* MOSRotating::m_spTempBitmapS16 = 0; + BITMAP* MOSRotating::m_spTempBitmapS32 = 0; + BITMAP* MOSRotating::m_spTempBitmapS64 = 0; + BITMAP* MOSRotating::m_spTempBitmapS128 = 0; + BITMAP* MOSRotating::m_spTempBitmapS256 = 0; + BITMAP* MOSRotating::m_spTempBitmapS512 = 0; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MOSRotating, effectively + // resetting the members of this abstraction level only. + + void MOSRotating::Clear() { + m_pAtomGroup = 0; + m_pDeepGroup = 0; + m_DeepCheck = false; + m_ForceDeepCheck = false; + m_DeepHardness = 0; + m_TravelImpulse.Reset(); + m_SpriteCenter.Reset(); + m_OrientToVel = 0; + m_Recoiled = false; + m_RecoilForce.Reset(); + m_RecoilOffset.Reset(); + m_Wounds.clear(); + m_Attachables.clear(); + m_ReferenceHardcodedAttachableUniqueIDs.clear(); + m_HardcodedAttachableUniqueIDsAndSetters.clear(); + m_HardcodedAttachableUniqueIDsAndRemovers.clear(); + m_RadiusAffectingAttachable = nullptr; + m_FarthestAttachableDistanceAndRadius = 0.0F; + m_AttachableAndWoundMass = 0.0F; + m_Gibs.clear(); + m_GibImpulseLimit = 0; + m_GibWoundLimit = 0; + m_GibBlastStrength = 10.0F; + m_GibScreenShakeAmount = -1.0F; + m_WoundCountAffectsImpulseLimitRatio = 0.25F; + m_DetachAttachablesBeforeGibbingFromWounds = true; + m_GibAtEndOfLifetime = false; + m_GibSound = nullptr; + m_EffectOnGib = true; + m_pFlipBitmap = 0; + m_pFlipBitmapS = 0; + m_pTempBitmap = 0; + m_pTempBitmapS = 0; + m_LoudnessOnGib = 1; + m_DamageMultiplier = 0; + m_NoSetDamageMultiplier = true; + m_FlashWhiteTimer.Reset(); + m_FlashWhiteTimer.SetRealTimeLimitMS(0); + } -BITMAP * MOSRotating::m_spTempBitmap16 = 0; -BITMAP * MOSRotating::m_spTempBitmap32 = 0; -BITMAP * MOSRotating::m_spTempBitmap64 = 0; -BITMAP * MOSRotating::m_spTempBitmap128 = 0; -BITMAP * MOSRotating::m_spTempBitmap256 = 0; -BITMAP * MOSRotating::m_spTempBitmap512 = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSParticle object ready for use. -BITMAP * MOSRotating::m_spTempBitmapS16 = 0; -BITMAP * MOSRotating::m_spTempBitmapS32 = 0; -BITMAP * MOSRotating::m_spTempBitmapS64 = 0; -BITMAP * MOSRotating::m_spTempBitmapS128 = 0; -BITMAP * MOSRotating::m_spTempBitmapS256 = 0; -BITMAP * MOSRotating::m_spTempBitmapS512 = 0; + int MOSRotating::Create() { + if (MOSprite::Create() < 0) + return -1; + if (!m_pAtomGroup) { + RTEAbort("Encountered empty AtomGroup while trying to create preset \"" + this->GetPresetName() + "\"!\nAtomGroups must be defined for MOSRotating based presets!\n\nError happened " + this->GetFormattedReaderPosition() + "!"); + } else { + if (m_pAtomGroup->AutoGenerate() /* && m_pAtomGroup->GetAtomCount() == 0*/) { + m_pAtomGroup->Create(this); + } else { + m_pAtomGroup->SetOwner(this); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MOSRotating, effectively -// resetting the members of this abstraction level only. - -void MOSRotating::Clear() -{ - m_pAtomGroup = 0; - m_pDeepGroup = 0; - m_DeepCheck = false; - m_ForceDeepCheck = false; - m_DeepHardness = 0; - m_TravelImpulse.Reset(); - m_SpriteCenter.Reset(); - m_OrientToVel = 0; - m_Recoiled = false; - m_RecoilForce.Reset(); - m_RecoilOffset.Reset(); - m_Wounds.clear(); - m_Attachables.clear(); - m_ReferenceHardcodedAttachableUniqueIDs.clear(); - m_HardcodedAttachableUniqueIDsAndSetters.clear(); - m_HardcodedAttachableUniqueIDsAndRemovers.clear(); - m_RadiusAffectingAttachable = nullptr; - m_FarthestAttachableDistanceAndRadius = 0.0F; - m_AttachableAndWoundMass = 0.0F; - m_Gibs.clear(); - m_GibImpulseLimit = 0; - m_GibWoundLimit = 0; - m_GibBlastStrength = 10.0F; - m_GibScreenShakeAmount = -1.0F; - m_WoundCountAffectsImpulseLimitRatio = 0.25F; - m_DetachAttachablesBeforeGibbingFromWounds = true; - m_GibAtEndOfLifetime = false; - m_GibSound = nullptr; - m_EffectOnGib = true; - m_pFlipBitmap = 0; - m_pFlipBitmapS = 0; - m_pTempBitmap = 0; - m_pTempBitmapS = 0; - m_LoudnessOnGib = 1; - m_DamageMultiplier = 0; - m_NoSetDamageMultiplier = true; - m_FlashWhiteTimer.Reset(); - m_FlashWhiteTimer.SetRealTimeLimitMS(0); -} + if (m_pDeepGroup && m_pDeepGroup->AutoGenerate() /* && m_pDeepGroup->GetAtomCount() == 0*/) + m_pDeepGroup->Create(this); + else if (m_pDeepGroup) + m_pDeepGroup->SetOwner(this); + m_SpriteCenter.SetXY(m_aSprite[m_Frame]->w / 2, m_aSprite[m_Frame]->h / 2); + m_SpriteCenter += m_SpriteOffset; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSParticle object ready for use. - -int MOSRotating::Create() -{ - if (MOSprite::Create() < 0) - return -1; - - if (!m_pAtomGroup) { - RTEAbort("Encountered empty AtomGroup while trying to create preset \"" + this->GetPresetName() + "\"!\nAtomGroups must be defined for MOSRotating based presets!\n\nError happened " + this->GetFormattedReaderPosition() + "!"); - } else { - if (m_pAtomGroup->AutoGenerate() /* && m_pAtomGroup->GetAtomCount() == 0*/) { - m_pAtomGroup->Create(this); + if (!m_pFlipBitmap && m_aSprite[0]) { + m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); + } + if (!m_pFlipBitmapS && m_aSprite[0]) { + m_pFlipBitmapS = create_bitmap_ex(c_MOIDLayerBitDepth, m_aSprite[0]->w, m_aSprite[0]->h); + } + + /* Not anymore; points to shared static bitmaps + if (!m_pTempBitmap && m_aSprite[0]) + m_pTempBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); + */ + + // Can't create these earlier in the static declaration because allegro_init needs to be called before create_bitmap + if (!m_spTempBitmap16) + m_spTempBitmap16 = create_bitmap_ex(8, 16, 16); + if (!m_spTempBitmap32) + m_spTempBitmap32 = create_bitmap_ex(8, 32, 32); + if (!m_spTempBitmap64) + m_spTempBitmap64 = create_bitmap_ex(8, 64, 64); + if (!m_spTempBitmap128) + m_spTempBitmap128 = create_bitmap_ex(8, 128, 128); + if (!m_spTempBitmap256) + m_spTempBitmap256 = create_bitmap_ex(8, 256, 256); + if (!m_spTempBitmap512) + m_spTempBitmap512 = create_bitmap_ex(8, 512, 512); + + // Can't create these earlier in the static declaration because allegro_init needs to be called before create_bitmap + if (!m_spTempBitmapS16) + m_spTempBitmapS16 = create_bitmap_ex(c_MOIDLayerBitDepth, 16, 16); + if (!m_spTempBitmapS32) + m_spTempBitmapS32 = create_bitmap_ex(c_MOIDLayerBitDepth, 32, 32); + if (!m_spTempBitmapS64) + m_spTempBitmapS64 = create_bitmap_ex(c_MOIDLayerBitDepth, 64, 64); + if (!m_spTempBitmapS128) + m_spTempBitmapS128 = create_bitmap_ex(c_MOIDLayerBitDepth, 128, 128); + if (!m_spTempBitmapS256) + m_spTempBitmapS256 = create_bitmap_ex(c_MOIDLayerBitDepth, 256, 256); + if (!m_spTempBitmapS512) + m_spTempBitmapS512 = create_bitmap_ex(c_MOIDLayerBitDepth, 512, 512); + + // Choose an appropriate size for this' diameter + if (m_SpriteDiameter >= 256) { + m_pTempBitmap = m_spTempBitmap512; + m_pTempBitmapS = m_spTempBitmapS512; + } else if (m_SpriteDiameter >= 128) { + m_pTempBitmap = m_spTempBitmap256; + m_pTempBitmapS = m_spTempBitmapS256; + } else if (m_SpriteDiameter >= 64) { + m_pTempBitmap = m_spTempBitmap128; + m_pTempBitmapS = m_spTempBitmapS128; + } else if (m_SpriteDiameter >= 32) { + m_pTempBitmap = m_spTempBitmap64; + m_pTempBitmapS = m_spTempBitmapS64; + } else if (m_SpriteDiameter >= 16) { + m_pTempBitmap = m_spTempBitmap32; + m_pTempBitmapS = m_spTempBitmapS32; } else { - m_pAtomGroup->SetOwner(this); + m_pTempBitmap = m_spTempBitmap16; + m_pTempBitmapS = m_spTempBitmapS16; } - } - if (m_pDeepGroup && m_pDeepGroup->AutoGenerate()/* && m_pDeepGroup->GetAtomCount() == 0*/) - m_pDeepGroup->Create(this); - else if (m_pDeepGroup) - m_pDeepGroup->SetOwner(this); + return 0; + } - m_SpriteCenter.SetXY(m_aSprite[m_Frame]->w / 2, m_aSprite[m_Frame]->h / 2); - m_SpriteCenter += m_SpriteOffset; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSParticle object ready for use. + + int MOSRotating::Create(ContentFile spriteFile, + const int frameCount, + const float mass, + const Vector& position, + const Vector& velocity, + const unsigned long lifetime) { + MOSprite::Create(spriteFile, frameCount, mass, position, velocity, lifetime); + + if (!m_pFlipBitmap && m_aSprite[0]) { + m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); + } + if (!m_pFlipBitmapS && m_aSprite[0]) { + m_pFlipBitmapS = create_bitmap_ex(c_MOIDLayerBitDepth, m_aSprite[0]->w, m_aSprite[0]->h); + } - if (!m_pFlipBitmap && m_aSprite[0]) { - m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); - } - if (!m_pFlipBitmapS && m_aSprite[0]) { - m_pFlipBitmapS = create_bitmap_ex(c_MOIDLayerBitDepth, m_aSprite[0]->w, m_aSprite[0]->h); + return 0; } -/* Not anymore; points to shared static bitmaps - if (!m_pTempBitmap && m_aSprite[0]) - m_pTempBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); -*/ - - // Can't create these earlier in the static declaration because allegro_init needs to be called before create_bitmap - if (!m_spTempBitmap16) - m_spTempBitmap16 = create_bitmap_ex(8, 16, 16); - if (!m_spTempBitmap32) - m_spTempBitmap32 = create_bitmap_ex(8, 32, 32); - if (!m_spTempBitmap64) - m_spTempBitmap64 = create_bitmap_ex(8, 64, 64); - if (!m_spTempBitmap128) - m_spTempBitmap128 = create_bitmap_ex(8, 128, 128); - if (!m_spTempBitmap256) - m_spTempBitmap256 = create_bitmap_ex(8, 256, 256); - if (!m_spTempBitmap512) - m_spTempBitmap512 = create_bitmap_ex(8, 512, 512); - - // Can't create these earlier in the static declaration because allegro_init needs to be called before create_bitmap - if (!m_spTempBitmapS16) - m_spTempBitmapS16 = create_bitmap_ex(c_MOIDLayerBitDepth, 16, 16); - if (!m_spTempBitmapS32) - m_spTempBitmapS32 = create_bitmap_ex(c_MOIDLayerBitDepth, 32, 32); - if (!m_spTempBitmapS64) - m_spTempBitmapS64 = create_bitmap_ex(c_MOIDLayerBitDepth, 64, 64); - if (!m_spTempBitmapS128) - m_spTempBitmapS128 = create_bitmap_ex(c_MOIDLayerBitDepth, 128, 128); - if (!m_spTempBitmapS256) - m_spTempBitmapS256 = create_bitmap_ex(c_MOIDLayerBitDepth, 256, 256); - if (!m_spTempBitmapS512) - m_spTempBitmapS512 = create_bitmap_ex(c_MOIDLayerBitDepth, 512, 512); - - // Choose an appropriate size for this' diameter - if (m_SpriteDiameter >= 256) - { - m_pTempBitmap = m_spTempBitmap512; - m_pTempBitmapS = m_spTempBitmapS512; - } - else if (m_SpriteDiameter >= 128) - { - m_pTempBitmap = m_spTempBitmap256; - m_pTempBitmapS = m_spTempBitmapS256; - } - else if (m_SpriteDiameter >= 64) - { - m_pTempBitmap = m_spTempBitmap128; - m_pTempBitmapS = m_spTempBitmapS128; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOSRotating to be identical to another, by deep copy. + + int MOSRotating::Create(const MOSRotating& reference) { + MOSprite::Create(reference); + + if (!reference.m_pAtomGroup) { + return -1; + } + + // THESE ATOMGROUP COPYING ARE A TIME SINK! + m_pAtomGroup = new AtomGroup(); + m_pAtomGroup->Create(*reference.m_pAtomGroup, true); + if (m_pAtomGroup) { + m_pAtomGroup->SetOwner(this); + } + + if (reference.m_pDeepGroup) { + m_pDeepGroup = dynamic_cast(reference.m_pDeepGroup->Clone()); + if (m_pDeepGroup) { + m_pDeepGroup->SetOwner(this); + } + } + + m_DeepCheck = reference.m_DeepCheck; + m_SpriteCenter = reference.m_SpriteCenter; + m_OrientToVel = reference.m_OrientToVel; + + m_Recoiled = reference.m_Recoiled; + m_RecoilForce = reference.m_RecoilForce; + m_RecoilOffset = reference.m_RecoilOffset; + + for (const AEmitter* wound: reference.m_Wounds) { + AddWound(dynamic_cast(wound->Clone()), wound->GetParentOffset(), false); + } + + // TODO This could probably be replaced with just using HardcodedAttachableUniqueIDs entirely. At this point in, these lists should have the same UIDs in them, so it should work. + for (const Attachable* referenceAttachable: reference.m_Attachables) { + if (m_ReferenceHardcodedAttachableUniqueIDs.find(referenceAttachable->GetUniqueID()) == m_ReferenceHardcodedAttachableUniqueIDs.end()) { + AddAttachable(dynamic_cast(referenceAttachable->Clone())); + } + } + m_ReferenceHardcodedAttachableUniqueIDs.clear(); + + for (const Gib& gib: reference.m_Gibs) { + m_Gibs.push_back(gib); + } + + m_GibImpulseLimit = reference.m_GibImpulseLimit; + m_GibWoundLimit = reference.m_GibWoundLimit; + m_GibBlastStrength = reference.m_GibBlastStrength; + m_GibScreenShakeAmount = reference.m_GibScreenShakeAmount; + m_WoundCountAffectsImpulseLimitRatio = reference.m_WoundCountAffectsImpulseLimitRatio; + m_DetachAttachablesBeforeGibbingFromWounds = reference.m_DetachAttachablesBeforeGibbingFromWounds; + m_GibAtEndOfLifetime = reference.m_GibAtEndOfLifetime; + if (reference.m_GibSound) { + m_GibSound = dynamic_cast(reference.m_GibSound->Clone()); + } + m_EffectOnGib = reference.m_EffectOnGib; + m_LoudnessOnGib = reference.m_LoudnessOnGib; + + m_DamageMultiplier = reference.m_DamageMultiplier; + m_NoSetDamageMultiplier = reference.m_NoSetDamageMultiplier; + + m_pTempBitmap = reference.m_pTempBitmap; + m_pTempBitmapS = reference.m_pTempBitmapS; + + if (!m_pFlipBitmap && m_aSprite[0]) { + m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); + } + if (!m_pFlipBitmapS && m_aSprite[0]) { + m_pFlipBitmapS = create_bitmap_ex(c_MOIDLayerBitDepth, m_aSprite[0]->w, m_aSprite[0]->h); + } + + return 0; } - else if (m_SpriteDiameter >= 32) - { - m_pTempBitmap = m_spTempBitmap64; - m_pTempBitmapS = m_spTempBitmapS64; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int MOSRotating::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return MOSprite::ReadProperty(propName, reader)); + + MatchProperty("AtomGroup", + { + delete m_pAtomGroup; + m_pAtomGroup = new AtomGroup(); + reader >> *m_pAtomGroup; + }); + MatchProperty("DeepGroup", + { + delete m_pDeepGroup; + m_pDeepGroup = new AtomGroup(); + reader >> *m_pDeepGroup; + }); + MatchProperty("DeepCheck", { reader >> m_DeepCheck; }); + MatchProperty("OrientToVel", { reader >> m_OrientToVel; }); + MatchProperty("SpecialBehaviour_ClearAllAttachables", { + // This special property is used to make Attachables work with our limited serialization system, when saving the game. Note that we discard the property value here, because all that matters is whether or not we have the property. + reader.ReadPropValue(); + for (auto attachableIterator = m_Attachables.begin(); attachableIterator != m_Attachables.end();) { + Attachable* attachable = *attachableIterator; + ++attachableIterator; + delete RemoveAttachable(attachable); + } + }); + MatchForwards("AddAttachable") MatchForwards("AddAEmitter") MatchProperty("AddEmitter", { + Entity* readerEntity = g_PresetMan.ReadReflectedPreset(reader); + if (Attachable* readerAttachable = dynamic_cast(readerEntity)) { + AddAttachable(readerAttachable); + } else { + reader.ReportError("Tried to AddAttachable a non-Attachable type!"); + } + }); + MatchProperty("SpecialBehaviour_AddWound", { + AEmitter* wound = new AEmitter; + reader >> wound; + AddWound(wound, wound->GetParentOffset()); + }); + MatchProperty("AddGib", + { + Gib gib; + reader >> gib; + m_Gibs.push_back(gib); + }); + MatchProperty("GibImpulseLimit", { reader >> m_GibImpulseLimit; }); + MatchForwards("GibWoundLimit") MatchProperty("WoundLimit", { reader >> m_GibWoundLimit; }); + MatchProperty("GibBlastStrength", { reader >> m_GibBlastStrength; }); + MatchProperty("GibScreenShakeAmount", { reader >> m_GibScreenShakeAmount; }); + MatchProperty("WoundCountAffectsImpulseLimitRatio", { reader >> m_WoundCountAffectsImpulseLimitRatio; }); + MatchProperty("DetachAttachablesBeforeGibbingFromWounds", { reader >> m_DetachAttachablesBeforeGibbingFromWounds; }); + MatchProperty("GibAtEndOfLifetime", { reader >> m_GibAtEndOfLifetime; }); + MatchProperty("GibSound", { + if (!m_GibSound) { + m_GibSound = new SoundContainer; + } + reader >> m_GibSound; + }); + MatchProperty("EffectOnGib", { reader >> m_EffectOnGib; }); + MatchProperty("LoudnessOnGib", { reader >> m_LoudnessOnGib; }); + MatchProperty("DamageMultiplier", { + reader >> m_DamageMultiplier; + m_NoSetDamageMultiplier = false; + }); + + EndPropertyList; } - else if (m_SpriteDiameter >= 16) - { - m_pTempBitmap = m_spTempBitmap32; - m_pTempBitmapS = m_spTempBitmapS32; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this MOSRotating with a Writer for + // later recreation with Create(Reader &reader); + + int MOSRotating::Save(Writer& writer) const { + MOSprite::Save(writer); + + // TODO: Make proper save system that knows not to save redundant data! + /* + writer.NewProperty("AtomGroup"); + writer << m_pAtomGroup; + writer.NewProperty("DeepGroup"); + writer << m_pDeepGroup; + writer.NewProperty("DeepCheck"); + writer << m_DeepCheck; + writer.NewProperty("OrientToVel"); + writer << m_OrientToVel; + + for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) + { + writer.NewProperty("AddEmitter"); + writer << (*itr); + } + for (auto aItr = m_Attachables.begin(); aItr != m_Attachables.end(); ++aItr) + { + writer.NewProperty("AddAttachable"); + writer << (*aItr); + } + */ + for (auto gItr = m_Gibs.begin(); gItr != m_Gibs.end(); ++gItr) { + writer.NewProperty("AddGib"); + writer << (*gItr); + } + /* + writer.NewProperty("GibImpulseLimit"); + writer << m_GibImpulseLimit; + writer.NewProperty("GibWoundLimit"); + writer << m_GibWoundLimit; + writer.NewPropertyWithValue("GibAtEndOfLifetime", m_GibAtEndOfLifetime); + writer.NewProperty("GibSound"); + writer << m_GibSound; + writer.NewProperty("EffectOnGib"); + writer << m_EffectOnGib; + */ + return 0; } - else - { - m_pTempBitmap = m_spTempBitmap16; - m_pTempBitmapS = m_spTempBitmapS16; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MOSRotating::GetGibWoundLimit(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const { + int gibWoundLimit = m_GibWoundLimit; + if (includePositiveDamageAttachables || includeNegativeDamageAttachables || includeNoDamageAttachables) { + for (const Attachable* attachable: m_Attachables) { + bool attachableSatisfiesConditions = (includePositiveDamageAttachables && attachable->GetDamageMultiplier() > 0) || + (includeNegativeDamageAttachables && attachable->GetDamageMultiplier() < 0) || + (includeNoDamageAttachables && attachable->GetDamageMultiplier() == 0); + + if (attachableSatisfiesConditions) { + gibWoundLimit += attachable->GetGibWoundLimit(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); + } + } + } + return gibWoundLimit; } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int MOSRotating::GetWoundCount(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const { + int woundCount = m_Wounds.size(); + if (includePositiveDamageAttachables || includeNegativeDamageAttachables || includeNoDamageAttachables) { + for (const Attachable* attachable: m_Attachables) { + bool attachableSatisfiesConditions = (includePositiveDamageAttachables && attachable->GetDamageMultiplier() > 0) || + (includeNegativeDamageAttachables && attachable->GetDamageMultiplier() < 0) || + (includeNoDamageAttachables && attachable->GetDamageMultiplier() == 0); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSParticle object ready for use. - -int MOSRotating::Create(ContentFile spriteFile, - const int frameCount, - const float mass, - const Vector &position, - const Vector &velocity, - const unsigned long lifetime) -{ - MOSprite::Create(spriteFile, frameCount, mass, position, velocity, lifetime); - - if (!m_pFlipBitmap && m_aSprite[0]) { - m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); + if (attachableSatisfiesConditions) { + woundCount += attachable->GetWoundCount(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); + } + } + } + return woundCount; } - if (!m_pFlipBitmapS && m_aSprite[0]) { - m_pFlipBitmapS = create_bitmap_ex(c_MOIDLayerBitDepth, m_aSprite[0]->w, m_aSprite[0]->h); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Attachable* MOSRotating::GetNearestDetachableAttachableToOffset(const Vector& offset) const { + Attachable* nearestAttachable = nullptr; + float closestRadius = m_SpriteRadius; + for (Attachable* attachable: m_Attachables) { + if (attachable->GetsHitByMOs() && attachable->GetGibImpulseLimit() > 0 && attachable->GetJointStrength() > 0 && attachable->GetDamageMultiplier() > 0 && offset.Dot(attachable->GetParentOffset()) > 0) { + float radius = (offset - attachable->GetParentOffset()).GetMagnitude(); + if (radius < closestRadius) { + closestRadius = radius; + nearestAttachable = attachable; + } + } + } + return nearestAttachable; } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::DetachAttachablesFromImpulse(Vector& impulseVector) { + float impulseRemainder = impulseVector.GetMagnitude(); + // Find the attachable closest to the impact point by using an inverted impulse vector. + Vector invertedImpulseOffset = Vector(impulseVector.GetX(), impulseVector.GetY()).SetMagnitude(-GetRadius()) * -m_Rotation; + Attachable* nearestAttachableToImpulse = GetNearestDetachableAttachableToOffset(invertedImpulseOffset); + while (nearestAttachableToImpulse) { + float attachableImpulseLimit = nearestAttachableToImpulse->GetGibImpulseLimit(); + float attachableJointStrength = nearestAttachableToImpulse->GetJointStrength(); + if (impulseRemainder > attachableImpulseLimit) { + nearestAttachableToImpulse->GibThis(impulseVector.SetMagnitude(attachableImpulseLimit)); + impulseRemainder -= attachableImpulseLimit; + } else if (impulseRemainder > attachableJointStrength) { + RemoveAttachable(nearestAttachableToImpulse, true, true); + impulseRemainder -= attachableJointStrength; + } else { + break; + } + nearestAttachableToImpulse = GetNearestDetachableAttachableToOffset(invertedImpulseOffset); + } + impulseVector.SetMagnitude(impulseRemainder); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOSRotating to be identical to another, by deep copy. - -int MOSRotating::Create(const MOSRotating &reference) { - MOSprite::Create(reference); - - if (!reference.m_pAtomGroup) { - return -1; - } - - // THESE ATOMGROUP COPYING ARE A TIME SINK! - m_pAtomGroup = new AtomGroup(); - m_pAtomGroup->Create(*reference.m_pAtomGroup, true); - if (m_pAtomGroup) { m_pAtomGroup->SetOwner(this); } - - if (reference.m_pDeepGroup) { - m_pDeepGroup = dynamic_cast(reference.m_pDeepGroup->Clone()); - if (m_pDeepGroup) { m_pDeepGroup->SetOwner(this); } - } - - m_DeepCheck = reference.m_DeepCheck; - m_SpriteCenter = reference.m_SpriteCenter; - m_OrientToVel = reference.m_OrientToVel; - - m_Recoiled = reference.m_Recoiled; - m_RecoilForce = reference.m_RecoilForce; - m_RecoilOffset = reference.m_RecoilOffset; - - for (const AEmitter *wound : reference.m_Wounds) { - AddWound(dynamic_cast(wound->Clone()), wound->GetParentOffset(), false); - } - - //TODO This could probably be replaced with just using HardcodedAttachableUniqueIDs entirely. At this point in, these lists should have the same UIDs in them, so it should work. - for (const Attachable *referenceAttachable : reference.m_Attachables) { - if (m_ReferenceHardcodedAttachableUniqueIDs.find(referenceAttachable->GetUniqueID()) == m_ReferenceHardcodedAttachableUniqueIDs.end()) { - AddAttachable(dynamic_cast(referenceAttachable->Clone())); - } - } - m_ReferenceHardcodedAttachableUniqueIDs.clear(); - - for (const Gib &gib : reference.m_Gibs) { - m_Gibs.push_back(gib); - } - - m_GibImpulseLimit = reference.m_GibImpulseLimit; - m_GibWoundLimit = reference.m_GibWoundLimit; - m_GibBlastStrength = reference.m_GibBlastStrength; - m_GibScreenShakeAmount = reference.m_GibScreenShakeAmount; - m_WoundCountAffectsImpulseLimitRatio = reference.m_WoundCountAffectsImpulseLimitRatio; - m_DetachAttachablesBeforeGibbingFromWounds = reference.m_DetachAttachablesBeforeGibbingFromWounds; - m_GibAtEndOfLifetime = reference.m_GibAtEndOfLifetime; - if (reference.m_GibSound) { m_GibSound = dynamic_cast(reference.m_GibSound->Clone()); } - m_EffectOnGib = reference.m_EffectOnGib; - m_LoudnessOnGib = reference.m_LoudnessOnGib; - - m_DamageMultiplier = reference.m_DamageMultiplier; - m_NoSetDamageMultiplier = reference.m_NoSetDamageMultiplier; - - m_pTempBitmap = reference.m_pTempBitmap; - m_pTempBitmapS = reference.m_pTempBitmapS; - - if (!m_pFlipBitmap && m_aSprite[0]) { - m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[0]->w, m_aSprite[0]->h); - } - if (!m_pFlipBitmapS && m_aSprite[0]) { - m_pFlipBitmapS = create_bitmap_ex(c_MOIDLayerBitDepth, m_aSprite[0]->w, m_aSprite[0]->h); + void MOSRotating::AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit) { + if (woundToAdd && !m_ToDelete) { + if (checkGibWoundLimit && m_GibWoundLimit > 0 && m_Wounds.size() + 1 >= m_GibWoundLimit) { + // Find and detach an attachable near the new wound before gibbing the object itself. TODO: Perhaps move this to Actor, since it's more relevant there? + if (Attachable* attachableToDetach = GetNearestDetachableAttachableToOffset(parentOffsetToSet); attachableToDetach && m_DetachAttachablesBeforeGibbingFromWounds) { + RemoveAttachable(attachableToDetach, true, true); + } else { + // TODO: Don't hardcode the blast strength! + GibThis(Vector(-5.0F, 0).RadRotate(woundToAdd->GetEmitAngle())); + woundToAdd->DestroyScriptState(); + delete woundToAdd; + return; + } + } + woundToAdd->SetCollidesWithTerrainWhileAttached(false); + woundToAdd->SetParentOffset(parentOffsetToSet); + woundToAdd->SetParent(this); + woundToAdd->SetIsWound(true); + if (woundToAdd->HasNoSetDamageMultiplier()) { + woundToAdd->SetDamageMultiplier(1.0F); + } + m_AttachableAndWoundMass += woundToAdd->GetMass(); + m_Wounds.push_back(woundToAdd); + } } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float MOSRotating::RemoveWounds(int numberOfWoundsToRemove, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) { + float damage = 0; + int woundCount = GetWoundCount(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int MOSRotating::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return MOSprite::ReadProperty(propName, reader)); - - MatchProperty("AtomGroup", - { - delete m_pAtomGroup; - m_pAtomGroup = new AtomGroup(); - reader >> *m_pAtomGroup; - }); - MatchProperty("DeepGroup", - { - delete m_pDeepGroup; - m_pDeepGroup = new AtomGroup(); - reader >> *m_pDeepGroup; - }); - MatchProperty("DeepCheck", { reader >> m_DeepCheck; }); - MatchProperty("OrientToVel", { reader >> m_OrientToVel; }); - MatchProperty("SpecialBehaviour_ClearAllAttachables", { - // This special property is used to make Attachables work with our limited serialization system, when saving the game. Note that we discard the property value here, because all that matters is whether or not we have the property. - reader.ReadPropValue(); - for (auto attachableIterator = m_Attachables.begin(); attachableIterator != m_Attachables.end(); ) { - Attachable *attachable = *attachableIterator; - ++attachableIterator; - delete RemoveAttachable(attachable); + std::vector> woundedParts; + if (woundCount > 0) { + woundedParts.push_back({this, woundCount}); } - }); - MatchForwards("AddAttachable") MatchForwards("AddAEmitter") MatchProperty("AddEmitter", { - Entity *readerEntity = g_PresetMan.ReadReflectedPreset(reader); - if (Attachable *readerAttachable = dynamic_cast(readerEntity)) { - AddAttachable(readerAttachable); - } else { - reader.ReportError("Tried to AddAttachable a non-Attachable type!"); - } - }); - MatchProperty("SpecialBehaviour_AddWound", { - AEmitter *wound = new AEmitter; - reader >> wound; - AddWound(wound, wound->GetParentOffset()); - }); - MatchProperty("AddGib", - { - Gib gib; - reader >> gib; - m_Gibs.push_back(gib); - }); - MatchProperty("GibImpulseLimit", { reader >> m_GibImpulseLimit; }); - MatchForwards("GibWoundLimit") MatchProperty("WoundLimit", { reader >> m_GibWoundLimit; }); - MatchProperty("GibBlastStrength", { reader >> m_GibBlastStrength; }); - MatchProperty("GibScreenShakeAmount", { reader >> m_GibScreenShakeAmount; }); - MatchProperty("WoundCountAffectsImpulseLimitRatio", { reader >> m_WoundCountAffectsImpulseLimitRatio; }); - MatchProperty("DetachAttachablesBeforeGibbingFromWounds", { reader >> m_DetachAttachablesBeforeGibbingFromWounds; }); - MatchProperty("GibAtEndOfLifetime", { reader >> m_GibAtEndOfLifetime; }); - MatchProperty("GibSound", { - if (!m_GibSound) { m_GibSound = new SoundContainer; } - reader >> m_GibSound; - }); - MatchProperty("EffectOnGib", { reader >> m_EffectOnGib; }); - MatchProperty("LoudnessOnGib", { reader >> m_LoudnessOnGib; }); - MatchProperty("DamageMultiplier", { - reader >> m_DamageMultiplier; - m_NoSetDamageMultiplier = false; - }); - - EndPropertyList; -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this MOSRotating with a Writer for -// later recreation with Create(Reader &reader); - -int MOSRotating::Save(Writer &writer) const -{ - MOSprite::Save(writer); - -// TODO: Make proper save system that knows not to save redundant data! -/* - writer.NewProperty("AtomGroup"); - writer << m_pAtomGroup; - writer.NewProperty("DeepGroup"); - writer << m_pDeepGroup; - writer.NewProperty("DeepCheck"); - writer << m_DeepCheck; - writer.NewProperty("OrientToVel"); - writer << m_OrientToVel; - - for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) - { - writer.NewProperty("AddEmitter"); - writer << (*itr); - } - for (auto aItr = m_Attachables.begin(); aItr != m_Attachables.end(); ++aItr) - { - writer.NewProperty("AddAttachable"); - writer << (*aItr); - } -*/ - for (auto gItr = m_Gibs.begin(); gItr != m_Gibs.end(); ++gItr) - { - writer.NewProperty("AddGib"); - writer << (*gItr); - } -/* - writer.NewProperty("GibImpulseLimit"); - writer << m_GibImpulseLimit; - writer.NewProperty("GibWoundLimit"); - writer << m_GibWoundLimit; - writer.NewPropertyWithValue("GibAtEndOfLifetime", m_GibAtEndOfLifetime); - writer.NewProperty("GibSound"); - writer << m_GibSound; - writer.NewProperty("EffectOnGib"); - writer << m_EffectOnGib; -*/ - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int MOSRotating::GetGibWoundLimit(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const { - int gibWoundLimit = m_GibWoundLimit; - if (includePositiveDamageAttachables || includeNegativeDamageAttachables || includeNoDamageAttachables) { - for (const Attachable *attachable : m_Attachables) { - bool attachableSatisfiesConditions = (includePositiveDamageAttachables && attachable->GetDamageMultiplier() > 0) || - (includeNegativeDamageAttachables && attachable->GetDamageMultiplier() < 0) || - (includeNoDamageAttachables && attachable->GetDamageMultiplier() == 0); - - if (attachableSatisfiesConditions) { - gibWoundLimit += attachable->GetGibWoundLimit(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); - } - } - } - return gibWoundLimit; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int MOSRotating::GetWoundCount(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const { - int woundCount = m_Wounds.size(); - if (includePositiveDamageAttachables || includeNegativeDamageAttachables || includeNoDamageAttachables) { - for (const Attachable *attachable : m_Attachables) { - bool attachableSatisfiesConditions = (includePositiveDamageAttachables && attachable->GetDamageMultiplier() > 0) || - (includeNegativeDamageAttachables && attachable->GetDamageMultiplier() < 0) || - (includeNoDamageAttachables && attachable->GetDamageMultiplier() == 0); - - if (attachableSatisfiesConditions) { - woundCount += attachable->GetWoundCount(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); - } - } - } - return woundCount; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Attachable * MOSRotating::GetNearestDetachableAttachableToOffset(const Vector &offset) const { - Attachable *nearestAttachable = nullptr; - float closestRadius = m_SpriteRadius; - for (Attachable *attachable : m_Attachables) { - if (attachable->GetsHitByMOs() && attachable->GetGibImpulseLimit() > 0 && attachable->GetJointStrength() > 0 && attachable->GetDamageMultiplier() > 0 && offset.Dot(attachable->GetParentOffset()) > 0) { - float radius = (offset - attachable->GetParentOffset()).GetMagnitude(); - if (radius < closestRadius) { - closestRadius = radius; - nearestAttachable = attachable; + for (Attachable* attachable: m_Attachables) { + bool attachableSatisfiesConditions = (includePositiveDamageAttachables && attachable->GetDamageMultiplier() > 0) || + (includeNegativeDamageAttachables && attachable->GetDamageMultiplier() < 0) || + (includeNoDamageAttachables && attachable->GetDamageMultiplier() == 0); + int attachableWoundCount = attachable->GetWoundCount(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); + + if (attachableSatisfiesConditions && attachableWoundCount > 0) { + woundedParts.push_back({attachable, attachableWoundCount}); } } - } - return nearestAttachable; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::DetachAttachablesFromImpulse(Vector &impulseVector) { - float impulseRemainder = impulseVector.GetMagnitude(); - // Find the attachable closest to the impact point by using an inverted impulse vector. - Vector invertedImpulseOffset = Vector(impulseVector.GetX(), impulseVector.GetY()).SetMagnitude(-GetRadius()) * -m_Rotation; - Attachable *nearestAttachableToImpulse = GetNearestDetachableAttachableToOffset(invertedImpulseOffset); - while (nearestAttachableToImpulse) { - float attachableImpulseLimit = nearestAttachableToImpulse->GetGibImpulseLimit(); - float attachableJointStrength = nearestAttachableToImpulse->GetJointStrength(); - if (impulseRemainder > attachableImpulseLimit) { - nearestAttachableToImpulse->GibThis(impulseVector.SetMagnitude(attachableImpulseLimit)); - impulseRemainder -= attachableImpulseLimit; - } else if (impulseRemainder > attachableJointStrength) { - RemoveAttachable(nearestAttachableToImpulse, true, true); - impulseRemainder -= attachableJointStrength; - } else { - break; + + if (woundedParts.empty()) { + return damage; } - nearestAttachableToImpulse = GetNearestDetachableAttachableToOffset(invertedImpulseOffset); - } - impulseVector.SetMagnitude(impulseRemainder); -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// + /// Internal lambda function to remove the first wound emitter from this MOSRotating. + /// + auto removeFirstWoundEmitter = [this]() { + if (m_Wounds.empty()) { + return 0.0F; + } + AEmitter* wound = m_Wounds.front(); + float woundDamage = wound->GetBurstDamage(); + m_AttachableAndWoundMass -= wound->GetMass(); + std::iter_swap(m_Wounds.begin(), m_Wounds.end() - 1); + m_Wounds.pop_back(); + wound->DestroyScriptState(); + delete wound; + return woundDamage; + }; + + for (int i = 0; i < numberOfWoundsToRemove; i++) { + if (woundedParts.empty()) { + break; + } -void MOSRotating::AddWound(AEmitter *woundToAdd, const Vector &parentOffsetToSet, bool checkGibWoundLimit) { - if (woundToAdd && !m_ToDelete) { - if (checkGibWoundLimit && m_GibWoundLimit > 0 && m_Wounds.size() + 1 >= m_GibWoundLimit) { - // Find and detach an attachable near the new wound before gibbing the object itself. TODO: Perhaps move this to Actor, since it's more relevant there? - if (Attachable *attachableToDetach = GetNearestDetachableAttachableToOffset(parentOffsetToSet); attachableToDetach && m_DetachAttachablesBeforeGibbingFromWounds) { - RemoveAttachable(attachableToDetach, true, true); + int woundedPartIndex = RandomNum(0, static_cast(woundedParts.size()) - 1); + MOSRotating* woundedPart = woundedParts[woundedPartIndex].first; + if (woundedPart == this) { + damage += removeFirstWoundEmitter() * GetDamageMultiplier(); } else { - // TODO: Don't hardcode the blast strength! - GibThis(Vector(-5.0F, 0).RadRotate(woundToAdd->GetEmitAngle())); - woundToAdd->DestroyScriptState(); - delete woundToAdd; - return; - } - } - woundToAdd->SetCollidesWithTerrainWhileAttached(false); - woundToAdd->SetParentOffset(parentOffsetToSet); - woundToAdd->SetParent(this); - woundToAdd->SetIsWound(true); - if (woundToAdd->HasNoSetDamageMultiplier()) { woundToAdd->SetDamageMultiplier(1.0F); } - m_AttachableAndWoundMass += woundToAdd->GetMass(); - m_Wounds.push_back(woundToAdd); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float MOSRotating::RemoveWounds(int numberOfWoundsToRemove, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) { - float damage = 0; - int woundCount = GetWoundCount(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); - - std::vector> woundedParts; - if (woundCount > 0) { woundedParts.push_back({this, woundCount}); } - - for (Attachable *attachable : m_Attachables) { - bool attachableSatisfiesConditions = (includePositiveDamageAttachables && attachable->GetDamageMultiplier() > 0) || - (includeNegativeDamageAttachables && attachable->GetDamageMultiplier() < 0) || - (includeNoDamageAttachables && attachable->GetDamageMultiplier() == 0); - int attachableWoundCount = attachable->GetWoundCount(includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); - - if (attachableSatisfiesConditions && attachableWoundCount > 0) { woundedParts.push_back({attachable, attachableWoundCount}); } - } - - if (woundedParts.empty()) { - return damage; - } - - /// - /// Internal lambda function to remove the first wound emitter from this MOSRotating. - /// - auto removeFirstWoundEmitter = [this]() { - if (m_Wounds.empty()) { - return 0.0F; - } - AEmitter *wound = m_Wounds.front(); - float woundDamage = wound->GetBurstDamage(); - m_AttachableAndWoundMass -= wound->GetMass(); - std::iter_swap(m_Wounds.begin(), m_Wounds.end() - 1); - m_Wounds.pop_back(); - wound->DestroyScriptState(); - delete wound; - return woundDamage; - }; - - for (int i = 0; i < numberOfWoundsToRemove; i++) { - if (woundedParts.empty()) { - break; - } - - int woundedPartIndex = RandomNum(0, static_cast(woundedParts.size()) - 1); - MOSRotating *woundedPart = woundedParts[woundedPartIndex].first; - if (woundedPart == this) { - damage += removeFirstWoundEmitter() * GetDamageMultiplier(); - } else { - //TODO This is less efficient than it should be. We already collected all wounded parts and their wounds above, we should pass that in (make another function overload) instead of collecting everything again. It might be wise to use a tree for this purpose. - damage += woundedPart->RemoveWounds(1, includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); - } - if (woundedParts[woundedPartIndex].second-- <= 0) { woundedParts.erase(woundedParts.begin() + woundedPartIndex); } - } - - return damage; -} - -void MOSRotating::DestroyScriptState() { - for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) { - (*itr)->DestroyScriptState(); - } - - for (auto itr = m_Attachables.begin(); itr != m_Attachables.end(); ++itr) { - (*itr)->DestroyScriptState(); - } - - MovableObject::DestroyScriptState(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // TODO This is less efficient than it should be. We already collected all wounded parts and their wounds above, we should pass that in (make another function overload) instead of collecting everything again. It might be wise to use a tree for this purpose. + damage += woundedPart->RemoveWounds(1, includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables); + } + if (woundedParts[woundedPartIndex].second-- <= 0) { + woundedParts.erase(woundedParts.begin() + woundedPartIndex); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MOSRotating object. + return damage; + } -void MOSRotating::Destroy(bool notInherited) -{ - delete m_pAtomGroup; - delete m_pDeepGroup; + void MOSRotating::DestroyScriptState() { + for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) { + (*itr)->DestroyScriptState(); + } - for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) { - delete (*itr); - } + for (auto itr = m_Attachables.begin(); itr != m_Attachables.end(); ++itr) { + (*itr)->DestroyScriptState(); + } - for (auto aItr = m_Attachables.begin(); aItr != m_Attachables.end(); ++aItr) { - if (m_HardcodedAttachableUniqueIDsAndRemovers.find((*aItr)->GetUniqueID()) == m_HardcodedAttachableUniqueIDsAndRemovers.end()) { - delete (*aItr); - } - } + MovableObject::DestroyScriptState(); + } - destroy_bitmap(m_pFlipBitmap); - destroy_bitmap(m_pFlipBitmapS); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Not anymore; point to shared static bitmaps -// destroy_bitmap(m_pTempBitmap); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MOSRotating object. - delete m_GibSound; + void MOSRotating::Destroy(bool notInherited) { + delete m_pAtomGroup; + delete m_pDeepGroup; - if (!notInherited) - MOSprite::Destroy(); - Clear(); -} + for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) { + delete (*itr); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + for (auto aItr = m_Attachables.begin(); aItr != m_Attachables.end(); ++aItr) { + if (m_HardcodedAttachableUniqueIDsAndRemovers.find((*aItr)->GetUniqueID()) == m_HardcodedAttachableUniqueIDsAndRemovers.end()) { + delete (*aItr); + } + } -void MOSRotating::SetAsNoID() { - MovableObject::SetAsNoID(); - for (Attachable *attachable : m_Attachables) { - attachable->SetAsNoID(); - } -} + destroy_bitmap(m_pFlipBitmap); + destroy_bitmap(m_pFlipBitmapS); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Not anymore; point to shared static bitmaps + // destroy_bitmap(m_pTempBitmap); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMaterial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the main Material of this MOSRotating. + delete m_GibSound; -Material const * MOSRotating::GetMaterial() const -{ -// if (m_pAtomGroup) - return m_pAtomGroup->GetMaterial(); -// return 0; -} + if (!notInherited) + MOSprite::Destroy(); + Clear(); + } -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: HitsMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets whether this MovableObject is set to collide with other -// MovableObject:s during travel. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MOSRotating::HitsMOs() const -{ - if (m_pAtomGroup) - return m_pAtomGroup->HitsMOs(); - return false; -} -*/ + void MOSRotating::SetAsNoID() { + MovableObject::SetAsNoID(); + for (Attachable* attachable: m_Attachables) { + attachable->SetAsNoID(); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetDrawPriority -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the drawing priority of this MovableObject, if two things were -// overlap when copying to the terrain, the higher priority MO would -// end up getting drawn. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int MOSRotating::GetDrawPriority() const -{ - return INT_MAX; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMaterial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the main Material of this MOSRotating. -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAtom -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Replaces the current AtomGroup of this MOSRotating with a new one. -// Arguments: A reference to the new AtomGroup. -// Return value: None. - -void MOSRotating::SetAtom(AtomGroup *newAtom) -{ - delete m_pAtomGroup; - m_pAtomGroup = newAtom; -} -*/ -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetToHitMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this MovableObject to collide with other MovableObjects during -// travel. + Material const* MOSRotating::GetMaterial() const { + // if (m_pAtomGroup) + return m_pAtomGroup->GetMaterial(); + // return 0; + } -void MOSRotating::SetToHitMOs(bool hitMOs) -{ - if (m_pAtomGroup) - m_pAtomGroup->SetToHitMOs(hitMOs); -} -*/ + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: HitsMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets whether this MovableObject is set to collide with other + // MovableObject:s during travel. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddRecoil -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds recoil effects to this MOSprite. + bool MOSRotating::HitsMOs() const + { + if (m_pAtomGroup) + return m_pAtomGroup->HitsMOs(); + return false; + } + */ -void MOSRotating::AddRecoil() -{ - m_RecoilOffset.SetXY(1, 0); - m_RecoilOffset.RadRotate(m_Rotation.GetRadAngle() + c_PI); - m_Recoiled = true; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetDrawPriority + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the drawing priority of this MovableObject, if two things were + // overlap when copying to the terrain, the higher priority MO would + // end up getting drawn. + int MOSRotating::GetDrawPriority() const { + return INT_MAX; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. - -bool MOSRotating::CollideAtPoint(HitData &hd) -{ - if (m_ToDelete) { - return false; // TODO: Add a settings flag to enable old school particle sponges! + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAtom + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Replaces the current AtomGroup of this MOSRotating with a new one. + // Arguments: A reference to the new AtomGroup. + // Return value: None. + + void MOSRotating::SetAtom(AtomGroup *newAtom) + { + delete m_pAtomGroup; + m_pAtomGroup = newAtom; } + */ + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetToHitMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this MovableObject to collide with other MovableObjects during + // travel. + + void MOSRotating::SetToHitMOs(bool hitMOs) + { + if (m_pAtomGroup) + m_pAtomGroup->SetToHitMOs(hitMOs); + } + */ - hd.ResImpulse[HITOR].Reset(); - hd.ResImpulse[HITEE].Reset(); - -// if (m_AlreadyHitBy.find(hd.Body[HITOR]->GetID()) == m_AlreadyHitBy.end()) -// { -// m_AlreadyHitBy.insert(hd.Body[HITOR]->GetID()); - - hd.HitRadius[HITEE] = (hd.HitPoint - m_Pos) * c_MPP; -/* - // Cancel if both hitor and hitee's hitpoint radii are pointing int he same direction, meaning the objects are really tangled - if (!hd.HitRadius[HITOR].IsZero() && hd.HitRadius[HITOR].Dot(hd.HitRadius[HITEE]) >= 0) - return false; -*/ - hd.TotalMass[HITEE] = m_Mass; - hd.MomInertia[HITEE] = m_pAtomGroup->GetMomentOfInertia(); - hd.HitVel[HITEE] = m_Vel + hd.HitRadius[HITEE].GetPerpendicular() * m_AngularVel; - hd.VelDiff = hd.HitVel[HITOR] - hd.HitVel[HITEE]; - - // Only do collision response for this if it appears the collision is happening in the 'right' direction, meaning away from the hitee collision normal - // The wrong way happens when things are sunk into each other, and thus getting 'hooked' on each other - if (hd.VelDiff.Dot(hd.BitmapNormal) < 0) - { - Vector hitAcc = -hd.VelDiff * (1 + (hd.Body[HITOR]->GetMaterial()->GetRestitution() * GetMaterial()->GetRestitution())); - - float hittorLever = hd.HitRadius[HITOR].GetPerpendicular().Dot(hd.BitmapNormal); - float hitteeLever = hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.BitmapNormal); - hittorLever *= hittorLever; - hitteeLever *= hitteeLever; - float impulse = hitAcc.Dot(hd.BitmapNormal) / (((1 / hd.TotalMass[HITOR]) + (1 / hd.TotalMass[HITEE])) + - (hittorLever / hd.MomInertia[HITOR]) + (hitteeLever / hd.MomInertia[HITEE])); - // TODO: Should the impfactor not be swapped? -EE vs -OR?") - hd.ResImpulse[HITOR] = hd.BitmapNormal * impulse * hd.ImpulseFactor[HITOR]; - hd.ResImpulse[HITEE] = hd.BitmapNormal * -impulse * hd.ImpulseFactor[HITEE]; - - // If a particle, which does not penetrate, but bounces, do any additional - // effects of that bounce. - if (!ParticlePenetration(hd)) - { -// TODO: Add blunt trauma effects here!") - ; - } - - // If the hittee is pinned, see if the collision's impulse is enough to dislodge it. - float hiteePin = hd.Body[HITEE]->GetPinStrength(); - // See if it's pinned, and compare it to the impulse force from the collision - if (m_PinStrength > 0 && hd.ResImpulse[HITEE].MagnitudeIsGreaterThan(m_PinStrength)) - { - // Unpin and set the threshold to 0 - hd.Body[HITEE]->SetPinStrength(0); - } - // If not knocked loose, then move the impulse of the hitee to the hitor - else if (hiteePin) - { -// No good, causes crazy bounces -// hd.ResImpulse[HITOR] -= hd.ResImpulse[HITEE]; - hd.ResImpulse[HITEE].Reset(); - } - - AddImpulseForce(hd.ResImpulse[HITEE], hd.HitRadius[HITEE]); -// m_Vel += hd.ResImpulse[HITEE] / hd.mass[HITEE]; -// m_AngularVel += hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.ResImpulse[HITEE]) / hd.MomInertia[HITEE]; - } - else - return false; - - return true; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddRecoil + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds recoil effects to this MOSprite. + void MOSRotating::AddRecoil() { + m_RecoilOffset.SetXY(1, 0); + m_RecoilOffset.RadRotate(m_Rotation.GetRadAngle() + c_PI); + m_Recoiled = true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnBounce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// bounces off of something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. -bool MOSRotating::OnBounce(HitData &hd) -{ + bool MOSRotating::CollideAtPoint(HitData& hd) { + if (m_ToDelete) { + return false; // TODO: Add a settings flag to enable old school particle sponges! + } - return false; -} + hd.ResImpulse[HITOR].Reset(); + hd.ResImpulse[HITEE].Reset(); + + // if (m_AlreadyHitBy.find(hd.Body[HITOR]->GetID()) == m_AlreadyHitBy.end()) + // { + // m_AlreadyHitBy.insert(hd.Body[HITOR]->GetID()); + + hd.HitRadius[HITEE] = (hd.HitPoint - m_Pos) * c_MPP; + /* + // Cancel if both hitor and hitee's hitpoint radii are pointing int he same direction, meaning the objects are really tangled + if (!hd.HitRadius[HITOR].IsZero() && hd.HitRadius[HITOR].Dot(hd.HitRadius[HITEE]) >= 0) + return false; + */ + hd.TotalMass[HITEE] = m_Mass; + hd.MomInertia[HITEE] = m_pAtomGroup->GetMomentOfInertia(); + hd.HitVel[HITEE] = m_Vel + hd.HitRadius[HITEE].GetPerpendicular() * m_AngularVel; + hd.VelDiff = hd.HitVel[HITOR] - hd.HitVel[HITEE]; + + // Only do collision response for this if it appears the collision is happening in the 'right' direction, meaning away from the hitee collision normal + // The wrong way happens when things are sunk into each other, and thus getting 'hooked' on each other + if (hd.VelDiff.Dot(hd.BitmapNormal) < 0) { + Vector hitAcc = -hd.VelDiff * (1 + (hd.Body[HITOR]->GetMaterial()->GetRestitution() * GetMaterial()->GetRestitution())); + + float hittorLever = hd.HitRadius[HITOR].GetPerpendicular().Dot(hd.BitmapNormal); + float hitteeLever = hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.BitmapNormal); + hittorLever *= hittorLever; + hitteeLever *= hitteeLever; + float impulse = hitAcc.Dot(hd.BitmapNormal) / (((1 / hd.TotalMass[HITOR]) + (1 / hd.TotalMass[HITEE])) + + (hittorLever / hd.MomInertia[HITOR]) + (hitteeLever / hd.MomInertia[HITEE])); + // TODO: Should the impfactor not be swapped? -EE vs -OR?") + hd.ResImpulse[HITOR] = hd.BitmapNormal * impulse * hd.ImpulseFactor[HITOR]; + hd.ResImpulse[HITEE] = hd.BitmapNormal * -impulse * hd.ImpulseFactor[HITEE]; + + // If a particle, which does not penetrate, but bounces, do any additional + // effects of that bounce. + if (!ParticlePenetration(hd)) { + // TODO: Add blunt trauma effects here!") + ; + } + // If the hittee is pinned, see if the collision's impulse is enough to dislodge it. + float hiteePin = hd.Body[HITEE]->GetPinStrength(); + // See if it's pinned, and compare it to the impulse force from the collision + if (m_PinStrength > 0 && hd.ResImpulse[HITEE].MagnitudeIsGreaterThan(m_PinStrength)) { + // Unpin and set the threshold to 0 + hd.Body[HITEE]->SetPinStrength(0); + } + // If not knocked loose, then move the impulse of the hitee to the hitor + else if (hiteePin) { + // No good, causes crazy bounces + // hd.ResImpulse[HITOR] -= hd.ResImpulse[HITEE]; + hd.ResImpulse[HITEE].Reset(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnSink -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// sink into something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. + AddImpulseForce(hd.ResImpulse[HITEE], hd.HitRadius[HITEE]); + // m_Vel += hd.ResImpulse[HITEE] / hd.mass[HITEE]; + // m_AngularVel += hd.HitRadius[HITEE].GetPerpendicular().Dot(hd.ResImpulse[HITEE]) / hd.MomInertia[HITEE]; + } else + return false; -bool MOSRotating::OnSink(HitData &hd) -{ - return false; -} + return true; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnBounce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // bounces off of something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ParticlePenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Determines whether a particle which has hit this MO will penetrate, -// and if so, whether it gets lodged or exits on the other side of this -// MO. Appropriate effects will be determined and applied ONLY IF there -// was penetration! If not, nothing will be affected. - -bool MOSRotating::ParticlePenetration(HitData &hd) -{ - // Only particles can penetrate. - if (!(dynamic_cast(hd.Body[HITOR]) || dynamic_cast(hd.Body[HITOR]))) - return false; - - float impulseForce = hd.ResImpulse[HITEE].GetMagnitude(); - Material const * myMat = GetMaterial(); - float myStrength = myMat->GetIntegrity() / hd.Body[HITOR]->GetSharpness(); - - // See if there is enough energy in the collision for the particle to penetrate - if (impulseForce * hd.Body[HITOR]->GetSharpness() > myMat->GetIntegrity()) - { - // Ok penetration happened, now figure out if and where the exit point - // would be by tracing a rasterized line through the sprite. - - // Declare all vars needed for good ole' Bresenham.. - int intPos[2], delta[2], delta2[2], increment[2], bounds[2]; - int error, dom, sub, domSteps, subSteps; - bool inside = false, exited = false, subStepped = false; - - // Lock all bitmaps involved outside the loop. - acquire_bitmap(m_aSprite[m_Frame]); - - bounds[X] = m_aSprite[m_Frame]->w; - bounds[Y] = m_aSprite[m_Frame]->h; - - // Figure out the entry position in the un-rotated sprite's coordinates. - Vector entryPos = (g_SceneMan.ShortestDistance(m_Pos, hd.HitPoint) / m_Rotation).GetXFlipped(m_HFlipped) - m_SpriteOffset; - intPos[X] = std::floor(entryPos.m_X); - intPos[Y] = std::floor(entryPos.m_Y); - - // Get the un-rotated direction and max possible - // travel length of the particle. - Vector dir(std::max(bounds[X], bounds[Y]), 0); - dir.AbsRotateTo(hd.HitVel[HITOR] / m_Rotation); - dir = dir.GetXFlipped(m_HFlipped); - - // Bresenham's line drawing algorithm preparation - delta[X] = std::floor(entryPos.m_X + dir.m_X) - intPos[X]; - delta[Y] = std::floor(entryPos.m_Y + dir.m_Y) - intPos[Y]; - domSteps = 0; - subSteps = 0; - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) - { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - error = delta2[sub] - delta[dom]; - - // Bresenham's line drawing algorithm execution - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - if (intPos[X] < 0 || intPos[X] >= bounds[X] || - intPos[Y] < 0 || intPos[Y] >= bounds[Y]) - { - exited = false; - break; - } - - RTEAssert(is_inside_bitmap(m_aSprite[m_Frame], intPos[X], intPos[Y], 0), "Particle penetration test is outside of sprite!"); - - // Check if we are inside the sprite. - if (_getpixel(m_aSprite[m_Frame], intPos[X], intPos[Y]) != g_MaskColor) - { - inside = true; - // Break if the particle can't force its way through any further. - if (impulseForce <= myStrength) { - exited = false; - break; - } - // Do the resistance calculation which is retarding the - // kinetic force of the penetrating particle by each pixel penetrated. - impulseForce -= myStrength; - } - // If we are inside and are now outside, we have just exited! - else if (inside) - { - impulseForce += myStrength; - exited = true; - break; - } - - // Advance to the next pixel - intPos[dom] += increment[dom]; - if (error >= 0) { - intPos[sub] += increment[sub]; - ++subSteps; - error -= delta2[dom]; - } - error += delta2[sub]; - } - // Unlock all bitmaps involved outside the loop. - release_bitmap(m_aSprite[m_Frame]); - - if (m_pEntryWound) - { - // Add entry wound AEmitter to actor where the particle penetrated. - AEmitter *pEntryWound = dynamic_cast(m_pEntryWound->Clone()); - pEntryWound->SetInheritedRotAngleOffset(dir.GetAbsRadAngle() + c_PI); - float damageMultiplier = pEntryWound->HasNoSetDamageMultiplier() ? 1.0F : pEntryWound->GetDamageMultiplier(); - pEntryWound->SetDamageMultiplier(damageMultiplier * hd.Body[HITOR]->WoundDamageMultiplier()); - // Adjust position so that it looks like the hole is actually *on* the Hitee. - entryPos[dom] += increment[dom] * (pEntryWound->GetSpriteWidth() / 2); - AddWound(pEntryWound, entryPos + m_SpriteOffset); - pEntryWound = 0; - } - - // Add exit wound AEmitter to actor, if applicable. - if (exited) - { - Vector exitPos; - exitPos[dom] = entryPos[dom] + (increment[dom] * domSteps); - exitPos[sub] = entryPos[sub] + (increment[sub] * subSteps); - if (m_pExitWound) - { - AEmitter *pExitWound = dynamic_cast(m_pExitWound->Clone()); - // Adjust position so that it looks like the hole is actually *on* the Hitee. - exitPos[dom] -= increment[dom] * (pExitWound->GetSpriteWidth() / 2); - pExitWound->SetInheritedRotAngleOffset(dir.GetAbsRadAngle()); - float damageMultiplier = pExitWound->HasNoSetDamageMultiplier() ? 1.0F : pExitWound->GetDamageMultiplier(); - pExitWound->SetDamageMultiplier(damageMultiplier * hd.Body[HITOR]->WoundDamageMultiplier()); - AddWound(pExitWound, exitPos + m_SpriteOffset); - pExitWound = 0; - } - - // Set the exiting particle's position to where the exit wound is, - // in world coordinates. - hd.Body[HITOR]->SetPos(((exitPos + m_SpriteOffset) / m_Rotation) + m_Pos); - - // Finally apply the forces imposed on both this MOSRotating - // and the hitting particle due to the penetrating and exiting hit. - // These don't need to be manipulated if there was no exit, since this - // absorbed all the energy, and the hittee gets deleted from the scene. - hd.ResImpulse[HITEE] -= hd.ResImpulse[HITEE] * (impulseForce / hd.ResImpulse[HITEE].GetMagnitude()); - hd.ResImpulse[HITOR] = -(hd.ResImpulse[HITEE]); - } - // Particle got lodged inside this MOSRotating, so stop it and delete it from scene. - else - { - // Set the exiting particle's position to where it looks lodged -// hd.Body[HITOR]->SetPos(m_Pos - m_SpriteOffset + entryPos); -// hd.Body[HITOR]->SetVel(Vector()); - hd.Body[HITOR]->SetToDelete(true); - hd.Terminate[HITOR] = true; - } - - // Report that penetration occured. - return true; - } - - // Report that penetration didn't occur and signal to client to - // calculate bounce effects instead. - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::GibThis(const Vector &impactImpulse, MovableObject *movableObjectToIgnore) { - if (m_MissionCritical || m_ToDelete) { - return; - } - - if (impactImpulse.MagnitudeIsGreaterThan(GetGibImpulseLimit())) { - // Add a counterforce equal to GibImpulseLimit to the impulse list in order to simulate the force spent on breaking the object apart - Vector counterForce = impactImpulse; - counterForce.SetMagnitude(GetGibImpulseLimit()); - m_ImpulseForces.emplace_back(-counterForce, Vector()); - MOSprite::ApplyImpulses(); - } - - CreateGibsWhenGibbing(impactImpulse, movableObjectToIgnore); - - RemoveAttachablesWhenGibbing(impactImpulse, movableObjectToIgnore); - - if (m_GibSound) { m_GibSound->Play(m_Pos); } - - if (m_pScreenEffect && m_EffectOnGib && (m_EffectAlwaysShows || !g_SceneMan.ObscuredPoint(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY()))) { - g_PostProcessMan.RegisterPostEffect(m_Pos, m_pScreenEffect, m_ScreenEffectHash, 255, m_EffectRotAngle); - } - - if (m_LoudnessOnGib > 0) { g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, m_LoudnessOnGib)); } - - m_ToDelete = true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::CreateGibsWhenGibbing(const Vector &impactImpulse, MovableObject *movableObjectToIgnore) { - if (m_GibScreenShakeAmount != -1.0F) { - g_CameraMan.AddScreenShake(m_GibScreenShakeAmount, m_Pos); - } - - for (const Gib &gibSettingsObject : m_Gibs) { - if (gibSettingsObject.GetCount() == 0) { - continue; - } - MovableObject *gibParticleClone = dynamic_cast(gibSettingsObject.GetParticlePreset()->Clone()); - - int count = gibSettingsObject.GetCount(); - float lifeVariation = gibSettingsObject.GetLifeVariation(); - float spread = gibSettingsObject.GetSpread(); - float minVelocity = gibSettingsObject.GetMinVelocity(); - float maxVelocity = gibSettingsObject.GetMaxVelocity(); - - float mass = (gibParticleClone->GetMass() != 0 ? gibParticleClone->GetMass() : 0.0001F); - int lifetime = gibParticleClone->GetLifetime(); - - if (minVelocity == 0 && maxVelocity == 0) { - minVelocity = m_GibBlastStrength / mass; - maxVelocity = minVelocity + 10.0F; - } - - if (m_GibScreenShakeAmount == -1.0F) { - // Automatically calculate a value based on the amount of energy going on here - float averageSpeed = (minVelocity + maxVelocity) * 0.5F; - float energy = mass * averageSpeed * static_cast(count); - g_CameraMan.AddScreenShake(energy * g_CameraMan.GetDefaultShakePerUnitOfGibEnergy(), m_Pos); - } - - float velocityRange = maxVelocity - minVelocity; - Vector rotatedGibOffset = RotateOffset(gibSettingsObject.GetOffset()); - - // The "Spiral" spread mode uses the fermat spiral as means to determine the velocity of the gib particles, resulting in a evenly spaced out circle (or ring) of particles. - if (gibSettingsObject.GetSpreadMode() == Gib::SpreadMode::SpreadSpiral) { - float maxRadius = std::sqrt(static_cast(count)); - float scale = velocityRange / maxRadius; - float randAngle = c_PI * RandomNormalNum(); - float goldenAngle = 2.39996F; - - for (int i = 0; i < count; i++) { - if (i > 0) { gibParticleClone = dynamic_cast(gibSettingsObject.GetParticlePreset()->Clone()); } - - float radius = std::sqrt(static_cast(count - i)); - gibParticleClone->SetPos(m_Pos + rotatedGibOffset); - gibParticleClone->SetHFlipped(m_HFlipped); - Vector gibVelocity(radius * scale + minVelocity, 0); - gibVelocity.RadRotate(randAngle + RandomNum(0.0F, spread) + static_cast(i) * goldenAngle); - if (lifetime != 0) { - gibParticleClone->SetLifetime(std::max(static_cast(static_cast(lifetime) * (1.0F - lifeVariation * ((radius / maxRadius) * 0.75F + RandomNormalNum() * 0.25F))), 1)); - } - gibParticleClone->SetRotAngle(gibVelocity.GetAbsRadAngle() + (m_HFlipped ? c_PI : 0)); - gibParticleClone->SetAngularVel((gibParticleClone->GetAngularVel() * 0.35F) + (gibParticleClone->GetAngularVel() * 0.65F / mass) * RandomNum()); - gibParticleClone->SetVel(gibVelocity + ((m_PrevVel + m_Vel) / 2) * gibSettingsObject.InheritsVelocity()); - if (movableObjectToIgnore) { gibParticleClone->SetWhichMOToNotHit(movableObjectToIgnore); } - if (gibSettingsObject.IgnoresTeamHits()) { - gibParticleClone->SetTeam(m_Team); - gibParticleClone->SetIgnoresTeamHits(true); - } + bool MOSRotating::OnBounce(HitData& hd) { - g_MovableMan.AddParticle(gibParticleClone); + return false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnSink + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // sink into something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. + + bool MOSRotating::OnSink(HitData& hd) { + return false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ParticlePenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Determines whether a particle which has hit this MO will penetrate, + // and if so, whether it gets lodged or exits on the other side of this + // MO. Appropriate effects will be determined and applied ONLY IF there + // was penetration! If not, nothing will be affected. + + bool MOSRotating::ParticlePenetration(HitData& hd) { + // Only particles can penetrate. + if (!(dynamic_cast(hd.Body[HITOR]) || dynamic_cast(hd.Body[HITOR]))) + return false; + + float impulseForce = hd.ResImpulse[HITEE].GetMagnitude(); + Material const* myMat = GetMaterial(); + float myStrength = myMat->GetIntegrity() / hd.Body[HITOR]->GetSharpness(); + + // See if there is enough energy in the collision for the particle to penetrate + if (impulseForce * hd.Body[HITOR]->GetSharpness() > myMat->GetIntegrity()) { + // Ok penetration happened, now figure out if and where the exit point + // would be by tracing a rasterized line through the sprite. + + // Declare all vars needed for good ole' Bresenham.. + int intPos[2], delta[2], delta2[2], increment[2], bounds[2]; + int error, dom, sub, domSteps, subSteps; + bool inside = false, exited = false, subStepped = false; + + // Lock all bitmaps involved outside the loop. + acquire_bitmap(m_aSprite[m_Frame]); + + bounds[X] = m_aSprite[m_Frame]->w; + bounds[Y] = m_aSprite[m_Frame]->h; + + // Figure out the entry position in the un-rotated sprite's coordinates. + Vector entryPos = (g_SceneMan.ShortestDistance(m_Pos, hd.HitPoint) / m_Rotation).GetXFlipped(m_HFlipped) - m_SpriteOffset; + intPos[X] = std::floor(entryPos.m_X); + intPos[Y] = std::floor(entryPos.m_Y); + + // Get the un-rotated direction and max possible + // travel length of the particle. + Vector dir(std::max(bounds[X], bounds[Y]), 0); + dir.AbsRotateTo(hd.HitVel[HITOR] / m_Rotation); + dir = dir.GetXFlipped(m_HFlipped); + + // Bresenham's line drawing algorithm preparation + delta[X] = std::floor(entryPos.m_X + dir.m_X) - intPos[X]; + delta[Y] = std::floor(entryPos.m_Y + dir.m_Y) - intPos[Y]; + domSteps = 0; + subSteps = 0; + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; } - } else { - for (int i = 0; i < count; i++) { - if (i > 0) { gibParticleClone = dynamic_cast(gibSettingsObject.GetParticlePreset()->Clone()); } + error = delta2[sub] - delta[dom]; - if (gibParticleClone->GetLifetime() != 0) { - gibParticleClone->SetLifetime(std::max(static_cast(static_cast(gibParticleClone->GetLifetime()) * (1.0F + (lifeVariation * RandomNormalNum()))), 1)); + // Bresenham's line drawing algorithm execution + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + if (intPos[X] < 0 || intPos[X] >= bounds[X] || + intPos[Y] < 0 || intPos[Y] >= bounds[Y]) { + exited = false; + break; } - gibParticleClone->SetRotAngle(GetRotAngle() + gibParticleClone->GetRotAngle()); - gibParticleClone->SetAngularVel((gibParticleClone->GetAngularVel() * 0.35F) + (gibParticleClone->GetAngularVel() * 0.65F / mass) * RandomNum()); - if (rotatedGibOffset.GetRoundIntX() > m_aSprite[0]->w / 3) { - float offCenterRatio = rotatedGibOffset.m_X / (static_cast(m_aSprite[0]->w) / 2.0F); - float angularVel = std::abs(gibParticleClone->GetAngularVel() * 0.5F) + std::abs(gibParticleClone->GetAngularVel() * 0.5F * offCenterRatio); - gibParticleClone->SetAngularVel(angularVel * (rotatedGibOffset.m_X > 0 ? -1 : 1)); - } else { - gibParticleClone->SetAngularVel((gibParticleClone->GetAngularVel() * 0.5F + (gibParticleClone->GetAngularVel() * RandomNum())) * (RandomNormalNum() > 0.0F ? 1.0F : -1.0F)); + RTEAssert(is_inside_bitmap(m_aSprite[m_Frame], intPos[X], intPos[Y], 0), "Particle penetration test is outside of sprite!"); + + // Check if we are inside the sprite. + if (_getpixel(m_aSprite[m_Frame], intPos[X], intPos[Y]) != g_MaskColor) { + inside = true; + // Break if the particle can't force its way through any further. + if (impulseForce <= myStrength) { + exited = false; + break; + } + // Do the resistance calculation which is retarding the + // kinetic force of the penetrating particle by each pixel penetrated. + impulseForce -= myStrength; } - - gibParticleClone->SetPos(m_Pos + rotatedGibOffset); - gibParticleClone->SetHFlipped(m_HFlipped); - Vector gibVelocity = Vector(minVelocity + RandomNum(0.0F, velocityRange), 0.0F); - - // TODO: Figure out how much the magnitude of an offset should affect spread - float gibSpread = (rotatedGibOffset.IsZero() && spread == 0.1F) ? c_PI : spread; - // Determine the primary direction of the gib particles. - if (gibSettingsObject.InheritsVelocity() > 0 && !impactImpulse.IsZero()) { - gibVelocity.RadRotate(impactImpulse.GetAbsRadAngle()); - } else if (!rotatedGibOffset.IsZero()) { - gibVelocity.RadRotate(rotatedGibOffset.GetAbsRadAngle()); - } else { - gibVelocity.RadRotate(m_Rotation.GetRadAngle() + (m_HFlipped ? c_PI : 0)); + // If we are inside and are now outside, we have just exited! + else if (inside) { + impulseForce += myStrength; + exited = true; + break; } - // The "Even" spread will spread all gib particles evenly in an arc, while maintaining a randomized velocity magnitude. - if (gibSettingsObject.GetSpreadMode() == Gib::SpreadMode::SpreadEven) { - gibVelocity.RadRotate(gibSpread - (gibSpread * 2.0F * static_cast(i) / static_cast(count))); - } else { - gibVelocity.RadRotate(gibSpread * RandomNormalNum()); + + // Advance to the next pixel + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + ++subSteps; + error -= delta2[dom]; } - gibParticleClone->SetVel(gibVelocity + ((m_PrevVel + m_Vel) / 2) * gibSettingsObject.InheritsVelocity()); - if (movableObjectToIgnore) { gibParticleClone->SetWhichMOToNotHit(movableObjectToIgnore); } - if (gibSettingsObject.IgnoresTeamHits()) { - gibParticleClone->SetTeam(m_Team); - gibParticleClone->SetIgnoresTeamHits(true); + error += delta2[sub]; + } + // Unlock all bitmaps involved outside the loop. + release_bitmap(m_aSprite[m_Frame]); + + if (m_pEntryWound) { + // Add entry wound AEmitter to actor where the particle penetrated. + AEmitter* pEntryWound = dynamic_cast(m_pEntryWound->Clone()); + pEntryWound->SetInheritedRotAngleOffset(dir.GetAbsRadAngle() + c_PI); + float damageMultiplier = pEntryWound->HasNoSetDamageMultiplier() ? 1.0F : pEntryWound->GetDamageMultiplier(); + pEntryWound->SetDamageMultiplier(damageMultiplier * hd.Body[HITOR]->WoundDamageMultiplier()); + // Adjust position so that it looks like the hole is actually *on* the Hitee. + entryPos[dom] += increment[dom] * (pEntryWound->GetSpriteWidth() / 2); + AddWound(pEntryWound, entryPos + m_SpriteOffset); + pEntryWound = 0; + } + + // Add exit wound AEmitter to actor, if applicable. + if (exited) { + Vector exitPos; + exitPos[dom] = entryPos[dom] + (increment[dom] * domSteps); + exitPos[sub] = entryPos[sub] + (increment[sub] * subSteps); + if (m_pExitWound) { + AEmitter* pExitWound = dynamic_cast(m_pExitWound->Clone()); + // Adjust position so that it looks like the hole is actually *on* the Hitee. + exitPos[dom] -= increment[dom] * (pExitWound->GetSpriteWidth() / 2); + pExitWound->SetInheritedRotAngleOffset(dir.GetAbsRadAngle()); + float damageMultiplier = pExitWound->HasNoSetDamageMultiplier() ? 1.0F : pExitWound->GetDamageMultiplier(); + pExitWound->SetDamageMultiplier(damageMultiplier * hd.Body[HITOR]->WoundDamageMultiplier()); + AddWound(pExitWound, exitPos + m_SpriteOffset); + pExitWound = 0; } - g_MovableMan.AddParticle(gibParticleClone); + // Set the exiting particle's position to where the exit wound is, + // in world coordinates. + hd.Body[HITOR]->SetPos(((exitPos + m_SpriteOffset) / m_Rotation) + m_Pos); + + // Finally apply the forces imposed on both this MOSRotating + // and the hitting particle due to the penetrating and exiting hit. + // These don't need to be manipulated if there was no exit, since this + // absorbed all the energy, and the hittee gets deleted from the scene. + hd.ResImpulse[HITEE] -= hd.ResImpulse[HITEE] * (impulseForce / hd.ResImpulse[HITEE].GetMagnitude()); + hd.ResImpulse[HITOR] = -(hd.ResImpulse[HITEE]); } + // Particle got lodged inside this MOSRotating, so stop it and delete it from scene. + else { + // Set the exiting particle's position to where it looks lodged + // hd.Body[HITOR]->SetPos(m_Pos - m_SpriteOffset + entryPos); + // hd.Body[HITOR]->SetVel(Vector()); + hd.Body[HITOR]->SetToDelete(true); + hd.Terminate[HITOR] = true; + } + + // Report that penetration occured. + return true; } - } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Report that penetration didn't occur and signal to client to + // calculate bounce effects instead. + return false; + } -void MOSRotating::RemoveAttachablesWhenGibbing(const Vector &impactImpulse, MovableObject *movableObjectToIgnore) { - const std::vector nonVolatileAttachablesVectorForLuaSafety { m_Attachables.begin(), m_Attachables.end() }; - for (Attachable *attachable : nonVolatileAttachablesVectorForLuaSafety) { - RTEAssert(attachable, "Broken Attachable when Gibbing!"); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (RandomNum() < attachable->GetGibWithParentChance() || attachable->GetGibWhenRemovedFromParent()) { - attachable->GibThis(); - continue; - } + void MOSRotating::GibThis(const Vector& impactImpulse, MovableObject* movableObjectToIgnore) { + if (m_MissionCritical || m_ToDelete) { + return; + } - if (!attachable->GetDeleteWhenRemovedFromParent()) { - float attachableGibBlastStrength = (attachable->GetParentGibBlastStrengthMultiplier() * m_GibBlastStrength) / (1 + attachable->GetMass()); - attachable->SetAngularVel((attachable->GetAngularVel() * 0.5F) + (attachable->GetAngularVel() * 0.5F * attachableGibBlastStrength * RandomNormalNum())); - Vector gibBlastVel = Vector(attachable->GetParentOffset()).SetMagnitude(attachableGibBlastStrength * 0.5F + (attachableGibBlastStrength * RandomNum())); - attachable->SetVel(m_Vel + gibBlastVel); // Attachables have already had their velocity updated by ApplyImpulses(), no need to add impactImpulse again + if (impactImpulse.MagnitudeIsGreaterThan(GetGibImpulseLimit())) { + // Add a counterforce equal to GibImpulseLimit to the impulse list in order to simulate the force spent on breaking the object apart + Vector counterForce = impactImpulse; + counterForce.SetMagnitude(GetGibImpulseLimit()); + m_ImpulseForces.emplace_back(-counterForce, Vector()); + MOSprite::ApplyImpulses(); + } - if (movableObjectToIgnore) { attachable->SetWhichMOToNotHit(movableObjectToIgnore); } - } + CreateGibsWhenGibbing(impactImpulse, movableObjectToIgnore); - RemoveAttachable(attachable, true, true); - } - m_Attachables.clear(); -} + RemoveAttachablesWhenGibbing(impactImpulse, movableObjectToIgnore); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (m_GibSound) { + m_GibSound->Play(m_Pos); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: MoveOutOfTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether any of the Atom:s in this MovableObject are on top of -// terrain pixels, and if so, attempt to move this out so none of this' -// Atoms are on top of the terrain any more. + if (m_pScreenEffect && m_EffectOnGib && (m_EffectAlwaysShows || !g_SceneMan.ObscuredPoint(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY()))) { + g_PostProcessMan.RegisterPostEffect(m_Pos, m_pScreenEffect, m_ScreenEffectHash, 255, m_EffectRotAngle); + } -bool MOSRotating::MoveOutOfTerrain(unsigned char strongerThan) -{ - return m_pAtomGroup->ResolveTerrainIntersection(m_Pos, strongerThan); -} + if (m_LoudnessOnGib > 0) { + g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, m_Team, m_LoudnessOnGib)); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m_ToDelete = true; + } -void MOSRotating::ApplyForces() { - float deltaTime = g_TimerMan.GetDeltaTimeSecs(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - for (const auto &[forceVector, forceOffset] : m_Forces) { - if (!forceOffset.IsZero()) { m_AngularVel += (forceOffset.GetPerpendicular().Dot(forceVector) / m_pAtomGroup->GetMomentOfInertia()) * deltaTime; } - } + void MOSRotating::CreateGibsWhenGibbing(const Vector& impactImpulse, MovableObject* movableObjectToIgnore) { + if (m_GibScreenShakeAmount != -1.0F) { + g_CameraMan.AddScreenShake(m_GibScreenShakeAmount, m_Pos); + } - MOSprite::ApplyForces(); -} + for (const Gib& gibSettingsObject: m_Gibs) { + if (gibSettingsObject.GetCount() == 0) { + continue; + } + MovableObject* gibParticleClone = dynamic_cast(gibSettingsObject.GetParticlePreset()->Clone()); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int count = gibSettingsObject.GetCount(); + float lifeVariation = gibSettingsObject.GetLifeVariation(); + float spread = gibSettingsObject.GetSpread(); + float minVelocity = gibSettingsObject.GetMinVelocity(); + float maxVelocity = gibSettingsObject.GetMaxVelocity(); -void MOSRotating::ApplyImpulses() { - for (const auto &[impulseForceVector, impulseForceOffset] : m_ImpulseForces) { - if (!impulseForceOffset.IsZero()) { m_AngularVel += impulseForceOffset.GetPerpendicular().Dot(impulseForceVector) / m_pAtomGroup->GetMomentOfInertia(); } - } + float mass = (gibParticleClone->GetMass() != 0 ? gibParticleClone->GetMass() : 0.0001F); + int lifetime = gibParticleClone->GetLifetime(); - Vector totalImpulse; - Vector averagedImpulseForceOffset; - for (const auto &[impulseForceVector, impulseForceOffset] : m_ImpulseForces) { - totalImpulse += impulseForceVector; - averagedImpulseForceOffset += impulseForceOffset; - } - averagedImpulseForceOffset /= static_cast(m_ImpulseForces.size()); + if (minVelocity == 0 && maxVelocity == 0) { + minVelocity = m_GibBlastStrength / mass; + maxVelocity = minVelocity + 10.0F; + } - if (m_GibImpulseLimit > 0) { - float impulseLimit = m_GibImpulseLimit; - if (m_WoundCountAffectsImpulseLimitRatio != 0 && m_GibWoundLimit > 0) { - impulseLimit *= 1.0F - (static_cast(m_Wounds.size()) / static_cast(m_GibWoundLimit)) * m_WoundCountAffectsImpulseLimitRatio; - } - if (totalImpulse.MagnitudeIsGreaterThan(impulseLimit)) { - DetachAttachablesFromImpulse(totalImpulse); - // Use the remainder of the impulses left over from detaching to gib the parent object. - if (totalImpulse.MagnitudeIsGreaterThan(impulseLimit)) { GibThis(totalImpulse); } + if (m_GibScreenShakeAmount == -1.0F) { + // Automatically calculate a value based on the amount of energy going on here + float averageSpeed = (minVelocity + maxVelocity) * 0.5F; + float energy = mass * averageSpeed * static_cast(count); + g_CameraMan.AddScreenShake(energy * g_CameraMan.GetDefaultShakePerUnitOfGibEnergy(), m_Pos); + } + + float velocityRange = maxVelocity - minVelocity; + Vector rotatedGibOffset = RotateOffset(gibSettingsObject.GetOffset()); + + // The "Spiral" spread mode uses the fermat spiral as means to determine the velocity of the gib particles, resulting in a evenly spaced out circle (or ring) of particles. + if (gibSettingsObject.GetSpreadMode() == Gib::SpreadMode::SpreadSpiral) { + float maxRadius = std::sqrt(static_cast(count)); + float scale = velocityRange / maxRadius; + float randAngle = c_PI * RandomNormalNum(); + float goldenAngle = 2.39996F; + + for (int i = 0; i < count; i++) { + if (i > 0) { + gibParticleClone = dynamic_cast(gibSettingsObject.GetParticlePreset()->Clone()); + } + + float radius = std::sqrt(static_cast(count - i)); + gibParticleClone->SetPos(m_Pos + rotatedGibOffset); + gibParticleClone->SetHFlipped(m_HFlipped); + Vector gibVelocity(radius * scale + minVelocity, 0); + gibVelocity.RadRotate(randAngle + RandomNum(0.0F, spread) + static_cast(i) * goldenAngle); + if (lifetime != 0) { + gibParticleClone->SetLifetime(std::max(static_cast(static_cast(lifetime) * (1.0F - lifeVariation * ((radius / maxRadius) * 0.75F + RandomNormalNum() * 0.25F))), 1)); + } + gibParticleClone->SetRotAngle(gibVelocity.GetAbsRadAngle() + (m_HFlipped ? c_PI : 0)); + gibParticleClone->SetAngularVel((gibParticleClone->GetAngularVel() * 0.35F) + (gibParticleClone->GetAngularVel() * 0.65F / mass) * RandomNum()); + gibParticleClone->SetVel(gibVelocity + ((m_PrevVel + m_Vel) / 2) * gibSettingsObject.InheritsVelocity()); + if (movableObjectToIgnore) { + gibParticleClone->SetWhichMOToNotHit(movableObjectToIgnore); + } + if (gibSettingsObject.IgnoresTeamHits()) { + gibParticleClone->SetTeam(m_Team); + gibParticleClone->SetIgnoresTeamHits(true); + } + + g_MovableMan.AddParticle(gibParticleClone); + } + } else { + for (int i = 0; i < count; i++) { + if (i > 0) { + gibParticleClone = dynamic_cast(gibSettingsObject.GetParticlePreset()->Clone()); + } + + if (gibParticleClone->GetLifetime() != 0) { + gibParticleClone->SetLifetime(std::max(static_cast(static_cast(gibParticleClone->GetLifetime()) * (1.0F + (lifeVariation * RandomNormalNum()))), 1)); + } + + gibParticleClone->SetRotAngle(GetRotAngle() + gibParticleClone->GetRotAngle()); + gibParticleClone->SetAngularVel((gibParticleClone->GetAngularVel() * 0.35F) + (gibParticleClone->GetAngularVel() * 0.65F / mass) * RandomNum()); + if (rotatedGibOffset.GetRoundIntX() > m_aSprite[0]->w / 3) { + float offCenterRatio = rotatedGibOffset.m_X / (static_cast(m_aSprite[0]->w) / 2.0F); + float angularVel = std::abs(gibParticleClone->GetAngularVel() * 0.5F) + std::abs(gibParticleClone->GetAngularVel() * 0.5F * offCenterRatio); + gibParticleClone->SetAngularVel(angularVel * (rotatedGibOffset.m_X > 0 ? -1 : 1)); + } else { + gibParticleClone->SetAngularVel((gibParticleClone->GetAngularVel() * 0.5F + (gibParticleClone->GetAngularVel() * RandomNum())) * (RandomNormalNum() > 0.0F ? 1.0F : -1.0F)); + } + + gibParticleClone->SetPos(m_Pos + rotatedGibOffset); + gibParticleClone->SetHFlipped(m_HFlipped); + Vector gibVelocity = Vector(minVelocity + RandomNum(0.0F, velocityRange), 0.0F); + + // TODO: Figure out how much the magnitude of an offset should affect spread + float gibSpread = (rotatedGibOffset.IsZero() && spread == 0.1F) ? c_PI : spread; + // Determine the primary direction of the gib particles. + if (gibSettingsObject.InheritsVelocity() > 0 && !impactImpulse.IsZero()) { + gibVelocity.RadRotate(impactImpulse.GetAbsRadAngle()); + } else if (!rotatedGibOffset.IsZero()) { + gibVelocity.RadRotate(rotatedGibOffset.GetAbsRadAngle()); + } else { + gibVelocity.RadRotate(m_Rotation.GetRadAngle() + (m_HFlipped ? c_PI : 0)); + } + // The "Even" spread will spread all gib particles evenly in an arc, while maintaining a randomized velocity magnitude. + if (gibSettingsObject.GetSpreadMode() == Gib::SpreadMode::SpreadEven) { + gibVelocity.RadRotate(gibSpread - (gibSpread * 2.0F * static_cast(i) / static_cast(count))); + } else { + gibVelocity.RadRotate(gibSpread * RandomNormalNum()); + } + gibParticleClone->SetVel(gibVelocity + ((m_PrevVel + m_Vel) / 2) * gibSettingsObject.InheritsVelocity()); + if (movableObjectToIgnore) { + gibParticleClone->SetWhichMOToNotHit(movableObjectToIgnore); + } + if (gibSettingsObject.IgnoresTeamHits()) { + gibParticleClone->SetTeam(m_Team); + gibParticleClone->SetIgnoresTeamHits(true); + } + + g_MovableMan.AddParticle(gibParticleClone); + } + } } } - MOSprite::ApplyImpulses(); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void MOSRotating::RemoveAttachablesWhenGibbing(const Vector& impactImpulse, MovableObject* movableObjectToIgnore) { + const std::vector nonVolatileAttachablesVectorForLuaSafety{m_Attachables.begin(), m_Attachables.end()}; + for (Attachable* attachable: nonVolatileAttachablesVectorForLuaSafety) { + RTEAssert(attachable, "Broken Attachable when Gibbing!"); + if (RandomNum() < attachable->GetGibWithParentChance() || attachable->GetGibWhenRemovedFromParent()) { + attachable->GibThis(); + continue; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ResetAllTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resest all the timers used by this. Can be emitters, etc. This is to -// prevent backed up emissions to come out all at once while this has been -// held dormant in an inventory. + if (!attachable->GetDeleteWhenRemovedFromParent()) { + float attachableGibBlastStrength = (attachable->GetParentGibBlastStrengthMultiplier() * m_GibBlastStrength) / (1 + attachable->GetMass()); + attachable->SetAngularVel((attachable->GetAngularVel() * 0.5F) + (attachable->GetAngularVel() * 0.5F * attachableGibBlastStrength * RandomNormalNum())); + Vector gibBlastVel = Vector(attachable->GetParentOffset()).SetMagnitude(attachableGibBlastStrength * 0.5F + (attachableGibBlastStrength * RandomNum())); + attachable->SetVel(m_Vel + gibBlastVel); // Attachables have already had their velocity updated by ApplyImpulses(), no need to add impactImpulse again -void MOSRotating::ResetAllTimers() -{ - MovableObject::ResetAllTimers(); + if (movableObjectToIgnore) { + attachable->SetWhichMOToNotHit(movableObjectToIgnore); + } + } - for (auto emitter = m_Wounds.begin(); emitter != m_Wounds.end(); ++emitter) - (*emitter)->ResetAllTimers(); + RemoveAttachable(attachable, true, true); + } + m_Attachables.clear(); + } - for (auto attachable = m_Attachables.begin(); attachable != m_Attachables.end(); ++attachable) - (*attachable)->ResetAllTimers(); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: MoveOutOfTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether any of the Atom:s in this MovableObject are on top of + // terrain pixels, and if so, attempt to move this out so none of this' + // Atoms are on top of the terrain any more. -void MOSRotating::RestDetection() { - MOSprite::RestDetection(); + bool MOSRotating::MoveOutOfTerrain(unsigned char strongerThan) { + return m_pAtomGroup->ResolveTerrainIntersection(m_Pos, strongerThan); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Rotational settling detection. - if ((m_AngularVel > 0 && m_PrevAngVel < 0) || (m_AngularVel < 0 && m_PrevAngVel > 0)) { - ++m_AngOscillations; - } else { - m_AngOscillations = 0; + void MOSRotating::ApplyForces() { + float deltaTime = g_TimerMan.GetDeltaTimeSecs(); + + for (const auto& [forceVector, forceOffset]: m_Forces) { + if (!forceOffset.IsZero()) { + m_AngularVel += (forceOffset.GetPerpendicular().Dot(forceVector) / m_pAtomGroup->GetMomentOfInertia()) * deltaTime; + } + } + + MOSprite::ApplyForces(); } - if (std::abs(m_Rotation.GetRadAngle() - m_PrevRotation.GetRadAngle()) >= 0.01) { m_RestTimer.Reset(); } - - // If about to settle, make sure the object isn't flying in the air. - // Note that this uses sprite radius to avoid possibly settling when it shouldn't (e.g. if there's a lopsided attachable enlarging the radius, using GetRadius might make it settle in the air). - if (m_ToSettle || IsAtRest()) { - bool resting = true; - if (g_SceneMan.OverAltitude(m_Pos, static_cast(m_SpriteRadius) + 4, 3)) { - resting = false; - for (const Attachable *attachable : m_Attachables) { - if (attachable->GetCollidesWithTerrainWhileAttached() && !g_SceneMan.OverAltitude(attachable->GetPos(), static_cast(attachable->GetIndividualRadius()) + 2, 3)) { - resting = true; - break; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::ApplyImpulses() { + for (const auto& [impulseForceVector, impulseForceOffset]: m_ImpulseForces) { + if (!impulseForceOffset.IsZero()) { + m_AngularVel += impulseForceOffset.GetPerpendicular().Dot(impulseForceVector) / m_pAtomGroup->GetMomentOfInertia(); + } + } + + Vector totalImpulse; + Vector averagedImpulseForceOffset; + for (const auto& [impulseForceVector, impulseForceOffset]: m_ImpulseForces) { + totalImpulse += impulseForceVector; + averagedImpulseForceOffset += impulseForceOffset; + } + averagedImpulseForceOffset /= static_cast(m_ImpulseForces.size()); + + if (m_GibImpulseLimit > 0) { + float impulseLimit = m_GibImpulseLimit; + if (m_WoundCountAffectsImpulseLimitRatio != 0 && m_GibWoundLimit > 0) { + impulseLimit *= 1.0F - (static_cast(m_Wounds.size()) / static_cast(m_GibWoundLimit)) * m_WoundCountAffectsImpulseLimitRatio; + } + if (totalImpulse.MagnitudeIsGreaterThan(impulseLimit)) { + DetachAttachablesFromImpulse(totalImpulse); + // Use the remainder of the impulses left over from detaching to gib the parent object. + if (totalImpulse.MagnitudeIsGreaterThan(impulseLimit)) { + GibThis(totalImpulse); } } } - if (!resting) { - m_VelOscillations = 0; + + MOSprite::ApplyImpulses(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. + + void MOSRotating::ResetAllTimers() { + MovableObject::ResetAllTimers(); + + for (auto emitter = m_Wounds.begin(); emitter != m_Wounds.end(); ++emitter) + (*emitter)->ResetAllTimers(); + + for (auto attachable = m_Attachables.begin(); attachable != m_Attachables.end(); ++attachable) + (*attachable)->ResetAllTimers(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::RestDetection() { + MOSprite::RestDetection(); + + // Rotational settling detection. + if ((m_AngularVel > 0 && m_PrevAngVel < 0) || (m_AngularVel < 0 && m_PrevAngVel > 0)) { + ++m_AngOscillations; + } else { m_AngOscillations = 0; + } + + if (std::abs(m_Rotation.GetRadAngle() - m_PrevRotation.GetRadAngle()) >= 0.01) { m_RestTimer.Reset(); - m_ToSettle = false; } + + // If about to settle, make sure the object isn't flying in the air. + // Note that this uses sprite radius to avoid possibly settling when it shouldn't (e.g. if there's a lopsided attachable enlarging the radius, using GetRadius might make it settle in the air). + if (m_ToSettle || IsAtRest()) { + bool resting = true; + if (g_SceneMan.OverAltitude(m_Pos, static_cast(m_SpriteRadius) + 4, 3)) { + resting = false; + for (const Attachable* attachable: m_Attachables) { + if (attachable->GetCollidesWithTerrainWhileAttached() && !g_SceneMan.OverAltitude(attachable->GetPos(), static_cast(attachable->GetIndividualRadius()) + 2, 3)) { + resting = true; + break; + } + } + } + if (!resting) { + m_VelOscillations = 0; + m_AngOscillations = 0; + m_RestTimer.Reset(); + m_ToSettle = false; + } + } + m_PrevRotation = m_Rotation; + m_PrevAngVel = m_AngularVel; } - m_PrevRotation = m_Rotation; - m_PrevAngVel = m_AngularVel; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MOSRotating::IsAtRest() { - if (m_RestThreshold < 0 || m_PinStrength != 0) { - return false; - } else if (m_VelOscillations > 2 || m_AngOscillations > 2) { - return true; + bool MOSRotating::IsAtRest() { + if (m_RestThreshold < 0 || m_PinStrength != 0) { + return false; + } else if (m_VelOscillations > 2 || m_AngOscillations > 2) { + return true; + } + return m_RestTimer.IsPastSimMS(m_RestThreshold); } - return m_RestTimer.IsPastSimMS(m_RestThreshold); -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MOSRotating::IsOnScenePoint(Vector &scenePoint) const { - if (!m_aSprite[m_Frame]) { - return false; - } + bool MOSRotating::IsOnScenePoint(Vector& scenePoint) const { + if (!m_aSprite[m_Frame]) { + return false; + } - //TODO this should really use GetRadius() instead of sprite radius, then check attachable's sprites directly here. It'd save some computation but I didn't wanna deal with it. - if (WithinBox(scenePoint, m_Pos.m_X - m_SpriteRadius, m_Pos.m_Y - m_SpriteRadius, m_Pos.m_X + m_SpriteRadius, m_Pos.m_Y + m_SpriteRadius)) { - Vector spritePoint = scenePoint - m_Pos; - spritePoint = UnRotateOffset(spritePoint); - int pixel = getpixel(m_aSprite[m_Frame], static_cast(spritePoint.m_X - m_SpriteOffset.m_X), static_cast(spritePoint.m_Y - m_SpriteOffset.m_Y)); - if (pixel != -1 && pixel != g_MaskColor) { - return true; - } - } + // TODO this should really use GetRadius() instead of sprite radius, then check attachable's sprites directly here. It'd save some computation but I didn't wanna deal with it. + if (WithinBox(scenePoint, m_Pos.m_X - m_SpriteRadius, m_Pos.m_Y - m_SpriteRadius, m_Pos.m_X + m_SpriteRadius, m_Pos.m_Y + m_SpriteRadius)) { + Vector spritePoint = scenePoint - m_Pos; + spritePoint = UnRotateOffset(spritePoint); + int pixel = getpixel(m_aSprite[m_Frame], static_cast(spritePoint.m_X - m_SpriteOffset.m_X), static_cast(spritePoint.m_Y - m_SpriteOffset.m_Y)); + if (pixel != -1 && pixel != g_MaskColor) { + return true; + } + } - for (const Attachable *attachable : m_Attachables) { - if (attachable->IsOnScenePoint(scenePoint)) { - return true; - } - } + for (const Attachable* attachable: m_Attachables) { + if (attachable->IsOnScenePoint(scenePoint)) { + return true; + } + } - return false; -} + return false; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: EraseFromTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Cuts this' silhouette out from the terrain's material and color layers. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: EraseFromTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Cuts this' silhouette out from the terrain's material and color layers. -void MOSRotating::EraseFromTerrain() -{ - Vector pivot = -m_SpriteOffset; + void MOSRotating::EraseFromTerrain() { + Vector pivot = -m_SpriteOffset; - if (m_HFlipped) - { - // Create intermediate flipping bitmap if there isn't one yet - // Don't size the intermediate bitmaps to teh m_Scale, because the scaling happens after they are done - if (!m_pFlipBitmap) - m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[m_Frame]->w, m_aSprite[m_Frame]->h); - clear_to_color(m_pFlipBitmap, g_MaskColor); + if (m_HFlipped) { + // Create intermediate flipping bitmap if there isn't one yet + // Don't size the intermediate bitmaps to teh m_Scale, because the scaling happens after they are done + if (!m_pFlipBitmap) + m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[m_Frame]->w, m_aSprite[m_Frame]->h); + clear_to_color(m_pFlipBitmap, g_MaskColor); - // Draw eitehr the source color bitmap or the intermediate material bitmap onto the intermediate flipping bitmap - draw_sprite_h_flip(m_pFlipBitmap, m_aSprite[m_Frame], 0, 0); + // Draw eitehr the source color bitmap or the intermediate material bitmap onto the intermediate flipping bitmap + draw_sprite_h_flip(m_pFlipBitmap, m_aSprite[m_Frame], 0, 0); - pivot.m_X = m_pFlipBitmap->w + m_SpriteOffset.m_X; - } + pivot.m_X = m_pFlipBitmap->w + m_SpriteOffset.m_X; + } - std::deque pixels = g_SceneMan.GetTerrain()->EraseSilhouette(m_HFlipped ? m_pFlipBitmap : m_aSprite[m_Frame], m_Pos, pivot, m_Rotation, m_Scale, false); -} + std::deque pixels = g_SceneMan.GetTerrain()->EraseSilhouette(m_HFlipped ? m_pFlipBitmap : m_aSprite[m_Frame], m_Pos, pivot, m_Rotation, m_Scale, false); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DeepCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if any of this' deep group atmos are on top of the terrain, and + // if so, erases this' silhouette from the terrain. + + bool MOSRotating::DeepCheck(bool makeMOPs, int skipMOP, int maxMOPs) { + // Check for deep penetration of the terrain and + // generate splash of MOPixels accordingly. + if (m_pDeepGroup && (m_pDeepGroup->InTerrain() || m_ForceDeepCheck)) { + m_ForceDeepCheck = false; + m_DeepHardness = true; + + // TODO: This stuff is just way too slow, EraseSilhouette is a hog + // Make particles fly at least somewhat + float velMag = MAX(10.0f, m_Vel.GetMagnitude()); + float splashDir = m_Vel.m_X >= 0 ? 1 : -1; + float splashRatio = g_MovableMan.GetSplashRatio(); + float tally = 0.0; + int depth = m_pDeepGroup->GetDepth() >> 1; + Vector pivot = -m_SpriteOffset; + + if (m_HFlipped) { + // Create intermediate flipping bitmap if there isn't one yet + // Don't size the intermediate bitmaps to teh m_Scale, because the scaling happens after they are done + if (!m_pFlipBitmap) + m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[m_Frame]->w, m_aSprite[m_Frame]->h); + clear_to_color(m_pFlipBitmap, g_MaskColor); + + // Draw eitehr the source color bitmap or the intermediate material bitmap onto the intermediate flipping bitmap + draw_sprite_h_flip(m_pFlipBitmap, m_aSprite[m_Frame], 0, 0); + + pivot.m_X = m_pFlipBitmap->w + m_SpriteOffset.m_X; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DeepCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if any of this' deep group atmos are on top of the terrain, and -// if so, erases this' silhouette from the terrain. - -bool MOSRotating::DeepCheck(bool makeMOPs, int skipMOP, int maxMOPs) -{ - // Check for deep penetration of the terrain and - // generate splash of MOPixels accordingly. - if (m_pDeepGroup && (m_pDeepGroup->InTerrain() || m_ForceDeepCheck)) - { - m_ForceDeepCheck = false; - m_DeepHardness = true; - -// TODO: This stuff is just way too slow, EraseSilhouette is a hog - // Make particles fly at least somewhat - float velMag = MAX(10.0f, m_Vel.GetMagnitude()); - float splashDir = m_Vel.m_X >= 0 ? 1 : -1; - float splashRatio = g_MovableMan.GetSplashRatio(); - float tally = 0.0; - int depth = m_pDeepGroup->GetDepth() >> 1; - Vector pivot = -m_SpriteOffset; - - if (m_HFlipped) - { - // Create intermediate flipping bitmap if there isn't one yet - // Don't size the intermediate bitmaps to teh m_Scale, because the scaling happens after they are done - if (!m_pFlipBitmap) - m_pFlipBitmap = create_bitmap_ex(8, m_aSprite[m_Frame]->w, m_aSprite[m_Frame]->h); - clear_to_color(m_pFlipBitmap, g_MaskColor); - - // Draw eitehr the source color bitmap or the intermediate material bitmap onto the intermediate flipping bitmap - draw_sprite_h_flip(m_pFlipBitmap, m_aSprite[m_Frame], 0, 0); - - pivot.m_X = m_pFlipBitmap->w + m_SpriteOffset.m_X; - } - - { - // Particle generation - // Erase the silhouette and get all the pixels that were created as a result - std::deque pixels = g_SceneMan.GetTerrain()->EraseSilhouette(m_HFlipped ? m_pFlipBitmap : m_aSprite[m_Frame], m_Pos, pivot, m_Rotation, m_Scale, makeMOPs, skipMOP, maxMOPs); - - for (std::deque::iterator itr = pixels.begin(); itr != pixels.end(); ++itr) - { - tally += splashRatio; - if (tally >= 1.0) - { - tally -= 1.0; - (*itr)->SetPos((*itr)->GetPos() - m_Vel.GetNormalized() * depth); - (*itr)->SetVel(Vector(velMag * RandomNum(0.0F, splashDir), -RandomNum(0.0F, velMag))); - m_DeepHardness += (*itr)->GetMaterial()->GetIntegrity() * (*itr)->GetMaterial()->GetPixelDensity(); - g_MovableMan.AddParticle(*itr); - *itr = 0; - } - else - { - delete (*itr); - *itr = 0; - } - } - } -// EXPERIMENTAL - // Move the remaining out and away from teh terrain to help unsticking - MoveOutOfTerrain(g_MaterialSand); - - return true; - } - - return false; -} + { + // Particle generation + // Erase the silhouette and get all the pixels that were created as a result + std::deque pixels = g_SceneMan.GetTerrain()->EraseSilhouette(m_HFlipped ? m_pFlipBitmap : m_aSprite[m_Frame], m_Pos, pivot, m_Rotation, m_Scale, makeMOPs, skipMOP, maxMOPs); + + for (std::deque::iterator itr = pixels.begin(); itr != pixels.end(); ++itr) { + tally += splashRatio; + if (tally >= 1.0) { + tally -= 1.0; + (*itr)->SetPos((*itr)->GetPos() - m_Vel.GetNormalized() * depth); + (*itr)->SetVel(Vector(velMag * RandomNum(0.0F, splashDir), -RandomNum(0.0F, velMag))); + m_DeepHardness += (*itr)->GetMaterial()->GetIntegrity() * (*itr)->GetMaterial()->GetPixelDensity(); + g_MovableMan.AddParticle(*itr); + *itr = 0; + } else { + delete (*itr); + *itr = 0; + } + } + } + // EXPERIMENTAL + // Move the remaining out and away from teh terrain to help unsticking + MoveOutOfTerrain(g_MaterialSand); + return true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done before Travel(). Always call before -// calling Travel. -// Arguments: None. -// Return value: None. + return false; + } -void MOSRotating::PreTravel() { - MOSprite::PreTravel(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done before Travel(). Always call before + // calling Travel. + // Arguments: None. + // Return value: None. + + void MOSRotating::PreTravel() { + MOSprite::PreTravel(); #ifdef DRAW_MOID_LAYER - // If this is going slow enough, check for and redraw the MOID representations of any other MOSRotatings that may be overlapping this - if (m_GetsHitByMOs && m_HitsMOs && m_Vel.GetX() < 2.0F && m_Vel.GetY() < 2.0F) { g_MovableMan.RedrawOverlappingMOIDs(this); } + // If this is going slow enough, check for and redraw the MOID representations of any other MOSRotatings that may be overlapping this + if (m_GetsHitByMOs && m_HitsMOs && m_Vel.GetX() < 2.0F && m_Vel.GetY() < 2.0F) { + g_MovableMan.RedrawOverlappingMOIDs(this); + } #endif -} + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Travel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Travels this MovableObject, using its physical representation. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Travel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Travels this MovableObject, using its physical representation. + void MOSRotating::Travel() { + MOSprite::Travel(); -void MOSRotating::Travel() -{ - MOSprite::Travel(); + // Pinned objects don't travel! + if (m_PinStrength) + return; - // Pinned objects don't travel! - if (m_PinStrength) - return; + float deltaTime = g_TimerMan.GetDeltaTimeSecs(); - float deltaTime = g_TimerMan.GetDeltaTimeSecs(); + // Reset the travel impulse for this frame + m_TravelImpulse.Reset(); - // Reset the travel impulse for this frame - m_TravelImpulse.Reset(); + RTEAssert(m_pAtomGroup, "No AtomGroup defined for MOSRotating " + GetPresetName() + " in Travel!"); - RTEAssert(m_pAtomGroup, "No AtomGroup defined for MOSRotating " + GetPresetName() + " in Travel!"); + // Set the atom to ignore a certain MO, if set and applicable. + if (m_HitsMOs && m_pMOToNotHit && g_MovableMan.ValidMO(m_pMOToNotHit) && !m_MOIgnoreTimer.IsPastSimTimeLimit()) { + std::vector MOIDsNotToHit; + m_pMOToNotHit->GetMOIDs(MOIDsNotToHit); + for (const MOID& MOIDNotToHit: MOIDsNotToHit) { + m_pAtomGroup->AddMOIDToIgnore(MOIDNotToHit); + } + } - // Set the atom to ignore a certain MO, if set and applicable. - if (m_HitsMOs && m_pMOToNotHit && g_MovableMan.ValidMO(m_pMOToNotHit) && !m_MOIgnoreTimer.IsPastSimTimeLimit()) { - std::vector MOIDsNotToHit; - m_pMOToNotHit->GetMOIDs(MOIDsNotToHit); - for (const MOID &MOIDNotToHit : MOIDsNotToHit) { - m_pAtomGroup->AddMOIDToIgnore(MOIDNotToHit); - } - } + ///////////////////////////////// + // AtomGroup travel - ///////////////////////////////// - // AtomGroup travel + if (!IsTooFast()) + m_pAtomGroup->Travel(deltaTime, true, true, g_SceneMan.SceneIsLocked()); - if (!IsTooFast()) - m_pAtomGroup->Travel(deltaTime, true, true, g_SceneMan.SceneIsLocked()); + // Now clear out the ignore override for next frame + m_pAtomGroup->ClearMOIDIgnoreList(); + } - // Now clear out the ignore override for next frame - m_pAtomGroup->ClearMOIDIgnoreList(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PostTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done after Update(). Always call after + // calling Update. + void MOSRotating::PostTravel() { + // Check for stupid velocities to gib instead of outright deletion that MOSprite::PostTravel() will do + if (IsTooFast()) { + GibThis(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PostTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done after Update(). Always call after -// calling Update. + // For some reason MovableObject lifetime death is in post travel rather than update, so this is done here too + if (m_GibAtEndOfLifetime && m_Lifetime && m_AgeTimer.GetElapsedSimTimeMS() > m_Lifetime) { + GibThis(); + } + + MOSprite::PostTravel(); -void MOSRotating::PostTravel() -{ - // Check for stupid velocities to gib instead of outright deletion that MOSprite::PostTravel() will do - if (IsTooFast()) { GibThis(); } + // Check if travel hits created enough impulse forces to gib this + if (m_GibImpulseLimit > 0) { + float impulseLimit = m_GibImpulseLimit; + if (m_WoundCountAffectsImpulseLimitRatio != 0 && m_GibWoundLimit > 0) { + impulseLimit *= 1.0F - (static_cast(m_Wounds.size()) / static_cast(m_GibWoundLimit)) * m_WoundCountAffectsImpulseLimitRatio; + } + if (m_TravelImpulse.MagnitudeIsGreaterThan(impulseLimit)) { + Vector totalImpulse(m_TravelImpulse.GetX(), m_TravelImpulse.GetY()); + DetachAttachablesFromImpulse(totalImpulse); + // Use the remainder of the impulses left over from detaching to gib the parent object. + if (totalImpulse.MagnitudeIsGreaterThan(impulseLimit)) { + GibThis(); + } + } + } + // Reset + m_DeepHardness = 0; + + // Check for deep penetration of the terrain and + // generate splash of MOPixels accordingly. + // TODO: don't hardcode the MOPixel limits! + if (g_MovableMan.IsMOSubtractionEnabled() && (m_ForceDeepCheck || m_DeepCheck)) + DeepCheck(true, 8, 50); + + Attachable* attachable; + for (auto attachableIterator = m_Attachables.begin(); attachableIterator != m_Attachables.end();) { + attachable = *attachableIterator; + RTEAssert(attachable, "Broken Attachable in PostTravel!"); + ++attachableIterator; + attachable->PostTravel(); + } + } - // For some reason MovableObject lifetime death is in post travel rather than update, so this is done here too - if (m_GibAtEndOfLifetime && m_Lifetime && m_AgeTimer.GetElapsedSimTimeMS() > m_Lifetime) { GibThis(); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MOSRotating. Supposed to be done every frame. - MOSprite::PostTravel(); + void MOSRotating::Update() { + MOSprite::Update(); - // Check if travel hits created enough impulse forces to gib this - if (m_GibImpulseLimit > 0) { - float impulseLimit = m_GibImpulseLimit; - if (m_WoundCountAffectsImpulseLimitRatio != 0 && m_GibWoundLimit > 0) { - impulseLimit *= 1.0F - (static_cast(m_Wounds.size()) / static_cast(m_GibWoundLimit)) * m_WoundCountAffectsImpulseLimitRatio; + if (m_InheritEffectRotAngle) { + m_EffectRotAngle = m_Rotation.GetRadAngle(); } - if (m_TravelImpulse.MagnitudeIsGreaterThan(impulseLimit)) { - Vector totalImpulse(m_TravelImpulse.GetX(), m_TravelImpulse.GetY()); - DetachAttachablesFromImpulse(totalImpulse); - // Use the remainder of the impulses left over from detaching to gib the parent object. - if (totalImpulse.MagnitudeIsGreaterThan(impulseLimit)) { GibThis(); } + + if (m_OrientToVel > 0 && m_Vel.GetLargest() > 5.0F) { + m_OrientToVel = std::clamp(m_OrientToVel, 0.0F, 1.0F); + + float velInfluence = std::clamp(m_OrientToVel < 1.0F ? m_Vel.GetMagnitude() / 100.0F : 1.0F, 0.0F, 1.0F); + float radsToGo = m_Rotation.GetRadAngleTo(m_Vel.GetAbsRadAngle() + (m_HFlipped ? -c_PI : 0)); + m_Rotation += radsToGo * m_OrientToVel * velInfluence; + } + + for (auto woundItr = m_Wounds.begin(); woundItr != m_Wounds.end();) { + AEmitter* wound = *woundItr; + RTEAssert(wound && wound->IsAttachedTo(this), "Broken wound AEmitter in Update"); + wound->Update(); + + if (wound->IsSetToDelete() || (wound->GetLifetime() > 0 && wound->GetAge() > wound->GetLifetime())) { + std::iter_swap(woundItr, m_Wounds.end() - 1); + m_Wounds.pop_back(); + m_AttachableAndWoundMass -= wound->GetMass(); + delete wound; + } else { + Vector totalImpulseForce; + for (const std::pair& impulseForce: wound->GetImpulses()) { + totalImpulseForce += impulseForce.first; + } + totalImpulseForce *= wound->GetJointStiffness(); + + if (!totalImpulseForce.IsZero()) { + AddImpulseForce(totalImpulseForce, wound->GetApplyTransferredForcesAtOffset() ? wound->GetParentOffset() * m_Rotation * c_MPP : Vector()); + } + + wound->ClearImpulseForces(); + ++woundItr; + } + } + + for (auto attachableItr = m_Attachables.begin(); attachableItr != m_Attachables.end();) { + Attachable* attachable = *attachableItr; + ++attachableItr; + RTEAssert(attachable, "Broken Attachable in Update!"); + RTEAssert(attachable->IsAttached(), "Found Attachable on " + GetModuleAndPresetName() + " (" + attachable->GetModuleAndPresetName() + ") with no parent, this should never happen!"); + RTEAssert(attachable->IsAttachedTo(this), "Found Attachable on " + GetModuleAndPresetName() + " (" + attachable->GetModuleAndPresetName() + ") with another parent (" + attachable->GetParent()->GetModuleAndPresetName() + "), this should never happen!"); + attachable->Update(); + + if (attachable->IsAttachedTo(this) && attachable->IsSetToDelete()) { + RemoveAttachable(attachable, true, true); + } else if (attachable->IsAttachedTo(this) && !attachable->IsSetToDelete()) { + TransferForcesFromAttachable(attachable); + } } } - // Reset - m_DeepHardness = 0; - // Check for deep penetration of the terrain and - // generate splash of MOPixels accordingly. -// TODO: don't hardcode the MOPixel limits! - if (g_MovableMan.IsMOSubtractionEnabled() && (m_ForceDeepCheck || m_DeepCheck)) - DeepCheck(true, 8, 50); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void MOSRotating::PostUpdate() { + for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) { + (*itr)->PostUpdate(); + } - Attachable *attachable; - for (auto attachableIterator = m_Attachables.begin(); attachableIterator != m_Attachables.end(); ) { - attachable = *attachableIterator; - RTEAssert(attachable, "Broken Attachable in PostTravel!"); - ++attachableIterator; - attachable->PostTravel(); - } -} + for (auto itr = m_Attachables.begin(); itr != m_Attachables.end(); ++itr) { + (*itr)->PostUpdate(); + } + MovableObject::PostUpdate(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool MOSRotating::DrawMOIDIfOverlapping(MovableObject* pOverlapMO) { + if (pOverlapMO == this || !m_GetsHitByMOs || !pOverlapMO->GetsHitByMOs()) { + return false; + } + + if (m_IgnoresTeamHits && pOverlapMO->IgnoresTeamHits() && m_Team == pOverlapMO->GetTeam()) { + return false; + } + + if (g_SceneMan.ShortestDistance(m_Pos, pOverlapMO->GetPos(), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(GetRadius() + pOverlapMO->GetRadius())) { + Draw(g_SceneMan.GetMOIDBitmap(), Vector(), g_DrawMOID, true); + return true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MOSRotating. Supposed to be done every frame. - -void MOSRotating::Update() { - MOSprite::Update(); - - if (m_InheritEffectRotAngle) { m_EffectRotAngle = m_Rotation.GetRadAngle(); } - - if (m_OrientToVel > 0 && m_Vel.GetLargest() > 5.0F) { - m_OrientToVel = std::clamp(m_OrientToVel, 0.0F, 1.0F); - - float velInfluence = std::clamp(m_OrientToVel < 1.0F ? m_Vel.GetMagnitude() / 100.0F : 1.0F, 0.0F, 1.0F); - float radsToGo = m_Rotation.GetRadAngleTo(m_Vel.GetAbsRadAngle() + (m_HFlipped ? -c_PI : 0)); - m_Rotation += radsToGo * m_OrientToVel * velInfluence; - } - - for (auto woundItr = m_Wounds.begin(); woundItr != m_Wounds.end(); ) { - AEmitter* wound = *woundItr; - RTEAssert(wound && wound->IsAttachedTo(this), "Broken wound AEmitter in Update"); - wound->Update(); - - if (wound->IsSetToDelete() || (wound->GetLifetime() > 0 && wound->GetAge() > wound->GetLifetime())) { - std::iter_swap(woundItr, m_Wounds.end() - 1); - m_Wounds.pop_back(); - m_AttachableAndWoundMass -= wound->GetMass(); - delete wound; - } else { - Vector totalImpulseForce; - for (const std::pair& impulseForce : wound->GetImpulses()) { - totalImpulseForce += impulseForce.first; - } - totalImpulseForce *= wound->GetJointStiffness(); - - if (!totalImpulseForce.IsZero()) { - AddImpulseForce(totalImpulseForce, wound->GetApplyTransferredForcesAtOffset() ? wound->GetParentOffset() * m_Rotation * c_MPP : Vector()); - } - - wound->ClearImpulseForces(); - ++woundItr; - } - } - - for (auto attachableItr = m_Attachables.begin(); attachableItr != m_Attachables.end(); ) { - Attachable* attachable = *attachableItr; - ++attachableItr; - RTEAssert(attachable, "Broken Attachable in Update!"); - RTEAssert(attachable->IsAttached(), "Found Attachable on " + GetModuleAndPresetName() + " (" + attachable->GetModuleAndPresetName() + ") with no parent, this should never happen!"); - RTEAssert(attachable->IsAttachedTo(this), "Found Attachable on " + GetModuleAndPresetName() + " (" + attachable->GetModuleAndPresetName() + ") with another parent (" + attachable->GetParent()->GetModuleAndPresetName() + "), this should never happen!"); - attachable->Update(); - - if (attachable->IsAttachedTo(this) && attachable->IsSetToDelete()) { - RemoveAttachable(attachable, true, true); - } else if (attachable->IsAttachedTo(this) && !attachable->IsSetToDelete()) { - TransferForcesFromAttachable(attachable); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::PostUpdate() { - for (auto itr = m_Wounds.begin(); itr != m_Wounds.end(); ++itr) { - (*itr)->PostUpdate(); - } - - for (auto itr = m_Attachables.begin(); itr != m_Attachables.end(); ++itr) { - (*itr)->PostUpdate(); - } - - MovableObject::PostUpdate(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool MOSRotating::DrawMOIDIfOverlapping(MovableObject *pOverlapMO) { - if (pOverlapMO == this || !m_GetsHitByMOs || !pOverlapMO->GetsHitByMOs()) { - return false; - } - - if (m_IgnoresTeamHits && pOverlapMO->IgnoresTeamHits() && m_Team == pOverlapMO->GetTeam()) { - return false; - } - - if (g_SceneMan.ShortestDistance(m_Pos, pOverlapMO->GetPos(), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(GetRadius() + pOverlapMO->GetRadius())) { - Draw(g_SceneMan.GetMOIDBitmap(), Vector(), g_DrawMOID, true); - return true; - } - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//TODO This should just be defined in MOSR instead of having an empty definition in MO. MOSR would need to override UpdateMOID accordingly, but this would clean things up a little. -void MOSRotating::UpdateChildMOIDs(std::vector &MOIDIndex, MOID rootMOID, bool makeNewMOID) { - MOSprite::UpdateChildMOIDs(MOIDIndex, m_RootMOID, makeNewMOID); - - for (Attachable *attachable : m_Attachables) { - // Anything that doesn't get hit by MOs doesn't need an ID, since that's only actually used for collision stuff. - if (attachable->GetsHitByMOs()) { attachable->UpdateMOID(MOIDIndex, m_RootMOID, makeNewMOID); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool MOSRotating::AttachableIsHardcoded(const Attachable *attachableToCheck) const { - if (attachableToCheck->GetParent() != this) { return false; } - unsigned long attachableUniqueID = attachableToCheck->GetUniqueID(); - return m_HardcodedAttachableUniqueIDsAndRemovers.find(attachableUniqueID) != m_HardcodedAttachableUniqueIDsAndRemovers.end() || m_HardcodedAttachableUniqueIDsAndSetters.find(attachableUniqueID) != m_HardcodedAttachableUniqueIDsAndSetters.end(); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // TODO This should just be defined in MOSR instead of having an empty definition in MO. MOSR would need to override UpdateMOID accordingly, but this would clean things up a little. + void MOSRotating::UpdateChildMOIDs(std::vector& MOIDIndex, MOID rootMOID, bool makeNewMOID) { + MOSprite::UpdateChildMOIDs(MOIDIndex, m_RootMOID, makeNewMOID); -void MOSRotating::AddAttachable(Attachable *attachable) { - if (attachable) { AddAttachable(attachable, attachable->GetParentOffset()); } -} + for (Attachable* attachable: m_Attachables) { + // Anything that doesn't get hit by MOs doesn't need an ID, since that's only actually used for collision stuff. + if (attachable->GetsHitByMOs()) { + attachable->UpdateMOID(MOIDIndex, m_RootMOID, makeNewMOID); + } + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MOSRotating::AddAttachable(Attachable *attachable, const Vector& parentOffsetToSet) { - if (attachable) { - RTEAssert(!attachable->IsAttached(), "Tried to add Attachable " + attachable->GetModuleAndPresetName() + " but it already has a parent, " + (attachable->IsAttached() ? attachable->GetParent()->GetModuleAndPresetName() : "ERROR") + "."); - if (g_MovableMan.ValidMO(attachable)) { g_MovableMan.RemoveMO(attachable); } - attachable->SetParentOffset(parentOffsetToSet); - attachable->SetParent(this); - m_AttachableAndWoundMass += attachable->GetMass(); - HandlePotentialRadiusAffectingAttachable(attachable); - m_Attachables.push_back(attachable); + bool MOSRotating::AttachableIsHardcoded(const Attachable* attachableToCheck) const { + if (attachableToCheck->GetParent() != this) { + return false; + } + + unsigned long attachableUniqueID = attachableToCheck->GetUniqueID(); + return m_HardcodedAttachableUniqueIDsAndRemovers.find(attachableUniqueID) != m_HardcodedAttachableUniqueIDsAndRemovers.end() || m_HardcodedAttachableUniqueIDsAndSetters.find(attachableUniqueID) != m_HardcodedAttachableUniqueIDsAndSetters.end(); } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Attachable * MOSRotating::RemoveAttachable(long attachableUniqueID, bool addToMovableMan, bool addBreakWounds) { - if (MovableObject *attachableAsMovableObject = g_MovableMan.FindObjectByUniqueID(attachableUniqueID)) { - return RemoveAttachable(dynamic_cast(attachableAsMovableObject), addToMovableMan, addBreakWounds); - } - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -Attachable * MOSRotating::RemoveAttachable(Attachable *attachable, bool addToMovableMan, bool addBreakWounds) { - if (!attachable || !attachable->IsAttached()) { - return attachable; - } - RTEAssert(attachable->IsAttachedTo(this), "Tried to remove Attachable " + attachable->GetPresetNameAndUniqueID() + " from presumed parent " + GetPresetNameAndUniqueID() + ", but it had a different parent (" + (attachable->GetParent() ? attachable->GetParent()->GetPresetNameAndUniqueID() : "ERROR") + "). This should never happen!"); - - if (!m_Attachables.empty()) { m_Attachables.remove(attachable); } - attachable->SetParent(nullptr); - m_AttachableAndWoundMass -= attachable->GetMass(); - - std::unordered_map>::iterator hardcodedAttachableMapEntry = m_HardcodedAttachableUniqueIDsAndSetters.find(attachable->GetUniqueID()); - if (hardcodedAttachableMapEntry != m_HardcodedAttachableUniqueIDsAndSetters.end()) { - hardcodedAttachableMapEntry->second(this, nullptr); - m_HardcodedAttachableUniqueIDsAndSetters.erase(hardcodedAttachableMapEntry); - } - - // Note, this version handles cases where you can't pass null to a setter cause you're calling a remover function, i.e. when dealing with hardcoded Attachable lists. - hardcodedAttachableMapEntry = m_HardcodedAttachableUniqueIDsAndRemovers.find(attachable->GetUniqueID()); - if (hardcodedAttachableMapEntry != m_HardcodedAttachableUniqueIDsAndRemovers.end()) { - hardcodedAttachableMapEntry->second(this, attachable); - m_HardcodedAttachableUniqueIDsAndRemovers.erase(hardcodedAttachableMapEntry); - } - - if (addBreakWounds) { - if (!m_ToDelete && attachable->GetParentBreakWound()) { - AEmitter *parentBreakWound = dynamic_cast(attachable->GetParentBreakWound()->Clone()); - if (parentBreakWound) { - parentBreakWound->SetDrawnAfterParent(attachable->IsDrawnAfterParent()); - parentBreakWound->SetInheritedRotAngleOffset((attachable->GetParentOffset() * m_Rotation).GetAbsRadAngle()); - AddWound(parentBreakWound, attachable->GetParentOffset(), false); - parentBreakWound = nullptr; - } - } - if (!attachable->IsSetToDelete() && attachable->GetBreakWound()) { - AEmitter *childBreakWound = dynamic_cast(attachable->GetBreakWound()->Clone()); - if (childBreakWound) { - childBreakWound->SetInheritedRotAngleOffset(attachable->GetJointOffset().GetAbsRadAngle()); - attachable->AddWound(childBreakWound, attachable->GetJointOffset()); - childBreakWound = nullptr; - } - } - } - - if (attachable == m_RadiusAffectingAttachable) { - m_RadiusAffectingAttachable = nullptr; - m_FarthestAttachableDistanceAndRadius = 0; - std::for_each(m_Attachables.begin(), m_Attachables.end(), [this](const Attachable *attachableToCheck) { HandlePotentialRadiusAffectingAttachable(attachableToCheck); }); - - Attachable *thisAsAttachable = dynamic_cast(this); - if (thisAsAttachable && m_Attachables.empty() && thisAsAttachable->IsAttached()) { - thisAsAttachable->m_Parent->HandlePotentialRadiusAffectingAttachable(thisAsAttachable); - } - } - - if (attachable->GetDeleteWhenRemovedFromParent()) { attachable->SetToDelete(); } - if (addToMovableMan || attachable->IsSetToDelete()) { - g_MovableMan.AddMO(attachable); - if (attachable->GetGibWhenRemovedFromParent()) { attachable->GibThis(); } - return nullptr; - } - - return attachable; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::RemoveAndDeleteAttachable(Attachable *attachable) { - attachable->SetToDelete(); - RemoveAttachable(attachable); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::RemoveOrDestroyAllAttachables(bool destroy) { - Attachable *attachable; - for (auto attachableIterator = m_Attachables.begin(); attachableIterator != m_Attachables.end(); ) { - attachable = *attachableIterator; - RTEAssert(attachable, "Broken Attachable!"); - ++attachableIterator; - - if (destroy) { - RemoveAndDeleteAttachable(attachable); - } else { - RemoveAttachable(attachable, true, true); - } - } - m_Attachables.clear(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::GetMOIDs(std::vector &MOIDs) const { - MOIDs.reserve(GetMOIDFootprint()); - MOSprite::GetMOIDs(MOIDs); - for (const Attachable *attachable : m_Attachables) { - if (attachable->GetsHitByMOs()) { attachable->GetMOIDs(MOIDs); } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::SetWhichMOToNotHit(MovableObject *moToNotHit, float forHowLong) { - MOSprite::SetWhichMOToNotHit(moToNotHit, forHowLong); - for (Attachable *attachable : m_Attachables) { attachable->SetWhichMOToNotHit(moToNotHit, forHowLong); } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MOSRotating's current graphical representation to a -// BITMAP of choice. - -void MOSRotating::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { - RTEAssert(!m_aSprite.empty(), "No sprite bitmaps loaded to draw!"); - RTEAssert(m_Frame >= 0 && m_Frame < m_FrameCount, "Frame is out of bounds!"); - - // Only draw MOID if this has a valid MOID assigned to it - if (mode == g_DrawMOID && m_MOID == g_NoMOID) { - return; - } - - if (mode == g_DrawColor && !m_FlashWhiteTimer.IsPastRealTimeLimit()) { mode = g_DrawWhite; } - - // Draw all the attached wound emitters, and only if the mode is g_DrawColor and not onlyphysical - // Only draw attachables and emitters which are not drawn after parent, so we draw them before - if (mode == g_DrawColor || (!onlyPhysical && mode == g_DrawMaterial)) { - for (const AEmitter *woundToDraw : m_Wounds) { - if (!woundToDraw->IsDrawnAfterParent()) { woundToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); } - } - } - - // Draw all the attached attachables - for (const Attachable *attachableToDraw : m_Attachables) { - if (!attachableToDraw->IsDrawnAfterParent() && attachableToDraw->IsDrawnNormallyByParent()) { attachableToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); } - } - - BITMAP * pTempBitmap = m_pTempBitmap; - BITMAP * pFlipBitmap = m_pFlipBitmap; - int keyColor = g_MaskColor; - - // Switch to non 8-bit drawing mode if we're drawing onto MO layer - if (mode == g_DrawMOID || mode == g_DrawNoMOID) { - pTempBitmap = m_pTempBitmapS; - pFlipBitmap = m_pFlipBitmapS; - keyColor = g_MOIDMaskColor; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::AddAttachable(Attachable* attachable) { + if (attachable) { + AddAttachable(attachable, attachable->GetParentOffset()); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::AddAttachable(Attachable* attachable, const Vector& parentOffsetToSet) { + if (attachable) { + RTEAssert(!attachable->IsAttached(), "Tried to add Attachable " + attachable->GetModuleAndPresetName() + " but it already has a parent, " + (attachable->IsAttached() ? attachable->GetParent()->GetModuleAndPresetName() : "ERROR") + "."); + if (g_MovableMan.ValidMO(attachable)) { + g_MovableMan.RemoveMO(attachable); + } + attachable->SetParentOffset(parentOffsetToSet); + attachable->SetParent(this); + m_AttachableAndWoundMass += attachable->GetMass(); + HandlePotentialRadiusAffectingAttachable(attachable); + m_Attachables.push_back(attachable); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Attachable* MOSRotating::RemoveAttachable(long attachableUniqueID, bool addToMovableMan, bool addBreakWounds) { + if (MovableObject* attachableAsMovableObject = g_MovableMan.FindObjectByUniqueID(attachableUniqueID)) { + return RemoveAttachable(dynamic_cast(attachableAsMovableObject), addToMovableMan, addBreakWounds); + } + return nullptr; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Attachable* MOSRotating::RemoveAttachable(Attachable* attachable, bool addToMovableMan, bool addBreakWounds) { + if (!attachable || !attachable->IsAttached()) { + return attachable; + } + RTEAssert(attachable->IsAttachedTo(this), "Tried to remove Attachable " + attachable->GetPresetNameAndUniqueID() + " from presumed parent " + GetPresetNameAndUniqueID() + ", but it had a different parent (" + (attachable->GetParent() ? attachable->GetParent()->GetPresetNameAndUniqueID() : "ERROR") + "). This should never happen!"); + + if (!m_Attachables.empty()) { + m_Attachables.remove(attachable); + } + attachable->SetParent(nullptr); + m_AttachableAndWoundMass -= attachable->GetMass(); + + std::unordered_map>::iterator hardcodedAttachableMapEntry = m_HardcodedAttachableUniqueIDsAndSetters.find(attachable->GetUniqueID()); + if (hardcodedAttachableMapEntry != m_HardcodedAttachableUniqueIDsAndSetters.end()) { + hardcodedAttachableMapEntry->second(this, nullptr); + m_HardcodedAttachableUniqueIDsAndSetters.erase(hardcodedAttachableMapEntry); + } + + // Note, this version handles cases where you can't pass null to a setter cause you're calling a remover function, i.e. when dealing with hardcoded Attachable lists. + hardcodedAttachableMapEntry = m_HardcodedAttachableUniqueIDsAndRemovers.find(attachable->GetUniqueID()); + if (hardcodedAttachableMapEntry != m_HardcodedAttachableUniqueIDsAndRemovers.end()) { + hardcodedAttachableMapEntry->second(this, attachable); + m_HardcodedAttachableUniqueIDsAndRemovers.erase(hardcodedAttachableMapEntry); + } + + if (addBreakWounds) { + if (!m_ToDelete && attachable->GetParentBreakWound()) { + AEmitter* parentBreakWound = dynamic_cast(attachable->GetParentBreakWound()->Clone()); + if (parentBreakWound) { + parentBreakWound->SetDrawnAfterParent(attachable->IsDrawnAfterParent()); + parentBreakWound->SetInheritedRotAngleOffset((attachable->GetParentOffset() * m_Rotation).GetAbsRadAngle()); + AddWound(parentBreakWound, attachable->GetParentOffset(), false); + parentBreakWound = nullptr; + } + } + if (!attachable->IsSetToDelete() && attachable->GetBreakWound()) { + AEmitter* childBreakWound = dynamic_cast(attachable->GetBreakWound()->Clone()); + if (childBreakWound) { + childBreakWound->SetInheritedRotAngleOffset(attachable->GetJointOffset().GetAbsRadAngle()); + attachable->AddWound(childBreakWound, attachable->GetJointOffset()); + childBreakWound = nullptr; + } + } + } + + if (attachable == m_RadiusAffectingAttachable) { + m_RadiusAffectingAttachable = nullptr; + m_FarthestAttachableDistanceAndRadius = 0; + std::for_each(m_Attachables.begin(), m_Attachables.end(), [this](const Attachable* attachableToCheck) { HandlePotentialRadiusAffectingAttachable(attachableToCheck); }); + + Attachable* thisAsAttachable = dynamic_cast(this); + if (thisAsAttachable && m_Attachables.empty() && thisAsAttachable->IsAttached()) { + thisAsAttachable->m_Parent->HandlePotentialRadiusAffectingAttachable(thisAsAttachable); + } + } + + if (attachable->GetDeleteWhenRemovedFromParent()) { + attachable->SetToDelete(); + } + if (addToMovableMan || attachable->IsSetToDelete()) { + g_MovableMan.AddMO(attachable); + if (attachable->GetGibWhenRemovedFromParent()) { + attachable->GibThis(); + } + return nullptr; + } + + return attachable; } - Vector spritePos(m_Pos.GetRounded() - targetPos); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (m_Recoiled) { - spritePos += m_RecoilOffset; - } + void MOSRotating::RemoveAndDeleteAttachable(Attachable* attachable) { + attachable->SetToDelete(); + RemoveAttachable(attachable); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::RemoveOrDestroyAllAttachables(bool destroy) { + Attachable* attachable; + for (auto attachableIterator = m_Attachables.begin(); attachableIterator != m_Attachables.end();) { + attachable = *attachableIterator; + RTEAssert(attachable, "Broken Attachable!"); + ++attachableIterator; - // If we're drawing a material silhouette, then create an intermediate material bitmap as well + if (destroy) { + RemoveAndDeleteAttachable(attachable); + } else { + RemoveAttachable(attachable, true, true); + } + } + m_Attachables.clear(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::GetMOIDs(std::vector& MOIDs) const { + MOIDs.reserve(GetMOIDFootprint()); + MOSprite::GetMOIDs(MOIDs); + for (const Attachable* attachable: m_Attachables) { + if (attachable->GetsHitByMOs()) { + attachable->GetMOIDs(MOIDs); + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::SetWhichMOToNotHit(MovableObject* moToNotHit, float forHowLong) { + MOSprite::SetWhichMOToNotHit(moToNotHit, forHowLong); + for (Attachable* attachable: m_Attachables) { + attachable->SetWhichMOToNotHit(moToNotHit, forHowLong); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MOSRotating's current graphical representation to a + // BITMAP of choice. + + void MOSRotating::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + RTEAssert(!m_aSprite.empty(), "No sprite bitmaps loaded to draw!"); + RTEAssert(m_Frame >= 0 && m_Frame < m_FrameCount, "Frame is out of bounds!"); + + // Only draw MOID if this has a valid MOID assigned to it + if (mode == g_DrawMOID && m_MOID == g_NoMOID) { + return; + } + + if (mode == g_DrawColor && !m_FlashWhiteTimer.IsPastRealTimeLimit()) { + mode = g_DrawWhite; + } + + // Draw all the attached wound emitters, and only if the mode is g_DrawColor and not onlyphysical + // Only draw attachables and emitters which are not drawn after parent, so we draw them before + if (mode == g_DrawColor || (!onlyPhysical && mode == g_DrawMaterial)) { + for (const AEmitter* woundToDraw: m_Wounds) { + if (!woundToDraw->IsDrawnAfterParent()) { + woundToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } + } + } + + // Draw all the attached attachables + for (const Attachable* attachableToDraw: m_Attachables) { + if (!attachableToDraw->IsDrawnAfterParent() && attachableToDraw->IsDrawnNormallyByParent()) { + attachableToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } + } + + BITMAP* pTempBitmap = m_pTempBitmap; + BITMAP* pFlipBitmap = m_pFlipBitmap; + int keyColor = g_MaskColor; + + // Switch to non 8-bit drawing mode if we're drawing onto MO layer + if (mode == g_DrawMOID || mode == g_DrawNoMOID) { + pTempBitmap = m_pTempBitmapS; + pFlipBitmap = m_pFlipBitmapS; + keyColor = g_MOIDMaskColor; + } + + Vector spritePos(m_Pos.GetRounded() - targetPos); + + if (m_Recoiled) { + spritePos += m_RecoilOffset; + } + + // If we're drawing a material silhouette, then create an intermediate material bitmap as well #ifdef DRAW_MOID_LAYER - bool intermediateBitmapUsed = mode != g_DrawColor && mode != g_DrawTrans; + bool intermediateBitmapUsed = mode != g_DrawColor && mode != g_DrawTrans; #else - bool intermediateBitmapUsed = mode != g_DrawColor && mode != g_DrawTrans && mode != g_DrawMOID; - RTEAssert(mode != g_DrawNoMOID, "DrawNoMOID drawing mode used with no MOID layer!"); + bool intermediateBitmapUsed = mode != g_DrawColor && mode != g_DrawTrans && mode != g_DrawMOID; + RTEAssert(mode != g_DrawNoMOID, "DrawNoMOID drawing mode used with no MOID layer!"); #endif - if (intermediateBitmapUsed) { - clear_to_color(pTempBitmap, keyColor); - - // TODO: Fix that MaterialAir and KeyColor don't work at all because they're drawing 0 to a field of 0's - // Draw the requested material silhouette on the material bitmap - if (mode == g_DrawMaterial) { - draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, m_SettleMaterialDisabled ? GetMaterial()->GetIndex() : GetMaterial()->GetSettleMaterial(), -1); - } else if (mode == g_DrawWhite) { - draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, g_WhiteColor, -1); - } else if (mode == g_DrawMOID) { - draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, m_MOID, -1); - } else if (mode == g_DrawNoMOID) { - draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, g_NoMOID, -1); - } else if (mode == g_DrawDoor) { - draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, g_MaterialDoor, -1); - } else { - RTEAbort("Unknown draw mode selected in MOSRotating::Draw()!"); - } - } + if (intermediateBitmapUsed) { + clear_to_color(pTempBitmap, keyColor); + + // TODO: Fix that MaterialAir and KeyColor don't work at all because they're drawing 0 to a field of 0's + // Draw the requested material silhouette on the material bitmap + if (mode == g_DrawMaterial) { + draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, m_SettleMaterialDisabled ? GetMaterial()->GetIndex() : GetMaterial()->GetSettleMaterial(), -1); + } else if (mode == g_DrawWhite) { + draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, g_WhiteColor, -1); + } else if (mode == g_DrawMOID) { + draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, m_MOID, -1); + } else if (mode == g_DrawNoMOID) { + draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, g_NoMOID, -1); + } else if (mode == g_DrawDoor) { + draw_character_ex(pTempBitmap, m_aSprite[m_Frame], 0, 0, g_MaterialDoor, -1); + } else { + RTEAbort("Unknown draw mode selected in MOSRotating::Draw()!"); + } + } #ifdef DRAW_MOID_LAYER - bool needsWrap = true; + bool needsWrap = true; #else - bool needsWrap = mode != g_DrawMOID; + bool needsWrap = mode != g_DrawMOID; #endif + // Take care of wrapping situations + Vector aDrawPos[4]; + int passes = 1; + + aDrawPos[0] = spritePos; + + if (needsWrap && g_SceneMan.SceneWrapsX()) { + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero() && m_WrapDoubleDraw) { + if (spritePos.m_X < m_SpriteDiameter) { + aDrawPos[passes] = spritePos; + aDrawPos[passes].m_X += pTargetBitmap->w; + passes++; + } else if (spritePos.m_X > pTargetBitmap->w - m_SpriteDiameter) { + aDrawPos[passes] = spritePos; + aDrawPos[passes].m_X -= pTargetBitmap->w; + passes++; + } + } else if (m_WrapDoubleDraw) { + // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam + if (targetPos.m_X < 0) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= g_SceneMan.GetSceneWidth(); + passes++; + } + if (targetPos.m_X + pTargetBitmap->w > g_SceneMan.GetSceneWidth()) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += g_SceneMan.GetSceneWidth(); + passes++; + } + } + } - // Take care of wrapping situations - Vector aDrawPos[4]; - int passes = 1; - - aDrawPos[0] = spritePos; - - if (needsWrap && g_SceneMan.SceneWrapsX()) { - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero() && m_WrapDoubleDraw) { - if (spritePos.m_X < m_SpriteDiameter) { - aDrawPos[passes] = spritePos; - aDrawPos[passes].m_X += pTargetBitmap->w; - passes++; - } else if (spritePos.m_X > pTargetBitmap->w - m_SpriteDiameter) { - aDrawPos[passes] = spritePos; - aDrawPos[passes].m_X -= pTargetBitmap->w; - passes++; - } - } else if (m_WrapDoubleDraw) { - // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam - if (targetPos.m_X < 0) { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= g_SceneMan.GetSceneWidth(); - passes++; - } - if (targetPos.m_X + pTargetBitmap->w > g_SceneMan.GetSceneWidth()) { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += g_SceneMan.GetSceneWidth(); - passes++; - } - } - } - - if (m_HFlipped && pFlipBitmap) { + if (m_HFlipped && pFlipBitmap) { #ifdef DRAW_MOID_LAYER - bool drawIntermediate = true; + bool drawIntermediate = true; #else - bool drawIntermediate = mode != g_DrawMOID; + bool drawIntermediate = mode != g_DrawMOID; #endif - if (drawIntermediate) { - // Don't size the intermediate bitmaps to the m_Scale, because the scaling happens after they are done - clear_to_color(pFlipBitmap, keyColor); + if (drawIntermediate) { + // Don't size the intermediate bitmaps to the m_Scale, because the scaling happens after they are done + clear_to_color(pFlipBitmap, keyColor); - // Draw either the source color bitmap or the intermediate material bitmap onto the intermediate flipping bitmap - if (mode == g_DrawColor || mode == g_DrawTrans) { - draw_sprite_h_flip(pFlipBitmap, m_aSprite[m_Frame], 0, 0); - } else { - // If using the temp bitmap (which is always larger than the sprite) make sure the flipped image ends up in the upper right corner as if it was just as small as the sprite bitmap - draw_sprite_h_flip(pFlipBitmap, pTempBitmap, -(pTempBitmap->w - m_aSprite[m_Frame]->w), 0); - } - } - - if (mode == g_DrawTrans) { - clear_to_color(pTempBitmap, keyColor); - - // Draw the rotated thing onto the intermediate bitmap so its COM position aligns with the middle of the temp bitmap. - // The temp bitmap should be able to hold the full size since it is larger than the max diameter. - // Take into account the h-flipped pivot point - pivot_scaled_sprite(pTempBitmap, pFlipBitmap, pTempBitmap->w / 2, pTempBitmap->h / 2, pFlipBitmap->w + m_SpriteOffset.m_X, -(m_SpriteOffset.m_Y), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); - - // Draw the now rotated object's temporary bitmap onto the final drawing bitmap with transperency - // Do the passes loop in here so the intermediate drawing doesn't get done multiple times - for (int i = 0; i < passes; ++i) { - int spriteX = aDrawPos[i].GetFloorIntX() - (pTempBitmap->w / 2); - int spriteY = aDrawPos[i].GetFloorIntY() - (pTempBitmap->h / 2); - g_SceneMan.RegisterDrawing(pTargetBitmap, g_NoMOID, spriteX, spriteY, spriteX + pTempBitmap->w, spriteY + pTempBitmap->h); - draw_trans_sprite(pTargetBitmap, pTempBitmap, spriteX, spriteY); - } - } else { - // Do the passes loop in here so the flipping operation doesn't get done multiple times - for (int i = 0; i < passes; ++i) { - int spriteX = aDrawPos[i].GetFloorIntX(); - int spriteY = aDrawPos[i].GetFloorIntY(); - g_SceneMan.RegisterDrawing(pTargetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, spriteX + m_SpriteOffset.m_X - (m_SpriteRadius * m_Scale), spriteY + m_SpriteOffset.m_Y - (m_SpriteRadius * m_Scale), spriteX - m_SpriteOffset.m_X + (m_SpriteRadius * m_Scale), spriteY - m_SpriteOffset.m_Y + (m_SpriteRadius * m_Scale)); + // Draw either the source color bitmap or the intermediate material bitmap onto the intermediate flipping bitmap + if (mode == g_DrawColor || mode == g_DrawTrans) { + draw_sprite_h_flip(pFlipBitmap, m_aSprite[m_Frame], 0, 0); + } else { + // If using the temp bitmap (which is always larger than the sprite) make sure the flipped image ends up in the upper right corner as if it was just as small as the sprite bitmap + draw_sprite_h_flip(pFlipBitmap, pTempBitmap, -(pTempBitmap->w - m_aSprite[m_Frame]->w), 0); + } + } + + if (mode == g_DrawTrans) { + clear_to_color(pTempBitmap, keyColor); + + // Draw the rotated thing onto the intermediate bitmap so its COM position aligns with the middle of the temp bitmap. + // The temp bitmap should be able to hold the full size since it is larger than the max diameter. + // Take into account the h-flipped pivot point + pivot_scaled_sprite(pTempBitmap, pFlipBitmap, pTempBitmap->w / 2, pTempBitmap->h / 2, pFlipBitmap->w + m_SpriteOffset.m_X, -(m_SpriteOffset.m_Y), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); + + // Draw the now rotated object's temporary bitmap onto the final drawing bitmap with transperency + // Do the passes loop in here so the intermediate drawing doesn't get done multiple times + for (int i = 0; i < passes; ++i) { + int spriteX = aDrawPos[i].GetFloorIntX() - (pTempBitmap->w / 2); + int spriteY = aDrawPos[i].GetFloorIntY() - (pTempBitmap->h / 2); + g_SceneMan.RegisterDrawing(pTargetBitmap, g_NoMOID, spriteX, spriteY, spriteX + pTempBitmap->w, spriteY + pTempBitmap->h); + draw_trans_sprite(pTargetBitmap, pTempBitmap, spriteX, spriteY); + } + } else { + // Do the passes loop in here so the flipping operation doesn't get done multiple times + for (int i = 0; i < passes; ++i) { + int spriteX = aDrawPos[i].GetFloorIntX(); + int spriteY = aDrawPos[i].GetFloorIntY(); + g_SceneMan.RegisterDrawing(pTargetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, spriteX + m_SpriteOffset.m_X - (m_SpriteRadius * m_Scale), spriteY + m_SpriteOffset.m_Y - (m_SpriteRadius * m_Scale), spriteX - m_SpriteOffset.m_X + (m_SpriteRadius * m_Scale), spriteY - m_SpriteOffset.m_Y + (m_SpriteRadius * m_Scale)); #ifndef DRAW_MOID_LAYER - if (mode == g_DrawMOID) { - continue; - } + if (mode == g_DrawMOID) { + continue; + } #endif - // Take into account the h-flipped pivot point - pivot_scaled_sprite(pTargetBitmap, pFlipBitmap, spriteX, spriteY, pFlipBitmap->w + m_SpriteOffset.GetFloorIntX(), -(m_SpriteOffset.GetFloorIntY()), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); - } - } - } else { - if (mode == g_DrawTrans) { - clear_to_color(pTempBitmap, keyColor); - - // Draw the rotated thing onto the intermediate bitmap so its COM position aligns with the middle of the temp bitmap. - // The temp bitmap should be able to hold the full size since it is larger than the max diameter. - // Take into account the h-flipped pivot point - pivot_scaled_sprite(pTempBitmap, m_aSprite[m_Frame], pTempBitmap->w / 2, pTempBitmap->h / 2, -m_SpriteOffset.GetFloorIntX(), -m_SpriteOffset.GetFloorIntY(), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); - - // Draw the now rotated object's temporary bitmap onto the final drawing bitmap with transperency - // Do the passes loop in here so the intermediate drawing doesn't get done multiple times - for (int i = 0; i < passes; ++i) { - int spriteX = aDrawPos[i].GetFloorIntX() - (pTempBitmap->w / 2); - int spriteY = aDrawPos[i].GetFloorIntY() - (pTempBitmap->h / 2); - g_SceneMan.RegisterDrawing(pTargetBitmap, g_NoMOID, spriteX, spriteY, spriteX + pTempBitmap->w, spriteY + pTempBitmap->h); - draw_trans_sprite(pTargetBitmap, pTempBitmap, spriteX, spriteY); - } - } else { - for (int i = 0; i < passes; ++i) { - int spriteX = aDrawPos[i].GetFloorIntX(); - int spriteY = aDrawPos[i].GetFloorIntY(); - g_SceneMan.RegisterDrawing(pTargetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, spriteX + m_SpriteOffset.m_X - (m_SpriteRadius * m_Scale), spriteY + m_SpriteOffset.m_Y - (m_SpriteRadius * m_Scale), spriteX - m_SpriteOffset.m_X + (m_SpriteRadius * m_Scale), spriteY - m_SpriteOffset.m_Y + (m_SpriteRadius * m_Scale)); + // Take into account the h-flipped pivot point + pivot_scaled_sprite(pTargetBitmap, pFlipBitmap, spriteX, spriteY, pFlipBitmap->w + m_SpriteOffset.GetFloorIntX(), -(m_SpriteOffset.GetFloorIntY()), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); + } + } + } else { + if (mode == g_DrawTrans) { + clear_to_color(pTempBitmap, keyColor); + + // Draw the rotated thing onto the intermediate bitmap so its COM position aligns with the middle of the temp bitmap. + // The temp bitmap should be able to hold the full size since it is larger than the max diameter. + // Take into account the h-flipped pivot point + pivot_scaled_sprite(pTempBitmap, m_aSprite[m_Frame], pTempBitmap->w / 2, pTempBitmap->h / 2, -m_SpriteOffset.GetFloorIntX(), -m_SpriteOffset.GetFloorIntY(), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); + + // Draw the now rotated object's temporary bitmap onto the final drawing bitmap with transperency + // Do the passes loop in here so the intermediate drawing doesn't get done multiple times + for (int i = 0; i < passes; ++i) { + int spriteX = aDrawPos[i].GetFloorIntX() - (pTempBitmap->w / 2); + int spriteY = aDrawPos[i].GetFloorIntY() - (pTempBitmap->h / 2); + g_SceneMan.RegisterDrawing(pTargetBitmap, g_NoMOID, spriteX, spriteY, spriteX + pTempBitmap->w, spriteY + pTempBitmap->h); + draw_trans_sprite(pTargetBitmap, pTempBitmap, spriteX, spriteY); + } + } else { + for (int i = 0; i < passes; ++i) { + int spriteX = aDrawPos[i].GetFloorIntX(); + int spriteY = aDrawPos[i].GetFloorIntY(); + g_SceneMan.RegisterDrawing(pTargetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, spriteX + m_SpriteOffset.m_X - (m_SpriteRadius * m_Scale), spriteY + m_SpriteOffset.m_Y - (m_SpriteRadius * m_Scale), spriteX - m_SpriteOffset.m_X + (m_SpriteRadius * m_Scale), spriteY - m_SpriteOffset.m_Y + (m_SpriteRadius * m_Scale)); #ifndef DRAW_MOID_LAYER - if (mode == g_DrawMOID) { - continue; - } + if (mode == g_DrawMOID) { + continue; + } #endif - pivot_scaled_sprite(pTargetBitmap, mode == g_DrawColor ? m_aSprite[m_Frame] : pTempBitmap, spriteX, spriteY, -m_SpriteOffset.GetFloorIntX(), -m_SpriteOffset.GetFloorIntY(), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); - } - } - } - - // Draw all the attached wound emitters, and only if the mode is g_DrawColor and not onlyphysical - // Only draw attachables and emitters which are not drawn after parent, so we draw them before - if (mode == g_DrawColor || (!onlyPhysical && mode == g_DrawMaterial)) { - for (const AEmitter *woundToDraw : m_Wounds) { - if (woundToDraw->IsDrawnAfterParent()) { woundToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); } - } - } - - // Draw all the attached attachables - for (const Attachable *attachableToDraw : m_Attachables) { - if (attachableToDraw->IsDrawnAfterParent() && attachableToDraw->IsDrawnNormallyByParent()) { attachableToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); } - } - - if (mode == g_DrawColor && !onlyPhysical && m_pAtomGroup && g_SettingsMan.DrawAtomGroupVisualizations() && GetRootParent() == this) { - m_pAtomGroup->Draw(pTargetBitmap, targetPos, false, 122); - //m_pDeepGroup->Draw(pTargetBitmap, targetPos, false, 13); - } -} - -bool MOSRotating::HandlePotentialRadiusAffectingAttachable(const Attachable *attachable) { - if (!attachable->IsAttachedTo(this) && !attachable->IsWound()) { - return false; - } - const HDFirearm *thisAsFirearm = dynamic_cast(this); - const AEmitter *thisAsEmitter = dynamic_cast(this); - if ((thisAsFirearm && attachable == thisAsFirearm->GetFlash()) || (thisAsEmitter && attachable == thisAsEmitter->GetFlash())) { - return false; - } - float distanceAndRadiusFromParent = g_SceneMan.ShortestDistance(m_Pos, attachable->m_Pos, g_SceneMan.SceneWrapsX()).GetMagnitude() + attachable->GetRadius(); - if (attachable == m_RadiusAffectingAttachable && distanceAndRadiusFromParent < m_FarthestAttachableDistanceAndRadius) { - m_FarthestAttachableDistanceAndRadius = distanceAndRadiusFromParent; - if (m_Attachables.size() > 1) { - std::for_each(m_Attachables.begin(), m_Attachables.end(), [this](Attachable *attachableToCheck) { attachableToCheck->UpdatePositionAndJointPositionBasedOnOffsets(); HandlePotentialRadiusAffectingAttachable(attachableToCheck); }); - } - return true; - } else if (distanceAndRadiusFromParent > m_FarthestAttachableDistanceAndRadius) { - m_FarthestAttachableDistanceAndRadius = distanceAndRadiusFromParent; - m_RadiusAffectingAttachable = attachable; - return true; - } - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MOSRotating::CorrectAttachableAndWoundPositionsAndRotations() const { - for (Attachable *attachable : m_Attachables) { - attachable->PreUpdate(); - attachable->m_PreUpdateHasRunThisFrame = false; - attachable->UpdatePositionAndJointPositionBasedOnOffsets(); - attachable->CorrectAttachableAndWoundPositionsAndRotations(); + pivot_scaled_sprite(pTargetBitmap, mode == g_DrawColor ? m_aSprite[m_Frame] : pTempBitmap, spriteX, spriteY, -m_SpriteOffset.GetFloorIntX(), -m_SpriteOffset.GetFloorIntY(), ftofix(m_Rotation.GetAllegroAngle()), ftofix(m_Scale)); + } + } + } + + // Draw all the attached wound emitters, and only if the mode is g_DrawColor and not onlyphysical + // Only draw attachables and emitters which are not drawn after parent, so we draw them before + if (mode == g_DrawColor || (!onlyPhysical && mode == g_DrawMaterial)) { + for (const AEmitter* woundToDraw: m_Wounds) { + if (woundToDraw->IsDrawnAfterParent()) { + woundToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } + } + } + + // Draw all the attached attachables + for (const Attachable* attachableToDraw: m_Attachables) { + if (attachableToDraw->IsDrawnAfterParent() && attachableToDraw->IsDrawnNormallyByParent()) { + attachableToDraw->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } + } + + if (mode == g_DrawColor && !onlyPhysical && m_pAtomGroup && g_SettingsMan.DrawAtomGroupVisualizations() && GetRootParent() == this) { + m_pAtomGroup->Draw(pTargetBitmap, targetPos, false, 122); + // m_pDeepGroup->Draw(pTargetBitmap, targetPos, false, 13); + } } - for (Attachable *wound : m_Wounds) { - wound->PreUpdate(); - wound->m_PreUpdateHasRunThisFrame = false; - wound->UpdatePositionAndJointPositionBasedOnOffsets(); - wound->CorrectAttachableAndWoundPositionsAndRotations(); + + bool MOSRotating::HandlePotentialRadiusAffectingAttachable(const Attachable* attachable) { + if (!attachable->IsAttachedTo(this) && !attachable->IsWound()) { + return false; + } + const HDFirearm* thisAsFirearm = dynamic_cast(this); + const AEmitter* thisAsEmitter = dynamic_cast(this); + if ((thisAsFirearm && attachable == thisAsFirearm->GetFlash()) || (thisAsEmitter && attachable == thisAsEmitter->GetFlash())) { + return false; + } + float distanceAndRadiusFromParent = g_SceneMan.ShortestDistance(m_Pos, attachable->m_Pos, g_SceneMan.SceneWrapsX()).GetMagnitude() + attachable->GetRadius(); + if (attachable == m_RadiusAffectingAttachable && distanceAndRadiusFromParent < m_FarthestAttachableDistanceAndRadius) { + m_FarthestAttachableDistanceAndRadius = distanceAndRadiusFromParent; + if (m_Attachables.size() > 1) { + std::for_each(m_Attachables.begin(), m_Attachables.end(), [this](Attachable* attachableToCheck) { attachableToCheck->UpdatePositionAndJointPositionBasedOnOffsets(); HandlePotentialRadiusAffectingAttachable(attachableToCheck); }); + } + return true; + } else if (distanceAndRadiusFromParent > m_FarthestAttachableDistanceAndRadius) { + m_FarthestAttachableDistanceAndRadius = distanceAndRadiusFromParent; + m_RadiusAffectingAttachable = attachable; + return true; + } + return false; } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MOSRotating::OnSave() { - for (AEmitter *wound : m_Wounds) { - wound->OnSave(); + void MOSRotating::CorrectAttachableAndWoundPositionsAndRotations() const { + for (Attachable* attachable: m_Attachables) { + attachable->PreUpdate(); + attachable->m_PreUpdateHasRunThisFrame = false; + attachable->UpdatePositionAndJointPositionBasedOnOffsets(); + attachable->CorrectAttachableAndWoundPositionsAndRotations(); + } + for (Attachable* wound: m_Wounds) { + wound->PreUpdate(); + wound->m_PreUpdateHasRunThisFrame = false; + wound->UpdatePositionAndJointPositionBasedOnOffsets(); + wound->CorrectAttachableAndWoundPositionsAndRotations(); + } } - for (Attachable *attachable : m_Attachables) { - attachable->OnSave(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MOSRotating::OnSave() { + for (AEmitter* wound: m_Wounds) { + wound->OnSave(); + } + for (Attachable* attachable: m_Attachables) { + attachable->OnSave(); + } + MovableObject::OnSave(); } - MovableObject::OnSave(); -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MOSRotating::TransferForcesFromAttachable(Attachable *attachable) { - bool intact = false; - Vector forces; - Vector impulses; - intact = attachable->TransferJointForces(forces) && attachable->TransferJointImpulses(impulses); + bool MOSRotating::TransferForcesFromAttachable(Attachable* attachable) { + bool intact = false; + Vector forces; + Vector impulses; + intact = attachable->TransferJointForces(forces) && attachable->TransferJointImpulses(impulses); - if (!forces.IsZero()) { AddForce(forces, attachable->GetApplyTransferredForcesAtOffset() ? attachable->GetParentOffset() * m_Rotation * c_MPP : Vector()); } - if (!impulses.IsZero()) { AddImpulseForce(impulses, attachable->GetApplyTransferredForcesAtOffset() ? attachable->GetParentOffset() * m_Rotation * c_MPP : Vector()); } - return intact; -} + if (!forces.IsZero()) { + AddForce(forces, attachable->GetApplyTransferredForcesAtOffset() ? attachable->GetParentOffset() * m_Rotation * c_MPP : Vector()); + } + if (!impulses.IsZero()) { + AddImpulseForce(impulses, attachable->GetApplyTransferredForcesAtOffset() ? attachable->GetParentOffset() * m_Rotation * c_MPP : Vector()); + } + return intact; + } } // namespace RTE diff --git a/Source/Entities/MOSRotating.h b/Source/Entities/MOSRotating.h index 6d98f0061..eb900ae0e 100644 --- a/Source/Entities/MOSRotating.h +++ b/Source/Entities/MOSRotating.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,965 +18,927 @@ #include "PostProcessMan.h" #include "SoundContainer.h" -namespace RTE -{ - -class AtomGroup; -struct HitData; -class AEmitter; -class Attachable; - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: MOSRotating -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A sprite movable object that can rotate. -// Parent(s): MOSprite. -// Class history: 05/30/2002 MOSRotating created. - -class MOSRotating : public MOSprite { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -friend class AtomGroup; -friend class SLTerrain; -friend struct EntityLuaBindings; - - -// Concrete allocation and cloning definitions -EntityAllocation(MOSRotating); -SerializableOverrideMethods; -ClassInfoGetters; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MOSRotating -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a MOSRotating object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - MOSRotating() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~MOSRotating -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a MOSRotating object before deletion -// from system memory. -// Arguments: None. - - ~MOSRotating() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSRotating object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSRotating object ready for use. -// Arguments: A pointer to ContentFile that represents the bitmap file that will be -// used to create the Sprite. -// The number of frames in the Sprite's animation. -// A float specifying the object's mass in Kilograms (kg). -// A Vector specifying the initial position. -// A Vector specifying the initial velocity. -// The amount of time in ms this MovableObject will exist. 0 means unlim. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(ContentFile spriteFile, const int frameCount = 1, const float mass = 1, const Vector &position = Vector(0, 0), const Vector &velocity = Vector(0, 0), const unsigned long lifetime = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOSRotating to be identical to another, by deep copy. -// Arguments: A reference to the MOSRotating to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const MOSRotating &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire MOSRotating, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); MOSprite::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - /// - /// Gets the radius of this MOSRotating, not including any Attachables. - /// - /// - float GetIndividualRadius() const { return m_SpriteRadius; } - - /// - /// Gets the radius of this MOSRotating, including any Attachables. - /// - /// The radius of this MOSRotating, including any Attachables. - float GetRadius() const override { return std::max(m_SpriteRadius, m_FarthestAttachableDistanceAndRadius); } - - /// - /// Gets the diameter of this MOSRotating, not including any Attachables. - /// - /// - float GetIndividualDiameter() const { return m_SpriteDiameter; } - - /// - /// Gets the diameter of this MOSRotating, including any Attachables. - /// - /// The diameter of this MOSRotating, including any Attachables. - float GetDiameter() const override { return GetRadius() * 2.0F; } - - /// - /// Checks if the given Attachable should affect radius, and handles it if it should. - /// - /// The Attachable to check. - /// Whether the radius affecting Attachable changed as a result of this call. - virtual bool HandlePotentialRadiusAffectingAttachable(const Attachable *attachable); - - /// - /// Gets the mass value of this MOSRotating, not including any Attachables or wounds. - /// - /// The mass of this MOSRotating. - float GetIndividualMass() const { return MovableObject::GetMass(); } - - /// - /// Gets the mass value of this MOSRotating, including the mass of all its Attachables and wounds, and their Attachables and so on. - /// - /// The mass of this MOSRotating and all of its Attachables and wounds in Kilograms (kg). - float GetMass() const override { return MovableObject::GetMass() + m_AttachableAndWoundMass; } - - /// - /// Updates the total mass of Attachables and wounds for this MOSRotating, intended to be used when Attachables' masses get modified. Simply subtracts the old mass and adds the new one. - /// - /// The mass the Attachable or wound had before its mass was modified. - /// The up-to-date mass of the Attachable or wound after its mass was modified. - virtual void UpdateAttachableAndWoundMass(float oldAttachableOrWoundMass, float newAttachableOrWoundMass) { m_AttachableAndWoundMass += newAttachableOrWoundMass - oldAttachableOrWoundMass; } - - /// - /// Gets the MOIDs of this MOSRotating and all its Attachables and Wounds, putting them into the MOIDs vector. - /// - /// The vector that will store all the MOIDs of this MOSRotating. - void GetMOIDs(std::vector &MOIDs) const override; - - /// - /// Sets the MOID of this MOSRotating and any Attachables on it to be g_NoMOID (255) for this frame. - /// - void SetAsNoID() override; - - /// - /// Sets this MOSRotating to not hit a specific other MO and all its children even though MO hitting is enabled on this MOSRotating. - /// - /// A pointer to the MO to not be hitting. Null pointer means don't ignore anything. Ownership is NOT transferred! - /// How long, in seconds, to ignore the specified MO. A negative number means forever. - void SetWhichMOToNotHit(MovableObject *moToNotHit = nullptr, float forHowLong = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAtomGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current AtomGroup of this MOSRotating. -// Arguments: None. -// Return value: A const reference to the current AtomGroup. - - AtomGroup * GetAtomGroup() { return m_pAtomGroup; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMaterial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the main Material of this MOSRotating. -// Arguments: None. -// Return value: The the Material of this MOSRotating. - - Material const * GetMaterial() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetDrawPriority -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the drawing priority of this MovableObject, if two things were -// overlap when copying to the terrain, the higher priority MO would -// end up getting drawn. -// Arguments: None. -// Return value: The the priority of this MovableObject. Higher number, the higher -// priority. - - int GetDrawPriority() const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRecoilForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current recoil impulse force Vector of this MOSprite. -// Arguments: None. -// Return value: A const reference to the current recoil impulse force in kg * m/s. - - const Vector & GetRecoilForce() const { return m_RecoilForce; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRecoilOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current recoil offset Vector of this MOSprite. -// Arguments: None. -// Return value: A const reference to the current recoil offset. - - const Vector & GetRecoilOffset() const { return m_RecoilOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGibList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets direct access to the list of object this is to generate upon gibbing. -// Arguments: None. -// Return value: A pointer to the list of gibs. Ownership is NOT transferred! - - std::list * GetGibList() { return &m_Gibs; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddRecoil -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds graphical recoil offset to this MOSprite according to its angle. -// Arguments: None. -// Return value: None. - - void AddRecoil(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetRecoil -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds recoil offset to this MOSprite. -// Arguments: A vector with the recoil impulse force in kg * m/s. -// A vector with the recoil offset in pixels. -// Whether recoil should be activated or not for the next Draw(). -// Return value: None. - - void SetRecoil(const Vector &force, const Vector &offset, bool recoil = true) - { - m_RecoilForce = force; - m_RecoilOffset = offset; - m_Recoiled = recoil; - } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsRecoiled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether this MOSprite is currently under the effects of -// recoil. -// Arguments: None. -// Return value: None. - - bool IsRecoiled() { return m_Recoiled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnableDeepCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether or not this MOSRotating should check for deep penetrations -// the terrain or not. -// Arguments: Whether to enable deep penetration checking or not. -// Return value: None. - - void EnableDeepCheck(const bool enable = true) { m_DeepCheck = enable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ForceDeepCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets to force a deep checking of this' silhouette against the terrain -// and create an outline hole in the terrain, generating particles of the -// intersecting pixels in the terrain. -// Arguments: Whether to force a deep penetration check for this sim frame or not.. -// Return value: None. - - void ForceDeepCheck(const bool enable = true) { m_ForceDeepCheck = enable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. -// Arguments: Reference to the HitData struct which describes the collision. This -// will be modified to represent the results of the collision. -// Return value: Whether the collision has been deemed valid. If false, then disregard -// any impulses in the Hitdata. - - bool CollideAtPoint(HitData &hitData) override; - - - /// - /// Defines what should happen when this MovableObject hits and then bounces off of something. - /// This is called by the owned Atom/AtomGroup of this MovableObject during travel. - /// - /// The HitData describing the collision in detail. - /// Whether the MovableObject should immediately halt any travel going on after this bounce. - bool OnBounce(HitData &hd) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: OnSink -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// sink into something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. -// Arguments: The HitData describing the collision in detail. -// Return value: Wheter the MovableObject should immediately halt any travel going on -// after this sinkage. - - bool OnSink(HitData &hd) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ParticlePenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Determines whether a particle which has hit this MO will penetrate, -// and if so, whether it gets lodged or exits on the other side of this -// MO. Appropriate effects will be determined and applied ONLY IF there -// was penetration! If not, nothing will be affected. -// Arguments: The HitData describing the collision in detail, the impulses have to -// have been filled out! -// Return value: Whether the particle managed to penetrate into this MO or not. If -// somehting but a MOPixel or MOSParticle is being passed in as hitor, -// false will trivially be returned here. - - virtual bool ParticlePenetration(HitData &hd); - - - /// - /// Destroys this MOSRotating and creates its specified Gibs in its place with appropriate velocities. Any Attachables are removed and also given appropriate velocities. - /// - /// The impulse (kg * m/s) of the impact causing the gibbing to happen. - /// A pointer to an MO which the Gibs and Attachables should not be colliding with. - virtual void GibThis(const Vector &impactImpulse = Vector(), MovableObject *movableObjectToIgnore = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: MoveOutOfTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether any of the Atom:s in this MovableObject are on top of -// terrain pixels, and if so, attempt to move this out so none of this' -// Atoms are on top of the terrain any more. -// Arguments: Only consider materials stronger than this in the terrain for -// intersections. -// Return value: Whether any intersection was successfully resolved. Will return true -// even if there wasn't any intersections to begin with. - - bool MoveOutOfTerrain(unsigned char strongerThan = g_MaterialAir) override; - - /// - /// Gathers, clears and applies this MOSRotating's accumulated forces. - /// - void ApplyForces() override; - - /// - /// Gathers, clears and applies this MOSRotating's accumulated impulse forces, gibbing if appropriate. - /// - void ApplyImpulses() override; - - /// - /// Gets the list of Attachables on this MOSRotating. - /// - /// The list of Attachables on this MOSRotating. - const std::list & GetAttachables() const { return m_Attachables; } - - /// - /// Gets whether or not the given Attachable is a hardcoded Attachable (e.g. an Arm, Leg, Turret, etc.) - /// - /// The Attachable to check. - /// Whether or not the Attachable is hardcoded. - bool AttachableIsHardcoded(const Attachable *attachableToCheck) const; - - /// - /// Adds the passed in Attachable the list of Attachables and sets its parent to this MOSRotating. - /// - /// The Attachable to add. - virtual void AddAttachable(Attachable *attachable); - - /// - /// Adds the passed in Attachable the list of Attachables, changes its parent offset to the passed in Vector, and sets its parent to this MOSRotating. - /// - /// The Attachable to add. - /// The Vector to set as the Attachable's parent offset. - virtual void AddAttachable(Attachable *attachable, const Vector &parentOffsetToSet); - - /// - /// Removes the Attachable corresponding to the passed in UniqueID and sets its parent to nullptr. Does not add it to MovableMan or add break wounds. - /// - /// The UniqueID of the Attachable to remove. - /// A pointer to the removed Attachable. Ownership IS transferred! - virtual Attachable * RemoveAttachable(long attachableUniqueID) { return RemoveAttachable(attachableUniqueID, false, false); } - - /// - /// Removes the Attachable corresponding to the passed in UniqueID and sets its parent to nullptr. Optionally adds it to MovableMan and/or adds break wounds. - /// If the Attachable is not set to delete or delete when removed from its parent, and addToMovableMan is false, the caller must hang onto a pointer to the Attachable ahead of time to avoid memory leaks. - /// - /// The UniqueID of the Attachable to remove. - /// Whether or not to add the Attachable to MovableMan once it has been removed. - /// Whether or not to add break wounds to the removed Attachable and this MOSRotating. - /// A pointer to the removed Attachable, if it wasn't added to MovableMan or nullptr if it was. Ownership IS transferred! - virtual Attachable * RemoveAttachable(long attachableUniqueID, bool addToMovableMan, bool addBreakWounds); - - /// - /// Removes the passed in Attachable and sets its parent to nullptr. Does not add it to MovableMan or add break wounds. - /// - /// The Attachable to remove. - /// A pointer to the removed Attachable. Ownership IS transferred! - virtual Attachable * RemoveAttachable(Attachable *attachable) { return RemoveAttachable(attachable, false, false); } - - /// - /// Removes the passed in Attachable and sets its parent to nullptr. Optionally adds it to MovableMan and/or adds break wounds. - /// If the Attachable is not set to delete or delete when removed from its parent, and addToMovableMan is false, the caller must hang onto a pointer to the Attachable ahead of time to avoid memory leaks. - /// - /// The Attachable to remove. - /// Whether or not to add the Attachable to MovableMan once it has been removed. - /// Whether or not to add break wounds to the removed Attachable and this MOSRotating. - /// A pointer to the removed Attachable, if it wasn't added to MovableMan or nullptr if it was. Ownership IS transferred! - virtual Attachable * RemoveAttachable(Attachable *attachable, bool addToMovableMan, bool addBreakWounds); - - /// - /// Removes the passed in Attachable, and sets it to delete so it will go straight to MovableMan and be handled there. - /// - /// The Attacahble to remove and delete. - void RemoveAndDeleteAttachable(Attachable *attachable); - - /// - /// Either removes or deletes all of this MOSRotating's Attachables. - /// - /// Whether to remove or delete the Attachables. Setting this to true deletes them, setting it to false removes them. - void RemoveOrDestroyAllAttachables(bool destroy); - - /// - /// Gets a damage-transferring, impulse-vulnerable Attachable nearest to the passed in offset. - /// - /// The offset that will be compared to each Attachable's ParentOffset. - /// The nearest detachable Attachable, or nullptr if none was found. - Attachable * GetNearestDetachableAttachableToOffset(const Vector &offset) const; - - /// - /// Gibs or detaches any Attachables that would normally gib or detach from the passed in impulses. - /// - /// The impulse vector which determines the Attachables to gib or detach. Will be filled out with the remainder of impulses. - void DetachAttachablesFromImpulse(Vector &impulseVector); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ResetAllTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resest all the timers used by this. Can be emitters, etc. This is to -// prevent backed up emissions to come out all at once while this has been -// held dormant in an inventory. -// Arguments: None. -// Return value: None. - - void ResetAllTimers() override; - - /// - /// Does the calculations necessary to detect whether this MOSRotating is at rest or not. IsAtRest() retrieves the answer. - /// - void RestDetection() override; - - /// - /// Indicates whether this MOSRotating has been at rest with no movement for longer than its RestThreshold. - /// - bool IsAtRest() override; - - /// - /// Indicates whether this MOSRotating's current graphical representation, including its Attachables, overlaps a point in absolute scene coordinates. - /// - /// The point in absolute scene coordinates to check for overlap with. - /// Whether or not this MOSRotating's graphical representation overlaps the given scene point. - bool IsOnScenePoint(Vector &scenePoint) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: EraseFromTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Cuts this' silhouette out from the terrain's material and color layers. -// Arguments: None. -// Return value: None. - - void EraseFromTerrain(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DeepCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if any of this' deep group atmos are on top of the terrain, and -// if so, erases this' silhouette from the terrain. -// Arguments: Whether to make any MOPixels from erased terrain pixels at all. -// The size of the gaps between MOPixels knocked loose by the terrain erasure. -// The max number of MOPixel:s to generate as dislodged particles from the -// erased terrain. -// Return value: Whether deep penetration was detected and erasure was done. - - bool DeepCheck(bool makeMOPs = true, int skipMOP = 2, int maxMOP = 100); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done before Travel(). Always call before -// calling Travel. -// Arguments: None. -// Return value: None. - - void PreTravel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Travel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Travels this MOSRotatin, using its physical representation. -// Arguments: None. -// Return value: None. - - void Travel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PostTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done after Update(). Always call after -// calling Update. -// Arguments: None. -// Return value: None. - - void PostTravel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - void PostUpdate() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawMOIDIfOverlapping -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the MOID representation of this to the SceneMan's MOID layer if -// this is found to potentially overlap another MovableObject. -// Arguments: The MovableObject to check this for overlap against. -// Return value: Whether it was drawn or not. - - bool DrawMOIDIfOverlapping(MovableObject *pOverlapMO) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MOSRotating's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - - /// - /// Gets the gib impulse limit for this MOSRotating, i.e. the amount of impulse force required in a frame to gib this MOSRotating. - /// - /// The gib impulse limit of this MOSRotating. - float GetGibImpulseLimit() const { return m_GibImpulseLimit; } - - /// - /// Sets the gib impulse limit for this MOSRotating, i.e. the amount of impulse force required in a frame to gib this MOSRotating. - /// - /// The new gib impulse limit to use. - void SetGibImpulseLimit(float newGibImpulseLimit) { m_GibImpulseLimit = newGibImpulseLimit; } - - /// - /// Gets the gib wound limit for this MOSRotating, i.e. the total number of wounds required to gib this MOSRotating. Does not include any Attachables. - /// - /// - int GetGibWoundLimit() const { return GetGibWoundLimit(false, false, false); } - - /// - /// Gets the gib wound limit for this MOSRotating, i.e. the total number of wounds required to gib this MOSRotating. - /// Optionally adds the gib wound limits of Attachables (and their Attachables, etc.) that match the conditions set by the provided parameters. - /// - /// Whether to count wounds from Attachables that have a positive damage multiplier, i.e. those that damage their parent (this MOSRotating) when wounded. - /// Whether to count wounds from Attachables that have a negative damage multiplier, i.e. those that heal their parent (this MOSRotating) when wounded. - /// Whether to count wounds from Attachables that a zero damage multiplier, i.e. those that do not affect their parent (this MOSRotating) when wounded. - /// The wound limit of this MOSRotating and, optionally, its Attachables. - int GetGibWoundLimit(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const; - - /// - /// Sets the gib wound limit for this MOSRotating, i.e. the total number of wounds required to gib this MOSRotating. - /// This will not directly trigger gibbing, even if the limit is lower than the current number of wounds. - /// - /// The new gib wound limit to use. - void SetGibWoundLimit(int newGibWoundLimit) { m_GibWoundLimit = newGibWoundLimit; } - - /// - /// Gets the rate at which wound count of this MOSRotating will diminish the impulse limit. - /// - /// The rate at which wound count affects the impulse limit. - float GetWoundCountAffectsImpulseLimitRatio() const { return m_WoundCountAffectsImpulseLimitRatio; } - - /// - /// Gets whether this MOSRotating should gib at the end of its lifetime instead of just being deleted. - /// - /// Whether this MOSRotating should gib at the end of its lifetime instead of just being deleted. - bool GetGibAtEndOfLifetime() const { return m_GibAtEndOfLifetime; } - - /// - /// Sets whether this MOSRotating should gib at the end of its lifetime instead of just being deleted. - /// - /// Whether or not this MOSRotating should gib at the end of its lifetime instead of just being deleted. - void SetGibAtEndOfLifetime(bool shouldGibAtEndOfLifetime) { m_GibAtEndOfLifetime = shouldGibAtEndOfLifetime; } - - /// - /// Gets the gib blast strength this MOSRotating, i.e. the strength with which Gibs and Attachables will be launched when this MOSRotating is gibbed. - /// - /// The gib blast strength of this MOSRotating. - float GetGibBlastStrength() const { return m_GibBlastStrength; } - - /// - /// Sets the gib blast strength this MOSRotating, i.e. the strength with which Gibs and Attachables will be launched when this MOSRotating is gibbed. - /// - /// The new gib blast strength to use. - void SetGibBlastStrength(float newGibBlastStrength) { m_GibBlastStrength = newGibBlastStrength; } - - /// - /// Gets the amount of screenshake this will cause upon gibbing. - /// - /// The amount of screenshake this will cause when gibbing. If -1, this is calculated automatically. - float GetGibScreenShakeAmount() const { return m_GibScreenShakeAmount; } - - /// - /// Gets a const reference to the list of Attachables on this MOSRotating. - /// - /// A const reference to the list of Attachables on this MOSRotating. - const std::list & GetAttachableList() const { return m_Attachables; } - - /// - /// Gets a const reference to the list of wounds on this MOSRotating. - /// - /// A const reference to the list of wounds on this MOSRotating. - const std::vector & GetWoundList() const { return m_Wounds; } - - /// - /// Gets the number of wounds attached to this MOSRotating. - /// Includes any Attachables (and their Attachables, etc.) that have a positive damage multiplier. - /// The number of wounds on this MOSRotating. - /// - int GetWoundCount() const { return GetWoundCount(true, false, false); } - - /// - /// Gets the number of wounds attached to this MOSRotating. - /// Optionally adds the wound counts of Attachables (and their Attachables, etc.) that match the conditions set by the provided parameters. - /// Whether to count wounds from Attachables that have a positive damage multiplier, i.e. those that damage their parent (this MOSRotating) when wounded. - /// Whether to count wounds from Attachables that have a negative damage multiplier, i.e. those that heal their parent (this MOSRotating) when wounded. - /// Whether to count wounds from Attachables that a zero damage multiplier, i.e. those that do not affect their parent (this MOSRotating) when wounded. - /// The number of wounds on this MOSRotating and, optionally, its Attachables. - /// - int GetWoundCount(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const; - - /// - /// Adds the passed in wound AEmitter to the list of wounds and changes its parent offset to the passed in Vector. - /// - /// The wound AEmitter to add. - /// The vector to set as the wound AEmitter's parent offset. - /// Whether to gib this MOSRotating if adding this wound raises its wound count past its gib wound limit. Defaults to true. - virtual void AddWound(AEmitter *woundToAdd, const Vector &parentOffsetToSet, bool checkGibWoundLimit = true); - - /// - /// Removes the specified number of wounds from this MOSRotating, and returns damage caused by these removed wounds. - /// Includes any Attachables (and their Attachables, etc.) that have a positive damage multiplier. - /// - /// The number of wounds that should be removed. - /// The amount of damage caused by these wounds, taking damage multipliers into account. - virtual float RemoveWounds(int numberOfWoundsToRemove) { return RemoveWounds(numberOfWoundsToRemove, true, false, false); } - - /// - /// Removes the specified number of wounds from this MOSRotating, and returns damage caused by these removed wounds. - /// Optionally removes wounds from Attachables (and their Attachables, etc.) that match the conditions set by the provided inclusion parameters. - /// - /// The number of wounds that should be removed. - /// Whether to count wounds from Attachables that have a positive damage multiplier, i.e. those that damage their parent (this MOSRotating) when wounded. - /// Whether to count wounds from Attachables that have a negative damage multiplier, i.e. those that heal their parent (this MOSRotating) when wounded. - /// Whether to count wounds from Attachables that a zero damage multiplier, i.e. those that do not affect their parent (this MOSRotating) when wounded. - /// The amount of damage caused by these wounds, taking damage multipliers into account. - virtual float RemoveWounds(int numberOfWoundsToRemove, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables); - - /// - /// Cleans up and destroys the script state of this object, calling the Destroy callback in lua - /// - void DestroyScriptState(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDamageMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets damage multiplier of this attachable. -// Arguments: New multiplier value. -// Return value: None. - - void SetDamageMultiplier(float newValue) { m_DamageMultiplier = newValue; m_NoSetDamageMultiplier = false; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDamageMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns damage multiplier of this attachable. -// Arguments: None. -// Return value: Current multiplier value. - - float GetDamageMultiplier() const { return m_DamageMultiplier; } - - /// - /// Gets whether the damage multiplier for this MOSRotating has been directly set, or is at its default value. - /// - /// Whether the damage multiplier for this MOSRotating has been set. - bool HasNoSetDamageMultiplier() const { return m_NoSetDamageMultiplier; } - - /// - /// Gets the velocity orientation scalar of this MOSRotating. - /// - /// New scalar value. - float GetOrientToVel() const { return m_OrientToVel; } - - /// - /// Sets the velocity orientation scalar of this MOSRotating. - /// - /// New scalar value. - void SetOrientToVel(float newValue) { m_OrientToVel = newValue; } - - /// - /// Sets this MOSRotating and all its children to drawn white for a specified amount of time. - /// - /// Duration of flash in real time MS. - void FlashWhite(int durationMS = 32) { m_FlashWhiteTimer.SetRealTimeLimitMS(durationMS); m_FlashWhiteTimer.Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTravelImpulse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Retrurns the amount of impulse force exerted on this during the last frame. -// Arguments: None. -// Return value: The amount of impulse force exerted on this during the last frame. - - Vector GetTravelImpulse() const { return m_TravelImpulse; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTravelImpulse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the amount of impulse force exerted on this during the last frame. -// Arguments: New impulse value -// Return value: None. - - void SetTravelImpulse(Vector impulse) { m_TravelImpulse = impulse; } - - /// - /// Gets this MOSRotating's gib sound. Ownership is NOT transferred! - /// - /// The SoundContainer for this MOSRotating's gib sound. - SoundContainer * GetGibSound() const { return m_GibSound; } - - /// - /// Sets this MOSRotating's gib sound. Ownership IS transferred! - /// - /// The new SoundContainer for this MOSRotating's gib sound. - void SetGibSound(SoundContainer *newSound) { m_GibSound = newSound; } - - /// - /// Ensures all attachables and wounds are positioned and rotated correctly. Must be run when this MOSRotating is added to MovableMan to avoid issues with Attachables spawning in at (0, 0). - /// - virtual void CorrectAttachableAndWoundPositionsAndRotations() const; - - /// - /// Method to be run when the game is saved via ActivityMan::SaveCurrentGame. Not currently used in metagame or editor saving. - /// - void OnSave() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Transfers forces and impulse forces from the given Attachable to this MOSRotating, gibbing and/or removing the Attachable if needed. - /// - /// A pointer to the Attachable to apply forces from. Ownership is NOT transferred! - /// Whether or not the Attachable has been removed, in which case it'll usually be passed to MovableMan. - bool TransferForcesFromAttachable(Attachable *attachable); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateChildMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this MO register itself and all its attached children in the -// MOID register and get ID:s for itself and its children for this frame. -// Arguments: The MOID index to register itself and its children in. -// The MOID of the root MO of this MO, ie the highest parent of this MO. -// 0 means that this MO is the root, ie it is owned by MovableMan. -// Whether this MO should make a new MOID to use for itself, or to use -// the same as the last one in the index (presumably its parent), -// Return value: None. - - void UpdateChildMOIDs(std::vector &MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true) override; - - /// - /// Creates the particles specified by this MOSRotating's list of Gibs and adds them to MovableMan with appropriately randomized velocities, based on this MOSRotating's gib blast strength. - /// - /// The impulse (kg * m/s) of the impact that caused the gibbing to happen. - /// A pointer to an MO which the Attachables should not be colliding with. - void CreateGibsWhenGibbing(const Vector &impactImpulse, MovableObject *movableObjectToIgnore); - - /// - /// Removes all Attachables from this MOSR, deleting them or adding them to MovableMan as appropriate, and giving them randomized velocities based on their properties and this MOSRotating's gib blast strength. - /// - /// The impulse (kg * m/s) of the impact that caused the gibbing to happen. - /// A pointer to an MO which the Attachables should not be colliding with. - void RemoveAttachablesWhenGibbing(const Vector &impactImpulse, MovableObject *movableObjectToIgnore); - - // Member variables - static Entity::ClassInfo m_sClass; -// float m_Torque; // In kg * r/s^2 (Newtons). -// float m_ImpulseTorque; // In kg * r/s. - // The group of Atom:s that will be the physical reperesentation of this MOSRotating. - AtomGroup *m_pAtomGroup; - // The group of Atom:s that will serve as a means to detect deep terrain penetration. - AtomGroup *m_pDeepGroup; - // Whether or not to check for deep penetrations. - bool m_DeepCheck; - // A trigger for forcing a deep check to happen - bool m_ForceDeepCheck; - // Whether deep penetration happaned in the last frame or not, and how hard it was. - float m_DeepHardness; - // The amount of impulse force exerted on this during the last frame. - Vector m_TravelImpulse; - // The precomupted center location of the sprite relative to the MovableObject::m_Pos. - Vector m_SpriteCenter; - // How much to orient the rotation of this to match the velocity vector each frame 0 = none, 1.0 = immediately align with vel vector - float m_OrientToVel; - // Whether the SpriteMO is currently pushed back by recoil or not. - bool m_Recoiled; - // The impulse force in kg * m/s that represents the recoil. - Vector m_RecoilForce; - // The vector that the recoil offsets the sprite when m_Recoiled is true. - Vector m_RecoilOffset; - // The list of wound AEmitters currently attached to this MOSRotating, and owned here as well. - std::vector m_Wounds; - // The list of Attachables currently attached and Owned by this. - std::list m_Attachables; - std::unordered_set m_ReferenceHardcodedAttachableUniqueIDs; //!< An unordered set is filled with the Unique IDs of all of the reference object's hardcoded Attachables when using the copy Create. - std::unordered_map> m_HardcodedAttachableUniqueIDsAndSetters; //!< An unordered map of Unique IDs to setter lambda functions, used to call the appropriate hardcoded Attachable setter when a hardcoded Attachable is removed. - std::unordered_map> m_HardcodedAttachableUniqueIDsAndRemovers; //!< An unordered map of Unique IDs to remove lambda functions, used to call the appropriate hardcoded Attachable remover when a hardcoded Attachable is removed and calling the setter with nullptr won't work. - const Attachable *m_RadiusAffectingAttachable; //!< A pointer to the Attachable that is currently affecting the radius. Used for some efficiency benefits. - float m_FarthestAttachableDistanceAndRadius; //!< The distance + radius of the radius affecting Attachable. - float m_AttachableAndWoundMass; //!< The mass of all Attachables and wounds on this MOSRotating. Used in combination with its actual mass and any other affecting factors to get its total mass. - // The list of Gib:s this will create when gibbed - std::list m_Gibs; - // The amount of impulse force required to gib this, in kg * (m/s). 0 means no limit - float m_GibImpulseLimit; - int m_GibWoundLimit; //!< The number of wounds that will gib this MOSRotating. 0 means that it can't be gibbed via wounds. - float m_GibBlastStrength; //!< The strength with which Gibs and Attachables will get launched when this MOSRotating is gibbed. - float m_GibScreenShakeAmount; //!< Determines how much screenshake this causes upon gibbing. - float m_WoundCountAffectsImpulseLimitRatio; //!< The rate at which this MOSRotating's wound count will diminish the impulse limit. - bool m_DetachAttachablesBeforeGibbingFromWounds; //!< Whether to detach any Attachables of this MOSRotating when it should gib from hitting its wound limit, instead of gibbing the MOSRotating itself. - bool m_GibAtEndOfLifetime; //!< Whether or not this MOSRotating should gib when it reaches the end of its lifetime, instead of just deleting. - // Gib sound effect - SoundContainer *m_GibSound; - // Whether to flash effect on gib - bool m_EffectOnGib; - // How far this is audiable (in screens) when gibbing - float m_LoudnessOnGib; - - float m_DamageMultiplier; //!< Damage multiplier for this MOSRotating. - bool m_NoSetDamageMultiplier; //!< Whether or not the damage multiplier for this MOSRotating was set. - - Timer m_FlashWhiteTimer; //!< The timer for timing white draw mode duration. - - // Intermediary drawing bitmap used to flip rotating bitmaps. Owned! - BITMAP *m_pFlipBitmap; - BITMAP *m_pFlipBitmapS; - // Intermediary drawing bitmap used to draw sihouettes and other effects. Not owned; points to the shared static bitmaps - BITMAP *m_pTempBitmap; - // Temp drawing bitmaps shared between all MOSRotatings - static BITMAP *m_spTempBitmap16; - static BITMAP *m_spTempBitmap32; - static BITMAP *m_spTempBitmap64; - static BITMAP *m_spTempBitmap128; - static BITMAP *m_spTempBitmap256; - static BITMAP *m_spTempBitmap512; - - // Intermediary drawing bitmap used to draw MO silhouettes. Not owned; points to the shared static bitmaps - BITMAP *m_pTempBitmapS; - // Temp drawing bitmaps shared between all MOSRotatings - static BITMAP *m_spTempBitmapS16; - static BITMAP *m_spTempBitmapS32; - static BITMAP *m_spTempBitmapS64; - static BITMAP *m_spTempBitmapS128; - static BITMAP *m_spTempBitmapS256; - static BITMAP *m_spTempBitmapS512; - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MOSRotating, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - // Disallow the use of some implicit methods. - MOSRotating(const MOSRotating &reference) = delete; - MOSRotating& operator=(const MOSRotating &rhs) = delete; - -}; +namespace RTE { + + class AtomGroup; + struct HitData; + class AEmitter; + class Attachable; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: MOSRotating + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A sprite movable object that can rotate. + // Parent(s): MOSprite. + // Class history: 05/30/2002 MOSRotating created. + + class MOSRotating : public MOSprite { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + friend class AtomGroup; + friend class SLTerrain; + friend struct EntityLuaBindings; + + // Concrete allocation and cloning definitions + EntityAllocation(MOSRotating); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MOSRotating + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a MOSRotating object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + MOSRotating() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~MOSRotating + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a MOSRotating object before deletion + // from system memory. + // Arguments: None. + + ~MOSRotating() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSRotating object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSRotating object ready for use. + // Arguments: A pointer to ContentFile that represents the bitmap file that will be + // used to create the Sprite. + // The number of frames in the Sprite's animation. + // A float specifying the object's mass in Kilograms (kg). + // A Vector specifying the initial position. + // A Vector specifying the initial velocity. + // The amount of time in ms this MovableObject will exist. 0 means unlim. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(ContentFile spriteFile, const int frameCount = 1, const float mass = 1, const Vector& position = Vector(0, 0), const Vector& velocity = Vector(0, 0), const unsigned long lifetime = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOSRotating to be identical to another, by deep copy. + // Arguments: A reference to the MOSRotating to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const MOSRotating& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire MOSRotating, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + MOSprite::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + /// + /// Gets the radius of this MOSRotating, not including any Attachables. + /// + /// + float GetIndividualRadius() const { return m_SpriteRadius; } + + /// + /// Gets the radius of this MOSRotating, including any Attachables. + /// + /// The radius of this MOSRotating, including any Attachables. + float GetRadius() const override { return std::max(m_SpriteRadius, m_FarthestAttachableDistanceAndRadius); } + + /// + /// Gets the diameter of this MOSRotating, not including any Attachables. + /// + /// + float GetIndividualDiameter() const { return m_SpriteDiameter; } + + /// + /// Gets the diameter of this MOSRotating, including any Attachables. + /// + /// The diameter of this MOSRotating, including any Attachables. + float GetDiameter() const override { return GetRadius() * 2.0F; } + + /// + /// Checks if the given Attachable should affect radius, and handles it if it should. + /// + /// The Attachable to check. + /// Whether the radius affecting Attachable changed as a result of this call. + virtual bool HandlePotentialRadiusAffectingAttachable(const Attachable* attachable); + + /// + /// Gets the mass value of this MOSRotating, not including any Attachables or wounds. + /// + /// The mass of this MOSRotating. + float GetIndividualMass() const { return MovableObject::GetMass(); } + + /// + /// Gets the mass value of this MOSRotating, including the mass of all its Attachables and wounds, and their Attachables and so on. + /// + /// The mass of this MOSRotating and all of its Attachables and wounds in Kilograms (kg). + float GetMass() const override { return MovableObject::GetMass() + m_AttachableAndWoundMass; } + + /// + /// Updates the total mass of Attachables and wounds for this MOSRotating, intended to be used when Attachables' masses get modified. Simply subtracts the old mass and adds the new one. + /// + /// The mass the Attachable or wound had before its mass was modified. + /// The up-to-date mass of the Attachable or wound after its mass was modified. + virtual void UpdateAttachableAndWoundMass(float oldAttachableOrWoundMass, float newAttachableOrWoundMass) { m_AttachableAndWoundMass += newAttachableOrWoundMass - oldAttachableOrWoundMass; } + + /// + /// Gets the MOIDs of this MOSRotating and all its Attachables and Wounds, putting them into the MOIDs vector. + /// + /// The vector that will store all the MOIDs of this MOSRotating. + void GetMOIDs(std::vector& MOIDs) const override; + + /// + /// Sets the MOID of this MOSRotating and any Attachables on it to be g_NoMOID (255) for this frame. + /// + void SetAsNoID() override; + + /// + /// Sets this MOSRotating to not hit a specific other MO and all its children even though MO hitting is enabled on this MOSRotating. + /// + /// A pointer to the MO to not be hitting. Null pointer means don't ignore anything. Ownership is NOT transferred! + /// How long, in seconds, to ignore the specified MO. A negative number means forever. + void SetWhichMOToNotHit(MovableObject* moToNotHit = nullptr, float forHowLong = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAtomGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current AtomGroup of this MOSRotating. + // Arguments: None. + // Return value: A const reference to the current AtomGroup. + + AtomGroup* GetAtomGroup() { return m_pAtomGroup; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMaterial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the main Material of this MOSRotating. + // Arguments: None. + // Return value: The the Material of this MOSRotating. + + Material const* GetMaterial() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetDrawPriority + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the drawing priority of this MovableObject, if two things were + // overlap when copying to the terrain, the higher priority MO would + // end up getting drawn. + // Arguments: None. + // Return value: The the priority of this MovableObject. Higher number, the higher + // priority. + + int GetDrawPriority() const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRecoilForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current recoil impulse force Vector of this MOSprite. + // Arguments: None. + // Return value: A const reference to the current recoil impulse force in kg * m/s. + + const Vector& GetRecoilForce() const { return m_RecoilForce; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRecoilOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current recoil offset Vector of this MOSprite. + // Arguments: None. + // Return value: A const reference to the current recoil offset. + + const Vector& GetRecoilOffset() const { return m_RecoilOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGibList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets direct access to the list of object this is to generate upon gibbing. + // Arguments: None. + // Return value: A pointer to the list of gibs. Ownership is NOT transferred! + + std::list* GetGibList() { return &m_Gibs; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddRecoil + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds graphical recoil offset to this MOSprite according to its angle. + // Arguments: None. + // Return value: None. + + void AddRecoil(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRecoil + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds recoil offset to this MOSprite. + // Arguments: A vector with the recoil impulse force in kg * m/s. + // A vector with the recoil offset in pixels. + // Whether recoil should be activated or not for the next Draw(). + // Return value: None. + + void SetRecoil(const Vector& force, const Vector& offset, bool recoil = true) { + m_RecoilForce = force; + m_RecoilOffset = offset; + m_Recoiled = recoil; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsRecoiled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether this MOSprite is currently under the effects of + // recoil. + // Arguments: None. + // Return value: None. + + bool IsRecoiled() { return m_Recoiled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableDeepCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether or not this MOSRotating should check for deep penetrations + // the terrain or not. + // Arguments: Whether to enable deep penetration checking or not. + // Return value: None. + + void EnableDeepCheck(const bool enable = true) { m_DeepCheck = enable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ForceDeepCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets to force a deep checking of this' silhouette against the terrain + // and create an outline hole in the terrain, generating particles of the + // intersecting pixels in the terrain. + // Arguments: Whether to force a deep penetration check for this sim frame or not.. + // Return value: None. + + void ForceDeepCheck(const bool enable = true) { m_ForceDeepCheck = enable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + // Arguments: Reference to the HitData struct which describes the collision. This + // will be modified to represent the results of the collision. + // Return value: Whether the collision has been deemed valid. If false, then disregard + // any impulses in the Hitdata. + + bool CollideAtPoint(HitData& hitData) override; + + /// + /// Defines what should happen when this MovableObject hits and then bounces off of something. + /// This is called by the owned Atom/AtomGroup of this MovableObject during travel. + /// + /// The HitData describing the collision in detail. + /// Whether the MovableObject should immediately halt any travel going on after this bounce. + bool OnBounce(HitData& hd) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: OnSink + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // sink into something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. + // Arguments: The HitData describing the collision in detail. + // Return value: Wheter the MovableObject should immediately halt any travel going on + // after this sinkage. + + bool OnSink(HitData& hd) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ParticlePenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Determines whether a particle which has hit this MO will penetrate, + // and if so, whether it gets lodged or exits on the other side of this + // MO. Appropriate effects will be determined and applied ONLY IF there + // was penetration! If not, nothing will be affected. + // Arguments: The HitData describing the collision in detail, the impulses have to + // have been filled out! + // Return value: Whether the particle managed to penetrate into this MO or not. If + // somehting but a MOPixel or MOSParticle is being passed in as hitor, + // false will trivially be returned here. + + virtual bool ParticlePenetration(HitData& hd); + + /// + /// Destroys this MOSRotating and creates its specified Gibs in its place with appropriate velocities. Any Attachables are removed and also given appropriate velocities. + /// + /// The impulse (kg * m/s) of the impact causing the gibbing to happen. + /// A pointer to an MO which the Gibs and Attachables should not be colliding with. + virtual void GibThis(const Vector& impactImpulse = Vector(), MovableObject* movableObjectToIgnore = nullptr); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: MoveOutOfTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether any of the Atom:s in this MovableObject are on top of + // terrain pixels, and if so, attempt to move this out so none of this' + // Atoms are on top of the terrain any more. + // Arguments: Only consider materials stronger than this in the terrain for + // intersections. + // Return value: Whether any intersection was successfully resolved. Will return true + // even if there wasn't any intersections to begin with. + + bool MoveOutOfTerrain(unsigned char strongerThan = g_MaterialAir) override; + + /// + /// Gathers, clears and applies this MOSRotating's accumulated forces. + /// + void ApplyForces() override; + + /// + /// Gathers, clears and applies this MOSRotating's accumulated impulse forces, gibbing if appropriate. + /// + void ApplyImpulses() override; + + /// + /// Gets the list of Attachables on this MOSRotating. + /// + /// The list of Attachables on this MOSRotating. + const std::list& GetAttachables() const { return m_Attachables; } + + /// + /// Gets whether or not the given Attachable is a hardcoded Attachable (e.g. an Arm, Leg, Turret, etc.) + /// + /// The Attachable to check. + /// Whether or not the Attachable is hardcoded. + bool AttachableIsHardcoded(const Attachable* attachableToCheck) const; + + /// + /// Adds the passed in Attachable the list of Attachables and sets its parent to this MOSRotating. + /// + /// The Attachable to add. + virtual void AddAttachable(Attachable* attachable); + + /// + /// Adds the passed in Attachable the list of Attachables, changes its parent offset to the passed in Vector, and sets its parent to this MOSRotating. + /// + /// The Attachable to add. + /// The Vector to set as the Attachable's parent offset. + virtual void AddAttachable(Attachable* attachable, const Vector& parentOffsetToSet); + + /// + /// Removes the Attachable corresponding to the passed in UniqueID and sets its parent to nullptr. Does not add it to MovableMan or add break wounds. + /// + /// The UniqueID of the Attachable to remove. + /// A pointer to the removed Attachable. Ownership IS transferred! + virtual Attachable* RemoveAttachable(long attachableUniqueID) { return RemoveAttachable(attachableUniqueID, false, false); } + + /// + /// Removes the Attachable corresponding to the passed in UniqueID and sets its parent to nullptr. Optionally adds it to MovableMan and/or adds break wounds. + /// If the Attachable is not set to delete or delete when removed from its parent, and addToMovableMan is false, the caller must hang onto a pointer to the Attachable ahead of time to avoid memory leaks. + /// + /// The UniqueID of the Attachable to remove. + /// Whether or not to add the Attachable to MovableMan once it has been removed. + /// Whether or not to add break wounds to the removed Attachable and this MOSRotating. + /// A pointer to the removed Attachable, if it wasn't added to MovableMan or nullptr if it was. Ownership IS transferred! + virtual Attachable* RemoveAttachable(long attachableUniqueID, bool addToMovableMan, bool addBreakWounds); + + /// + /// Removes the passed in Attachable and sets its parent to nullptr. Does not add it to MovableMan or add break wounds. + /// + /// The Attachable to remove. + /// A pointer to the removed Attachable. Ownership IS transferred! + virtual Attachable* RemoveAttachable(Attachable* attachable) { return RemoveAttachable(attachable, false, false); } + + /// + /// Removes the passed in Attachable and sets its parent to nullptr. Optionally adds it to MovableMan and/or adds break wounds. + /// If the Attachable is not set to delete or delete when removed from its parent, and addToMovableMan is false, the caller must hang onto a pointer to the Attachable ahead of time to avoid memory leaks. + /// + /// The Attachable to remove. + /// Whether or not to add the Attachable to MovableMan once it has been removed. + /// Whether or not to add break wounds to the removed Attachable and this MOSRotating. + /// A pointer to the removed Attachable, if it wasn't added to MovableMan or nullptr if it was. Ownership IS transferred! + virtual Attachable* RemoveAttachable(Attachable* attachable, bool addToMovableMan, bool addBreakWounds); + + /// + /// Removes the passed in Attachable, and sets it to delete so it will go straight to MovableMan and be handled there. + /// + /// The Attacahble to remove and delete. + void RemoveAndDeleteAttachable(Attachable* attachable); + + /// + /// Either removes or deletes all of this MOSRotating's Attachables. + /// + /// Whether to remove or delete the Attachables. Setting this to true deletes them, setting it to false removes them. + void RemoveOrDestroyAllAttachables(bool destroy); + + /// + /// Gets a damage-transferring, impulse-vulnerable Attachable nearest to the passed in offset. + /// + /// The offset that will be compared to each Attachable's ParentOffset. + /// The nearest detachable Attachable, or nullptr if none was found. + Attachable* GetNearestDetachableAttachableToOffset(const Vector& offset) const; + + /// + /// Gibs or detaches any Attachables that would normally gib or detach from the passed in impulses. + /// + /// The impulse vector which determines the Attachables to gib or detach. Will be filled out with the remainder of impulses. + void DetachAttachablesFromImpulse(Vector& impulseVector); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. + // Arguments: None. + // Return value: None. + + void ResetAllTimers() override; + + /// + /// Does the calculations necessary to detect whether this MOSRotating is at rest or not. IsAtRest() retrieves the answer. + /// + void RestDetection() override; + + /// + /// Indicates whether this MOSRotating has been at rest with no movement for longer than its RestThreshold. + /// + bool IsAtRest() override; + + /// + /// Indicates whether this MOSRotating's current graphical representation, including its Attachables, overlaps a point in absolute scene coordinates. + /// + /// The point in absolute scene coordinates to check for overlap with. + /// Whether or not this MOSRotating's graphical representation overlaps the given scene point. + bool IsOnScenePoint(Vector& scenePoint) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: EraseFromTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Cuts this' silhouette out from the terrain's material and color layers. + // Arguments: None. + // Return value: None. + + void EraseFromTerrain(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DeepCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if any of this' deep group atmos are on top of the terrain, and + // if so, erases this' silhouette from the terrain. + // Arguments: Whether to make any MOPixels from erased terrain pixels at all. + // The size of the gaps between MOPixels knocked loose by the terrain erasure. + // The max number of MOPixel:s to generate as dislodged particles from the + // erased terrain. + // Return value: Whether deep penetration was detected and erasure was done. + + bool DeepCheck(bool makeMOPs = true, int skipMOP = 2, int maxMOP = 100); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done before Travel(). Always call before + // calling Travel. + // Arguments: None. + // Return value: None. + + void PreTravel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Travel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Travels this MOSRotatin, using its physical representation. + // Arguments: None. + // Return value: None. + + void Travel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PostTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done after Update(). Always call after + // calling Update. + // Arguments: None. + // Return value: None. + + void PostTravel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + void PostUpdate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawMOIDIfOverlapping + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the MOID representation of this to the SceneMan's MOID layer if + // this is found to potentially overlap another MovableObject. + // Arguments: The MovableObject to check this for overlap against. + // Return value: Whether it was drawn or not. + + bool DrawMOIDIfOverlapping(MovableObject* pOverlapMO) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MOSRotating's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + /// + /// Gets the gib impulse limit for this MOSRotating, i.e. the amount of impulse force required in a frame to gib this MOSRotating. + /// + /// The gib impulse limit of this MOSRotating. + float GetGibImpulseLimit() const { return m_GibImpulseLimit; } + + /// + /// Sets the gib impulse limit for this MOSRotating, i.e. the amount of impulse force required in a frame to gib this MOSRotating. + /// + /// The new gib impulse limit to use. + void SetGibImpulseLimit(float newGibImpulseLimit) { m_GibImpulseLimit = newGibImpulseLimit; } + + /// + /// Gets the gib wound limit for this MOSRotating, i.e. the total number of wounds required to gib this MOSRotating. Does not include any Attachables. + /// + /// + int GetGibWoundLimit() const { return GetGibWoundLimit(false, false, false); } + + /// + /// Gets the gib wound limit for this MOSRotating, i.e. the total number of wounds required to gib this MOSRotating. + /// Optionally adds the gib wound limits of Attachables (and their Attachables, etc.) that match the conditions set by the provided parameters. + /// + /// Whether to count wounds from Attachables that have a positive damage multiplier, i.e. those that damage their parent (this MOSRotating) when wounded. + /// Whether to count wounds from Attachables that have a negative damage multiplier, i.e. those that heal their parent (this MOSRotating) when wounded. + /// Whether to count wounds from Attachables that a zero damage multiplier, i.e. those that do not affect their parent (this MOSRotating) when wounded. + /// The wound limit of this MOSRotating and, optionally, its Attachables. + int GetGibWoundLimit(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const; + + /// + /// Sets the gib wound limit for this MOSRotating, i.e. the total number of wounds required to gib this MOSRotating. + /// This will not directly trigger gibbing, even if the limit is lower than the current number of wounds. + /// + /// The new gib wound limit to use. + void SetGibWoundLimit(int newGibWoundLimit) { m_GibWoundLimit = newGibWoundLimit; } + + /// + /// Gets the rate at which wound count of this MOSRotating will diminish the impulse limit. + /// + /// The rate at which wound count affects the impulse limit. + float GetWoundCountAffectsImpulseLimitRatio() const { return m_WoundCountAffectsImpulseLimitRatio; } + + /// + /// Gets whether this MOSRotating should gib at the end of its lifetime instead of just being deleted. + /// + /// Whether this MOSRotating should gib at the end of its lifetime instead of just being deleted. + bool GetGibAtEndOfLifetime() const { return m_GibAtEndOfLifetime; } + + /// + /// Sets whether this MOSRotating should gib at the end of its lifetime instead of just being deleted. + /// + /// Whether or not this MOSRotating should gib at the end of its lifetime instead of just being deleted. + void SetGibAtEndOfLifetime(bool shouldGibAtEndOfLifetime) { m_GibAtEndOfLifetime = shouldGibAtEndOfLifetime; } + + /// + /// Gets the gib blast strength this MOSRotating, i.e. the strength with which Gibs and Attachables will be launched when this MOSRotating is gibbed. + /// + /// The gib blast strength of this MOSRotating. + float GetGibBlastStrength() const { return m_GibBlastStrength; } + + /// + /// Sets the gib blast strength this MOSRotating, i.e. the strength with which Gibs and Attachables will be launched when this MOSRotating is gibbed. + /// + /// The new gib blast strength to use. + void SetGibBlastStrength(float newGibBlastStrength) { m_GibBlastStrength = newGibBlastStrength; } + + /// + /// Gets the amount of screenshake this will cause upon gibbing. + /// + /// The amount of screenshake this will cause when gibbing. If -1, this is calculated automatically. + float GetGibScreenShakeAmount() const { return m_GibScreenShakeAmount; } + + /// + /// Gets a const reference to the list of Attachables on this MOSRotating. + /// + /// A const reference to the list of Attachables on this MOSRotating. + const std::list& GetAttachableList() const { return m_Attachables; } + + /// + /// Gets a const reference to the list of wounds on this MOSRotating. + /// + /// A const reference to the list of wounds on this MOSRotating. + const std::vector& GetWoundList() const { return m_Wounds; } + + /// + /// Gets the number of wounds attached to this MOSRotating. + /// Includes any Attachables (and their Attachables, etc.) that have a positive damage multiplier. + /// The number of wounds on this MOSRotating. + /// + int GetWoundCount() const { return GetWoundCount(true, false, false); } + + /// + /// Gets the number of wounds attached to this MOSRotating. + /// Optionally adds the wound counts of Attachables (and their Attachables, etc.) that match the conditions set by the provided parameters. + /// Whether to count wounds from Attachables that have a positive damage multiplier, i.e. those that damage their parent (this MOSRotating) when wounded. + /// Whether to count wounds from Attachables that have a negative damage multiplier, i.e. those that heal their parent (this MOSRotating) when wounded. + /// Whether to count wounds from Attachables that a zero damage multiplier, i.e. those that do not affect their parent (this MOSRotating) when wounded. + /// The number of wounds on this MOSRotating and, optionally, its Attachables. + /// + int GetWoundCount(bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) const; + + /// + /// Adds the passed in wound AEmitter to the list of wounds and changes its parent offset to the passed in Vector. + /// + /// The wound AEmitter to add. + /// The vector to set as the wound AEmitter's parent offset. + /// Whether to gib this MOSRotating if adding this wound raises its wound count past its gib wound limit. Defaults to true. + virtual void AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit = true); + + /// + /// Removes the specified number of wounds from this MOSRotating, and returns damage caused by these removed wounds. + /// Includes any Attachables (and their Attachables, etc.) that have a positive damage multiplier. + /// + /// The number of wounds that should be removed. + /// The amount of damage caused by these wounds, taking damage multipliers into account. + virtual float RemoveWounds(int numberOfWoundsToRemove) { return RemoveWounds(numberOfWoundsToRemove, true, false, false); } + + /// + /// Removes the specified number of wounds from this MOSRotating, and returns damage caused by these removed wounds. + /// Optionally removes wounds from Attachables (and their Attachables, etc.) that match the conditions set by the provided inclusion parameters. + /// + /// The number of wounds that should be removed. + /// Whether to count wounds from Attachables that have a positive damage multiplier, i.e. those that damage their parent (this MOSRotating) when wounded. + /// Whether to count wounds from Attachables that have a negative damage multiplier, i.e. those that heal their parent (this MOSRotating) when wounded. + /// Whether to count wounds from Attachables that a zero damage multiplier, i.e. those that do not affect their parent (this MOSRotating) when wounded. + /// The amount of damage caused by these wounds, taking damage multipliers into account. + virtual float RemoveWounds(int numberOfWoundsToRemove, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables); + + /// + /// Cleans up and destroys the script state of this object, calling the Destroy callback in lua + /// + void DestroyScriptState(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDamageMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets damage multiplier of this attachable. + // Arguments: New multiplier value. + // Return value: None. + + void SetDamageMultiplier(float newValue) { + m_DamageMultiplier = newValue; + m_NoSetDamageMultiplier = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDamageMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns damage multiplier of this attachable. + // Arguments: None. + // Return value: Current multiplier value. + + float GetDamageMultiplier() const { return m_DamageMultiplier; } + + /// + /// Gets whether the damage multiplier for this MOSRotating has been directly set, or is at its default value. + /// + /// Whether the damage multiplier for this MOSRotating has been set. + bool HasNoSetDamageMultiplier() const { return m_NoSetDamageMultiplier; } + + /// + /// Gets the velocity orientation scalar of this MOSRotating. + /// + /// New scalar value. + float GetOrientToVel() const { return m_OrientToVel; } + + /// + /// Sets the velocity orientation scalar of this MOSRotating. + /// + /// New scalar value. + void SetOrientToVel(float newValue) { m_OrientToVel = newValue; } + + /// + /// Sets this MOSRotating and all its children to drawn white for a specified amount of time. + /// + /// Duration of flash in real time MS. + void FlashWhite(int durationMS = 32) { + m_FlashWhiteTimer.SetRealTimeLimitMS(durationMS); + m_FlashWhiteTimer.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTravelImpulse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Retrurns the amount of impulse force exerted on this during the last frame. + // Arguments: None. + // Return value: The amount of impulse force exerted on this during the last frame. + + Vector GetTravelImpulse() const { return m_TravelImpulse; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTravelImpulse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the amount of impulse force exerted on this during the last frame. + // Arguments: New impulse value + // Return value: None. + + void SetTravelImpulse(Vector impulse) { m_TravelImpulse = impulse; } + + /// + /// Gets this MOSRotating's gib sound. Ownership is NOT transferred! + /// + /// The SoundContainer for this MOSRotating's gib sound. + SoundContainer* GetGibSound() const { return m_GibSound; } + + /// + /// Sets this MOSRotating's gib sound. Ownership IS transferred! + /// + /// The new SoundContainer for this MOSRotating's gib sound. + void SetGibSound(SoundContainer* newSound) { m_GibSound = newSound; } + + /// + /// Ensures all attachables and wounds are positioned and rotated correctly. Must be run when this MOSRotating is added to MovableMan to avoid issues with Attachables spawning in at (0, 0). + /// + virtual void CorrectAttachableAndWoundPositionsAndRotations() const; + + /// + /// Method to be run when the game is saved via ActivityMan::SaveCurrentGame. Not currently used in metagame or editor saving. + /// + void OnSave() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Transfers forces and impulse forces from the given Attachable to this MOSRotating, gibbing and/or removing the Attachable if needed. + /// + /// A pointer to the Attachable to apply forces from. Ownership is NOT transferred! + /// Whether or not the Attachable has been removed, in which case it'll usually be passed to MovableMan. + bool TransferForcesFromAttachable(Attachable* attachable); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateChildMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this MO register itself and all its attached children in the + // MOID register and get ID:s for itself and its children for this frame. + // Arguments: The MOID index to register itself and its children in. + // The MOID of the root MO of this MO, ie the highest parent of this MO. + // 0 means that this MO is the root, ie it is owned by MovableMan. + // Whether this MO should make a new MOID to use for itself, or to use + // the same as the last one in the index (presumably its parent), + // Return value: None. + + void UpdateChildMOIDs(std::vector& MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true) override; + + /// + /// Creates the particles specified by this MOSRotating's list of Gibs and adds them to MovableMan with appropriately randomized velocities, based on this MOSRotating's gib blast strength. + /// + /// The impulse (kg * m/s) of the impact that caused the gibbing to happen. + /// A pointer to an MO which the Attachables should not be colliding with. + void CreateGibsWhenGibbing(const Vector& impactImpulse, MovableObject* movableObjectToIgnore); + + /// + /// Removes all Attachables from this MOSR, deleting them or adding them to MovableMan as appropriate, and giving them randomized velocities based on their properties and this MOSRotating's gib blast strength. + /// + /// The impulse (kg * m/s) of the impact that caused the gibbing to happen. + /// A pointer to an MO which the Attachables should not be colliding with. + void RemoveAttachablesWhenGibbing(const Vector& impactImpulse, MovableObject* movableObjectToIgnore); + + // Member variables + static Entity::ClassInfo m_sClass; + // float m_Torque; // In kg * r/s^2 (Newtons). + // float m_ImpulseTorque; // In kg * r/s. + // The group of Atom:s that will be the physical reperesentation of this MOSRotating. + AtomGroup* m_pAtomGroup; + // The group of Atom:s that will serve as a means to detect deep terrain penetration. + AtomGroup* m_pDeepGroup; + // Whether or not to check for deep penetrations. + bool m_DeepCheck; + // A trigger for forcing a deep check to happen + bool m_ForceDeepCheck; + // Whether deep penetration happaned in the last frame or not, and how hard it was. + float m_DeepHardness; + // The amount of impulse force exerted on this during the last frame. + Vector m_TravelImpulse; + // The precomupted center location of the sprite relative to the MovableObject::m_Pos. + Vector m_SpriteCenter; + // How much to orient the rotation of this to match the velocity vector each frame 0 = none, 1.0 = immediately align with vel vector + float m_OrientToVel; + // Whether the SpriteMO is currently pushed back by recoil or not. + bool m_Recoiled; + // The impulse force in kg * m/s that represents the recoil. + Vector m_RecoilForce; + // The vector that the recoil offsets the sprite when m_Recoiled is true. + Vector m_RecoilOffset; + // The list of wound AEmitters currently attached to this MOSRotating, and owned here as well. + std::vector m_Wounds; + // The list of Attachables currently attached and Owned by this. + std::list m_Attachables; + std::unordered_set m_ReferenceHardcodedAttachableUniqueIDs; //!< An unordered set is filled with the Unique IDs of all of the reference object's hardcoded Attachables when using the copy Create. + std::unordered_map> m_HardcodedAttachableUniqueIDsAndSetters; //!< An unordered map of Unique IDs to setter lambda functions, used to call the appropriate hardcoded Attachable setter when a hardcoded Attachable is removed. + std::unordered_map> m_HardcodedAttachableUniqueIDsAndRemovers; //!< An unordered map of Unique IDs to remove lambda functions, used to call the appropriate hardcoded Attachable remover when a hardcoded Attachable is removed and calling the setter with nullptr won't work. + const Attachable* m_RadiusAffectingAttachable; //!< A pointer to the Attachable that is currently affecting the radius. Used for some efficiency benefits. + float m_FarthestAttachableDistanceAndRadius; //!< The distance + radius of the radius affecting Attachable. + float m_AttachableAndWoundMass; //!< The mass of all Attachables and wounds on this MOSRotating. Used in combination with its actual mass and any other affecting factors to get its total mass. + // The list of Gib:s this will create when gibbed + std::list m_Gibs; + // The amount of impulse force required to gib this, in kg * (m/s). 0 means no limit + float m_GibImpulseLimit; + int m_GibWoundLimit; //!< The number of wounds that will gib this MOSRotating. 0 means that it can't be gibbed via wounds. + float m_GibBlastStrength; //!< The strength with which Gibs and Attachables will get launched when this MOSRotating is gibbed. + float m_GibScreenShakeAmount; //!< Determines how much screenshake this causes upon gibbing. + float m_WoundCountAffectsImpulseLimitRatio; //!< The rate at which this MOSRotating's wound count will diminish the impulse limit. + bool m_DetachAttachablesBeforeGibbingFromWounds; //!< Whether to detach any Attachables of this MOSRotating when it should gib from hitting its wound limit, instead of gibbing the MOSRotating itself. + bool m_GibAtEndOfLifetime; //!< Whether or not this MOSRotating should gib when it reaches the end of its lifetime, instead of just deleting. + // Gib sound effect + SoundContainer* m_GibSound; + // Whether to flash effect on gib + bool m_EffectOnGib; + // How far this is audiable (in screens) when gibbing + float m_LoudnessOnGib; + + float m_DamageMultiplier; //!< Damage multiplier for this MOSRotating. + bool m_NoSetDamageMultiplier; //!< Whether or not the damage multiplier for this MOSRotating was set. + + Timer m_FlashWhiteTimer; //!< The timer for timing white draw mode duration. + + // Intermediary drawing bitmap used to flip rotating bitmaps. Owned! + BITMAP* m_pFlipBitmap; + BITMAP* m_pFlipBitmapS; + // Intermediary drawing bitmap used to draw sihouettes and other effects. Not owned; points to the shared static bitmaps + BITMAP* m_pTempBitmap; + // Temp drawing bitmaps shared between all MOSRotatings + static BITMAP* m_spTempBitmap16; + static BITMAP* m_spTempBitmap32; + static BITMAP* m_spTempBitmap64; + static BITMAP* m_spTempBitmap128; + static BITMAP* m_spTempBitmap256; + static BITMAP* m_spTempBitmap512; + + // Intermediary drawing bitmap used to draw MO silhouettes. Not owned; points to the shared static bitmaps + BITMAP* m_pTempBitmapS; + // Temp drawing bitmaps shared between all MOSRotatings + static BITMAP* m_spTempBitmapS16; + static BITMAP* m_spTempBitmapS32; + static BITMAP* m_spTempBitmapS64; + static BITMAP* m_spTempBitmapS128; + static BITMAP* m_spTempBitmapS256; + static BITMAP* m_spTempBitmapS512; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MOSRotating, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + MOSRotating(const MOSRotating& reference) = delete; + MOSRotating& operator=(const MOSRotating& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/MOSprite.cpp b/Source/Entities/MOSprite.cpp index 9851a8ee6..4f5862373 100644 --- a/Source/Entities/MOSprite.cpp +++ b/Source/Entities/MOSprite.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -18,608 +17,570 @@ namespace RTE { -AbstractClassInfo(MOSprite, MovableObject); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MOSprite, effectively -// resetting the members of this abstraction level only. - -void MOSprite::Clear() -{ - m_SpriteFile.Reset(); - m_aSprite.clear(); - m_IconFile.Reset(); - m_GraphicalIcon = nullptr; - m_FrameCount = 1; - m_SpriteOffset.Reset(); - m_Frame = 0; - m_SpriteAnimMode = NOANIM; - m_SpriteAnimDuration = 500; - m_SpriteAnimTimer.Reset(); - m_SpriteAnimIsReversingFrames = false; - m_HFlipped = false; - m_SpriteRadius = 1.0F; - m_SpriteDiameter = 2.0F; - m_Rotation.Reset(); - m_PrevRotation.Reset(); - m_AngularVel = 0; - m_PrevAngVel = 0; - m_AngOscillations = 0; - m_SettleMaterialDisabled = false; - m_pEntryWound = 0; - m_pExitWound = 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSprite object ready for use. - -int MOSprite::Create() -{ - if (MovableObject::Create() < 0) - return -1; - - // Post-process reading - m_aSprite.clear(); - m_SpriteFile.GetAsAnimation(m_aSprite, m_FrameCount); - - if (!m_aSprite.empty() && m_aSprite[0]) - { - // Set default sprite offset - if (m_SpriteOffset.IsZero()) { m_SpriteOffset.SetXY(static_cast(-m_aSprite[0]->w) / 2.0F, static_cast(-m_aSprite[0]->h) / 2.0F); } - - // Calc maximum dimensions from the Pos, based on the sprite - float maxX = std::max(std::fabs(m_SpriteOffset.GetX()), std::fabs(static_cast(m_aSprite[0]->w) + m_SpriteOffset.GetX())); - float maxY = std::max(std::fabs(m_SpriteOffset.GetY()), std::fabs(static_cast(m_aSprite[0]->h) + m_SpriteOffset.GetY())); - m_SpriteRadius = std::sqrt((maxX * maxX) + (maxY * maxY)); - m_SpriteDiameter = m_SpriteRadius * 2.0F; - } - else - return -1; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSprite object ready for use. - -int MOSprite::Create(ContentFile spriteFile, - const int frameCount, - const float mass, - const Vector &position, - const Vector &velocity, - const unsigned long lifetime) -{ - MovableObject::Create(mass, position, velocity, 0, 0, lifetime); - - m_SpriteFile = spriteFile; - m_FrameCount = frameCount; - m_aSprite.clear(); - m_SpriteFile.GetAsAnimation(m_aSprite, m_FrameCount); - m_SpriteOffset.SetXY(static_cast(-m_aSprite[0]->w) / 2.0F, static_cast(-m_aSprite[0]->h) / 2.0F); - - m_HFlipped = false; - - // Calc maximum dimensions from the Pos, based on the sprite - float maxX = std::max(std::fabs(m_SpriteOffset.GetX()), std::fabs(static_cast(m_aSprite[0]->w) + m_SpriteOffset.GetX())); - float maxY = std::max(std::fabs(m_SpriteOffset.GetY()), std::fabs(static_cast(m_aSprite[0]->h) + m_SpriteOffset.GetY())); - m_SpriteRadius = std::sqrt((maxX * maxX) + (maxY * maxY)); - m_SpriteDiameter = m_SpriteRadius * 2.0F; + AbstractClassInfo(MOSprite, MovableObject); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MOSprite, effectively + // resetting the members of this abstraction level only. + + void MOSprite::Clear() { + m_SpriteFile.Reset(); + m_aSprite.clear(); + m_IconFile.Reset(); + m_GraphicalIcon = nullptr; + m_FrameCount = 1; + m_SpriteOffset.Reset(); + m_Frame = 0; + m_SpriteAnimMode = NOANIM; + m_SpriteAnimDuration = 500; + m_SpriteAnimTimer.Reset(); + m_SpriteAnimIsReversingFrames = false; + m_HFlipped = false; + m_SpriteRadius = 1.0F; + m_SpriteDiameter = 2.0F; + m_Rotation.Reset(); + m_PrevRotation.Reset(); + m_AngularVel = 0; + m_PrevAngVel = 0; + m_AngOscillations = 0; + m_SettleMaterialDisabled = false; + m_pEntryWound = 0; + m_pExitWound = 0; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSprite object ready for use. + int MOSprite::Create() { + if (MovableObject::Create() < 0) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOSprite to be identical to another, by deep copy. + // Post-process reading + m_aSprite.clear(); + m_SpriteFile.GetAsAnimation(m_aSprite, m_FrameCount); -int MOSprite::Create(const MOSprite &reference) -{ - MovableObject::Create(reference); + if (!m_aSprite.empty() && m_aSprite[0]) { + // Set default sprite offset + if (m_SpriteOffset.IsZero()) { + m_SpriteOffset.SetXY(static_cast(-m_aSprite[0]->w) / 2.0F, static_cast(-m_aSprite[0]->h) / 2.0F); + } - if (reference.m_aSprite.empty()) - return -1; + // Calc maximum dimensions from the Pos, based on the sprite + float maxX = std::max(std::fabs(m_SpriteOffset.GetX()), std::fabs(static_cast(m_aSprite[0]->w) + m_SpriteOffset.GetX())); + float maxY = std::max(std::fabs(m_SpriteOffset.GetY()), std::fabs(static_cast(m_aSprite[0]->h) + m_SpriteOffset.GetY())); + m_SpriteRadius = std::sqrt((maxX * maxX) + (maxY * maxY)); + m_SpriteDiameter = m_SpriteRadius * 2.0F; + } else + return -1; - m_SpriteFile = reference.m_SpriteFile; - m_IconFile = reference.m_IconFile; - m_GraphicalIcon = m_IconFile.GetAsBitmap(); + return 0; + } - m_FrameCount = reference.m_FrameCount; - m_Frame = reference.m_Frame; - m_aSprite = reference.m_aSprite; - m_SpriteOffset = reference.m_SpriteOffset; - m_SpriteAnimMode = reference.m_SpriteAnimMode; - m_SpriteAnimDuration = reference.m_SpriteAnimDuration; - m_HFlipped = reference.m_HFlipped; - m_SpriteRadius = reference.m_SpriteRadius; - m_SpriteDiameter = reference.m_SpriteDiameter; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSprite object ready for use. + + int MOSprite::Create(ContentFile spriteFile, + const int frameCount, + const float mass, + const Vector& position, + const Vector& velocity, + const unsigned long lifetime) { + MovableObject::Create(mass, position, velocity, 0, 0, lifetime); + + m_SpriteFile = spriteFile; + m_FrameCount = frameCount; + m_aSprite.clear(); + m_SpriteFile.GetAsAnimation(m_aSprite, m_FrameCount); + m_SpriteOffset.SetXY(static_cast(-m_aSprite[0]->w) / 2.0F, static_cast(-m_aSprite[0]->h) / 2.0F); + + m_HFlipped = false; + + // Calc maximum dimensions from the Pos, based on the sprite + float maxX = std::max(std::fabs(m_SpriteOffset.GetX()), std::fabs(static_cast(m_aSprite[0]->w) + m_SpriteOffset.GetX())); + float maxY = std::max(std::fabs(m_SpriteOffset.GetY()), std::fabs(static_cast(m_aSprite[0]->h) + m_SpriteOffset.GetY())); + m_SpriteRadius = std::sqrt((maxX * maxX) + (maxY * maxY)); + m_SpriteDiameter = m_SpriteRadius * 2.0F; + + return 0; + } - m_Rotation = reference.m_Rotation; - m_AngularVel = reference.m_AngularVel; - m_SettleMaterialDisabled = reference.m_SettleMaterialDisabled; - m_pEntryWound = reference.m_pEntryWound; - m_pExitWound = reference.m_pExitWound; -// if (reference.m_pExitWound) Not doing anymore since we're not owning -// m_pExitWound = dynamic_cast(reference.m_pExitWound->Clone()); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOSprite to be identical to another, by deep copy. - return 0; -} + int MOSprite::Create(const MOSprite& reference) { + MovableObject::Create(reference); + if (reference.m_aSprite.empty()) + return -1; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int MOSprite::ReadProperty(const std::string_view &propName, Reader &reader) { - StartPropertyList(return MovableObject::ReadProperty(propName, reader)); - - MatchProperty("SpriteFile", { reader >> m_SpriteFile; }); - MatchProperty("IconFile", { - reader >> m_IconFile; + m_SpriteFile = reference.m_SpriteFile; + m_IconFile = reference.m_IconFile; m_GraphicalIcon = m_IconFile.GetAsBitmap(); - }); - MatchProperty("FrameCount", { - reader >> m_FrameCount; - m_aSprite.reserve(m_FrameCount); - }); - MatchProperty("SpriteOffset", { reader >> m_SpriteOffset; }); - MatchProperty("SpriteAnimMode", - { -// string mode; -// reader >> mode; - int mode; - reader >> mode; - m_SpriteAnimMode = (SpriteAnimMode)mode; -/* - if (mode == "NOANIM") - m_SpriteAnimMode = NOANIM; - else if (mode == "ALWAYSLOOP") - m_SpriteAnimMode = ALWAYSLOOP; - else if (mode == "ALWAYSPINGPONG") - m_SpriteAnimMode = ALWAYSPINGPONG; - else if (mode == "LOOPWHENACTIVE") - m_SpriteAnimMode = LOOPWHENACTIVE; - else - Abort -*/ - }); - MatchProperty("SpriteAnimDuration", { reader >> m_SpriteAnimDuration; }); - MatchProperty("HFlipped", { reader >> m_HFlipped; }); - MatchProperty("Rotation", { reader >> m_Rotation; }); - MatchProperty("AngularVel", { reader >> m_AngularVel; }); - MatchProperty("SettleMaterialDisabled", { reader >> m_SettleMaterialDisabled; }); - MatchProperty("EntryWound", { m_pEntryWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); - MatchProperty("ExitWound", { m_pExitWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); - - EndPropertyList; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetEntryWound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets entry wound emitter for this MOSprite -void MOSprite::SetEntryWound(std::string presetName, std::string moduleName) -{ - if (presetName == "") - m_pEntryWound = 0; - else - m_pEntryWound = dynamic_cast(g_PresetMan.GetEntityPreset("AEmitter", presetName, moduleName)); -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetExitWound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets exit wound emitter for this MOSprite -void MOSprite::SetExitWound(std::string presetName, std::string moduleName) -{ - if (presetName == "") - m_pExitWound = 0; - else - m_pExitWound = dynamic_cast(g_PresetMan.GetEntityPreset("AEmitter", presetName, moduleName)); -} + m_FrameCount = reference.m_FrameCount; + m_Frame = reference.m_Frame; + m_aSprite = reference.m_aSprite; + m_SpriteOffset = reference.m_SpriteOffset; + m_SpriteAnimMode = reference.m_SpriteAnimMode; + m_SpriteAnimDuration = reference.m_SpriteAnimDuration; + m_HFlipped = reference.m_HFlipped; + m_SpriteRadius = reference.m_SpriteRadius; + m_SpriteDiameter = reference.m_SpriteDiameter; + + m_Rotation = reference.m_Rotation; + m_AngularVel = reference.m_AngularVel; + m_SettleMaterialDisabled = reference.m_SettleMaterialDisabled; + m_pEntryWound = reference.m_pEntryWound; + m_pExitWound = reference.m_pExitWound; + // if (reference.m_pExitWound) Not doing anymore since we're not owning + // m_pExitWound = dynamic_cast(reference.m_pExitWound->Clone()); + + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int MOSprite::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return MovableObject::ReadProperty(propName, reader)); + + MatchProperty("SpriteFile", { reader >> m_SpriteFile; }); + MatchProperty("IconFile", { + reader >> m_IconFile; + m_GraphicalIcon = m_IconFile.GetAsBitmap(); + }); + MatchProperty("FrameCount", { + reader >> m_FrameCount; + m_aSprite.reserve(m_FrameCount); + }); + MatchProperty("SpriteOffset", { reader >> m_SpriteOffset; }); + MatchProperty("SpriteAnimMode", + { + // string mode; + // reader >> mode; + int mode; + reader >> mode; + m_SpriteAnimMode = (SpriteAnimMode)mode; + /* + if (mode == "NOANIM") + m_SpriteAnimMode = NOANIM; + else if (mode == "ALWAYSLOOP") + m_SpriteAnimMode = ALWAYSLOOP; + else if (mode == "ALWAYSPINGPONG") + m_SpriteAnimMode = ALWAYSPINGPONG; + else if (mode == "LOOPWHENACTIVE") + m_SpriteAnimMode = LOOPWHENACTIVE; + else + Abort + */ + }); + MatchProperty("SpriteAnimDuration", { reader >> m_SpriteAnimDuration; }); + MatchProperty("HFlipped", { reader >> m_HFlipped; }); + MatchProperty("Rotation", { reader >> m_Rotation; }); + MatchProperty("AngularVel", { reader >> m_AngularVel; }); + MatchProperty("SettleMaterialDisabled", { reader >> m_SettleMaterialDisabled; }); + MatchProperty("EntryWound", { m_pEntryWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); + MatchProperty("ExitWound", { m_pExitWound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); + + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEntryWoundPresetName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns entry wound emitter preset name for this MOSprite + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetEntryWound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets entry wound emitter for this MOSprite + void MOSprite::SetEntryWound(std::string presetName, std::string moduleName) { + if (presetName == "") + m_pEntryWound = 0; + else + m_pEntryWound = dynamic_cast(g_PresetMan.GetEntityPreset("AEmitter", presetName, moduleName)); + } -std::string MOSprite::GetEntryWoundPresetName() const -{ - return m_pEntryWound ? m_pEntryWound->GetPresetName() : ""; -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetExitWound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets exit wound emitter for this MOSprite + void MOSprite::SetExitWound(std::string presetName, std::string moduleName) { + if (presetName == "") + m_pExitWound = 0; + else + m_pExitWound = dynamic_cast(g_PresetMan.GetEntityPreset("AEmitter", presetName, moduleName)); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetExitWoundPresetName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns exit wound emitter preset name for this MOSprite + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEntryWoundPresetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns entry wound emitter preset name for this MOSprite + + std::string MOSprite::GetEntryWoundPresetName() const { + return m_pEntryWound ? m_pEntryWound->GetPresetName() : ""; + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetExitWoundPresetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns exit wound emitter preset name for this MOSprite + + std::string MOSprite::GetExitWoundPresetName() const { + return m_pExitWound ? m_pExitWound->GetPresetName() : ""; + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this MOSprite with a Writer for + // later recreation with Create(Reader &reader); + + int MOSprite::Save(Writer& writer) const { + MovableObject::Save(writer); + // TODO: Make proper save system that knows not to save redundant data! + /* + writer.NewProperty("SpriteFile"); + writer << m_SpriteFile; + writer.NewProperty("FrameCount"); + writer << m_FrameCount; + writer.NewProperty("SpriteOffset"); + writer << m_SpriteOffset; + writer.NewProperty("SpriteAnimMode"); + writer << m_SpriteAnimMode; + writer.NewProperty("SpriteAnimDuration"); + writer << m_SpriteAnimDuration; + writer.NewProperty("HFlipped"); + writer << m_HFlipped; + writer.NewProperty("Rotation"); + writer << m_Rotation.GetRadAngle(); + writer.NewProperty("AngularVel"); + writer << m_AngularVel; + writer.NewProperty("SettleMaterialDisabled"); + writer << m_SettleMaterialDisabled; + writer.NewProperty("EntryWound"); + writer << m_pEntryWound; + writer.NewProperty("ExitWound"); + writer << m_pExitWound; + */ + return 0; + } -std::string MOSprite::GetExitWoundPresetName() const -{ - return m_pExitWound ? m_pExitWound->GetPresetName() : ""; -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MOSprite object. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this MOSprite with a Writer for -// later recreation with Create(Reader &reader); - -int MOSprite::Save(Writer &writer) const -{ - MovableObject::Save(writer); -// TODO: Make proper save system that knows not to save redundant data! -/* - writer.NewProperty("SpriteFile"); - writer << m_SpriteFile; - writer.NewProperty("FrameCount"); - writer << m_FrameCount; - writer.NewProperty("SpriteOffset"); - writer << m_SpriteOffset; - writer.NewProperty("SpriteAnimMode"); - writer << m_SpriteAnimMode; - writer.NewProperty("SpriteAnimDuration"); - writer << m_SpriteAnimDuration; - writer.NewProperty("HFlipped"); - writer << m_HFlipped; - writer.NewProperty("Rotation"); - writer << m_Rotation.GetRadAngle(); - writer.NewProperty("AngularVel"); - writer << m_AngularVel; - writer.NewProperty("SettleMaterialDisabled"); - writer << m_SettleMaterialDisabled; - writer.NewProperty("EntryWound"); - writer << m_pEntryWound; - writer.NewProperty("ExitWound"); - writer << m_pExitWound; -*/ - return 0; -} + void MOSprite::Destroy(bool notInherited) { + // delete m_pEntryWound; Not doing this anymore since we're not owning + // delete m_pExitWound; + if (!notInherited) + MovableObject::Destroy(); + Clear(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MOSprite object. - -void MOSprite::Destroy(bool notInherited) -{ -// delete m_pEntryWound; Not doing this anymore since we're not owning -// delete m_pExitWound; - - if (!notInherited) - MovableObject::Destroy(); - Clear(); -} - -bool MOSprite::HitTestAtPixel(int pixelX, int pixelY) const { - if (!GetsHitByMOs() || GetRootParent()->GetTraveling()) { - return false; - } - - Vector distanceBetweenTestPositionAndMO = g_SceneMan.ShortestDistance(m_Pos, Vector(static_cast(pixelX), static_cast(pixelY))); - if (distanceBetweenTestPositionAndMO.MagnitudeIsGreaterThan(m_SpriteRadius)) { - return false; - } - - // Check the scene position in the current local space of the MO, accounting for Position, Sprite Offset, Angle and HFlipped. - //TODO Account for Scale as well someday, maybe. - Matrix rotation = m_Rotation; // <- Copy to non-const variable so / operator overload works. - Vector entryPos = (distanceBetweenTestPositionAndMO / rotation).GetXFlipped(m_HFlipped) - m_SpriteOffset; - int localX = entryPos.GetFloorIntX(); - int localY = entryPos.GetFloorIntY(); - - BITMAP* sprite = m_aSprite[m_Frame]; - return is_inside_bitmap(sprite, localX, localY, 0) && _getpixel(sprite, localX, localY) != ColorKeys::g_MaskColor; -} + bool MOSprite::HitTestAtPixel(int pixelX, int pixelY) const { + if (!GetsHitByMOs() || GetRootParent()->GetTraveling()) { + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Hard-sets the frame this sprite is supposed to show. + Vector distanceBetweenTestPositionAndMO = g_SceneMan.ShortestDistance(m_Pos, Vector(static_cast(pixelX), static_cast(pixelY))); + if (distanceBetweenTestPositionAndMO.MagnitudeIsGreaterThan(m_SpriteRadius)) { + return false; + } -void MOSprite::SetFrame(unsigned int newFrame) -{ - if (newFrame < 0) - newFrame = 0; - if (newFrame >= m_FrameCount) - newFrame = m_FrameCount - 1; + // Check the scene position in the current local space of the MO, accounting for Position, Sprite Offset, Angle and HFlipped. + // TODO Account for Scale as well someday, maybe. + Matrix rotation = m_Rotation; // <- Copy to non-const variable so / operator overload works. + Vector entryPos = (distanceBetweenTestPositionAndMO / rotation).GetXFlipped(m_HFlipped) - m_SpriteOffset; + int localX = entryPos.GetFloorIntX(); + int localY = entryPos.GetFloorIntY(); - m_Frame = newFrame; -} + BITMAP* sprite = m_aSprite[m_Frame]; + return is_inside_bitmap(sprite, localX, localY, 0) && _getpixel(sprite, localX, localY) != ColorKeys::g_MaskColor; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Hard-sets the frame this sprite is supposed to show. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetNextFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Hard-sets the frame this sprite is supposed to show, to the -// consecutive one after the current one. If currently the last fame is -// this will set it to the be the first, looping the animation. + void MOSprite::SetFrame(unsigned int newFrame) { + if (newFrame < 0) + newFrame = 0; + if (newFrame >= m_FrameCount) + newFrame = m_FrameCount - 1; -bool MOSprite::SetNextFrame() -{ - if (++m_Frame >= m_FrameCount) - { - m_Frame = 0; - return true; - } - return false; -} + m_Frame = newFrame; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetNextFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Hard-sets the frame this sprite is supposed to show, to the + // consecutive one after the current one. If currently the last fame is + // this will set it to the be the first, looping the animation. + + bool MOSprite::SetNextFrame() { + if (++m_Frame >= m_FrameCount) { + m_Frame = 0; + return true; + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. - -bool MOSprite::IsOnScenePoint(Vector &scenePoint) const -{ - if (!m_aSprite[m_Frame]) - return false; -// TODO: TAKE CARE OF WRAPPING -/* - // Take care of wrapping situations - bitmapPos = m_Pos + m_BitmapOffset; - Vector aScenePoint[4]; - aScenePoint[0] = scenePoint; - int passes = 1; - - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero()) - { - if (g_SceneMan.SceneWrapsX()) - { - if (bitmapPos.m_X < m_pFGColor->w) - { - aScenePoint[passes] = aScenePoint[0]; - aScenePoint[passes].m_X += g_SceneMan.GetSceneWidth(); - passes++; - } - else if (aScenePoint[0].m_X > pTargetBitmap->w - m_pFGColor->w) - { - aScenePoint[passes] = aScenePoint[0]; - aScenePoint[passes].m_X -= g_SceneMan.GetSceneWidth(); - passes++; - } - } - if (g_SceneMan.SceneWrapsY()) - { - - } - } - - // Check all the passes needed - for (int i = 0; i < passes; ++i) - { - if (IsWithinBox(aScenePoint[i], m_Pos + m_BitmapOffset, m_pFGColor->w, m_pFGColor->h)) - { - if (getpixel(m_pFGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor || - (m_pBGColor && getpixel(m_pBGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor) || - (m_pMaterial && getpixel(m_pMaterial, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaterialAir)) - return true; - } - } -*/ - if (WithinBox(scenePoint, m_Pos.m_X - m_SpriteRadius, m_Pos.m_Y - m_SpriteRadius, m_Pos.m_X + m_SpriteRadius, m_Pos.m_Y + m_SpriteRadius)) - { - // Get scene point in object's relative space - Vector spritePoint = scenePoint - m_Pos; - spritePoint.FlipX(m_HFlipped); - // Check over overlap - int pixel = getpixel(m_aSprite[m_Frame], spritePoint.m_X - m_SpriteOffset.m_X, spritePoint.m_Y - m_SpriteOffset.m_Y); - // Check that it isn't outside the bitmap, and not of the key color - if (pixel != -1 && pixel != g_MaskColor) - return true; - } - - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + + bool MOSprite::IsOnScenePoint(Vector& scenePoint) const { + if (!m_aSprite[m_Frame]) + return false; + // TODO: TAKE CARE OF WRAPPING + /* + // Take care of wrapping situations + bitmapPos = m_Pos + m_BitmapOffset; + Vector aScenePoint[4]; + aScenePoint[0] = scenePoint; + int passes = 1; + + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero()) + { + if (g_SceneMan.SceneWrapsX()) + { + if (bitmapPos.m_X < m_pFGColor->w) + { + aScenePoint[passes] = aScenePoint[0]; + aScenePoint[passes].m_X += g_SceneMan.GetSceneWidth(); + passes++; + } + else if (aScenePoint[0].m_X > pTargetBitmap->w - m_pFGColor->w) + { + aScenePoint[passes] = aScenePoint[0]; + aScenePoint[passes].m_X -= g_SceneMan.GetSceneWidth(); + passes++; + } + } + if (g_SceneMan.SceneWrapsY()) + { + + } + } + + // Check all the passes needed + for (int i = 0; i < passes; ++i) + { + if (IsWithinBox(aScenePoint[i], m_Pos + m_BitmapOffset, m_pFGColor->w, m_pFGColor->h)) + { + if (getpixel(m_pFGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor || + (m_pBGColor && getpixel(m_pBGColor, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaskColor) || + (m_pMaterial && getpixel(m_pMaterial, aScenePoint[i].m_X, aScenePoint[i].m_Y) != g_MaterialAir)) + return true; + } + } + */ + if (WithinBox(scenePoint, m_Pos.m_X - m_SpriteRadius, m_Pos.m_Y - m_SpriteRadius, m_Pos.m_X + m_SpriteRadius, m_Pos.m_Y + m_SpriteRadius)) { + // Get scene point in object's relative space + Vector spritePoint = scenePoint - m_Pos; + spritePoint.FlipX(m_HFlipped); + // Check over overlap + int pixel = getpixel(m_aSprite[m_Frame], spritePoint.m_X - m_SpriteOffset.m_X, spritePoint.m_Y - m_SpriteOffset.m_Y); + // Check that it isn't outside the bitmap, and not of the key color + if (pixel != -1 && pixel != g_MaskColor) + return true; + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: RotateOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Rotates a vector offset from this MORotating's position according to -// the rotate angle and flipping. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RotateOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Rotates a vector offset from this MORotating's position according to + // the rotate angle and flipping. -Vector MOSprite::RotateOffset(const Vector &offset) const -{ - Vector rotOff(offset.GetXFlipped(m_HFlipped)); - rotOff *= const_cast(m_Rotation); - return rotOff; -} + Vector MOSprite::RotateOffset(const Vector& offset) const { + Vector rotOff(offset.GetXFlipped(m_HFlipped)); + rotOff *= const_cast(m_Rotation); + return rotOff; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UnRotateOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Rotates a vector offset from this MORotating's position according to + // the NEGATIVE rotate angle and takes flipping into account. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UnRotateOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Rotates a vector offset from this MORotating's position according to -// the NEGATIVE rotate angle and takes flipping into account. + Vector MOSprite::UnRotateOffset(const Vector& offset) const { + Vector rotOff(offset.GetXFlipped(m_HFlipped)); + rotOff /= const_cast(m_Rotation); + return rotOff; + } -Vector MOSprite::UnRotateOffset(const Vector &offset) const -{ - Vector rotOff(offset.GetXFlipped(m_HFlipped)); - rotOff /= const_cast(m_Rotation); - return rotOff; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure v. method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MOSprite. Supposed to be done every frame. + void MOSprite::Update() { + MovableObject::Update(); -////////////////////////////////////////////////////////////////////////////////////////// -// Pure v. method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MOSprite. Supposed to be done every frame. - -void MOSprite::Update() { - MovableObject::Update(); - - // First, check that the sprite has enough frames to even have an animation and override the setting if not - if (m_FrameCount > 1) { - // If animation mode is set to something other than ALWAYSLOOP but only has 2 frames, override it because it's pointless - if ((m_SpriteAnimMode == ALWAYSRANDOM || m_SpriteAnimMode == ALWAYSPINGPONG) && m_FrameCount == 2) { - m_SpriteAnimMode = ALWAYSLOOP; - } else if (m_SpriteAnimMode == OVERLIFETIME) { - // If animation mode is set to over lifetime but lifetime is unlimited, override to always loop otherwise it will never animate. - if (m_Lifetime == 0) { + // First, check that the sprite has enough frames to even have an animation and override the setting if not + if (m_FrameCount > 1) { + // If animation mode is set to something other than ALWAYSLOOP but only has 2 frames, override it because it's pointless + if ((m_SpriteAnimMode == ALWAYSRANDOM || m_SpriteAnimMode == ALWAYSPINGPONG) && m_FrameCount == 2) { m_SpriteAnimMode = ALWAYSLOOP; - } else { - double lifeTimeFrame = static_cast(m_FrameCount) * (m_AgeTimer.GetElapsedSimTimeMS() / static_cast(m_Lifetime)); - m_Frame = static_cast(std::floor(lifeTimeFrame)); - if (m_Frame >= m_FrameCount) { m_Frame = m_FrameCount - 1; } - return; + } else if (m_SpriteAnimMode == OVERLIFETIME) { + // If animation mode is set to over lifetime but lifetime is unlimited, override to always loop otherwise it will never animate. + if (m_Lifetime == 0) { + m_SpriteAnimMode = ALWAYSLOOP; + } else { + double lifeTimeFrame = static_cast(m_FrameCount) * (m_AgeTimer.GetElapsedSimTimeMS() / static_cast(m_Lifetime)); + m_Frame = static_cast(std::floor(lifeTimeFrame)); + if (m_Frame >= m_FrameCount) { + m_Frame = m_FrameCount - 1; + } + return; + } } + } else { + m_SpriteAnimMode = NOANIM; } - } else { - m_SpriteAnimMode = NOANIM; - } - // Animate the sprite, if applicable - unsigned int frameTime = m_SpriteAnimDuration / m_FrameCount; - unsigned int prevFrame = m_Frame; - - if (m_SpriteAnimTimer.GetElapsedSimTimeMS() > frameTime) { - switch (m_SpriteAnimMode) { - case ALWAYSLOOP: - m_Frame = ((m_Frame + 1) % m_FrameCount); - m_SpriteAnimTimer.Reset(); - break; - case ALWAYSRANDOM: - while (m_Frame == prevFrame) { - m_Frame = RandomNum(0, m_FrameCount - 1); - } - m_SpriteAnimTimer.Reset(); - break; - case ALWAYSPINGPONG: - if (m_Frame == m_FrameCount - 1) { - m_SpriteAnimIsReversingFrames = true; - } else if (m_Frame == 0) { - m_SpriteAnimIsReversingFrames = false; - } - m_SpriteAnimIsReversingFrames ? m_Frame-- : m_Frame++; - m_SpriteAnimTimer.Reset(); - break; - default: - break; + // Animate the sprite, if applicable + unsigned int frameTime = m_SpriteAnimDuration / m_FrameCount; + unsigned int prevFrame = m_Frame; + + if (m_SpriteAnimTimer.GetElapsedSimTimeMS() > frameTime) { + switch (m_SpriteAnimMode) { + case ALWAYSLOOP: + m_Frame = ((m_Frame + 1) % m_FrameCount); + m_SpriteAnimTimer.Reset(); + break; + case ALWAYSRANDOM: + while (m_Frame == prevFrame) { + m_Frame = RandomNum(0, m_FrameCount - 1); + } + m_SpriteAnimTimer.Reset(); + break; + case ALWAYSPINGPONG: + if (m_Frame == m_FrameCount - 1) { + m_SpriteAnimIsReversingFrames = true; + } else if (m_Frame == 0) { + m_SpriteAnimIsReversingFrames = false; + } + m_SpriteAnimIsReversingFrames ? m_Frame-- : m_Frame++; + m_SpriteAnimTimer.Reset(); + break; + default: + break; + } } } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MOSprite's current graphical representation to a + // BITMAP of choice. + + void MOSprite::Draw(BITMAP* pTargetBitmap, + const Vector& targetPos, + DrawMode mode, + bool onlyPhysical) const { + if (!m_aSprite[m_Frame]) + RTEAbort("Sprite frame pointer is null when drawing MOSprite!"); + + // Apply offsets and positions. + Vector spriteOffset; + if (m_HFlipped) + spriteOffset.SetXY(-(m_aSprite[m_Frame]->w + m_SpriteOffset.m_X), m_SpriteOffset.m_Y); + else + spriteOffset = m_SpriteOffset; + + Vector spritePos(m_Pos + spriteOffset - targetPos); + + // Take care of wrapping situations + Vector aDrawPos[4]; + aDrawPos[0] = spritePos; + int passes = 1; + + // Only bother with wrap drawing if the scene actually wraps around + if (g_SceneMan.SceneWrapsX()) { + // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap + if (targetPos.IsZero() && m_WrapDoubleDraw) { + if (spritePos.m_X < m_aSprite[m_Frame]->w) { + aDrawPos[passes] = spritePos; + aDrawPos[passes].m_X += pTargetBitmap->w; + passes++; + } else if (spritePos.m_X > pTargetBitmap->w - m_aSprite[m_Frame]->w) { + aDrawPos[passes] = spritePos; + aDrawPos[passes].m_X -= pTargetBitmap->w; + passes++; + } + } + // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam + else if (m_WrapDoubleDraw) { + if (targetPos.m_X < 0) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X -= g_SceneMan.GetSceneWidth(); + passes++; + } + if (targetPos.m_X + pTargetBitmap->w > g_SceneMan.GetSceneWidth()) { + aDrawPos[passes] = aDrawPos[0]; + aDrawPos[passes].m_X += g_SceneMan.GetSceneWidth(); + passes++; + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MOSprite's current graphical representation to a -// BITMAP of choice. - -void MOSprite::Draw(BITMAP *pTargetBitmap, - const Vector &targetPos, - DrawMode mode, - bool onlyPhysical) const -{ - if (!m_aSprite[m_Frame]) - RTEAbort("Sprite frame pointer is null when drawing MOSprite!"); - - // Apply offsets and positions. - Vector spriteOffset; - if (m_HFlipped) - spriteOffset.SetXY(-(m_aSprite[m_Frame]->w + m_SpriteOffset.m_X), m_SpriteOffset.m_Y); - else - spriteOffset = m_SpriteOffset; - - Vector spritePos(m_Pos + spriteOffset - targetPos); - - // Take care of wrapping situations - Vector aDrawPos[4]; - aDrawPos[0] = spritePos; - int passes = 1; - - // Only bother with wrap drawing if the scene actually wraps around - if (g_SceneMan.SceneWrapsX()) - { - // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap - if (targetPos.IsZero() && m_WrapDoubleDraw) - { - if (spritePos.m_X < m_aSprite[m_Frame]->w) - { - aDrawPos[passes] = spritePos; - aDrawPos[passes].m_X += pTargetBitmap->w; - passes++; - } - else if (spritePos.m_X > pTargetBitmap->w - m_aSprite[m_Frame]->w) - { - aDrawPos[passes] = spritePos; - aDrawPos[passes].m_X -= pTargetBitmap->w; - passes++; - } - } - // Only screenwide target bitmap, so double draw within the screen if the screen is straddling a scene seam - else if (m_WrapDoubleDraw) - { - if (targetPos.m_X < 0) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X -= g_SceneMan.GetSceneWidth(); - passes++; - } - if (targetPos.m_X + pTargetBitmap->w > g_SceneMan.GetSceneWidth()) - { - aDrawPos[passes] = aDrawPos[0]; - aDrawPos[passes].m_X += g_SceneMan.GetSceneWidth(); - passes++; - } - } - } - - for (int i = 0; i < passes; ++i) - { - int spriteX = aDrawPos[i].GetFloorIntX(); - int spriteY = aDrawPos[i].GetFloorIntY(); - switch (mode) { - case g_DrawMaterial: - RTEAbort("Ordered to draw an MOSprite in its material, which is not possible!"); - break; - case g_DrawWhite: - draw_character_ex(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY, g_WhiteColor, -1); - break; - case g_DrawMOID: + for (int i = 0; i < passes; ++i) { + int spriteX = aDrawPos[i].GetFloorIntX(); + int spriteY = aDrawPos[i].GetFloorIntY(); + switch (mode) { + case g_DrawMaterial: + RTEAbort("Ordered to draw an MOSprite in its material, which is not possible!"); + break; + case g_DrawWhite: + draw_character_ex(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY, g_WhiteColor, -1); + break; + case g_DrawMOID: #ifdef DRAW_MOID_LAYER - draw_character_ex(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY, m_MOID, -1); + draw_character_ex(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY, m_MOID, -1); #endif - break; - case g_DrawNoMOID: - draw_character_ex(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY, g_NoMOID, -1); - break; - case g_DrawTrans: - draw_trans_sprite(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); - break; - case g_DrawAlpha: - set_alpha_blender(); - draw_trans_sprite(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); - break; - default: - if (!m_HFlipped) { - draw_sprite(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); - } else { - draw_sprite_h_flip(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); - } - } - - g_SceneMan.RegisterDrawing(pTargetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, spriteX, spriteY, spriteX + m_aSprite[m_Frame]->w, spriteY + m_aSprite[m_Frame]->h); - } -} - -} // namespace RTE \ No newline at end of file + break; + case g_DrawNoMOID: + draw_character_ex(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY, g_NoMOID, -1); + break; + case g_DrawTrans: + draw_trans_sprite(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); + break; + case g_DrawAlpha: + set_alpha_blender(); + draw_trans_sprite(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); + break; + default: + if (!m_HFlipped) { + draw_sprite(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); + } else { + draw_sprite_h_flip(pTargetBitmap, m_aSprite[m_Frame], spriteX, spriteY); + } + } + + g_SceneMan.RegisterDrawing(pTargetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, spriteX, spriteY, spriteX + m_aSprite[m_Frame]->w, spriteY + m_aSprite[m_Frame]->h); + } + } + +} // namespace RTE diff --git a/Source/Entities/MOSprite.h b/Source/Entities/MOSprite.h index c21a52834..7065f185a 100644 --- a/Source/Entities/MOSprite.h +++ b/Source/Entities/MOSprite.h @@ -10,624 +10,583 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "MovableObject.h" #include "Box.h" -namespace RTE -{ - -class AEmitter; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Abstract class: MOSprite -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A movable object with mass that is graphically represented by a -// BITMAP. -// Parent(s): MovableObject. -// Class history: 03/18/2001 MOSprite created. - -class MOSprite : public MovableObject { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableOverrideMethods; - ClassInfoGetters; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MOSprite -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a MOSprite object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - MOSprite() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~MOSprite -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a MOSprite object before deletion -// from system memory. -// Arguments: None. - - ~MOSprite() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSprite object ready for use. -// Arguments: A pointer to ContentFile that represents the bitmap file that will be -// used to create the Sprite. -// The number of frames in the Sprite's animation. -// A float specifying the object's mass in Kilograms (kg). -// A Vector specifying the initial position. -// A Vector specifying the initial velocity. -// The amount of time in ms this MovableObject will exist. 0 means unlim. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(ContentFile spriteFile, const int frameCount = 1, const float mass = 1, const Vector &position = Vector(0, 0), const Vector &velocity = Vector(0, 0), const unsigned long lifetime = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOSprite to be identical to another, by deep copy. -// Arguments: A reference to the MOSprite to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const MOSprite &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MOSprite object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire MOSprite, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); MovableObject::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MOSprite object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRadius -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the largest radius of this in pixels. -// Arguments: None. -// Return value: The radius from its center to the edge of its graphical representation. - - float GetRadius() const override { return m_SpriteRadius; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetDiameter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the largest diameter of this in pixels. -// Arguments: None. -// Return value: The largest diameter across its graphical representation. - - float GetDiameter() const override { return m_SpriteDiameter; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAboveHUDPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of the top of this' HUD stack. -// Arguments: None. -// Return value: A Vector with the absolute position of this' HUD stack top point. - - Vector GetAboveHUDPos() const override { return m_Pos + Vector(0, -GetRadius()); } - -// TODO: Improve this one! Really crappy fit -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetBoundingBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the oriented bounding box which is guaranteed to contain this, -// taking rotation etc into account. It's not guaranteed to be fit -// perfectly though. TODO: MAKE FIT BETTER -// Arguments: None. -// Return value: A Box which is guaranteed to contain this. Does nto take wrapping into -// account, and parts of this box may be out of bounds! - - Box GetBoundingBox() const { return Box(m_Pos + Vector(-GetRadius(), -GetRadius()), GetDiameter(), GetDiameter()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpriteFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a frame of this MOSprite's BITMAP array. -// Arguments: Which frame to get. -// Return value: A pointer to the requested frame of this MOSprite's BITMAP array. -// Ownership is NOT transferred! - - BITMAP * GetSpriteFrame(int whichFrame = 0) const { return (whichFrame >= 0 && whichFrame < m_FrameCount) ? m_aSprite[whichFrame] : 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpriteWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the width of the bitmap of this MOSprite -// Arguments: 0. -// Return value: Sprite width if loaded. - - int GetSpriteWidth() const { return m_aSprite[0] ? m_aSprite[0]->w : 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpriteHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the height of the bitmap of this MOSprite -// Arguments: 0. -// Return value: Sprite height if loaded. - - int GetSpriteHeight() const { return m_aSprite[0] ? m_aSprite[0]->h : 0; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFrameCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of frames in this MOSprite's animation. -// Arguments: None. -// Return value: The frame count. - - int GetFrameCount() const { return m_FrameCount; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpriteOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the offset that the BITMAP has from the position of this -// MOSprite. -// Arguments: None. -// Return value: A vector with the offset. - - Vector GetSpriteOffset() const { return m_SpriteOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsHFlipped -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether this MOSprite is being drawn flipped horizontally -// (along the vertical axis), or not. -// Arguments: None. -// Return value: Whether flipped or not. - - bool IsHFlipped() const override { return m_HFlipped; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRotMatrix -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current rotational Matrix of of this. -// Arguments: None. -// Return value: The rotational Matrix of this MovableObject. - - Matrix GetRotMatrix() const override { return m_Rotation; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRotAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current rotational angle of of this, in radians. -// Arguments: None. -// Return value: The rotational angle of this, in radians. - - float GetRotAngle() const override { return m_Rotation.GetRadAngle(); } - - /// - /// Gets the previous rotational angle of this MOSprite, prior to this frame. - /// - /// The previous rotational angle in radians. - float GetPrevRotAngle() const { return m_PrevRotation.GetRadAngle(); } - - /// - /// Whether a set of X, Y coordinates overlap us (in world space). - /// - /// The given X coordinate, in world space. - /// The given Y coordinate, in world space. - /// Whether the given coordinate overlap us. - bool HitTestAtPixel(int pixelX, int pixelY) const override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAngularVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current angular velocity of this MovableObject. Positive is -// a counter-clockwise rotation. -// Arguments: None. -// Return value: The angular velocity in radians per second. - - float GetAngularVel() const override { return m_AngularVel; } - - -/* Can't do this since sprite is owned by ContentMan. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSprite -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Replaces this MOSprite's BITMAP and deletes the old one. -// Arguments: A pointer to a BITMAP. -// Return value: None. - - void SetSprite(BITMAP *pSprite) { delete m_aSprite; m_aSprite = pSprite; } -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSpriteOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the offset that the BITMAP has from the position of this -// MOSprite. -// Arguments: A vector with the new offset. -// Return value: None. - - void SetSpriteOffset(const Vector &newOffset) { m_SpriteOffset = newOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Hard-sets the frame this sprite is supposed to show. -// Arguments: An unsigned int pecifiying the new frame. -// Return value: None. - - void SetFrame(unsigned int newFrame); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetNextFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Hard-sets the frame this sprite is supposed to show, to the -// consecutive one after the current one. If currently the last fame is -// this will set it to the be the first, looping the animation. -// Arguments: None. -// Return value: Whether the animation looped or not with this setting. - - bool SetNextFrame(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells which frame is currently set to show. -// Arguments: None. -// Return value: An unsigned int describing the current frame. - - unsigned int GetFrame() const { return m_Frame; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSpriteAnimMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the animation mode. -// Arguments: The animation mode we want to set. -// Return value: None. - - void SetSpriteAnimMode(int animMode = NOANIM) { m_SpriteAnimMode = (SpriteAnimMode)animMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSpriteAnimMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the animation mode. -// Arguments: None. -// Return value: The animation mode currently in effect. - - int GetSpriteAnimMode() const { return m_SpriteAnimMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: SetHFlipped -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this MOSprite should be drawn flipped horizontally -// (along the vertical axis). -// Arguments: A bool with the new value. -// Return value: None. - - void SetHFlipped(const bool flipped) override { m_HFlipped = flipped; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetRotAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current absolute angle of rotation of this MovableObject. -// Arguments: The new absolute angle in radians. -// Return value: None. - - void SetRotAngle(float newAngle) override { m_Rotation.SetRadAngle(newAngle); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetAngularVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current angular velocity of this MovableObject. Positive is -// a counter clockwise rotation. -// Arguments: The new angular velocity in radians per second. -// Return value: None. - - void SetAngularVel(float newRotVel) override { m_AngularVel = newRotVel; } - - - /// - /// Gets the GUI representation of this MOSprite, either based on the first frame of its sprite or separately defined icon file. - /// - /// The graphical representation of this MOSprite as a BITMAP. - BITMAP * GetGraphicalIcon() const override { return m_GraphicalIcon != nullptr ? m_GraphicalIcon : m_aSprite[0]; } - - /// - /// Gets the width of this MOSprite's GUI icon. - /// - /// The width of the GUI icon bitmap. - int GetIconWidth() const { return GetGraphicalIcon()->w; } - - /// - /// Gets the height of this MOSprite's GUI icon. - /// - /// The height of the GUI icon bitmap. - int GetIconHeight() const { return GetGraphicalIcon()->h; } - - /// - /// Forces this MOSprite out of resting conditions. - /// - void NotResting() override { MovableObject::NotResting(); m_AngOscillations = 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsTooFast -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is moving or rotating stupidly fast in a way -// that will screw up the simulation. -// Arguments: None. -// Return value: Whether this is either moving or rotating too fast. - - bool IsTooFast() const override { return m_Vel.MagnitudeIsGreaterThan(500.0F) || std::fabs(m_AngularVel) > (2000.0F / (GetRadius() + 1.0F)); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: FixTooFast -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Slows the speed of anything that is deemed to be too fast to within -// acceptable rates. -// Arguments: None. -// Return value: None. - - void FixTooFast() override { while (IsTooFast()) { m_Vel *= 0.5F; m_AngularVel *= 0.5F; } } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. -// Arguments: The point in absolute scene coordinates. -// Return value: Whether this' graphical rep overlaps the scene point. - - bool IsOnScenePoint(Vector &scenePoint) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: RotateOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes a vector which is offset from the center of this when not rotated -// or flipped, and then rotates and/or flips it to transform it into this' -// 'local space', if applicable. -// Arguments: A vector which is supposed to be offset from this' center when upright. -// Return value: The resulting vector whihch has been flipped and rotated as appropriate. - - Vector RotateOffset(const Vector &offset) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UnRotateOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes a vector which is offset from the center of this when not rotated -// or flipped, and then rotates and/or flips it to transform it into this' -// 'local space', but in REVERSE. -// Arguments: A vector which is supposed to be offset from this' center when upright. -// Return value: The resulting vector whihch has been flipped and rotated as appropriate. - - Vector UnRotateOffset(const Vector &offset) const; - - /// - /// Adjusts an absolute angle based on wether this MOSprite is flipped. - /// - /// The input angle in radians. - /// The output angle in radians, which will be unaltered if this MOSprite is not flipped. - float FacingAngle(float angle) const { return (m_HFlipped ? c_PI : 0) + (angle * GetFlipFactor()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetEntryWound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets entry wound emitter for this MOSprite -// Arguments: Emitter preset name and module name -// Return value: None - - void SetEntryWound(std::string presetName, std::string moduleName); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetExitWound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets exit wound emitter for this MOSprite -// Arguments: Emitter preset name and module name -// Return value: None - - void SetExitWound(std::string presetName, std::string moduleName); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEntryWoundPresetName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns entry wound emitter preset name for this MOSprite -// Arguments: None -// Return value: Wound emitter preset name - - std::string GetEntryWoundPresetName() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetExitWoundPresetName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns exit wound emitter preset name for this MOSprite -// Arguments: None -// Return value: Wound emitter preset name - - std::string GetExitWoundPresetName() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetSpriteAnimDuration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns animation duration in ms -// Arguments: None -// Return value: Animation duration in ms - - int GetSpriteAnimDuration() const { return m_SpriteAnimDuration; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetSpriteAnimDuration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets animation duration in ms -// Arguments: Animation duration in ms -// Return value: Mone - - void SetSpriteAnimDuration(int newDuration) { m_SpriteAnimDuration = newDuration; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MOSprite's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetFlipFactor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a positive or negative number value to multiply with for external calculations. -// Arguments: None. -// Return value: 1 for not flipped, -1 for flipped. - - float GetFlipFactor() const { return m_HFlipped ? -1.0F : 1.0F; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - - Matrix m_Rotation; // Rotational matrix of this MovableObject. - Matrix m_PrevRotation; // Rotational matrix of this MovableObject, last frame. - float m_AngularVel; // The angular velocity by which this MovableObject rotates, in radians per second (r/s). - float m_PrevAngVel; // Previous frame's angular velocity. - ContentFile m_SpriteFile; - // Vector of pointers to BITMAPs representing the multiple frames of this sprite. - std::vector m_aSprite; - ContentFile m_IconFile; //!< The file containing the GUI icon. - BITMAP *m_GraphicalIcon; //!< The GUI representation of this MOSprite as a BITMAP. - // Number of frames, or elements in the m_aSprite array. - unsigned int m_FrameCount; - Vector m_SpriteOffset; - // State, which frame of sprite to be drawn. - unsigned int m_Frame; - // Which animation to use for the body - SpriteAnimMode m_SpriteAnimMode; - // Body animation duration, how long in ms that each full body animation cycle takes. - int m_SpriteAnimDuration; - // The timer to keep track of the body animation - Timer m_SpriteAnimTimer; - // Keep track of animation direction (mainly for ALWAYSPINGPONG), true is decreasing frame, false is increasing frame - bool m_SpriteAnimIsReversingFrames; - // Whether flipped horizontally or not. - bool m_HFlipped; - // The precalculated maximum possible radius and diameter of this, in pixels - float m_SpriteRadius; - float m_SpriteDiameter; - int m_AngOscillations; //!< A counter for oscillations in rotation, in order to detect settling. - // Whether to disable the settle material ID when this gets drawn as material - bool m_SettleMaterialDisabled; - // Entry wound template - const AEmitter *m_pEntryWound; - // Exit wound template - const AEmitter *m_pExitWound; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MOSprite, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - MOSprite(const MOSprite &reference) = delete; - MOSprite & operator=(const MOSprite &rhs) = delete; - -}; +namespace RTE { + + class AEmitter; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Abstract class: MOSprite + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A movable object with mass that is graphically represented by a + // BITMAP. + // Parent(s): MovableObject. + // Class history: 03/18/2001 MOSprite created. + + class MOSprite : public MovableObject { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MOSprite + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a MOSprite object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + MOSprite() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~MOSprite + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a MOSprite object before deletion + // from system memory. + // Arguments: None. + + ~MOSprite() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSprite object ready for use. + // Arguments: A pointer to ContentFile that represents the bitmap file that will be + // used to create the Sprite. + // The number of frames in the Sprite's animation. + // A float specifying the object's mass in Kilograms (kg). + // A Vector specifying the initial position. + // A Vector specifying the initial velocity. + // The amount of time in ms this MovableObject will exist. 0 means unlim. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(ContentFile spriteFile, const int frameCount = 1, const float mass = 1, const Vector& position = Vector(0, 0), const Vector& velocity = Vector(0, 0), const unsigned long lifetime = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOSprite to be identical to another, by deep copy. + // Arguments: A reference to the MOSprite to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const MOSprite& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MOSprite object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire MOSprite, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + MovableObject::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MOSprite object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRadius + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the largest radius of this in pixels. + // Arguments: None. + // Return value: The radius from its center to the edge of its graphical representation. + + float GetRadius() const override { return m_SpriteRadius; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetDiameter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the largest diameter of this in pixels. + // Arguments: None. + // Return value: The largest diameter across its graphical representation. + + float GetDiameter() const override { return m_SpriteDiameter; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAboveHUDPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of the top of this' HUD stack. + // Arguments: None. + // Return value: A Vector with the absolute position of this' HUD stack top point. + + Vector GetAboveHUDPos() const override { return m_Pos + Vector(0, -GetRadius()); } + + // TODO: Improve this one! Really crappy fit + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetBoundingBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the oriented bounding box which is guaranteed to contain this, + // taking rotation etc into account. It's not guaranteed to be fit + // perfectly though. TODO: MAKE FIT BETTER + // Arguments: None. + // Return value: A Box which is guaranteed to contain this. Does nto take wrapping into + // account, and parts of this box may be out of bounds! + + Box GetBoundingBox() const { return Box(m_Pos + Vector(-GetRadius(), -GetRadius()), GetDiameter(), GetDiameter()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpriteFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a frame of this MOSprite's BITMAP array. + // Arguments: Which frame to get. + // Return value: A pointer to the requested frame of this MOSprite's BITMAP array. + // Ownership is NOT transferred! + + BITMAP* GetSpriteFrame(int whichFrame = 0) const { return (whichFrame >= 0 && whichFrame < m_FrameCount) ? m_aSprite[whichFrame] : 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpriteWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the width of the bitmap of this MOSprite + // Arguments: 0. + // Return value: Sprite width if loaded. + + int GetSpriteWidth() const { return m_aSprite[0] ? m_aSprite[0]->w : 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpriteHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the height of the bitmap of this MOSprite + // Arguments: 0. + // Return value: Sprite height if loaded. + + int GetSpriteHeight() const { return m_aSprite[0] ? m_aSprite[0]->h : 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFrameCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of frames in this MOSprite's animation. + // Arguments: None. + // Return value: The frame count. + + int GetFrameCount() const { return m_FrameCount; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpriteOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the offset that the BITMAP has from the position of this + // MOSprite. + // Arguments: None. + // Return value: A vector with the offset. + + Vector GetSpriteOffset() const { return m_SpriteOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsHFlipped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether this MOSprite is being drawn flipped horizontally + // (along the vertical axis), or not. + // Arguments: None. + // Return value: Whether flipped or not. + + bool IsHFlipped() const override { return m_HFlipped; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRotMatrix + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current rotational Matrix of of this. + // Arguments: None. + // Return value: The rotational Matrix of this MovableObject. + + Matrix GetRotMatrix() const override { return m_Rotation; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRotAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current rotational angle of of this, in radians. + // Arguments: None. + // Return value: The rotational angle of this, in radians. + + float GetRotAngle() const override { return m_Rotation.GetRadAngle(); } + + /// + /// Gets the previous rotational angle of this MOSprite, prior to this frame. + /// + /// The previous rotational angle in radians. + float GetPrevRotAngle() const { return m_PrevRotation.GetRadAngle(); } + + /// + /// Whether a set of X, Y coordinates overlap us (in world space). + /// + /// The given X coordinate, in world space. + /// The given Y coordinate, in world space. + /// Whether the given coordinate overlap us. + bool HitTestAtPixel(int pixelX, int pixelY) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAngularVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current angular velocity of this MovableObject. Positive is + // a counter-clockwise rotation. + // Arguments: None. + // Return value: The angular velocity in radians per second. + + float GetAngularVel() const override { return m_AngularVel; } + + /* Can't do this since sprite is owned by ContentMan. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSprite + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Replaces this MOSprite's BITMAP and deletes the old one. + // Arguments: A pointer to a BITMAP. + // Return value: None. + + void SetSprite(BITMAP *pSprite) { delete m_aSprite; m_aSprite = pSprite; } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSpriteOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the offset that the BITMAP has from the position of this + // MOSprite. + // Arguments: A vector with the new offset. + // Return value: None. + + void SetSpriteOffset(const Vector& newOffset) { m_SpriteOffset = newOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Hard-sets the frame this sprite is supposed to show. + // Arguments: An unsigned int pecifiying the new frame. + // Return value: None. + + void SetFrame(unsigned int newFrame); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetNextFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Hard-sets the frame this sprite is supposed to show, to the + // consecutive one after the current one. If currently the last fame is + // this will set it to the be the first, looping the animation. + // Arguments: None. + // Return value: Whether the animation looped or not with this setting. + + bool SetNextFrame(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells which frame is currently set to show. + // Arguments: None. + // Return value: An unsigned int describing the current frame. + + unsigned int GetFrame() const { return m_Frame; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSpriteAnimMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the animation mode. + // Arguments: The animation mode we want to set. + // Return value: None. + + void SetSpriteAnimMode(int animMode = NOANIM) { m_SpriteAnimMode = (SpriteAnimMode)animMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSpriteAnimMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the animation mode. + // Arguments: None. + // Return value: The animation mode currently in effect. + + int GetSpriteAnimMode() const { return m_SpriteAnimMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: SetHFlipped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this MOSprite should be drawn flipped horizontally + // (along the vertical axis). + // Arguments: A bool with the new value. + // Return value: None. + + void SetHFlipped(const bool flipped) override { m_HFlipped = flipped; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetRotAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current absolute angle of rotation of this MovableObject. + // Arguments: The new absolute angle in radians. + // Return value: None. + + void SetRotAngle(float newAngle) override { m_Rotation.SetRadAngle(newAngle); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetAngularVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current angular velocity of this MovableObject. Positive is + // a counter clockwise rotation. + // Arguments: The new angular velocity in radians per second. + // Return value: None. + + void SetAngularVel(float newRotVel) override { m_AngularVel = newRotVel; } + + /// + /// Gets the GUI representation of this MOSprite, either based on the first frame of its sprite or separately defined icon file. + /// + /// The graphical representation of this MOSprite as a BITMAP. + BITMAP* GetGraphicalIcon() const override { return m_GraphicalIcon != nullptr ? m_GraphicalIcon : m_aSprite[0]; } + + /// + /// Gets the width of this MOSprite's GUI icon. + /// + /// The width of the GUI icon bitmap. + int GetIconWidth() const { return GetGraphicalIcon()->w; } + + /// + /// Gets the height of this MOSprite's GUI icon. + /// + /// The height of the GUI icon bitmap. + int GetIconHeight() const { return GetGraphicalIcon()->h; } + + /// + /// Forces this MOSprite out of resting conditions. + /// + void NotResting() override { + MovableObject::NotResting(); + m_AngOscillations = 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsTooFast + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is moving or rotating stupidly fast in a way + // that will screw up the simulation. + // Arguments: None. + // Return value: Whether this is either moving or rotating too fast. + + bool IsTooFast() const override { return m_Vel.MagnitudeIsGreaterThan(500.0F) || std::fabs(m_AngularVel) > (2000.0F / (GetRadius() + 1.0F)); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: FixTooFast + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Slows the speed of anything that is deemed to be too fast to within + // acceptable rates. + // Arguments: None. + // Return value: None. + + void FixTooFast() override { + while (IsTooFast()) { + m_Vel *= 0.5F; + m_AngularVel *= 0.5F; + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + // Arguments: The point in absolute scene coordinates. + // Return value: Whether this' graphical rep overlaps the scene point. + + bool IsOnScenePoint(Vector& scenePoint) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RotateOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes a vector which is offset from the center of this when not rotated + // or flipped, and then rotates and/or flips it to transform it into this' + // 'local space', if applicable. + // Arguments: A vector which is supposed to be offset from this' center when upright. + // Return value: The resulting vector whihch has been flipped and rotated as appropriate. + + Vector RotateOffset(const Vector& offset) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UnRotateOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes a vector which is offset from the center of this when not rotated + // or flipped, and then rotates and/or flips it to transform it into this' + // 'local space', but in REVERSE. + // Arguments: A vector which is supposed to be offset from this' center when upright. + // Return value: The resulting vector whihch has been flipped and rotated as appropriate. + + Vector UnRotateOffset(const Vector& offset) const; + + /// + /// Adjusts an absolute angle based on wether this MOSprite is flipped. + /// + /// The input angle in radians. + /// The output angle in radians, which will be unaltered if this MOSprite is not flipped. + float FacingAngle(float angle) const { return (m_HFlipped ? c_PI : 0) + (angle * GetFlipFactor()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetEntryWound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets entry wound emitter for this MOSprite + // Arguments: Emitter preset name and module name + // Return value: None + + void SetEntryWound(std::string presetName, std::string moduleName); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetExitWound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets exit wound emitter for this MOSprite + // Arguments: Emitter preset name and module name + // Return value: None + + void SetExitWound(std::string presetName, std::string moduleName); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEntryWoundPresetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns entry wound emitter preset name for this MOSprite + // Arguments: None + // Return value: Wound emitter preset name + + std::string GetEntryWoundPresetName() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetExitWoundPresetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns exit wound emitter preset name for this MOSprite + // Arguments: None + // Return value: Wound emitter preset name + + std::string GetExitWoundPresetName() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetSpriteAnimDuration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns animation duration in ms + // Arguments: None + // Return value: Animation duration in ms + + int GetSpriteAnimDuration() const { return m_SpriteAnimDuration; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetSpriteAnimDuration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets animation duration in ms + // Arguments: Animation duration in ms + // Return value: Mone + + void SetSpriteAnimDuration(int newDuration) { m_SpriteAnimDuration = newDuration; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MOSprite's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetFlipFactor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a positive or negative number value to multiply with for external calculations. + // Arguments: None. + // Return value: 1 for not flipped, -1 for flipped. + + float GetFlipFactor() const { return m_HFlipped ? -1.0F : 1.0F; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + + Matrix m_Rotation; // Rotational matrix of this MovableObject. + Matrix m_PrevRotation; // Rotational matrix of this MovableObject, last frame. + float m_AngularVel; // The angular velocity by which this MovableObject rotates, in radians per second (r/s). + float m_PrevAngVel; // Previous frame's angular velocity. + ContentFile m_SpriteFile; + // Vector of pointers to BITMAPs representing the multiple frames of this sprite. + std::vector m_aSprite; + ContentFile m_IconFile; //!< The file containing the GUI icon. + BITMAP* m_GraphicalIcon; //!< The GUI representation of this MOSprite as a BITMAP. + // Number of frames, or elements in the m_aSprite array. + unsigned int m_FrameCount; + Vector m_SpriteOffset; + // State, which frame of sprite to be drawn. + unsigned int m_Frame; + // Which animation to use for the body + SpriteAnimMode m_SpriteAnimMode; + // Body animation duration, how long in ms that each full body animation cycle takes. + int m_SpriteAnimDuration; + // The timer to keep track of the body animation + Timer m_SpriteAnimTimer; + // Keep track of animation direction (mainly for ALWAYSPINGPONG), true is decreasing frame, false is increasing frame + bool m_SpriteAnimIsReversingFrames; + // Whether flipped horizontally or not. + bool m_HFlipped; + // The precalculated maximum possible radius and diameter of this, in pixels + float m_SpriteRadius; + float m_SpriteDiameter; + int m_AngOscillations; //!< A counter for oscillations in rotation, in order to detect settling. + // Whether to disable the settle material ID when this gets drawn as material + bool m_SettleMaterialDisabled; + // Entry wound template + const AEmitter* m_pEntryWound; + // Exit wound template + const AEmitter* m_pExitWound; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MOSprite, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + MOSprite(const MOSprite& reference) = delete; + MOSprite& operator=(const MOSprite& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/Magazine.cpp b/Source/Entities/Magazine.cpp index db49161a5..1001c9734 100644 --- a/Source/Entities/Magazine.cpp +++ b/Source/Entities/Magazine.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -17,296 +16,263 @@ namespace RTE { -ConcreteClassInfo(Magazine, Attachable, 50); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Magazine, effectively -// resetting the members of this abstraction level only. - -void Magazine::Clear() -{ - m_RoundCount = 0; - m_FullCapacity = 0; - m_RTTRatio = 0; - m_pRegularRound = 0; - m_pTracerRound = 0; - m_Discardable = true; - m_AIAimVel = 100; - m_AIAimMaxDistance = -1; - m_AIAimPenetration = 0; - m_AIBlastRadius = -1; - - // NOTE: This special override of a parent class member variable avoids needing an extra variable to avoid overwriting INI values. - m_CollidesWithTerrainWhileAttached = false; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Magazine object ready for use. - -int Magazine::Create() -{ - if (Attachable::Create() < 0) - return -1; - - // Read projectile properties for AI aim caluculations - const Round * pNextRound = GetNextRound(); - if (pNextRound) - { - // What muzzle velocity should the AI use when aiming? - m_AIAimVel = pNextRound->GetAIFireVel() < 0 ? pNextRound->GetFireVel() : pNextRound->GetAIFireVel(); - - // How much material can this projectile penetrate? - m_AIAimPenetration = pNextRound->GetAIPenetration(); - - if (pNextRound->GetAIFireVel() < 0) - { - const MovableObject * pBullet = pNextRound->GetNextParticle(); - if(pBullet) - { - // Also get FireVel on emitters from sharpness to assure backwards compability with mods - const AEmitter * pEmitter = dynamic_cast(pBullet); - if (pEmitter) - m_AIAimVel = std::max(m_AIAimVel, pEmitter->GetSharpness()); - } - } - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Magazine to be identical to another, by deep copy. - -int Magazine::Create(const Magazine &reference) -{ - Attachable::Create(reference); - - m_RoundCount = reference.m_RoundCount; - m_FullCapacity = reference.m_FullCapacity; - m_RTTRatio = reference.m_RTTRatio; - m_pRegularRound = reference.m_pRegularRound; - m_pTracerRound = reference.m_pTracerRound; - m_Discardable = reference.m_Discardable; - m_AIBlastRadius = reference.m_AIBlastRadius; - m_AIAimPenetration = reference.m_AIAimPenetration; - m_AIAimVel = reference.m_AIAimVel; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int Magazine::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Attachable::ReadProperty(propName, reader)); - - MatchProperty("RoundCount", { - reader >> m_RoundCount; - m_FullCapacity = m_RoundCount; - }); - MatchProperty("RTTRatio", { reader >> m_RTTRatio; }); - MatchProperty("RegularRound", { m_pRegularRound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); - MatchProperty("TracerRound", { m_pTracerRound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); - MatchProperty("Discardable", { reader >> m_Discardable; }); - MatchProperty("AIBlastRadius", { reader >> m_AIBlastRadius; }); - - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Magazine with a Writer for -// later recreation with Create(Reader &reader); - -int Magazine::Save(Writer &writer) const -{ - Attachable::Save(writer); - - writer.NewProperty("RoundCount"); - writer << m_RoundCount; - writer.NewProperty("RTTRatio"); - writer << m_RTTRatio; - writer.NewProperty("RegularRound"); - writer << m_pRegularRound; - writer.NewProperty("TracerRound"); - writer << m_pTracerRound; - writer.NewProperty("Discardable"); - writer << m_Discardable; - writer.NewProperty("AIBlastRadius"); - writer << m_AIBlastRadius; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the Magazine object. - -void Magazine::Destroy(bool notInherited) -{ - - if (!notInherited) - Attachable::Destroy(); - Clear(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetNextRound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next Round preset of ammo in this Magazine, without removing -// it. Ownership IS NOT transferred! - -const Round * Magazine::GetNextRound() const -{ - const Round *tempRound = 0; - if (m_RoundCount != 0) - { - if (m_RTTRatio && m_pTracerRound && m_RoundCount % m_RTTRatio == 0) - tempRound = m_pTracerRound; - else - tempRound = m_pRegularRound; - } - return tempRound; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PopNextRound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next Round of ammo in this Magazine, and removes it from the -// stack. Ownership IS transferred! - -Round * Magazine::PopNextRound() -{ - Round *tempRound = 0; - if (m_RoundCount != 0) - { - if (m_RTTRatio && m_pTracerRound && m_RoundCount % m_RTTRatio == 0) - tempRound = dynamic_cast(m_pTracerRound->Clone()); - else - tempRound = dynamic_cast(m_pRegularRound->Clone()); - // Negative roundcount means infinite ammo - if (m_FullCapacity > 0) - m_RoundCount--; - } - return tempRound; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EstimateDigStrength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Estimates what material strength the rounds in the magazine can destroy. - -float Magazine::EstimateDigStrength() const { - float maxPenetration = 1; - if (m_pTracerRound) - { - // Find the next tracer - const MovableObject * pBullet = m_pTracerRound->GetNextParticle(); - if (pBullet) - { - if (m_pTracerRound->GetAIFireVel() > 0) - maxPenetration = std::max(maxPenetration, m_pTracerRound->GetAIFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); - else - maxPenetration = std::max(maxPenetration, m_pTracerRound->GetFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); - } - } - - if (m_pRegularRound) - { - // Find the next regular bullet - const MovableObject * pBullet = m_pRegularRound->GetNextParticle(); - if (pBullet) - { - if (m_pRegularRound->GetAIFireVel() > 0) - maxPenetration = std::max(maxPenetration, m_pRegularRound->GetAIFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); - else - maxPenetration = std::max(maxPenetration, m_pRegularRound->GetFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); - } - } - - return maxPenetration; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBulletAccScalar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. - -float Magazine::GetBulletAccScalar() -{ - const Round * pRound = GetNextRound(); - if (pRound) - { - const MovableObject * pBullet = pRound->GetNextParticle(); - if (pBullet) - return pBullet->GetGlobalAccScalar(); - } - - return 1; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this Magazine. Supposed to be done every frame. - -void Magazine::Update() -{ - Attachable::Update(); - - /*if (!m_pParent) { - - } - else { - ///////////////////////////////// - // Update rotations and scale - - // Taken care of by holder/owner Arm. + ConcreteClassInfo(Magazine, Attachable, 50); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Magazine, effectively + // resetting the members of this abstraction level only. + + void Magazine::Clear() { + m_RoundCount = 0; + m_FullCapacity = 0; + m_RTTRatio = 0; + m_pRegularRound = 0; + m_pTracerRound = 0; + m_Discardable = true; + m_AIAimVel = 100; + m_AIAimMaxDistance = -1; + m_AIAimPenetration = 0; + m_AIBlastRadius = -1; + + // NOTE: This special override of a parent class member variable avoids needing an extra variable to avoid overwriting INI values. + m_CollidesWithTerrainWhileAttached = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Magazine object ready for use. + + int Magazine::Create() { + if (Attachable::Create() < 0) + return -1; + + // Read projectile properties for AI aim caluculations + const Round* pNextRound = GetNextRound(); + if (pNextRound) { + // What muzzle velocity should the AI use when aiming? + m_AIAimVel = pNextRound->GetAIFireVel() < 0 ? pNextRound->GetFireVel() : pNextRound->GetAIFireVel(); + + // How much material can this projectile penetrate? + m_AIAimPenetration = pNextRound->GetAIPenetration(); + + if (pNextRound->GetAIFireVel() < 0) { + const MovableObject* pBullet = pNextRound->GetNextParticle(); + if (pBullet) { + // Also get FireVel on emitters from sharpness to assure backwards compability with mods + const AEmitter* pEmitter = dynamic_cast(pBullet); + if (pEmitter) + m_AIAimVel = std::max(m_AIAimVel, pEmitter->GetSharpness()); + } + } + } + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Magazine to be identical to another, by deep copy. + + int Magazine::Create(const Magazine& reference) { + Attachable::Create(reference); + + m_RoundCount = reference.m_RoundCount; + m_FullCapacity = reference.m_FullCapacity; + m_RTTRatio = reference.m_RTTRatio; + m_pRegularRound = reference.m_pRegularRound; + m_pTracerRound = reference.m_pTracerRound; + m_Discardable = reference.m_Discardable; + m_AIBlastRadius = reference.m_AIBlastRadius; + m_AIAimPenetration = reference.m_AIAimPenetration; + m_AIAimVel = reference.m_AIAimVel; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int Magazine::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Attachable::ReadProperty(propName, reader)); + + MatchProperty("RoundCount", { + reader >> m_RoundCount; + m_FullCapacity = m_RoundCount; + }); + MatchProperty("RTTRatio", { reader >> m_RTTRatio; }); + MatchProperty("RegularRound", { m_pRegularRound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); + MatchProperty("TracerRound", { m_pTracerRound = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); + MatchProperty("Discardable", { reader >> m_Discardable; }); + MatchProperty("AIBlastRadius", { reader >> m_AIBlastRadius; }); + + EndPropertyList; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Magazine with a Writer for + // later recreation with Create(Reader &reader); + + int Magazine::Save(Writer& writer) const { + Attachable::Save(writer); + + writer.NewProperty("RoundCount"); + writer << m_RoundCount; + writer.NewProperty("RTTRatio"); + writer << m_RTTRatio; + writer.NewProperty("RegularRound"); + writer << m_pRegularRound; + writer.NewProperty("TracerRound"); + writer << m_pTracerRound; + writer.NewProperty("Discardable"); + writer << m_Discardable; + writer.NewProperty("AIBlastRadius"); + writer << m_AIBlastRadius; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the Magazine object. + + void Magazine::Destroy(bool notInherited) { + + if (!notInherited) + Attachable::Destroy(); + Clear(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetNextRound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next Round preset of ammo in this Magazine, without removing + // it. Ownership IS NOT transferred! + + const Round* Magazine::GetNextRound() const { + const Round* tempRound = 0; + if (m_RoundCount != 0) { + if (m_RTTRatio && m_pTracerRound && m_RoundCount % m_RTTRatio == 0) + tempRound = m_pTracerRound; + else + tempRound = m_pRegularRound; + } + return tempRound; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PopNextRound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next Round of ammo in this Magazine, and removes it from the + // stack. Ownership IS transferred! + + Round* Magazine::PopNextRound() { + Round* tempRound = 0; + if (m_RoundCount != 0) { + if (m_RTTRatio && m_pTracerRound && m_RoundCount % m_RTTRatio == 0) + tempRound = dynamic_cast(m_pTracerRound->Clone()); + else + tempRound = dynamic_cast(m_pRegularRound->Clone()); + // Negative roundcount means infinite ammo + if (m_FullCapacity > 0) + m_RoundCount--; + } + return tempRound; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EstimateDigStrength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Estimates what material strength the rounds in the magazine can destroy. + + float Magazine::EstimateDigStrength() const { + float maxPenetration = 1; + if (m_pTracerRound) { + // Find the next tracer + const MovableObject* pBullet = m_pTracerRound->GetNextParticle(); + if (pBullet) { + if (m_pTracerRound->GetAIFireVel() > 0) + maxPenetration = std::max(maxPenetration, m_pTracerRound->GetAIFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); + else + maxPenetration = std::max(maxPenetration, m_pTracerRound->GetFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); + } + } + + if (m_pRegularRound) { + // Find the next regular bullet + const MovableObject* pBullet = m_pRegularRound->GetNextParticle(); + if (pBullet) { + if (m_pRegularRound->GetAIFireVel() > 0) + maxPenetration = std::max(maxPenetration, m_pRegularRound->GetAIFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); + else + maxPenetration = std::max(maxPenetration, m_pRegularRound->GetFireVel() * abs(pBullet->GetMass()) * std::max(pBullet->GetSharpness(), 0.0f)); + } + } + + return maxPenetration; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBulletAccScalar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. + + float Magazine::GetBulletAccScalar() { + const Round* pRound = GetNextRound(); + if (pRound) { + const MovableObject* pBullet = pRound->GetNextParticle(); + if (pBullet) + return pBullet->GetGlobalAccScalar(); + } + + return 1; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this Magazine. Supposed to be done every frame. + + void Magazine::Update() { + Attachable::Update(); + + /*if (!m_pParent) { + + } + else { + ///////////////////////////////// + // Update rotations and scale + + // Taken care of by holder/owner Arm. // m_Pos += m_ParentOffset; // Only apply in Draw(). // m_aSprite->SetAngle(m_Rotation); // m_aSprite->SetScale(m_Scale); - }*/ -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Magazine's current graphical representation to a -// BITMAP of choice. - -void Magazine::Draw(BITMAP *pTargetBitmap, - const Vector &targetPos, - DrawMode mode, - bool onlyPhysical) const -{ - Attachable::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); -} + }*/ + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Magazine's current graphical representation to a + // BITMAP of choice. + + void Magazine::Draw(BITMAP* pTargetBitmap, + const Vector& targetPos, + DrawMode mode, + bool onlyPhysical) const { + Attachable::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } } // namespace RTE diff --git a/Source/Entities/Magazine.h b/Source/Entities/Magazine.h index 29f287ce3..07e336268 100644 --- a/Source/Entities/Magazine.h +++ b/Source/Entities/Magazine.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,314 +18,287 @@ namespace RTE { - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: Magazine -////////////////////////////////////////////////////////////////////////////////////////// -// Description: An Attachable ammo magazine that can hold rounds that can be fired -// by HDFirearm:s. -// Parent(s): Attachable. -// Class history: 07/03/2002 Magazine created. - -class Magazine : public Attachable { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -// Concrete allocation and cloning definitions -EntityAllocation(Magazine); -SerializableOverrideMethods; -ClassInfoGetters; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: Magazine -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a Magazine object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - Magazine() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~Magazine -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a Magazine object before deletion -// from system memory. -// Arguments: None. - - ~Magazine() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Magazine object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Magazine to be identical to another, by deep copy. -// Arguments: A reference to the Magazine to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const Magazine &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire Magazine, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Attachable::Reset(); m_CollidesWithTerrainWhileAttached = false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneLayer object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetNextRound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next Round preset of ammo in this Magazine, without removing -// it. Ownership IS NOT transferred! -// Arguments: None. -// Return value: A pointer to the next Round preset of ammo, or 0 if this Magazine is empty. - - const Round * GetNextRound() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PopNextRound -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next Round of ammo in this Magazine, and removes it from the -// stack. Ownership IS transferred! -// Arguments: None. -// Return value: A pointer to the next Round of ammo, or 0 if this Magazine is empty. - - Round * PopNextRound(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRoundCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns how many rounds are left in this Magazine. -// Arguments: None. -// Return value: The number of rounds left. Negative value means infinite ammo left! - - int GetRoundCount() const { return m_RoundCount; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetRoundCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets how many rounds are left in this Magazine. -// Arguments: The new number of rounds left. Negative value means infinite ammo! -// Return value: None. - - void SetRoundCount(int newCount) { m_RoundCount = newCount; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsEmpty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether this Magazine is out of rounds. -// Arguments: None. -// Return value: Whether this Magazine is out of rounds or not. - - bool IsEmpty() const { return m_FullCapacity >= 0 && m_RoundCount == 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsFull -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether this Magazine has not used up any rounds yet. -// Arguments: None. -// Return value: Whether this Magazine has not used any rounds yet. - - bool IsFull() const { return m_FullCapacity > 0 ? (m_RoundCount == m_FullCapacity || m_RoundCount < 0) : m_FullCapacity < 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsOverHalfFull -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether this Magazine has not used up half of the rounds yet. -// Arguments: None. -// Return value: Whether this Magazine has not used half of its rounds yet. - - bool IsOverHalfFull() const { return m_FullCapacity > 0 ? ((m_RoundCount > (m_FullCapacity / 2)) || m_RoundCount < 0) : m_FullCapacity < 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCapacity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns teh number of rounds this can hold when it's full. -// Arguments: None. -// Return value: The number of rounds this can hold. Negative value means infinite ammo. - - int GetCapacity() const { return m_FullCapacity; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDiscardable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Whether this Magazine should be released into the scene when discarded -// or just deleted. -// Arguments: None. -// Return value: Whether this Magazine should be relesed into scene or deleted when released. - - bool IsDiscardable() const { return m_Discardable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EstimateDigStrength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Estimates what material strength the rounds in the magazine can destroy. -// Arguments: None. -// Return value: The material strength. - - float EstimateDigStrength() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAimVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells the AI what muzzle velocity to assume when aiming this weapon. -// Arguments: None. -// Return value: Velocity in m/s. - - float GetAIAimVel() const { return m_AIAimVel; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIAimBlastRadius -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells the AI what distance in pixels from the rounds in this mag round -// are mostly safe. -// Arguments: None. -// Return value: Distance in pixels. - - int GetAIAimBlastRadius() const { return m_AIBlastRadius; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAIAimPenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells the AI how much material this projectile can penetrate. -// Arguments: None. -// Return value: The material strenght. - - float GetAIAimPenetration() const { return m_AIAimPenetration; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBulletAccScalar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. -// Arguments: None. -// Return value: A float with the scalar. - - float GetBulletAccScalar(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this Magazine's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// indicator arrows or hovering HUD text and so on. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - - // How many rounds in mag. Negative value means infinite ammo - int m_RoundCount; - // The number of rounds that this mag holds. negative menas infinite ammo capacity - int m_FullCapacity; - // The ratio between regular and tracer rounds. 0 means no tracers. - // e.g. 3 means every third round will be a tracer. ie Round To Tracer (RTT) ratio. - int m_RTTRatio; - // Round reference instances. - const Round *m_pRegularRound; - const Round *m_pTracerRound; - // Whether this magazine should be released into the scene when discarded, or just be deleted instead - bool m_Discardable; - // The muzzle velocity the AI use when aiming this gun. calculated when the magazine is created - float m_AIAimVel; - // The estimated maximum distance in pixels the projectiles can hit from - float m_AIAimMaxDistance; - // The half of the theoretical upper limit for the amount of material strength this weapon can destroy with one projectile - float m_AIAimPenetration; - // Tells the AI what distance in pixels from this round is mostly safe. - int m_AIBlastRadius; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Magazine, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - Magazine(const Magazine &reference) = delete; - Magazine & operator=(const Magazine &rhs) = delete; - -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: Magazine + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: An Attachable ammo magazine that can hold rounds that can be fired + // by HDFirearm:s. + // Parent(s): Attachable. + // Class history: 07/03/2002 Magazine created. + + class Magazine : public Attachable { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Concrete allocation and cloning definitions + EntityAllocation(Magazine); + SerializableOverrideMethods; + ClassInfoGetters; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Magazine + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Magazine object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Magazine() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~Magazine + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a Magazine object before deletion + // from system memory. + // Arguments: None. + + ~Magazine() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Magazine object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Magazine to be identical to another, by deep copy. + // Arguments: A reference to the Magazine to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Magazine& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Magazine, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Attachable::Reset(); + m_CollidesWithTerrainWhileAttached = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetNextRound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next Round preset of ammo in this Magazine, without removing + // it. Ownership IS NOT transferred! + // Arguments: None. + // Return value: A pointer to the next Round preset of ammo, or 0 if this Magazine is empty. + + const Round* GetNextRound() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PopNextRound + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next Round of ammo in this Magazine, and removes it from the + // stack. Ownership IS transferred! + // Arguments: None. + // Return value: A pointer to the next Round of ammo, or 0 if this Magazine is empty. + + Round* PopNextRound(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRoundCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns how many rounds are left in this Magazine. + // Arguments: None. + // Return value: The number of rounds left. Negative value means infinite ammo left! + + int GetRoundCount() const { return m_RoundCount; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRoundCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets how many rounds are left in this Magazine. + // Arguments: The new number of rounds left. Negative value means infinite ammo! + // Return value: None. + + void SetRoundCount(int newCount) { m_RoundCount = newCount; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEmpty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether this Magazine is out of rounds. + // Arguments: None. + // Return value: Whether this Magazine is out of rounds or not. + + bool IsEmpty() const { return m_FullCapacity >= 0 && m_RoundCount == 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsFull + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether this Magazine has not used up any rounds yet. + // Arguments: None. + // Return value: Whether this Magazine has not used any rounds yet. + + bool IsFull() const { return m_FullCapacity > 0 ? (m_RoundCount == m_FullCapacity || m_RoundCount < 0) : m_FullCapacity < 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsOverHalfFull + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether this Magazine has not used up half of the rounds yet. + // Arguments: None. + // Return value: Whether this Magazine has not used half of its rounds yet. + + bool IsOverHalfFull() const { return m_FullCapacity > 0 ? ((m_RoundCount > (m_FullCapacity / 2)) || m_RoundCount < 0) : m_FullCapacity < 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCapacity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns teh number of rounds this can hold when it's full. + // Arguments: None. + // Return value: The number of rounds this can hold. Negative value means infinite ammo. + + int GetCapacity() const { return m_FullCapacity; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDiscardable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Whether this Magazine should be released into the scene when discarded + // or just deleted. + // Arguments: None. + // Return value: Whether this Magazine should be relesed into scene or deleted when released. + + bool IsDiscardable() const { return m_Discardable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EstimateDigStrength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Estimates what material strength the rounds in the magazine can destroy. + // Arguments: None. + // Return value: The material strength. + + float EstimateDigStrength() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAimVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells the AI what muzzle velocity to assume when aiming this weapon. + // Arguments: None. + // Return value: Velocity in m/s. + + float GetAIAimVel() const { return m_AIAimVel; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIAimBlastRadius + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells the AI what distance in pixels from the rounds in this mag round + // are mostly safe. + // Arguments: None. + // Return value: Distance in pixels. + + int GetAIAimBlastRadius() const { return m_AIBlastRadius; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAIAimPenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells the AI how much material this projectile can penetrate. + // Arguments: None. + // Return value: The material strenght. + + float GetAIAimPenetration() const { return m_AIAimPenetration; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBulletAccScalar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bullet acceleration scalar the AI use when aiming this weapon. + // Arguments: None. + // Return value: A float with the scalar. + + float GetBulletAccScalar(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this Magazine's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + + // How many rounds in mag. Negative value means infinite ammo + int m_RoundCount; + // The number of rounds that this mag holds. negative menas infinite ammo capacity + int m_FullCapacity; + // The ratio between regular and tracer rounds. 0 means no tracers. + // e.g. 3 means every third round will be a tracer. ie Round To Tracer (RTT) ratio. + int m_RTTRatio; + // Round reference instances. + const Round* m_pRegularRound; + const Round* m_pTracerRound; + // Whether this magazine should be released into the scene when discarded, or just be deleted instead + bool m_Discardable; + // The muzzle velocity the AI use when aiming this gun. calculated when the magazine is created + float m_AIAimVel; + // The estimated maximum distance in pixels the projectiles can hit from + float m_AIAimMaxDistance; + // The half of the theoretical upper limit for the amount of material strength this weapon can destroy with one projectile + float m_AIAimPenetration; + // Tells the AI what distance in pixels from this round is mostly safe. + int m_AIBlastRadius; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Magazine, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + Magazine(const Magazine& reference) = delete; + Magazine& operator=(const Magazine& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/Material.cpp b/Source/Entities/Material.cpp index d3bc9d539..0af330030 100644 --- a/Source/Entities/Material.cpp +++ b/Source/Entities/Material.cpp @@ -5,7 +5,7 @@ namespace RTE { ConcreteClassInfo(Material, Entity, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Material::Clear() { m_Index = 0; @@ -30,9 +30,9 @@ namespace RTE { m_TerrainBGTexture = nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Material::Create(const Material &reference) { + int Material::Create(const Material& reference) { Entity::Create(reference); m_Index = reference.m_Index; @@ -59,11 +59,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Material::ReadProperty(const std::string_view &propName, Reader &reader) { + int Material::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("Index", { // TODO: Check for index collisions here reader >> m_Index; @@ -106,9 +106,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Material::Save(Writer &writer) const { + int Material::Save(Writer& writer) const { Entity::Save(writer); // Materials should never be altered, so no point in saving additional properties when it's a copy if (m_IsOriginalPreset) { @@ -131,4 +131,4 @@ namespace RTE { } return 0; } -} +} // namespace RTE diff --git a/Source/Entities/Material.h b/Source/Entities/Material.h index 92a726306..6e37a692a 100644 --- a/Source/Entities/Material.h +++ b/Source/Entities/Material.h @@ -13,7 +13,6 @@ namespace RTE { class Material : public Entity { public: - EntityAllocation(Material); SerializableOverrideMethods; ClassInfoGetters; @@ -28,21 +27,29 @@ namespace RTE { /// Copy constructor method used to instantiate a Material object identical to an already existing one. /// /// A Material object which is passed in by reference. - Material(const Material &reference) { if (this != &reference) { Clear(); Create(reference); } } + Material(const Material& reference) { + if (this != &reference) { + Clear(); + Create(reference); + } + } /// /// Creates a Material to be identical to another, by deep copy. /// /// A reference to the Material to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Material &reference); + int Create(const Material& reference); #pragma endregion #pragma region Destruction /// /// Resets the entire Material, including its inherited members, to it's default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -50,13 +57,13 @@ namespace RTE { /// Gets the foreground texture bitmap of this Material, if any is associated with it. /// /// Pointer to the foreground texture bitmap of this Material. - BITMAP * GetFGTexture() const { return m_TerrainFGTexture; } + BITMAP* GetFGTexture() const { return m_TerrainFGTexture; } /// /// Gets the background texture bitmap of this Material, if any is associated with it. /// /// Pointer to the background texture bitmap of this Material. - BITMAP * GetBGTexture() const { return m_TerrainBGTexture; } + BITMAP* GetBGTexture() const { return m_TerrainBGTexture; } /// /// Gets the index of this Material in the material palette. @@ -155,11 +162,16 @@ namespace RTE { /// /// A Material reference. /// A reference to the changed Material. - Material & operator=(const Material &rhs) { if (this != &rhs) { Destroy(); Create(rhs); } return *this; } + Material& operator=(const Material& rhs) { + if (this != &rhs) { + Destroy(); + Create(rhs); + } + return *this; + } #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. unsigned char m_Index; //!< Index of this in the material palette. 0 - 255. @@ -187,15 +199,14 @@ namespace RTE { ContentFile m_FGTextureFile; //!< The file pointing to the terrain foreground texture of this Material. ContentFile m_BGTextureFile; //!< The file pointing to the terrain background texture of this Material. - BITMAP *m_TerrainFGTexture; //!< The foreground texture of this Material, used when building an SLTerrain. Not owned. - BITMAP *m_TerrainBGTexture; //!< The background texture of this Material, used when building an SLTerrain. Not owned. + BITMAP* m_TerrainFGTexture; //!< The foreground texture of this Material, used when building an SLTerrain. Not owned. + BITMAP* m_TerrainBGTexture; //!< The background texture of this Material, used when building an SLTerrain. Not owned. private: - /// /// Clears all the member variables of this Material, effectively resetting the members of this abstraction level only. /// void Clear(); }; -} +} // namespace RTE #endif diff --git a/Source/Entities/MetaPlayer.cpp b/Source/Entities/MetaPlayer.cpp index 2398a8844..9213499cb 100644 --- a/Source/Entities/MetaPlayer.cpp +++ b/Source/Entities/MetaPlayer.cpp @@ -7,7 +7,7 @@ namespace RTE { ConcreteClassInfo(MetaPlayer, Entity, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MetaPlayer::Clear() { m_Name = ""; @@ -30,9 +30,9 @@ namespace RTE { m_OffensiveTarget = ""; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MetaPlayer::Create(const MetaPlayer &reference) { + int MetaPlayer::Create(const MetaPlayer& reference) { Entity::Create(reference); m_Name = reference.m_Name; @@ -54,11 +54,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MetaPlayer::ReadProperty(const std::string_view &propName, Reader &reader) { + int MetaPlayer::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("Name", { reader >> m_Name; }); MatchProperty("Team", { reader >> m_Team; }); MatchProperty("Human", { reader >> m_Human; }); @@ -66,12 +66,14 @@ namespace RTE { MatchProperty("Aggressiveness", { reader >> m_Aggressiveness; }); MatchProperty("GameOverRound", { reader >> m_GameOverRound; - // Need to match the name to the index + // Need to match the name to the index }); MatchProperty("NativeTechModule", { m_NativeTechModule = g_PresetMan.GetModuleID(reader.ReadPropValue()); // Default to no native tech if the one we're looking for couldn't be found - if (m_NativeTechModule < 0) { m_NativeTechModule = 0; } + if (m_NativeTechModule < 0) { + m_NativeTechModule = 0; + } }); MatchProperty("NativeCostMultiplier", { reader >> m_NativeCostMult; }); MatchProperty("ForeignCostMultiplier", { reader >> m_ForeignCostMult; }); @@ -79,14 +81,13 @@ namespace RTE { MatchProperty("Funds", { reader >> m_Funds; }); MatchProperty("OffensiveBudget", { reader >> m_OffensiveBudget; }); MatchProperty("OffensiveTarget", { reader >> m_OffensiveTarget; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MetaPlayer::Save(Writer &writer) const { + int MetaPlayer::Save(Writer& writer) const { Entity::Save(writer); writer.NewProperty("Name"); @@ -121,4 +122,4 @@ namespace RTE { return 0; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/MetaPlayer.h b/Source/Entities/MetaPlayer.h index 3671baa81..54f7d6f11 100644 --- a/Source/Entities/MetaPlayer.h +++ b/Source/Entities/MetaPlayer.h @@ -12,7 +12,6 @@ namespace RTE { friend class MetagameGUI; public: - EntityAllocation(MetaPlayer); SerializableOverrideMethods; ClassInfoGetters; @@ -27,7 +26,12 @@ namespace RTE { /// Copy constructor method used to instantiate a MetaPlayer object identical to an already existing one. /// /// A MetaPlayer object which is passed in by reference. - MetaPlayer(const MetaPlayer &reference) { if (this != &reference) { Clear(); Create(reference); } } + MetaPlayer(const MetaPlayer& reference) { + if (this != &reference) { + Clear(); + Create(reference); + } + } /// /// Makes the MetaPlayer object ready for use. @@ -40,7 +44,7 @@ namespace RTE { /// /// A reference to the MetaPlayer to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const MetaPlayer &reference); + int Create(const MetaPlayer& reference); #pragma endregion #pragma region Destruction @@ -53,12 +57,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the MetaPlayer object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Entity::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Entity::Destroy(); + } + Clear(); + } /// /// Resets the entire MetaPlayer, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -180,7 +192,11 @@ namespace RTE { /// /// The amount with which to change the funds balance. This should be a positive value to decrease the funds amount. /// The amount of funds that were spent. - float SpendFunds(float howMuch) { howMuch = std::min(m_Funds, howMuch); m_Funds -= howMuch; return howMuch; } + float SpendFunds(float howMuch) { + howMuch = std::min(m_Funds, howMuch); + m_Funds -= howMuch; + return howMuch; + } /// /// Gets the offensive budget of this MetaPlayer for this round, in oz. @@ -259,11 +275,16 @@ namespace RTE { /// /// A MetaPlayer reference. /// A reference to the changed MetaPlayer. - MetaPlayer & operator=(const MetaPlayer &rhs) { if (this != &rhs) { Destroy(); Create(rhs); } return *this; } + MetaPlayer& operator=(const MetaPlayer& rhs) { + if (this != &rhs) { + Destroy(); + Create(rhs); + } + return *this; + } #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. std::string m_Name; //!< The name of the player. @@ -289,11 +310,10 @@ namespace RTE { std::string m_OffensiveTarget; //!< Name of the Scene this player is targeting for its offensive this round. private: - /// /// Clears all the member variables of this MetaPlayer, effectively resetting the members of this abstraction level only. /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/MetaSave.cpp b/Source/Entities/MetaSave.cpp index d627fbb28..241b24607 100644 --- a/Source/Entities/MetaSave.cpp +++ b/Source/Entities/MetaSave.cpp @@ -7,7 +7,7 @@ namespace RTE { ConcreteClassInfo(MetaSave, Entity, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MetaSave::Clear() { m_SavePath.clear(); @@ -17,7 +17,7 @@ namespace RTE { m_SiteCount = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int MetaSave::Create(std::string savePath) { if (Entity::Create() < 0) { @@ -37,9 +37,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MetaSave::Create(const MetaSave &reference) { + int MetaSave::Create(const MetaSave& reference) { Entity::Create(reference); m_SavePath = reference.m_SavePath; @@ -51,11 +51,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MetaSave::ReadProperty(const std::string_view &propName, Reader &reader) { + int MetaSave::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("SavePath", { reader >> m_SavePath; }); MatchProperty("PlayerCount", { reader >> m_PlayerCount; }); MatchProperty("Difficulty", { reader >> m_Difficulty; }); @@ -65,9 +65,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int MetaSave::Save(Writer &writer) const { + int MetaSave::Save(Writer& writer) const { Entity::Save(writer); writer.NewProperty("SavePath"); @@ -83,4 +83,4 @@ namespace RTE { return 0; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/MetaSave.h b/Source/Entities/MetaSave.h index 55b9c24dc..02b03f97b 100644 --- a/Source/Entities/MetaSave.h +++ b/Source/Entities/MetaSave.h @@ -11,7 +11,6 @@ namespace RTE { class MetaSave : public Entity { public: - EntityAllocation(MetaSave); SerializableOverrideMethods; ClassInfoGetters; @@ -34,7 +33,7 @@ namespace RTE { /// /// A reference to the MetaSave to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const MetaSave &reference); + int Create(const MetaSave& reference); #pragma endregion #pragma region Destruction @@ -47,7 +46,12 @@ namespace RTE { /// Destroys and resets (through Clear()) the MetaSave object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Entity::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Entity::Destroy(); + } + Clear(); + } #pragma endregion #pragma region Getters @@ -83,9 +87,8 @@ namespace RTE { #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - + std::string m_SavePath; //!< The full path to the ini file which stores the stat of MetaMan this is associated with. int m_PlayerCount; //!< The number of players in this saved game. int m_Difficulty; //!< Game difficulty. @@ -93,15 +96,14 @@ namespace RTE { int m_SiteCount; //!< The site count of this game. private: - /// /// Clears all the member variables of this MetaSave, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - MetaSave(const MetaSave &reference) = delete; - MetaSave & operator=(const MetaSave &rhs) = delete; + MetaSave(const MetaSave& reference) = delete; + MetaSave& operator=(const MetaSave& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/MovableObject.cpp b/Source/Entities/MovableObject.cpp index bbca9f0d1..642f38137 100644 --- a/Source/Entities/MovableObject.cpp +++ b/Source/Entities/MovableObject.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -28,1309 +27,1265 @@ namespace RTE { -AbstractClassInfo(MovableObject, SceneObject); - -std::atomic MovableObject::m_UniqueIDCounter = 1; -std::string MovableObject::ms_EmptyString = ""; + AbstractClassInfo(MovableObject, SceneObject); + + std::atomic MovableObject::m_UniqueIDCounter = 1; + std::string MovableObject::ms_EmptyString = ""; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MovableObject, effectively + // resetting the members of this abstraction level only. + + void MovableObject::Clear() { + m_MOType = TypeGeneric; + m_Mass = 0; + m_Vel.Reset(); + m_PrevPos.Reset(); + m_PrevVel.Reset(); + m_DistanceTravelled = 0; + m_Scale = 1.0; + m_GlobalAccScalar = 1.0; + m_AirResistance = 0; + m_AirThreshold = 5; + m_PinStrength = 0; + m_RestThreshold = 500; + m_Forces.clear(); + m_ImpulseForces.clear(); + m_AgeTimer.Reset(); + m_RestTimer.Reset(); + m_Lifetime = 0; + m_Sharpness = 1.0; + // m_MaterialId = 0; + m_CheckTerrIntersection = false; + m_HitsMOs = false; + m_pMOToNotHit = 0; + m_MOIgnoreTimer.Reset(); + m_GetsHitByMOs = false; + m_IgnoresTeamHits = false; + m_IgnoresAtomGroupHits = false; + m_IgnoresAGHitsWhenSlowerThan = -1; + m_IgnoresActorHits = false; + m_MissionCritical = false; + m_CanBeSquished = true; + m_IsUpdated = false; + m_WrapDoubleDraw = true; + m_DidWrap = false; + m_MOID = g_NoMOID; + m_RootMOID = g_NoMOID; + m_HasEverBeenAddedToMovableMan = false; + m_MOIDFootprint = 0; + m_AlreadyHitBy.clear(); + m_VelOscillations = 0; + m_ToSettle = false; + m_ToDelete = false; + m_HUDVisible = true; + m_IsTraveling = false; + m_AllLoadedScripts.clear(); + m_FunctionsAndScripts.clear(); + m_StringValueMap.clear(); + m_NumberValueMap.clear(); + m_ObjectValueMap.clear(); + m_ThreadedLuaState = nullptr; + m_ForceIntoMasterLuaState = false; + m_ScriptObjectName.clear(); + m_ScreenEffectFile.Reset(); + m_pScreenEffect = 0; + m_EffectRotAngle = 0; + m_InheritEffectRotAngle = false; + m_RandomizeEffectRotAngle = false; + m_RandomizeEffectRotAngleEveryFrame = false; + m_ScreenEffectHash = 0; + m_EffectStartTime = 0; + m_EffectStopTime = 0; + m_EffectStartStrength = 128; + m_EffectStopStrength = 128; + m_EffectAlwaysShows = false; + + m_UniqueID = 0; + + m_RemoveOrphanTerrainRadius = 0; + m_RemoveOrphanTerrainMaxArea = 0; + m_RemoveOrphanTerrainRate = 0.0; + m_DamageOnCollision = 0.0; + m_DamageOnPenetration = 0.0; + m_WoundDamageMultiplier = 1.0; + m_ApplyWoundDamageOnCollision = false; + m_ApplyWoundBurstDamageOnCollision = false; + m_IgnoreTerrain = false; + + m_MOIDHit = g_NoMOID; + m_TerrainMatHit = g_MaterialAir; + m_ParticleUniqueIDHit = 0; + + m_LastCollisionSimFrameNumber = 0; + + m_SimUpdatesBetweenScriptedUpdates = 1; + m_SimUpdatesSinceLastScriptedUpdate = 0; + m_RequestedSyncedUpdate = false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MovableObject, effectively -// resetting the members of this abstraction level only. - -void MovableObject::Clear() -{ - m_MOType = TypeGeneric; - m_Mass = 0; - m_Vel.Reset(); - m_PrevPos.Reset(); - m_PrevVel.Reset(); - m_DistanceTravelled = 0; - m_Scale = 1.0; - m_GlobalAccScalar = 1.0; - m_AirResistance = 0; - m_AirThreshold = 5; - m_PinStrength = 0; - m_RestThreshold = 500; - m_Forces.clear(); - m_ImpulseForces.clear(); - m_AgeTimer.Reset(); - m_RestTimer.Reset(); - m_Lifetime = 0; - m_Sharpness = 1.0; -// m_MaterialId = 0; - m_CheckTerrIntersection = false; - m_HitsMOs = false; - m_pMOToNotHit = 0; - m_MOIgnoreTimer.Reset(); - m_GetsHitByMOs = false; - m_IgnoresTeamHits = false; - m_IgnoresAtomGroupHits = false; - m_IgnoresAGHitsWhenSlowerThan = -1; - m_IgnoresActorHits = false; - m_MissionCritical = false; - m_CanBeSquished = true; - m_IsUpdated = false; - m_WrapDoubleDraw = true; - m_DidWrap = false; - m_MOID = g_NoMOID; - m_RootMOID = g_NoMOID; - m_HasEverBeenAddedToMovableMan = false; - m_MOIDFootprint = 0; - m_AlreadyHitBy.clear(); - m_VelOscillations = 0; - m_ToSettle = false; - m_ToDelete = false; - m_HUDVisible = true; - m_IsTraveling = false; - m_AllLoadedScripts.clear(); - m_FunctionsAndScripts.clear(); - m_StringValueMap.clear(); - m_NumberValueMap.clear(); - m_ObjectValueMap.clear(); - m_ThreadedLuaState = nullptr; - m_ForceIntoMasterLuaState = false; - m_ScriptObjectName.clear(); - m_ScreenEffectFile.Reset(); - m_pScreenEffect = 0; - m_EffectRotAngle = 0; - m_InheritEffectRotAngle = false; - m_RandomizeEffectRotAngle = false; - m_RandomizeEffectRotAngleEveryFrame = false; - m_ScreenEffectHash = 0; - m_EffectStartTime = 0; - m_EffectStopTime = 0; - m_EffectStartStrength = 128; - m_EffectStopStrength = 128; - m_EffectAlwaysShows = false; - - m_UniqueID = 0; - - m_RemoveOrphanTerrainRadius = 0; - m_RemoveOrphanTerrainMaxArea = 0; - m_RemoveOrphanTerrainRate = 0.0; - m_DamageOnCollision = 0.0; - m_DamageOnPenetration = 0.0; - m_WoundDamageMultiplier = 1.0; - m_ApplyWoundDamageOnCollision = false; - m_ApplyWoundBurstDamageOnCollision = false; - m_IgnoreTerrain = false; - - m_MOIDHit = g_NoMOID; - m_TerrainMatHit = g_MaterialAir; - m_ParticleUniqueIDHit = 0; - - m_LastCollisionSimFrameNumber = 0; - - m_SimUpdatesBetweenScriptedUpdates = 1; - m_SimUpdatesSinceLastScriptedUpdate = 0; - m_RequestedSyncedUpdate = false; -} - -LuaStateWrapper & MovableObject::GetAndLockStateForScript(const std::string &scriptPath, const LuaFunction *function) { - if (m_ForceIntoMasterLuaState) { - m_ThreadedLuaState = &g_LuaMan.GetMasterScriptState(); - } - - if (m_ThreadedLuaState == nullptr) { - m_ThreadedLuaState = g_LuaMan.GetAndLockFreeScriptState(); - } else { - m_ThreadedLuaState->GetMutex().lock(); - } - - return *m_ThreadedLuaState; -} + LuaStateWrapper& MovableObject::GetAndLockStateForScript(const std::string& scriptPath, const LuaFunction* function) { + if (m_ForceIntoMasterLuaState) { + m_ThreadedLuaState = &g_LuaMan.GetMasterScriptState(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MovableObject object ready for use. + if (m_ThreadedLuaState == nullptr) { + m_ThreadedLuaState = g_LuaMan.GetAndLockFreeScriptState(); + } else { + m_ThreadedLuaState->GetMutex().lock(); + } -int MovableObject::Create() -{ - if (SceneObject::Create() < 0) - return -1; + return *m_ThreadedLuaState; + } - m_AgeTimer.Reset(); - m_RestTimer.Reset(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MovableObject object ready for use. - // If the stop time hasn't been assigned, just make the same as the life time. - if (m_EffectStopTime <= 0) - m_EffectStopTime = m_Lifetime; + int MovableObject::Create() { + if (SceneObject::Create() < 0) + return -1; - m_UniqueID = MovableObject::GetNextUniqueID(); + m_AgeTimer.Reset(); + m_RestTimer.Reset(); - m_MOIDHit = g_NoMOID; - m_TerrainMatHit = g_MaterialAir; - m_ParticleUniqueIDHit = 0; + // If the stop time hasn't been assigned, just make the same as the life time. + if (m_EffectStopTime <= 0) + m_EffectStopTime = m_Lifetime; - g_MovableMan.RegisterObject(this); + m_UniqueID = MovableObject::GetNextUniqueID(); - return 0; -} + m_MOIDHit = g_NoMOID; + m_TerrainMatHit = g_MaterialAir; + m_ParticleUniqueIDHit = 0; + g_MovableMan.RegisterObject(this); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MovableObject object ready for use. - -int MovableObject::Create(const float mass, - const Vector &position, - const Vector &velocity, - float rotAngle, - float angleVel, - unsigned long lifetime, - bool hitMOs, - bool getHitByMOs) -{ - m_Mass = mass; - m_Pos = position; - m_Vel = velocity; - m_AgeTimer.Reset(); - m_RestTimer.Reset(); - m_Lifetime = lifetime; -// m_MaterialId = matId; - m_HitsMOs = hitMOs; - m_GetsHitByMOs = getHitByMOs; - - m_UniqueID = MovableObject::GetNextUniqueID(); - - m_MOIDHit = g_NoMOID; - m_TerrainMatHit = g_MaterialAir; - m_ParticleUniqueIDHit = 0; - - g_MovableMan.RegisterObject(this); - - return 0; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MovableObject object ready for use. + + int MovableObject::Create(const float mass, + const Vector& position, + const Vector& velocity, + float rotAngle, + float angleVel, + unsigned long lifetime, + bool hitMOs, + bool getHitByMOs) { + m_Mass = mass; + m_Pos = position; + m_Vel = velocity; + m_AgeTimer.Reset(); + m_RestTimer.Reset(); + m_Lifetime = lifetime; + // m_MaterialId = matId; + m_HitsMOs = hitMOs; + m_GetsHitByMOs = getHitByMOs; + + m_UniqueID = MovableObject::GetNextUniqueID(); + + m_MOIDHit = g_NoMOID; + m_TerrainMatHit = g_MaterialAir; + m_ParticleUniqueIDHit = 0; + + g_MovableMan.RegisterObject(this); + + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MovableObject to be identical to another, by deep copy. - -int MovableObject::Create(const MovableObject &reference) -{ - SceneObject::Create(reference); - - m_MOType = reference.m_MOType; - m_Mass = reference.m_Mass; - m_Pos = reference.m_Pos; - m_Vel = reference.m_Vel; - m_Scale = reference.m_Scale; - m_GlobalAccScalar = reference.m_GlobalAccScalar; - m_AirResistance = reference.m_AirResistance; - m_AirThreshold = reference.m_AirThreshold; - m_PinStrength = reference.m_PinStrength; - m_RestThreshold = reference.m_RestThreshold; -// m_Force = reference.m_Force; -// m_ImpulseForce = reference.m_ImpulseForce; - // Should reset age instead?? -// m_AgeTimer = reference.m_AgeTimer; - m_AgeTimer.Reset(); - m_RestTimer.Reset(); - m_Lifetime = reference.m_Lifetime; - m_Sharpness = reference.m_Sharpness; -// m_MaterialId = reference.m_MaterialId; - m_CheckTerrIntersection = reference.m_CheckTerrIntersection; - m_HitsMOs = reference.m_HitsMOs; - m_GetsHitByMOs = reference.m_GetsHitByMOs; - m_IgnoresTeamHits = reference.m_IgnoresTeamHits; - m_IgnoresAtomGroupHits = reference.m_IgnoresAtomGroupHits; - m_IgnoresAGHitsWhenSlowerThan = reference.m_IgnoresAGHitsWhenSlowerThan; - m_IgnoresActorHits = reference.m_IgnoresActorHits; - m_pMOToNotHit = reference.m_pMOToNotHit; - m_MOIgnoreTimer = reference.m_MOIgnoreTimer; - m_MissionCritical = reference.m_MissionCritical; - m_CanBeSquished = reference.m_CanBeSquished; - m_HUDVisible = reference.m_HUDVisible; - - m_ForceIntoMasterLuaState = reference.m_ForceIntoMasterLuaState; - for (auto &[scriptPath, scriptEnabled] : reference.m_AllLoadedScripts) { - LoadScript(scriptPath, scriptEnabled); - } - - if (reference.m_pScreenEffect) - { - m_ScreenEffectFile = reference.m_ScreenEffectFile; - m_pScreenEffect = m_ScreenEffectFile.GetAsBitmap(); - - } - m_EffectRotAngle = reference.m_EffectRotAngle; - m_InheritEffectRotAngle = reference.m_InheritEffectRotAngle; - m_RandomizeEffectRotAngle = reference.m_RandomizeEffectRotAngle; - m_RandomizeEffectRotAngleEveryFrame = reference.m_RandomizeEffectRotAngleEveryFrame; - - if (m_RandomizeEffectRotAngle) - m_EffectRotAngle = c_PI * RandomNum(-2.0F, 2.0F); - - m_ScreenEffectHash = reference.m_ScreenEffectHash; - m_EffectStartTime = reference.m_EffectStartTime; - m_EffectStopTime = reference.m_EffectStopTime; - m_EffectStartStrength = reference.m_EffectStartStrength; - m_EffectStopStrength = reference.m_EffectStopStrength; - m_EffectAlwaysShows = reference.m_EffectAlwaysShows; - m_RemoveOrphanTerrainRadius = reference.m_RemoveOrphanTerrainRadius; - m_RemoveOrphanTerrainMaxArea = reference.m_RemoveOrphanTerrainMaxArea; - m_RemoveOrphanTerrainRate = reference.m_RemoveOrphanTerrainRate; - m_DamageOnCollision = reference.m_DamageOnCollision; - m_DamageOnPenetration = reference.m_DamageOnPenetration; - m_WoundDamageMultiplier = reference.m_WoundDamageMultiplier; - m_IgnoreTerrain = reference.m_IgnoreTerrain; - - m_MOIDHit = reference.m_MOIDHit; - m_TerrainMatHit = reference.m_TerrainMatHit; - m_ParticleUniqueIDHit = reference.m_ParticleUniqueIDHit; - - m_SimUpdatesBetweenScriptedUpdates = reference.m_SimUpdatesBetweenScriptedUpdates; - m_SimUpdatesSinceLastScriptedUpdate = reference.m_SimUpdatesSinceLastScriptedUpdate; - - m_StringValueMap = reference.m_StringValueMap; - m_NumberValueMap = reference.m_NumberValueMap; - m_ObjectValueMap = reference.m_ObjectValueMap; - - m_UniqueID = MovableObject::GetNextUniqueID(); - g_MovableMan.RegisterObject(this); - - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MovableObject to be identical to another, by deep copy. + + int MovableObject::Create(const MovableObject& reference) { + SceneObject::Create(reference); + + m_MOType = reference.m_MOType; + m_Mass = reference.m_Mass; + m_Pos = reference.m_Pos; + m_Vel = reference.m_Vel; + m_Scale = reference.m_Scale; + m_GlobalAccScalar = reference.m_GlobalAccScalar; + m_AirResistance = reference.m_AirResistance; + m_AirThreshold = reference.m_AirThreshold; + m_PinStrength = reference.m_PinStrength; + m_RestThreshold = reference.m_RestThreshold; + // m_Force = reference.m_Force; + // m_ImpulseForce = reference.m_ImpulseForce; + // Should reset age instead?? + // m_AgeTimer = reference.m_AgeTimer; + m_AgeTimer.Reset(); + m_RestTimer.Reset(); + m_Lifetime = reference.m_Lifetime; + m_Sharpness = reference.m_Sharpness; + // m_MaterialId = reference.m_MaterialId; + m_CheckTerrIntersection = reference.m_CheckTerrIntersection; + m_HitsMOs = reference.m_HitsMOs; + m_GetsHitByMOs = reference.m_GetsHitByMOs; + m_IgnoresTeamHits = reference.m_IgnoresTeamHits; + m_IgnoresAtomGroupHits = reference.m_IgnoresAtomGroupHits; + m_IgnoresAGHitsWhenSlowerThan = reference.m_IgnoresAGHitsWhenSlowerThan; + m_IgnoresActorHits = reference.m_IgnoresActorHits; + m_pMOToNotHit = reference.m_pMOToNotHit; + m_MOIgnoreTimer = reference.m_MOIgnoreTimer; + m_MissionCritical = reference.m_MissionCritical; + m_CanBeSquished = reference.m_CanBeSquished; + m_HUDVisible = reference.m_HUDVisible; + + m_ForceIntoMasterLuaState = reference.m_ForceIntoMasterLuaState; + for (auto& [scriptPath, scriptEnabled]: reference.m_AllLoadedScripts) { + LoadScript(scriptPath, scriptEnabled); + } + if (reference.m_pScreenEffect) { + m_ScreenEffectFile = reference.m_ScreenEffectFile; + m_pScreenEffect = m_ScreenEffectFile.GetAsBitmap(); + } + m_EffectRotAngle = reference.m_EffectRotAngle; + m_InheritEffectRotAngle = reference.m_InheritEffectRotAngle; + m_RandomizeEffectRotAngle = reference.m_RandomizeEffectRotAngle; + m_RandomizeEffectRotAngleEveryFrame = reference.m_RandomizeEffectRotAngleEveryFrame; + + if (m_RandomizeEffectRotAngle) + m_EffectRotAngle = c_PI * RandomNum(-2.0F, 2.0F); + + m_ScreenEffectHash = reference.m_ScreenEffectHash; + m_EffectStartTime = reference.m_EffectStartTime; + m_EffectStopTime = reference.m_EffectStopTime; + m_EffectStartStrength = reference.m_EffectStartStrength; + m_EffectStopStrength = reference.m_EffectStopStrength; + m_EffectAlwaysShows = reference.m_EffectAlwaysShows; + m_RemoveOrphanTerrainRadius = reference.m_RemoveOrphanTerrainRadius; + m_RemoveOrphanTerrainMaxArea = reference.m_RemoveOrphanTerrainMaxArea; + m_RemoveOrphanTerrainRate = reference.m_RemoveOrphanTerrainRate; + m_DamageOnCollision = reference.m_DamageOnCollision; + m_DamageOnPenetration = reference.m_DamageOnPenetration; + m_WoundDamageMultiplier = reference.m_WoundDamageMultiplier; + m_IgnoreTerrain = reference.m_IgnoreTerrain; + + m_MOIDHit = reference.m_MOIDHit; + m_TerrainMatHit = reference.m_TerrainMatHit; + m_ParticleUniqueIDHit = reference.m_ParticleUniqueIDHit; + + m_SimUpdatesBetweenScriptedUpdates = reference.m_SimUpdatesBetweenScriptedUpdates; + m_SimUpdatesSinceLastScriptedUpdate = reference.m_SimUpdatesSinceLastScriptedUpdate; + + m_StringValueMap = reference.m_StringValueMap; + m_NumberValueMap = reference.m_NumberValueMap; + m_ObjectValueMap = reference.m_ObjectValueMap; + + m_UniqueID = MovableObject::GetNextUniqueID(); + g_MovableMan.RegisterObject(this); + + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int MovableObject::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return SceneObject::ReadProperty(propName, reader)); - - MatchProperty("Mass", { reader >> m_Mass; }); - MatchProperty("Velocity", { reader >> m_Vel; }); - MatchProperty("Scale", { reader >> m_Scale; }); - MatchProperty("GlobalAccScalar", { reader >> m_GlobalAccScalar; }); - MatchProperty("AirResistance", - { - reader >> m_AirResistance; - // Backwards compatibility after we made this value scaled over time - m_AirResistance /= 0.01666F; - }); - MatchProperty("AirThreshold", { reader >> m_AirThreshold; }); - MatchProperty("PinStrength", { reader >> m_PinStrength; }); - MatchProperty("RestThreshold", { reader >> m_RestThreshold; }); - MatchProperty("LifeTime", { reader >> m_Lifetime; }); - MatchProperty("Age", { - double age; - reader >> age; - m_AgeTimer.SetElapsedSimTimeMS(age); - }); - MatchProperty("Sharpness", { reader >> m_Sharpness; }); - MatchProperty("HitsMOs", { reader >> m_HitsMOs; }); - MatchProperty("GetsHitByMOs", { reader >> m_GetsHitByMOs; }); - MatchProperty("IgnoresTeamHits", { reader >> m_IgnoresTeamHits; }); - MatchProperty("IgnoresAtomGroupHits", { reader >> m_IgnoresAtomGroupHits; }); - MatchProperty("IgnoresAGHitsWhenSlowerThan", { reader >> m_IgnoresAGHitsWhenSlowerThan; }); - MatchProperty("IgnoresActorHits", { reader >> m_IgnoresActorHits; }); - MatchProperty("RemoveOrphanTerrainRadius", - { - reader >> m_RemoveOrphanTerrainRadius; - if (m_RemoveOrphanTerrainRadius > MAXORPHANRADIUS) - m_RemoveOrphanTerrainRadius = MAXORPHANRADIUS; - }); - MatchProperty("RemoveOrphanTerrainMaxArea", - { - reader >> m_RemoveOrphanTerrainMaxArea; - if (m_RemoveOrphanTerrainMaxArea > MAXORPHANRADIUS * MAXORPHANRADIUS) - m_RemoveOrphanTerrainMaxArea = MAXORPHANRADIUS * MAXORPHANRADIUS; - }); - MatchProperty("RemoveOrphanTerrainRate", { reader >> m_RemoveOrphanTerrainRate; }); - MatchProperty("MissionCritical", { reader >> m_MissionCritical; }); - MatchProperty("CanBeSquished", { reader >> m_CanBeSquished; }); - MatchProperty("HUDVisible", { reader >> m_HUDVisible; }); - MatchProperty("ScriptPath", { - std::string scriptPath = g_PresetMan.GetFullModulePath(reader.ReadPropValue()); - switch (LoadScript(scriptPath)) { - case 0: - break; - case -1: - reader.ReportError("The script path " + scriptPath + " was empty."); - break; - case -2: - reader.ReportError("The script path " + scriptPath + " did not point to a valid file."); - break; - case -3: - reader.ReportError("The script path " + scriptPath + " is already loaded onto this object."); - break; - case -4: - // Error in lua file, this'll pop up in the console so no need to report an error through the reader. - break; - default: - RTEAbort("Reached default case while adding script in INI. This should never happen!"); - break; - } - }); - MatchProperty("ScreenEffect", { - reader >> m_ScreenEffectFile; - m_pScreenEffect = m_ScreenEffectFile.GetAsBitmap(); - m_ScreenEffectHash = m_ScreenEffectFile.GetHash(); - }); - MatchProperty("EffectStartTime", { reader >> m_EffectStartTime; }); - MatchProperty("EffectRotAngle", { reader >> m_EffectRotAngle; }); - MatchProperty("InheritEffectRotAngle", { reader >> m_InheritEffectRotAngle; }); - MatchProperty("RandomizeEffectRotAngle", { reader >> m_RandomizeEffectRotAngle; }); - MatchProperty("RandomizeEffectRotAngleEveryFrame", { reader >> m_RandomizeEffectRotAngleEveryFrame; }); - MatchProperty("EffectStopTime", { reader >> m_EffectStopTime; }); - MatchProperty("EffectStartStrength", { - float strength; - reader >> strength; - m_EffectStartStrength = std::floor((float)255 * strength); - }); - MatchProperty("EffectStopStrength", { - float strength; - reader >> strength; - m_EffectStopStrength = std::floor((float)255 * strength); - }); - MatchProperty("EffectAlwaysShows", { reader >> m_EffectAlwaysShows; }); - MatchProperty("DamageOnCollision", { reader >> m_DamageOnCollision; }); - MatchProperty("DamageOnPenetration", { reader >> m_DamageOnPenetration; }); - MatchProperty("WoundDamageMultiplier", { reader >> m_WoundDamageMultiplier; }); - MatchProperty("ApplyWoundDamageOnCollision", { reader >> m_ApplyWoundDamageOnCollision; }); - MatchProperty("ApplyWoundBurstDamageOnCollision", { reader >> m_ApplyWoundBurstDamageOnCollision; }); - MatchProperty("IgnoreTerrain", { reader >> m_IgnoreTerrain; }); - MatchProperty("SimUpdatesBetweenScriptedUpdates", { reader >> m_SimUpdatesBetweenScriptedUpdates; }); - MatchProperty("AddCustomValue", { ReadCustomValueProperty(reader); }); - MatchProperty("ForceIntoMasterLuaState", { reader >> m_ForceIntoMasterLuaState; }); - - EndPropertyList; -} - -void MovableObject::ReadCustomValueProperty(Reader& reader) { - std::string customValueType; - reader >> customValueType; - std::string customKey = reader.ReadPropName(); - std::string customValue = reader.ReadPropValue(); - if (customValueType == "NumberValue") { - try { - SetNumberValue(customKey, std::stod(customValue)); - } catch (const std::invalid_argument) { - reader.ReportError("Tried to read a non-number value for SetNumberValue."); - } - } else if (customValueType == "StringValue") { - SetStringValue(customKey, customValue); - } else { - reader.ReportError("Invalid CustomValue type " + customValueType); - } - // Artificially end reading this property since we got all we needed - reader.NextProperty(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int MovableObject::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return SceneObject::ReadProperty(propName, reader)); + + MatchProperty("Mass", { reader >> m_Mass; }); + MatchProperty("Velocity", { reader >> m_Vel; }); + MatchProperty("Scale", { reader >> m_Scale; }); + MatchProperty("GlobalAccScalar", { reader >> m_GlobalAccScalar; }); + MatchProperty("AirResistance", + { + reader >> m_AirResistance; + // Backwards compatibility after we made this value scaled over time + m_AirResistance /= 0.01666F; + }); + MatchProperty("AirThreshold", { reader >> m_AirThreshold; }); + MatchProperty("PinStrength", { reader >> m_PinStrength; }); + MatchProperty("RestThreshold", { reader >> m_RestThreshold; }); + MatchProperty("LifeTime", { reader >> m_Lifetime; }); + MatchProperty("Age", { + double age; + reader >> age; + m_AgeTimer.SetElapsedSimTimeMS(age); + }); + MatchProperty("Sharpness", { reader >> m_Sharpness; }); + MatchProperty("HitsMOs", { reader >> m_HitsMOs; }); + MatchProperty("GetsHitByMOs", { reader >> m_GetsHitByMOs; }); + MatchProperty("IgnoresTeamHits", { reader >> m_IgnoresTeamHits; }); + MatchProperty("IgnoresAtomGroupHits", { reader >> m_IgnoresAtomGroupHits; }); + MatchProperty("IgnoresAGHitsWhenSlowerThan", { reader >> m_IgnoresAGHitsWhenSlowerThan; }); + MatchProperty("IgnoresActorHits", { reader >> m_IgnoresActorHits; }); + MatchProperty("RemoveOrphanTerrainRadius", + { + reader >> m_RemoveOrphanTerrainRadius; + if (m_RemoveOrphanTerrainRadius > MAXORPHANRADIUS) + m_RemoveOrphanTerrainRadius = MAXORPHANRADIUS; + }); + MatchProperty("RemoveOrphanTerrainMaxArea", + { + reader >> m_RemoveOrphanTerrainMaxArea; + if (m_RemoveOrphanTerrainMaxArea > MAXORPHANRADIUS * MAXORPHANRADIUS) + m_RemoveOrphanTerrainMaxArea = MAXORPHANRADIUS * MAXORPHANRADIUS; + }); + MatchProperty("RemoveOrphanTerrainRate", { reader >> m_RemoveOrphanTerrainRate; }); + MatchProperty("MissionCritical", { reader >> m_MissionCritical; }); + MatchProperty("CanBeSquished", { reader >> m_CanBeSquished; }); + MatchProperty("HUDVisible", { reader >> m_HUDVisible; }); + MatchProperty("ScriptPath", { + std::string scriptPath = g_PresetMan.GetFullModulePath(reader.ReadPropValue()); + switch (LoadScript(scriptPath)) { + case 0: + break; + case -1: + reader.ReportError("The script path " + scriptPath + " was empty."); + break; + case -2: + reader.ReportError("The script path " + scriptPath + " did not point to a valid file."); + break; + case -3: + reader.ReportError("The script path " + scriptPath + " is already loaded onto this object."); + break; + case -4: + // Error in lua file, this'll pop up in the console so no need to report an error through the reader. + break; + default: + RTEAbort("Reached default case while adding script in INI. This should never happen!"); + break; + } + }); + MatchProperty("ScreenEffect", { + reader >> m_ScreenEffectFile; + m_pScreenEffect = m_ScreenEffectFile.GetAsBitmap(); + m_ScreenEffectHash = m_ScreenEffectFile.GetHash(); + }); + MatchProperty("EffectStartTime", { reader >> m_EffectStartTime; }); + MatchProperty("EffectRotAngle", { reader >> m_EffectRotAngle; }); + MatchProperty("InheritEffectRotAngle", { reader >> m_InheritEffectRotAngle; }); + MatchProperty("RandomizeEffectRotAngle", { reader >> m_RandomizeEffectRotAngle; }); + MatchProperty("RandomizeEffectRotAngleEveryFrame", { reader >> m_RandomizeEffectRotAngleEveryFrame; }); + MatchProperty("EffectStopTime", { reader >> m_EffectStopTime; }); + MatchProperty("EffectStartStrength", { + float strength; + reader >> strength; + m_EffectStartStrength = std::floor((float)255 * strength); + }); + MatchProperty("EffectStopStrength", { + float strength; + reader >> strength; + m_EffectStopStrength = std::floor((float)255 * strength); + }); + MatchProperty("EffectAlwaysShows", { reader >> m_EffectAlwaysShows; }); + MatchProperty("DamageOnCollision", { reader >> m_DamageOnCollision; }); + MatchProperty("DamageOnPenetration", { reader >> m_DamageOnPenetration; }); + MatchProperty("WoundDamageMultiplier", { reader >> m_WoundDamageMultiplier; }); + MatchProperty("ApplyWoundDamageOnCollision", { reader >> m_ApplyWoundDamageOnCollision; }); + MatchProperty("ApplyWoundBurstDamageOnCollision", { reader >> m_ApplyWoundBurstDamageOnCollision; }); + MatchProperty("IgnoreTerrain", { reader >> m_IgnoreTerrain; }); + MatchProperty("SimUpdatesBetweenScriptedUpdates", { reader >> m_SimUpdatesBetweenScriptedUpdates; }); + MatchProperty("AddCustomValue", { ReadCustomValueProperty(reader); }); + MatchProperty("ForceIntoMasterLuaState", { reader >> m_ForceIntoMasterLuaState; }); + + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this MovableObject to an output stream for -// later recreation with Create(istream &stream); - -int MovableObject::Save(Writer &writer) const -{ - SceneObject::Save(writer); -// TODO: Make proper save system that knows not to save redundant data! -// Note - this function isn't even called when saving a scene. Turns out that scene special-cases this stuff, see Scene::Save() -// In future, perhaps we ought to not do that. Who knows? - - writer.NewProperty("Mass"); - writer << m_Mass; - writer.NewProperty("Velocity"); - writer << m_Vel; - writer.NewProperty("Scale"); - writer << m_Scale; - writer.NewProperty("GlobalAccScalar"); - writer << m_GlobalAccScalar; - writer.NewProperty("AirResistance"); - writer << (m_AirResistance * 0.01666F); // Backwards compatibility after we made this value scaled over time - writer.NewProperty("AirThreshold"); - writer << m_AirThreshold; - writer.NewProperty("PinStrength"); - writer << m_PinStrength; - writer.NewProperty("RestThreshold"); - writer << m_RestThreshold; - writer.NewProperty("LifeTime"); - writer << m_Lifetime; - writer.NewProperty("Sharpness"); - writer << m_Sharpness; - writer.NewProperty("HitsMOs"); - writer << m_HitsMOs; - writer.NewProperty("GetsHitByMOs"); - writer << m_GetsHitByMOs; - writer.NewProperty("IgnoresTeamHits"); - writer << m_IgnoresTeamHits; - writer.NewProperty("IgnoresAtomGroupHits"); - writer << m_IgnoresAtomGroupHits; - writer.NewProperty("IgnoresAGHitsWhenSlowerThan"); - writer << m_IgnoresAGHitsWhenSlowerThan; - writer.NewProperty("IgnoresActorHits"); - writer << m_IgnoresActorHits; - writer.NewProperty("MissionCritical"); - writer << m_MissionCritical; - writer.NewProperty("CanBeSquished"); - writer << m_CanBeSquished; - writer.NewProperty("HUDVisible"); - writer << m_HUDVisible; - for (const auto &[scriptPath, scriptEnabled] : m_AllLoadedScripts) { - if (!scriptPath.empty()) { - writer.NewProperty("ScriptPath"); - writer << scriptPath; - } - } - writer.NewProperty("ScreenEffect"); - writer << m_ScreenEffectFile; - writer.NewProperty("EffectStartTime"); - writer << m_EffectStartTime; - writer.NewProperty("EffectStopTime"); - writer << m_EffectStopTime; - writer.NewProperty("EffectStartStrength"); - writer << (float)m_EffectStartStrength / 255.0f; - writer.NewProperty("EffectStopStrength"); - writer << (float)m_EffectStopStrength / 255.0f; - writer.NewProperty("EffectAlwaysShows"); - writer << m_EffectAlwaysShows; - writer.NewProperty("DamageOnCollision"); - writer << m_DamageOnCollision; - writer.NewProperty("DamageOnPenetration"); - writer << m_DamageOnPenetration; - writer.NewProperty("WoundDamageMultiplier"); - writer << m_WoundDamageMultiplier; - writer.NewProperty("ApplyWoundDamageOnCollision"); - writer << m_ApplyWoundDamageOnCollision; - writer.NewProperty("ApplyWoundBurstDamageOnCollision"); - writer << m_ApplyWoundBurstDamageOnCollision; - writer.NewProperty("IgnoreTerrain"); - writer << m_IgnoreTerrain; - writer.NewProperty("SimUpdatesBetweenScriptedUpdates"); - writer << m_SimUpdatesBetweenScriptedUpdates; - - for (const auto &[key, value] : m_NumberValueMap) { - writer.ObjectStart("AddCustomValue = NumberValue"); - writer.NewPropertyWithValue(key, value); - } - - for (const auto &[key, value] : m_StringValueMap) { - writer.ObjectStart("AddCustomValue = StringValue"); - writer.NewPropertyWithValue(key, value); - } - - writer.NewProperty("ForceIntoMasterLuaState"); - writer << m_ForceIntoMasterLuaState; - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MovableObject::DestroyScriptState() { - if (m_ThreadedLuaState) { - std::lock_guard lock(m_ThreadedLuaState->GetMutex()); - - if (ObjectScriptsInitialized()) { - RunScriptedFunctionInAppropriateScripts("Destroy"); - m_ThreadedLuaState->RunScriptString(m_ScriptObjectName + " = nil;"); - m_ScriptObjectName.clear(); - } - - m_ThreadedLuaState->UnregisterMO(this); - m_ThreadedLuaState = nullptr; - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MovableObject::Destroy(bool notInherited) { - // Unfortunately, shit can still get destroyed at random from Lua states having ownership and their GC deciding to delete it. - // This skips the DestroyScriptState call... so there's leftover stale script state that we just can't do shit about. - // This means Destroy() doesn't get called, and the lua memory shit leaks because it never gets set to nil. But oh well. - // So.. we need to do this shit... I guess. Even though it's fucking awful. And it definitely results in possible deadlocks depending on how different lua states interact. - // TODO: try to make this at least reasonably workable - //DestroyScriptState(); - - if (m_ThreadedLuaState) { - m_ThreadedLuaState->UnregisterMO(this); - } - - g_MovableMan.UnregisterObject(this); - if (!notInherited) { - SceneObject::Destroy(); - } - Clear(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int MovableObject::LoadScript(const std::string &scriptPath, bool loadAsEnabledScript) { - if (scriptPath.empty()) { - return -1; - } else if (!System::PathExistsCaseSensitive(scriptPath)) { - return -2; - } else if (HasScript(scriptPath)) { - return -3; + void MovableObject::ReadCustomValueProperty(Reader& reader) { + std::string customValueType; + reader >> customValueType; + std::string customKey = reader.ReadPropName(); + std::string customValue = reader.ReadPropValue(); + if (customValueType == "NumberValue") { + try { + SetNumberValue(customKey, std::stod(customValue)); + } catch (const std::invalid_argument) { + reader.ReportError("Tried to read a non-number value for SetNumberValue."); + } + } else if (customValueType == "StringValue") { + SetStringValue(customKey, customValue); + } else { + reader.ReportError("Invalid CustomValue type " + customValueType); + } + // Artificially end reading this property since we got all we needed + reader.NextProperty(); } - LuaStateWrapper& usedState = GetAndLockStateForScript(scriptPath); - std::lock_guard lock(usedState.GetMutex(), std::adopt_lock); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this MovableObject to an output stream for + // later recreation with Create(istream &stream); + + int MovableObject::Save(Writer& writer) const { + SceneObject::Save(writer); + // TODO: Make proper save system that knows not to save redundant data! + // Note - this function isn't even called when saving a scene. Turns out that scene special-cases this stuff, see Scene::Save() + // In future, perhaps we ought to not do that. Who knows? + + writer.NewProperty("Mass"); + writer << m_Mass; + writer.NewProperty("Velocity"); + writer << m_Vel; + writer.NewProperty("Scale"); + writer << m_Scale; + writer.NewProperty("GlobalAccScalar"); + writer << m_GlobalAccScalar; + writer.NewProperty("AirResistance"); + writer << (m_AirResistance * 0.01666F); // Backwards compatibility after we made this value scaled over time + writer.NewProperty("AirThreshold"); + writer << m_AirThreshold; + writer.NewProperty("PinStrength"); + writer << m_PinStrength; + writer.NewProperty("RestThreshold"); + writer << m_RestThreshold; + writer.NewProperty("LifeTime"); + writer << m_Lifetime; + writer.NewProperty("Sharpness"); + writer << m_Sharpness; + writer.NewProperty("HitsMOs"); + writer << m_HitsMOs; + writer.NewProperty("GetsHitByMOs"); + writer << m_GetsHitByMOs; + writer.NewProperty("IgnoresTeamHits"); + writer << m_IgnoresTeamHits; + writer.NewProperty("IgnoresAtomGroupHits"); + writer << m_IgnoresAtomGroupHits; + writer.NewProperty("IgnoresAGHitsWhenSlowerThan"); + writer << m_IgnoresAGHitsWhenSlowerThan; + writer.NewProperty("IgnoresActorHits"); + writer << m_IgnoresActorHits; + writer.NewProperty("MissionCritical"); + writer << m_MissionCritical; + writer.NewProperty("CanBeSquished"); + writer << m_CanBeSquished; + writer.NewProperty("HUDVisible"); + writer << m_HUDVisible; + for (const auto& [scriptPath, scriptEnabled]: m_AllLoadedScripts) { + if (!scriptPath.empty()) { + writer.NewProperty("ScriptPath"); + writer << scriptPath; + } + } + writer.NewProperty("ScreenEffect"); + writer << m_ScreenEffectFile; + writer.NewProperty("EffectStartTime"); + writer << m_EffectStartTime; + writer.NewProperty("EffectStopTime"); + writer << m_EffectStopTime; + writer.NewProperty("EffectStartStrength"); + writer << (float)m_EffectStartStrength / 255.0f; + writer.NewProperty("EffectStopStrength"); + writer << (float)m_EffectStopStrength / 255.0f; + writer.NewProperty("EffectAlwaysShows"); + writer << m_EffectAlwaysShows; + writer.NewProperty("DamageOnCollision"); + writer << m_DamageOnCollision; + writer.NewProperty("DamageOnPenetration"); + writer << m_DamageOnPenetration; + writer.NewProperty("WoundDamageMultiplier"); + writer << m_WoundDamageMultiplier; + writer.NewProperty("ApplyWoundDamageOnCollision"); + writer << m_ApplyWoundDamageOnCollision; + writer.NewProperty("ApplyWoundBurstDamageOnCollision"); + writer << m_ApplyWoundBurstDamageOnCollision; + writer.NewProperty("IgnoreTerrain"); + writer << m_IgnoreTerrain; + writer.NewProperty("SimUpdatesBetweenScriptedUpdates"); + writer << m_SimUpdatesBetweenScriptedUpdates; + + for (const auto& [key, value]: m_NumberValueMap) { + writer.ObjectStart("AddCustomValue = NumberValue"); + writer.NewPropertyWithValue(key, value); + } - for (const std::string &functionName : GetSupportedScriptFunctionNames()) { - if (m_FunctionsAndScripts.find(functionName) == m_FunctionsAndScripts.end()) { - m_FunctionsAndScripts.try_emplace(functionName); + for (const auto& [key, value]: m_StringValueMap) { + writer.ObjectStart("AddCustomValue = StringValue"); + writer.NewPropertyWithValue(key, value); } - } - m_AllLoadedScripts.try_emplace(scriptPath, loadAsEnabledScript); + writer.NewProperty("ForceIntoMasterLuaState"); + writer << m_ForceIntoMasterLuaState; - std::unordered_map scriptFileFunctions; - if (usedState.RunScriptFileAndRetrieveFunctions(scriptPath, GetSupportedScriptFunctionNames(), scriptFileFunctions) < 0) { - return -4; + return 0; } - for (const auto &[functionName, functionObject] : scriptFileFunctions) { - LuaFunction& luaFunction = m_FunctionsAndScripts.at(functionName).emplace_back(); - luaFunction.m_ScriptIsEnabled = loadAsEnabledScript; - luaFunction.m_LuaFunction = std::unique_ptr(functionObject); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableObject::DestroyScriptState() { + if (m_ThreadedLuaState) { + std::lock_guard lock(m_ThreadedLuaState->GetMutex()); + + if (ObjectScriptsInitialized()) { + RunScriptedFunctionInAppropriateScripts("Destroy"); + m_ThreadedLuaState->RunScriptString(m_ScriptObjectName + " = nil;"); + m_ScriptObjectName.clear(); + } + + m_ThreadedLuaState->UnregisterMO(this); + m_ThreadedLuaState = nullptr; + } } - if (ObjectScriptsInitialized()) { - if (RunFunctionOfScript(scriptPath, "Create") < 0) { - return -5; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableObject::Destroy(bool notInherited) { + // Unfortunately, shit can still get destroyed at random from Lua states having ownership and their GC deciding to delete it. + // This skips the DestroyScriptState call... so there's leftover stale script state that we just can't do shit about. + // This means Destroy() doesn't get called, and the lua memory shit leaks because it never gets set to nil. But oh well. + // So.. we need to do this shit... I guess. Even though it's fucking awful. And it definitely results in possible deadlocks depending on how different lua states interact. + // TODO: try to make this at least reasonably workable + // DestroyScriptState(); + + if (m_ThreadedLuaState) { + m_ThreadedLuaState->UnregisterMO(this); + } + + g_MovableMan.UnregisterObject(this); + if (!notInherited) { + SceneObject::Destroy(); + } + Clear(); } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int MovableObject::LoadScript(const std::string& scriptPath, bool loadAsEnabledScript) { + if (scriptPath.empty()) { + return -1; + } else if (!System::PathExistsCaseSensitive(scriptPath)) { + return -2; + } else if (HasScript(scriptPath)) { + return -3; + } + + LuaStateWrapper& usedState = GetAndLockStateForScript(scriptPath); + std::lock_guard lock(usedState.GetMutex(), std::adopt_lock); -int MovableObject::ReloadScripts() { - if (m_AllLoadedScripts.empty()) { - return 0; - } + for (const std::string& functionName: GetSupportedScriptFunctionNames()) { + if (m_FunctionsAndScripts.find(functionName) == m_FunctionsAndScripts.end()) { + m_FunctionsAndScripts.try_emplace(functionName); + } + } - int status = 0; + m_AllLoadedScripts.try_emplace(scriptPath, loadAsEnabledScript); - //TODO consider getting rid of this const_cast. It would require either code duplication or creating some non-const methods (specifically of PresetMan::GetEntityPreset, which may be unsafe. Could be this gross exceptional handling is the best way to go. - MovableObject *movableObjectPreset = const_cast(dynamic_cast(g_PresetMan.GetEntityPreset(GetClassName(), GetPresetName(), GetModuleID()))); - if (this != movableObjectPreset) { - movableObjectPreset->ReloadScripts(); - } + std::unordered_map scriptFileFunctions; + if (usedState.RunScriptFileAndRetrieveFunctions(scriptPath, GetSupportedScriptFunctionNames(), scriptFileFunctions) < 0) { + return -4; + } + + for (const auto& [functionName, functionObject]: scriptFileFunctions) { + LuaFunction& luaFunction = m_FunctionsAndScripts.at(functionName).emplace_back(); + luaFunction.m_ScriptIsEnabled = loadAsEnabledScript; + luaFunction.m_LuaFunction = std::unique_ptr(functionObject); + } - std::unordered_map loadedScriptsCopy = m_AllLoadedScripts; - m_AllLoadedScripts.clear(); - m_FunctionsAndScripts.clear(); - for (const auto &[scriptPath, scriptEnabled] : loadedScriptsCopy) { - status = LoadScript(scriptPath, scriptEnabled); - // If the script fails to load because of an error in its Lua, we need to manually add the script path so it's not lost forever. - if (status == -4) { - m_AllLoadedScripts.try_emplace(scriptPath, scriptEnabled); - } else if (status < 0) { - break; + if (ObjectScriptsInitialized()) { + if (RunFunctionOfScript(scriptPath, "Create") < 0) { + return -5; + } } + + return 0; } - return status; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int MovableObject::ReloadScripts() { + if (m_AllLoadedScripts.empty()) { + return 0; + } -int MovableObject::InitializeObjectScripts() { - std::lock_guard lock(m_ThreadedLuaState->GetMutex()); - m_ScriptObjectName = "_ScriptedObjects[\"" + std::to_string(m_UniqueID) + "\"]"; - m_ThreadedLuaState->RegisterMO(this); - m_ThreadedLuaState->SetTempEntity(this); - if (m_ThreadedLuaState->RunScriptString("_ScriptedObjects = _ScriptedObjects or {}; " + m_ScriptObjectName + " = To" + GetClassName() + "(LuaMan.TempEntity); ") < 0) { - RTEAbort("Failed to initialize object scripts for " + GetModuleAndPresetName() + ". Please report this to a developer."); - } + int status = 0; - if (!m_FunctionsAndScripts.at("Create").empty() && RunScriptedFunctionInAppropriateScripts("Create", false, true) < 0) { - m_ScriptObjectName = "ERROR"; - return -1; + // TODO consider getting rid of this const_cast. It would require either code duplication or creating some non-const methods (specifically of PresetMan::GetEntityPreset, which may be unsafe. Could be this gross exceptional handling is the best way to go. + MovableObject* movableObjectPreset = const_cast(dynamic_cast(g_PresetMan.GetEntityPreset(GetClassName(), GetPresetName(), GetModuleID()))); + if (this != movableObjectPreset) { + movableObjectPreset->ReloadScripts(); + } + + std::unordered_map loadedScriptsCopy = m_AllLoadedScripts; + m_AllLoadedScripts.clear(); + m_FunctionsAndScripts.clear(); + for (const auto& [scriptPath, scriptEnabled]: loadedScriptsCopy) { + status = LoadScript(scriptPath, scriptEnabled); + // If the script fails to load because of an error in its Lua, we need to manually add the script path so it's not lost forever. + if (status == -4) { + m_AllLoadedScripts.try_emplace(scriptPath, scriptEnabled); + } else if (status < 0) { + break; + } + } + + return status; } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableObject::InitializeObjectScripts() { + std::lock_guard lock(m_ThreadedLuaState->GetMutex()); + m_ScriptObjectName = "_ScriptedObjects[\"" + std::to_string(m_UniqueID) + "\"]"; + m_ThreadedLuaState->RegisterMO(this); + m_ThreadedLuaState->SetTempEntity(this); + if (m_ThreadedLuaState->RunScriptString("_ScriptedObjects = _ScriptedObjects or {}; " + m_ScriptObjectName + " = To" + GetClassName() + "(LuaMan.TempEntity); ") < 0) { + RTEAbort("Failed to initialize object scripts for " + GetModuleAndPresetName() + ". Please report this to a developer."); + } + + if (!m_FunctionsAndScripts.at("Create").empty() && RunScriptedFunctionInAppropriateScripts("Create", false, true) < 0) { + m_ScriptObjectName = "ERROR"; + return -1; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return 0; + } -bool MovableObject::EnableOrDisableScript(const std::string &scriptPath, bool enableScript) { - if (m_AllLoadedScripts.empty()) { - return false; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (auto scriptEntryIterator = m_AllLoadedScripts.find(scriptPath); scriptEntryIterator != m_AllLoadedScripts.end() && scriptEntryIterator->second == !enableScript) { - if (ObjectScriptsInitialized() && RunFunctionOfScript(scriptPath, enableScript ? "OnScriptEnable" : "OnScriptDisable") < 0) { + bool MovableObject::EnableOrDisableScript(const std::string& scriptPath, bool enableScript) { + if (m_AllLoadedScripts.empty()) { return false; } - scriptEntryIterator->second = enableScript; + if (auto scriptEntryIterator = m_AllLoadedScripts.find(scriptPath); scriptEntryIterator != m_AllLoadedScripts.end() && scriptEntryIterator->second == !enableScript) { + if (ObjectScriptsInitialized() && RunFunctionOfScript(scriptPath, enableScript ? "OnScriptEnable" : "OnScriptDisable") < 0) { + return false; + } - // Slow, but better to spend this time here in EnableOrDisableScript than every update hashing the script path as we used to do - for (auto &[functionName, functionObjects] : m_FunctionsAndScripts) { - for (LuaFunction &luaFunction : functionObjects) { - if (luaFunction.m_LuaFunction->GetFilePath() == scriptPath) { - luaFunction.m_ScriptIsEnabled = enableScript; - } - } - } + scriptEntryIterator->second = enableScript; - return true; - } - return false; -} + // Slow, but better to spend this time here in EnableOrDisableScript than every update hashing the script path as we used to do + for (auto& [functionName, functionObjects]: m_FunctionsAndScripts) { + for (LuaFunction& luaFunction: functionObjects) { + if (luaFunction.m_LuaFunction->GetFilePath() == scriptPath) { + luaFunction.m_ScriptIsEnabled = enableScript; + } + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return true; + } + return false; + } -void MovableObject::EnableOrDisableAllScripts(bool enableScripts) { - for (const auto &[scriptPath, scriptIsEnabled] : m_AllLoadedScripts) { - if (enableScripts != scriptIsEnabled) { - EnableOrDisableScript(scriptPath, enableScripts); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableObject::EnableOrDisableAllScripts(bool enableScripts) { + for (const auto& [scriptPath, scriptIsEnabled]: m_AllLoadedScripts) { + if (enableScripts != scriptIsEnabled) { + EnableOrDisableScript(scriptPath, enableScripts); + } } - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int MovableObject::RunScriptedFunctionInAppropriateScripts(const std::string &functionName, bool runOnDisabledScripts, bool stopOnError, const std::vector &functionEntityArguments, const std::vector &functionLiteralArguments, const std::vector &functionObjectArguments) { - int status = 0; - - auto itr = m_FunctionsAndScripts.find(functionName); - if (itr == m_FunctionsAndScripts.end() || itr->second.empty()) { - return -1; - } - - if (!ObjectScriptsInitialized()) { - status = InitializeObjectScripts(); - } - - if (status >= 0) { - ZoneScoped; - ZoneText(functionName.c_str(), functionName.length()); - for (const LuaFunction &luaFunction : itr->second) { - const LuabindObjectWrapper *luabindObjectWrapper = luaFunction.m_LuaFunction.get(); - if (runOnDisabledScripts || luaFunction.m_ScriptIsEnabled) { - LuaStateWrapper& usedState = GetAndLockStateForScript(luabindObjectWrapper->GetFilePath(), &luaFunction); - std::lock_guard lock(usedState.GetMutex(), std::adopt_lock); - status = usedState.RunScriptFunctionObject(luabindObjectWrapper, "_ScriptedObjects", std::to_string(m_UniqueID), functionEntityArguments, functionLiteralArguments, functionObjectArguments); - if (status < 0 && stopOnError) { - return status; - } - } - } - } - return status; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int MovableObject::RunFunctionOfScript(const std::string &scriptPath, const std::string &functionName, const std::vector &functionEntityArguments, const std::vector &functionLiteralArguments) { - if (m_AllLoadedScripts.empty() || !ObjectScriptsInitialized()) { - return -1; } - LuaStateWrapper& usedState = GetAndLockStateForScript(scriptPath); - std::lock_guard lock(usedState.GetMutex(), std::adopt_lock); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableObject::RunScriptedFunctionInAppropriateScripts(const std::string& functionName, bool runOnDisabledScripts, bool stopOnError, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments, const std::vector& functionObjectArguments) { + int status = 0; - for (const LuaFunction &luaFunction : m_FunctionsAndScripts.at(functionName)) { - const LuabindObjectWrapper *luabindObjectWrapper = luaFunction.m_LuaFunction.get(); - if (scriptPath == luabindObjectWrapper->GetFilePath() && usedState.RunScriptFunctionObject(luabindObjectWrapper, "_ScriptedObjects", std::to_string(m_UniqueID), functionEntityArguments, functionLiteralArguments) < 0) { - if (m_AllLoadedScripts.size() > 1) { - g_ConsoleMan.PrintString("ERROR: An error occured while trying to run the " + functionName + " function for script at path " + scriptPath); + auto itr = m_FunctionsAndScripts.find(functionName); + if (itr == m_FunctionsAndScripts.end() || itr->second.empty()) { + return -1; + } + + if (!ObjectScriptsInitialized()) { + status = InitializeObjectScripts(); + } + + if (status >= 0) { + ZoneScoped; + ZoneText(functionName.c_str(), functionName.length()); + for (const LuaFunction& luaFunction: itr->second) { + const LuabindObjectWrapper* luabindObjectWrapper = luaFunction.m_LuaFunction.get(); + if (runOnDisabledScripts || luaFunction.m_ScriptIsEnabled) { + LuaStateWrapper& usedState = GetAndLockStateForScript(luabindObjectWrapper->GetFilePath(), &luaFunction); + std::lock_guard lock(usedState.GetMutex(), std::adopt_lock); + status = usedState.RunScriptFunctionObject(luabindObjectWrapper, "_ScriptedObjects", std::to_string(m_UniqueID), functionEntityArguments, functionLiteralArguments, functionObjectArguments); + if (status < 0 && stopOnError) { + return status; + } + } } - return -2; } + return status; } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int MovableObject::RunFunctionOfScript(const std::string& scriptPath, const std::string& functionName, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments) { + if (m_AllLoadedScripts.empty() || !ObjectScriptsInitialized()) { + return -1; + } -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MovableObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Copy constructor method used to instantiate a MovableObject object -// identical to an already existing one. + LuaStateWrapper& usedState = GetAndLockStateForScript(scriptPath); + std::lock_guard lock(usedState.GetMutex(), std::adopt_lock); + + for (const LuaFunction& luaFunction: m_FunctionsAndScripts.at(functionName)) { + const LuabindObjectWrapper* luabindObjectWrapper = luaFunction.m_LuaFunction.get(); + if (scriptPath == luabindObjectWrapper->GetFilePath() && usedState.RunScriptFunctionObject(luabindObjectWrapper, "_ScriptedObjects", std::to_string(m_UniqueID), functionEntityArguments, functionLiteralArguments) < 0) { + if (m_AllLoadedScripts.size() > 1) { + g_ConsoleMan.PrintString("ERROR: An error occured while trying to run the " + functionName + " function for script at path " + scriptPath); + } + return -2; + } + } -MovableObject::MovableObject(const MovableObject &reference): - m_Mass(reference.GetMass()), - m_Pos(reference.GetPos()), - m_Vel(reference.GetVel()), - m_AgeTimer(reference.GetAge()), - m_Lifetime(reference.GetLifetime()) -{ + return 0; + } -} -*/ + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MovableObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Copy constructor method used to instantiate a MovableObject object + // identical to an already existing one. + + MovableObject::MovableObject(const MovableObject &reference): + m_Mass(reference.GetMass()), + m_Pos(reference.GetPos()), + m_Vel(reference.GetVel()), + m_AgeTimer(reference.GetAge()), + m_Lifetime(reference.GetLifetime()) + { -void MovableObject::SetTeam(int team) { - SceneObject::SetTeam(team); - if (Activity *activity = g_ActivityMan.GetActivity()) { activity->ForceSetTeamAsActive(team); } -} + } + */ -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the altitide of this' pos (or appropriate low point) over the -// terrain, in pixels. + void MovableObject::SetTeam(int team) { + SceneObject::SetTeam(team); + if (Activity* activity = g_ActivityMan.GetActivity()) { + activity->ForceSetTeamAsActive(team); + } + } -float MovableObject::GetAltitude(int max, int accuracy) -{ - return g_SceneMan.FindAltitude(m_Pos, max, accuracy); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the altitide of this' pos (or appropriate low point) over the + // terrain, in pixels. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float MovableObject::GetAltitude(int max, int accuracy) { + return g_SceneMan.FindAltitude(m_Pos, max, accuracy); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::AddAbsForce(const Vector &force, const Vector &absPos) -{ - m_Forces.push_back(std::make_pair(force, g_SceneMan.ShortestDistance(m_Pos, absPos) * c_MPP)); -} + void MovableObject::AddAbsForce(const Vector& force, const Vector& absPos) { + m_Forces.push_back(std::make_pair(force, g_SceneMan.ShortestDistance(m_Pos, absPos) * c_MPP)); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::AddAbsImpulseForce(const Vector &impulse, const Vector &absPos) -{ + void MovableObject::AddAbsImpulseForce(const Vector& impulse, const Vector& absPos) { #ifndef RELEASE_BUILD RTEAssert(impulse.GetLargest() < 500000, "HUEG IMPULSE FORCE"); #endif m_ImpulseForces.push_back(std::make_pair(impulse, g_SceneMan.ShortestDistance(m_Pos, absPos) * c_MPP)); -} + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::RestDetection() { - // Translational settling detection. - if (m_Vel.Dot(m_PrevVel) < 0) { - ++m_VelOscillations; - } else { - m_VelOscillations = 0; + void MovableObject::RestDetection() { + // Translational settling detection. + if (m_Vel.Dot(m_PrevVel) < 0) { + ++m_VelOscillations; + } else { + m_VelOscillations = 0; + } + if ((m_Pos - m_PrevPos).MagnitudeIsGreaterThan(1.0F)) { + m_RestTimer.Reset(); + } } - if ((m_Pos - m_PrevPos).MagnitudeIsGreaterThan(1.0F)) { m_RestTimer.Reset(); } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MovableObject::IsAtRest() { - if (m_RestThreshold < 0 || m_PinStrength) { - return false; - } else { - if (m_VelOscillations > 2) { - return true; + bool MovableObject::IsAtRest() { + if (m_RestThreshold < 0 || m_PinStrength) { + return false; + } else { + if (m_VelOscillations > 2) { + return true; + } + return m_RestTimer.IsPastSimMS(m_RestThreshold); } - return m_RestTimer.IsPastSimMS(m_RestThreshold); } -} -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: OnMOHit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits another MO. -// This is called by the owned Atom/AtomGroup of this MovableObject during -// travel. - -bool MovableObject::OnMOHit(HitData &hd) -{ - if (hd.RootBody[HITOR] != hd.RootBody[HITEE] && (hd.Body[HITOR] == this || hd.Body[HITEE] == this)) { - RunScriptedFunctionInAppropriateScripts("OnCollideWithMO", false, false, {hd.Body[hd.Body[HITOR] == this ? HITEE : HITOR], hd.RootBody[hd.Body[HITOR] == this ? HITEE : HITOR]}); - } - return hd.Terminate[hd.RootBody[HITOR] == this ? HITOR : HITEE] = false; -} - -unsigned char MovableObject::HitWhatTerrMaterial() const -{ - return m_LastCollisionSimFrameNumber == g_MovableMan.GetSimUpdateFrameNumber() ? m_TerrainMatHit : g_MaterialAir; -} - -void MovableObject::SetHitWhatTerrMaterial(unsigned char matID) -{ - m_TerrainMatHit = matID; - m_LastCollisionSimFrameNumber = g_MovableMan.GetSimUpdateFrameNumber(); - RunScriptedFunctionInAppropriateScripts("OnCollideWithTerrain", false, false, {}, {std::to_string(m_TerrainMatHit)}); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Vector MovableObject::GetTotalForce() { - Vector totalForceVector; - for (const auto &[force, forceOffset] : m_Forces) { - totalForceVector += force; - } - return totalForceVector; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: OnMOHit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits another MO. + // This is called by the owned Atom/AtomGroup of this MovableObject during + // travel. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ApplyForces -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gathers and applies the global and accumulated forces. Then it clears -// out the force list.Note that this does NOT apply the accumulated -// impulses (impulse forces)! - -void MovableObject::ApplyForces() -{ - // Don't apply forces to pinned objects - if (m_PinStrength > 0) - { - m_Forces.clear(); - return; - } - - float deltaTime = g_TimerMan.GetDeltaTimeSecs(); - -//// TODO: remove this!$@#$%#@%#@%#@^#@^#@^@#^@#") -// if (m_PresetName != "Test Player") - // Apply global acceleration (gravity), scaled by the scalar we have that can even be negative. - m_Vel += g_SceneMan.GetGlobalAcc() * m_GlobalAccScalar * deltaTime; - - // Calculate air resistance effects, only when something flies faster than a threshold - if (m_AirResistance > 0 && m_Vel.GetLargest() >= m_AirThreshold) - m_Vel *= 1.0 - (m_AirResistance * deltaTime); - - // Apply the translational effects of all the forces accumulated during the Update(). - if (m_Forces.size() > 0) { - // Continuous force application to transformational velocity (F = m * a -> a = F / m). - m_Vel += GetTotalForce() / (GetMass() != 0 ? GetMass() : 0.0001F) * deltaTime; + bool MovableObject::OnMOHit(HitData& hd) { + if (hd.RootBody[HITOR] != hd.RootBody[HITEE] && (hd.Body[HITOR] == this || hd.Body[HITEE] == this)) { + RunScriptedFunctionInAppropriateScripts("OnCollideWithMO", false, false, {hd.Body[hd.Body[HITOR] == this ? HITEE : HITOR], hd.RootBody[hd.Body[HITOR] == this ? HITEE : HITOR]}); + } + return hd.Terminate[hd.RootBody[HITOR] == this ? HITOR : HITEE] = false; } - // Clear out the forces list - m_Forces.clear(); -} + unsigned char MovableObject::HitWhatTerrMaterial() const { + return m_LastCollisionSimFrameNumber == g_MovableMan.GetSimUpdateFrameNumber() ? m_TerrainMatHit : g_MaterialAir; + } + void MovableObject::SetHitWhatTerrMaterial(unsigned char matID) { + m_TerrainMatHit = matID; + m_LastCollisionSimFrameNumber = g_MovableMan.GetSimUpdateFrameNumber(); + RunScriptedFunctionInAppropriateScripts("OnCollideWithTerrain", false, false, {}, {std::to_string(m_TerrainMatHit)}); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ApplyImpulses -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gathers and applies the accumulated impulse forces. Then it clears -// out the impulse list.Note that this does NOT apply the accumulated -// regular forces (non-impulse forces)! + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::ApplyImpulses() -{ - // Don't apply forces to pinned objects - if (m_PinStrength > 0) - { - m_ImpulseForces.clear(); - return; - } + Vector MovableObject::GetTotalForce() { + Vector totalForceVector; + for (const auto& [force, forceOffset]: m_Forces) { + totalForceVector += force; + } + return totalForceVector; + } -// float totalImpulses. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ApplyForces + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gathers and applies the global and accumulated forces. Then it clears + // out the force list.Note that this does NOT apply the accumulated + // impulses (impulse forces)! + + void MovableObject::ApplyForces() { + // Don't apply forces to pinned objects + if (m_PinStrength > 0) { + m_Forces.clear(); + return; + } - // Apply the translational effects of all the impulses accumulated during the Update() - for (auto iItr = m_ImpulseForces.begin(); iItr != m_ImpulseForces.end(); ++iItr) { - // Impulse force application to the transformational velocity of this MO. - // Don't timescale these because they're already in kg * m/s (as opposed to kg * m/s^2). - m_Vel += (*iItr).first / (GetMass() != 0 ? GetMass() : 0.0001F); - } + float deltaTime = g_TimerMan.GetDeltaTimeSecs(); - // Clear out the impulses list - m_ImpulseForces.clear(); -} + //// TODO: remove this!$@#$%#@%#@%#@^#@^#@^@#^@#") + // if (m_PresetName != "Test Player") + // Apply global acceleration (gravity), scaled by the scalar we have that can even be negative. + m_Vel += g_SceneMan.GetGlobalAcc() * m_GlobalAccScalar * deltaTime; + // Calculate air resistance effects, only when something flies faster than a threshold + if (m_AirResistance > 0 && m_Vel.GetLargest() >= m_AirThreshold) + m_Vel *= 1.0 - (m_AirResistance * deltaTime); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done before Travel(). Always call before -// calling Travel. - -void MovableObject::PreTravel() -{ - // Temporarily remove the representation of this from the scene MO sampler - if (m_GetsHitByMOs) { - m_IsTraveling = true; -#ifdef DRAW_MOID_LAYER - if (!g_SettingsMan.SimplifiedCollisionDetection()) { - Draw(g_SceneMan.GetMOIDBitmap(), Vector(), DrawMode::g_DrawNoMOID, true); + // Apply the translational effects of all the forces accumulated during the Update(). + if (m_Forces.size() > 0) { + // Continuous force application to transformational velocity (F = m * a -> a = F / m). + m_Vel += GetTotalForce() / (GetMass() != 0 ? GetMass() : 0.0001F) * deltaTime; } -#endif - } - // Save previous position and velocities before moving - m_PrevPos = m_Pos; - m_PrevVel = m_Vel; - - m_MOIDHit = g_NoMOID; - m_TerrainMatHit = g_MaterialAir; - m_ParticleUniqueIDHit = 0; -} + // Clear out the forces list + m_Forces.clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ApplyImpulses + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gathers and applies the accumulated impulse forces. Then it clears + // out the impulse list.Note that this does NOT apply the accumulated + // regular forces (non-impulse forces)! + + void MovableObject::ApplyImpulses() { + // Don't apply forces to pinned objects + if (m_PinStrength > 0) { + m_ImpulseForces.clear(); + return; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Travel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Travels this MovableObject, using its physical representation. + // float totalImpulses. -void MovableObject::Travel() -{ + // Apply the translational effects of all the impulses accumulated during the Update() + for (auto iItr = m_ImpulseForces.begin(); iItr != m_ImpulseForces.end(); ++iItr) { + // Impulse force application to the transformational velocity of this MO. + // Don't timescale these because they're already in kg * m/s (as opposed to kg * m/s^2). + m_Vel += (*iItr).first / (GetMass() != 0 ? GetMass() : 0.0001F); + } -} + // Clear out the impulses list + m_ImpulseForces.clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done before Travel(). Always call before + // calling Travel. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PostTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done after Travel(). Always call after -// calling Travel. - -void MovableObject::PostTravel() -{ - // Toggle whether this gets hit by other AtomGroup MOs depending on whether it's going slower than a set threshold - if (m_IgnoresAGHitsWhenSlowerThan > 0) { - m_IgnoresAtomGroupHits = m_Vel.MagnitudeIsLessThan(m_IgnoresAGHitsWhenSlowerThan); - } - - if (m_GetsHitByMOs) { - if (!GetParent()) { - m_IsTraveling = false; + void MovableObject::PreTravel() { + // Temporarily remove the representation of this from the scene MO sampler + if (m_GetsHitByMOs) { + m_IsTraveling = true; #ifdef DRAW_MOID_LAYER if (!g_SettingsMan.SimplifiedCollisionDetection()) { - Draw(g_SceneMan.GetMOIDBitmap(), Vector(), DrawMode::g_DrawMOID, true); + Draw(g_SceneMan.GetMOIDBitmap(), Vector(), DrawMode::g_DrawNoMOID, true); } #endif } - m_AlreadyHitBy.clear(); - } - m_IsUpdated = true; - - // Check for age expiration - if (m_Lifetime && m_AgeTimer.GetElapsedSimTimeMS() > m_Lifetime) { - m_ToDelete = true; - } - // Check for stupid positions - if (!GetParent() && !g_SceneMan.IsWithinBounds(m_Pos.m_X, m_Pos.m_Y, 1000)) { - m_ToDelete = true; - } + // Save previous position and velocities before moving + m_PrevPos = m_Pos; + m_PrevVel = m_Vel; - // Fix speeds that are too high - FixTooFast(); + m_MOIDHit = g_NoMOID; + m_TerrainMatHit = g_MaterialAir; + m_ParticleUniqueIDHit = 0; + } - // Never let mission critical stuff settle or delete - if (m_MissionCritical) { - m_ToSettle = false; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Travel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Travels this MovableObject, using its physical representation. - // Reset the terrain intersection warning - m_CheckTerrIntersection = false; + void MovableObject::Travel() { + } - m_DistanceTravelled += m_Vel.GetMagnitude() * c_PPM * g_TimerMan.GetDeltaTimeSecs(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PostTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done after Travel(). Always call after + // calling Travel. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void MovableObject::PostTravel() { + // Toggle whether this gets hit by other AtomGroup MOs depending on whether it's going slower than a set threshold + if (m_IgnoresAGHitsWhenSlowerThan > 0) { + m_IgnoresAtomGroupHits = m_Vel.MagnitudeIsLessThan(m_IgnoresAGHitsWhenSlowerThan); + } -void MovableObject::Update() { - if (m_RandomizeEffectRotAngleEveryFrame) { m_EffectRotAngle = c_PI * 2.0F * RandomNormalNum(); } -} + if (m_GetsHitByMOs) { + if (!GetParent()) { + m_IsTraveling = false; +#ifdef DRAW_MOID_LAYER + if (!g_SettingsMan.SimplifiedCollisionDetection()) { + Draw(g_SceneMan.GetMOIDBitmap(), Vector(), DrawMode::g_DrawMOID, true); + } +#endif + } + m_AlreadyHitBy.clear(); + } + m_IsUpdated = true; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Check for age expiration + if (m_Lifetime && m_AgeTimer.GetElapsedSimTimeMS() > m_Lifetime) { + m_ToDelete = true; + } -void MovableObject::Draw(BITMAP* targetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { - if (mode == g_DrawMOID && m_MOID == g_NoMOID) { - return; - } + // Check for stupid positions + if (!GetParent() && !g_SceneMan.IsWithinBounds(m_Pos.m_X, m_Pos.m_Y, 1000)) { + m_ToDelete = true; + } - g_SceneMan.RegisterDrawing(targetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, m_Pos - targetPos, 1.0F); -} + // Fix speeds that are too high + FixTooFast(); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Never let mission critical stuff settle or delete + if (m_MissionCritical) { + m_ToSettle = false; + } -int MovableObject::UpdateScripts() { - m_SimUpdatesSinceLastScriptedUpdate++; + // Reset the terrain intersection warning + m_CheckTerrIntersection = false; - if (m_AllLoadedScripts.empty()) { - return -1; + m_DistanceTravelled += m_Vel.GetMagnitude() * c_PPM * g_TimerMan.GetDeltaTimeSecs(); } - int status = 0; - if (!ObjectScriptsInitialized()) { - status = InitializeObjectScripts(); - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (m_SimUpdatesSinceLastScriptedUpdate < m_SimUpdatesBetweenScriptedUpdates) { - return 1; + void MovableObject::Update() { + if (m_RandomizeEffectRotAngleEveryFrame) { + m_EffectRotAngle = c_PI * 2.0F * RandomNormalNum(); + } } - m_SimUpdatesSinceLastScriptedUpdate = 0; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableObject::Draw(BITMAP* targetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { + if (mode == g_DrawMOID && m_MOID == g_NoMOID) { + return; + } - if (status >= 0) { - status = RunScriptedFunctionInAppropriateScripts("Update", false, true, {}, {}, {}); + g_SceneMan.RegisterDrawing(targetBitmap, mode == g_DrawNoMOID ? g_NoMOID : m_MOID, m_Pos - targetPos, 1.0F); } - return status; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableObject::UpdateScripts() { + m_SimUpdatesSinceLastScriptedUpdate++; + + if (m_AllLoadedScripts.empty()) { + return -1; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int status = 0; + if (!ObjectScriptsInitialized()) { + status = InitializeObjectScripts(); + } -const std::string & MovableObject::GetStringValue(const std::string &key) const -{ - auto itr = m_StringValueMap.find(key); - if (itr == m_StringValueMap.end()) { - return ms_EmptyString; - } - - return itr->second; -} + if (m_SimUpdatesSinceLastScriptedUpdate < m_SimUpdatesBetweenScriptedUpdates) { + return 1; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m_SimUpdatesSinceLastScriptedUpdate = 0; -std::string MovableObject::GetEncodedStringValue(const std::string &key) const -{ - auto itr = m_StringValueMap.find(key); - if (itr == m_StringValueMap.end()) { - return ms_EmptyString; - } + if (status >= 0) { + status = RunScriptedFunctionInAppropriateScripts("Update", false, true, {}, {}, {}); + } - return base64_decode(itr->second); -} + return status; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -double MovableObject::GetNumberValue(const std::string& key) const -{ - auto itr = m_NumberValueMap.find(key); - if (itr == m_NumberValueMap.end()) { - return 0.0; - } + const std::string& MovableObject::GetStringValue(const std::string& key) const { + auto itr = m_StringValueMap.find(key); + if (itr == m_StringValueMap.end()) { + return ms_EmptyString; + } - return itr->second; -} + return itr->second; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -Entity* MovableObject::GetObjectValue(const std::string &key) const -{ - auto itr = m_ObjectValueMap.find(key); - if (itr == m_ObjectValueMap.end()) { - return nullptr; - } + std::string MovableObject::GetEncodedStringValue(const std::string& key) const { + auto itr = m_StringValueMap.find(key); + if (itr == m_StringValueMap.end()) { + return ms_EmptyString; + } + + return base64_decode(itr->second); + } - return itr->second; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + double MovableObject::GetNumberValue(const std::string& key) const { + auto itr = m_NumberValueMap.find(key); + if (itr == m_NumberValueMap.end()) { + return 0.0; + } + + return itr->second; + } -void MovableObject::SetStringValue(const std::string &key, const std::string &value) -{ - m_StringValueMap[key] = value; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Entity* MovableObject::GetObjectValue(const std::string& key) const { + auto itr = m_ObjectValueMap.find(key); + if (itr == m_ObjectValueMap.end()) { + return nullptr; + } -void MovableObject::SetEncodedStringValue(const std::string &key, const std::string &value) -{ - m_StringValueMap[key] = base64_encode(value, true); -} + return itr->second; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::SetNumberValue(const std::string &key, double value) -{ - m_NumberValueMap[key] = value; -} + void MovableObject::SetStringValue(const std::string& key, const std::string& value) { + m_StringValueMap[key] = value; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::SetObjectValue(const std::string &key, Entity* value) -{ - m_ObjectValueMap[key] = value; -} + void MovableObject::SetEncodedStringValue(const std::string& key, const std::string& value) { + m_StringValueMap[key] = base64_encode(value, true); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::RemoveStringValue(const std::string &key) -{ - m_StringValueMap.erase(key); -} + void MovableObject::SetNumberValue(const std::string& key, double value) { + m_NumberValueMap[key] = value; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::RemoveNumberValue(const std::string &key) -{ - m_NumberValueMap.erase(key); -} + void MovableObject::SetObjectValue(const std::string& key, Entity* value) { + m_ObjectValueMap[key] = value; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::RemoveObjectValue(const std::string &key) -{ - m_ObjectValueMap.erase(key); -} + void MovableObject::RemoveStringValue(const std::string& key) { + m_StringValueMap.erase(key); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MovableObject::StringValueExists(const std::string &key) const -{ - return m_StringValueMap.find(key) != m_StringValueMap.end(); -} + void MovableObject::RemoveNumberValue(const std::string& key) { + m_NumberValueMap.erase(key); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MovableObject::NumberValueExists(const std::string &key) const -{ - return m_NumberValueMap.find(key) != m_NumberValueMap.end(); -} + void MovableObject::RemoveObjectValue(const std::string& key) { + m_ObjectValueMap.erase(key); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MovableObject::ObjectValueExists(const std::string &key) const -{ - return m_ObjectValueMap.find(key) != m_ObjectValueMap.end(); -} + bool MovableObject::StringValueExists(const std::string& key) const { + return m_StringValueMap.find(key) != m_StringValueMap.end(); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int MovableObject::WhilePieMenuOpenListener(const PieMenu *pieMenu) { - return RunScriptedFunctionInAppropriateScripts("WhilePieMenuOpen", false, false, { pieMenu }); -} + bool MovableObject::NumberValueExists(const std::string& key) const { + return m_NumberValueMap.find(key) != m_NumberValueMap.end(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this' and its childrens MOID status. Supposed to be done every frame. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void MovableObject::UpdateMOID(std::vector &MOIDIndex, MOID rootMOID, bool makeNewMOID) -{ - // Register the own MOID - RegMOID(MOIDIndex, rootMOID, makeNewMOID); + bool MovableObject::ObjectValueExists(const std::string& key) const { + return m_ObjectValueMap.find(key) != m_ObjectValueMap.end(); + } - // Register all the attachaed children of this, going through the class hierarchy - UpdateChildMOIDs(MOIDIndex, rootMOID, makeNewMOID); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Figure out the total MOID footstep of this and all its children combined - m_MOIDFootprint = MOIDIndex.size() - m_MOID; -} + int MovableObject::WhilePieMenuOpenListener(const PieMenu* pieMenu) { + return RunScriptedFunctionInAppropriateScripts("WhilePieMenuOpen", false, false, {pieMenu}); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this' and its childrens MOID status. Supposed to be done every frame. + void MovableObject::UpdateMOID(std::vector& MOIDIndex, MOID rootMOID, bool makeNewMOID) { + // Register the own MOID + RegMOID(MOIDIndex, rootMOID, makeNewMOID); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Puts all MOIDs associated with this MO and all it's descendants into MOIDs vector - -void MovableObject::GetMOIDs(std::vector &MOIDs) const -{ - if (m_MOID != g_NoMOID) { - MOIDs.push_back(m_MOID); - } -} - -MOID MovableObject::HitWhatMOID() const -{ - return m_LastCollisionSimFrameNumber == g_MovableMan.GetSimUpdateFrameNumber() ? m_MOIDHit : g_NoMOID; -} - -void MovableObject::SetHitWhatMOID(MOID id) -{ - m_MOIDHit = id; - m_LastCollisionSimFrameNumber = g_MovableMan.GetSimUpdateFrameNumber(); -} - -long int MovableObject::HitWhatParticleUniqueID() const -{ - return m_LastCollisionSimFrameNumber == g_MovableMan.GetSimUpdateFrameNumber() ? m_ParticleUniqueIDHit : 0; -} - -void MovableObject::SetHitWhatParticleUniqueID(long int id) -{ - m_ParticleUniqueIDHit = id; - m_LastCollisionSimFrameNumber = g_MovableMan.GetSimUpdateFrameNumber(); -} + // Register all the attachaed children of this, going through the class hierarchy + UpdateChildMOIDs(MOIDIndex, rootMOID, makeNewMOID); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: RegMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this MO register itself in the MOID register and get ID:s for -// itself and its children for this frame. -// BITMAP of choice. + // Figure out the total MOID footstep of this and all its children combined + m_MOIDFootprint = MOIDIndex.size() - m_MOID; + } -void MovableObject::RegMOID(std::vector &MOIDIndex, MOID rootMOID, bool makeNewMOID) { - if (!makeNewMOID && GetParent()) { - m_MOID = GetParent()->GetID(); - } else { - if (MOIDIndex.size() == g_NoMOID) { MOIDIndex.push_back(0); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Puts all MOIDs associated with this MO and all it's descendants into MOIDs vector - m_MOID = MOIDIndex.size(); - MOIDIndex.push_back(this); - } + void MovableObject::GetMOIDs(std::vector& MOIDs) const { + if (m_MOID != g_NoMOID) { + MOIDs.push_back(m_MOID); + } + } - m_RootMOID = rootMOID == g_NoMOID ? m_MOID : rootMOID; -} + MOID MovableObject::HitWhatMOID() const { + return m_LastCollisionSimFrameNumber == g_MovableMan.GetSimUpdateFrameNumber() ? m_MOIDHit : g_NoMOID; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void MovableObject::SetHitWhatMOID(MOID id) { + m_MOIDHit = id; + m_LastCollisionSimFrameNumber = g_MovableMan.GetSimUpdateFrameNumber(); + } -bool MovableObject::DrawToTerrain(SLTerrain *terrain) { - if (!terrain) { - return false; + long int MovableObject::HitWhatParticleUniqueID() const { + return m_LastCollisionSimFrameNumber == g_MovableMan.GetSimUpdateFrameNumber() ? m_ParticleUniqueIDHit : 0; } - if (dynamic_cast(this)) { - auto wrappedMaskedBlit = [](BITMAP *sourceBitmap, BITMAP *destinationBitmap, const Vector &bitmapPos, bool swapSourceWithDestination) { - std::array bitmaps = { sourceBitmap, destinationBitmap }; - std::array srcPos = { - Vector(bitmapPos.GetX(), bitmapPos.GetY()), - Vector(bitmapPos.GetX() + static_cast(g_SceneMan.GetSceneWidth()), bitmapPos.GetY()), - Vector(bitmapPos.GetX() - static_cast(g_SceneMan.GetSceneWidth()), bitmapPos.GetY()), - Vector(bitmapPos.GetX(), bitmapPos.GetY() + static_cast(g_SceneMan.GetSceneHeight())), - Vector(bitmapPos.GetX(), bitmapPos.GetY() - static_cast(g_SceneMan.GetSceneHeight())) - }; - std::array destPos; - destPos.fill(Vector()); - if (swapSourceWithDestination) { - std::swap(bitmaps[0], bitmaps[1]); - std::swap(srcPos, destPos); + void MovableObject::SetHitWhatParticleUniqueID(long int id) { + m_ParticleUniqueIDHit = id; + m_LastCollisionSimFrameNumber = g_MovableMan.GetSimUpdateFrameNumber(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RegMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this MO register itself in the MOID register and get ID:s for + // itself and its children for this frame. + // BITMAP of choice. + + void MovableObject::RegMOID(std::vector& MOIDIndex, MOID rootMOID, bool makeNewMOID) { + if (!makeNewMOID && GetParent()) { + m_MOID = GetParent()->GetID(); + } else { + if (MOIDIndex.size() == g_NoMOID) { + MOIDIndex.push_back(0); } - masked_blit(bitmaps[0], bitmaps[1], srcPos[0].GetFloorIntX(), srcPos[0].GetFloorIntY(), destPos[0].GetFloorIntX(), destPos[0].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); - if (g_SceneMan.SceneWrapsX()) { - if (bitmapPos.GetFloorIntX() < 0) { - masked_blit(bitmaps[0], bitmaps[1], srcPos[1].GetFloorIntX(), srcPos[1].GetFloorIntY(), destPos[1].GetFloorIntX(), destPos[1].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); - } else if (bitmapPos.GetFloorIntX() + destinationBitmap->w > g_SceneMan.GetSceneWidth()) { - masked_blit(bitmaps[0], bitmaps[1], srcPos[2].GetFloorIntX(), srcPos[2].GetFloorIntY(), destPos[2].GetFloorIntX(), destPos[2].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); + + m_MOID = MOIDIndex.size(); + MOIDIndex.push_back(this); + } + + m_RootMOID = rootMOID == g_NoMOID ? m_MOID : rootMOID; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool MovableObject::DrawToTerrain(SLTerrain* terrain) { + if (!terrain) { + return false; + } + if (dynamic_cast(this)) { + auto wrappedMaskedBlit = [](BITMAP* sourceBitmap, BITMAP* destinationBitmap, const Vector& bitmapPos, bool swapSourceWithDestination) { + std::array bitmaps = {sourceBitmap, destinationBitmap}; + std::array srcPos = { + Vector(bitmapPos.GetX(), bitmapPos.GetY()), + Vector(bitmapPos.GetX() + static_cast(g_SceneMan.GetSceneWidth()), bitmapPos.GetY()), + Vector(bitmapPos.GetX() - static_cast(g_SceneMan.GetSceneWidth()), bitmapPos.GetY()), + Vector(bitmapPos.GetX(), bitmapPos.GetY() + static_cast(g_SceneMan.GetSceneHeight())), + Vector(bitmapPos.GetX(), bitmapPos.GetY() - static_cast(g_SceneMan.GetSceneHeight()))}; + std::array destPos; + destPos.fill(Vector()); + + if (swapSourceWithDestination) { + std::swap(bitmaps[0], bitmaps[1]); + std::swap(srcPos, destPos); } - } - if (g_SceneMan.SceneWrapsY()) { - if (bitmapPos.GetFloorIntY() < 0) { - masked_blit(bitmaps[0], bitmaps[1], srcPos[3].GetFloorIntX(), srcPos[3].GetFloorIntY(), destPos[3].GetFloorIntX(), destPos[3].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); - } else if (bitmapPos.GetFloorIntY() + destinationBitmap->h > g_SceneMan.GetSceneHeight()) { - masked_blit(bitmaps[0], bitmaps[1], srcPos[4].GetFloorIntX(), srcPos[4].GetFloorIntY(), destPos[4].GetFloorIntX(), destPos[4].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); + masked_blit(bitmaps[0], bitmaps[1], srcPos[0].GetFloorIntX(), srcPos[0].GetFloorIntY(), destPos[0].GetFloorIntX(), destPos[0].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); + if (g_SceneMan.SceneWrapsX()) { + if (bitmapPos.GetFloorIntX() < 0) { + masked_blit(bitmaps[0], bitmaps[1], srcPos[1].GetFloorIntX(), srcPos[1].GetFloorIntY(), destPos[1].GetFloorIntX(), destPos[1].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); + } else if (bitmapPos.GetFloorIntX() + destinationBitmap->w > g_SceneMan.GetSceneWidth()) { + masked_blit(bitmaps[0], bitmaps[1], srcPos[2].GetFloorIntX(), srcPos[2].GetFloorIntY(), destPos[2].GetFloorIntX(), destPos[2].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); + } + } + if (g_SceneMan.SceneWrapsY()) { + if (bitmapPos.GetFloorIntY() < 0) { + masked_blit(bitmaps[0], bitmaps[1], srcPos[3].GetFloorIntX(), srcPos[3].GetFloorIntY(), destPos[3].GetFloorIntX(), destPos[3].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); + } else if (bitmapPos.GetFloorIntY() + destinationBitmap->h > g_SceneMan.GetSceneHeight()) { + masked_blit(bitmaps[0], bitmaps[1], srcPos[4].GetFloorIntX(), srcPos[4].GetFloorIntY(), destPos[4].GetFloorIntX(), destPos[4].GetFloorIntY(), destinationBitmap->w, destinationBitmap->h); + } } + }; + BITMAP* tempBitmap = g_SceneMan.GetIntermediateBitmapForSettlingIntoTerrain(static_cast(GetDiameter())); + Vector tempBitmapPos = m_Pos.GetFloored() - Vector(static_cast(tempBitmap->w / 2), static_cast(tempBitmap->w / 2)); + + clear_bitmap(tempBitmap); + // Draw the object to the temp bitmap, then draw the foreground layer on top of it, then draw it to the foreground layer. + Draw(tempBitmap, tempBitmapPos, DrawMode::g_DrawColor, true); + wrappedMaskedBlit(terrain->GetFGColorBitmap(), tempBitmap, tempBitmapPos, false); + wrappedMaskedBlit(terrain->GetFGColorBitmap(), tempBitmap, tempBitmapPos, true); + + clear_bitmap(tempBitmap); + // Draw the object to the temp bitmap, then draw the material layer on top of it, then draw it to the material layer. + Draw(tempBitmap, tempBitmapPos, DrawMode::g_DrawMaterial, true); + wrappedMaskedBlit(terrain->GetMaterialBitmap(), tempBitmap, tempBitmapPos, false); + wrappedMaskedBlit(terrain->GetMaterialBitmap(), tempBitmap, tempBitmapPos, true); + + terrain->AddUpdatedMaterialArea(Box(tempBitmapPos, static_cast(tempBitmap->w), static_cast(tempBitmap->h))); + g_SceneMan.RegisterTerrainChange(tempBitmapPos.GetFloorIntX(), tempBitmapPos.GetFloorIntY(), tempBitmap->w, tempBitmap->h, ColorKeys::g_MaskColor, false); + } else { + Draw(terrain->GetFGColorBitmap(), Vector(), DrawMode::g_DrawColor, true); + Material const* terrMat = g_SceneMan.GetMaterialFromID(g_SceneMan.GetTerrain()->GetMaterialPixel(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY())); + if (GetMaterial()->GetPriority() > terrMat->GetPriority()) { + Draw(terrain->GetMaterialBitmap(), Vector(), DrawMode::g_DrawMaterial, true); } - }; - BITMAP *tempBitmap = g_SceneMan.GetIntermediateBitmapForSettlingIntoTerrain(static_cast(GetDiameter())); - Vector tempBitmapPos = m_Pos.GetFloored() - Vector(static_cast(tempBitmap->w / 2), static_cast(tempBitmap->w / 2)); - - clear_bitmap(tempBitmap); - // Draw the object to the temp bitmap, then draw the foreground layer on top of it, then draw it to the foreground layer. - Draw(tempBitmap, tempBitmapPos, DrawMode::g_DrawColor, true); - wrappedMaskedBlit(terrain->GetFGColorBitmap(), tempBitmap, tempBitmapPos, false); - wrappedMaskedBlit(terrain->GetFGColorBitmap(), tempBitmap, tempBitmapPos, true); - - clear_bitmap(tempBitmap); - // Draw the object to the temp bitmap, then draw the material layer on top of it, then draw it to the material layer. - Draw(tempBitmap, tempBitmapPos, DrawMode::g_DrawMaterial, true); - wrappedMaskedBlit(terrain->GetMaterialBitmap(), tempBitmap, tempBitmapPos, false); - wrappedMaskedBlit(terrain->GetMaterialBitmap(), tempBitmap, tempBitmapPos, true); - - terrain->AddUpdatedMaterialArea(Box(tempBitmapPos, static_cast(tempBitmap->w), static_cast(tempBitmap->h))); - g_SceneMan.RegisterTerrainChange(tempBitmapPos.GetFloorIntX(), tempBitmapPos.GetFloorIntY(), tempBitmap->w, tempBitmap->h, ColorKeys::g_MaskColor, false); - } else { - Draw(terrain->GetFGColorBitmap(), Vector(), DrawMode::g_DrawColor, true); - Material const *terrMat = g_SceneMan.GetMaterialFromID(g_SceneMan.GetTerrain()->GetMaterialPixel(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY())); - if (GetMaterial()->GetPriority() > terrMat->GetPriority()) { - Draw(terrain->GetMaterialBitmap(), Vector(), DrawMode::g_DrawMaterial, true); + g_SceneMan.RegisterTerrainChange(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), 1, 1, DrawMode::g_DrawColor, false); } - g_SceneMan.RegisterTerrainChange(m_Pos.GetFloorIntX(), m_Pos.GetFloorIntY(), 1, 1, DrawMode::g_DrawColor, false); + return true; } - return true; -} -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/MovableObject.h b/Source/Entities/MovableObject.h index 194422865..bb4053e20 100644 --- a/Source/Entities/MovableObject.h +++ b/Source/Entities/MovableObject.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files, forward declarations, namespace stuff @@ -24,2164 +23,2092 @@ struct BITMAP; - namespace RTE { -struct HitData; - -class MOSRotating; -class PieMenu; -class SLTerrain; -class LuaStateWrapper; - -////////////////////////////////////////////////////////////////////////////////////////// -// Abstract class: MovableObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A movable object with mass. -// Parent(s): SceneObject. -// Class history: 03/18/2001 MovableObject created. - -class MovableObject : public SceneObject { - -friend class Atom; -friend struct EntityLuaBindings; - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - ScriptFunctionNames("Create", "Destroy", "Update", "ThreadedUpdate", "SyncedUpdate", "OnScriptDisable", "OnScriptEnable", "OnCollideWithTerrain", "OnCollideWithMO", "WhilePieMenuOpen", "OnSave", "OnMessage", "OnGlobalMessage"); - SerializableOverrideMethods; - ClassInfoGetters; - -enum MOType -{ - TypeGeneric = 0, - TypeActor, - TypeHeldDevice, - TypeThrownDevice -}; - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MovableObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a MovableObject object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - MovableObject() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~MovableObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a MovableObject object before deletion -// from system memory. -// Arguments: None. - - ~MovableObject() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MovableObject object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MovableObject object ready for use. -// Arguments: A float specifying the object's mass in Kilograms (kg). -// A Vector specifying the initial position. -// A Vector specifying the initial velocity. -// The rotation angle in r. -// The angular velocity in r/s. -// The amount of time in ms this MovableObject will exist. 0 means unlim. -// Whether or not this MO will collide with other MO's while travelling. -// Whether or not this MO be collided with bt other MO's during their travel. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(float mass, const Vector &position = Vector(0, 0), const Vector &velocity = Vector(0, 0), float rotAngle = 0, float angleVel = 0, unsigned long lifetime = 0, bool hitMOs = true, bool getHitByMOs = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MovableObject to be identical to another, by deep copy. -// Arguments: A reference to the MovableObject to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const MovableObject &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire MovableObject, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); SceneObject::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MovableObject object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; + struct HitData; + + class MOSRotating; + class PieMenu; + class SLTerrain; + class LuaStateWrapper; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Abstract class: MovableObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A movable object with mass. + // Parent(s): SceneObject. + // Class history: 03/18/2001 MovableObject created. + + class MovableObject : public SceneObject { + + friend class Atom; + friend struct EntityLuaBindings; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + ScriptFunctionNames("Create", "Destroy", "Update", "ThreadedUpdate", "SyncedUpdate", "OnScriptDisable", "OnScriptEnable", "OnCollideWithTerrain", "OnCollideWithMO", "WhilePieMenuOpen", "OnSave", "OnMessage", "OnGlobalMessage"); + SerializableOverrideMethods; + ClassInfoGetters; + + enum MOType { + TypeGeneric = 0, + TypeActor, + TypeHeldDevice, + TypeThrownDevice + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MovableObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a MovableObject object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + MovableObject() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~MovableObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a MovableObject object before deletion + // from system memory. + // Arguments: None. + + ~MovableObject() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MovableObject object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MovableObject object ready for use. + // Arguments: A float specifying the object's mass in Kilograms (kg). + // A Vector specifying the initial position. + // A Vector specifying the initial velocity. + // The rotation angle in r. + // The angular velocity in r/s. + // The amount of time in ms this MovableObject will exist. 0 means unlim. + // Whether or not this MO will collide with other MO's while travelling. + // Whether or not this MO be collided with bt other MO's during their travel. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(float mass, const Vector& position = Vector(0, 0), const Vector& velocity = Vector(0, 0), float rotAngle = 0, float angleVel = 0, unsigned long lifetime = 0, bool hitMOs = true, bool getHitByMOs = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MovableObject to be identical to another, by deep copy. + // Arguments: A reference to the MovableObject to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const MovableObject& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire MovableObject, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + SceneObject::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MovableObject object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; #pragma region Script Handling - /// - /// Loads the script at the given script path onto the object, checking for appropriately named functions within it. - /// If the script contains a Create function and this MO's scripts are running, the Create function will be run immediately. - /// - /// The path to the script to load. - /// Whether or not the script should load as enabled. Defaults to true. - /// 0 on success. -1 if scriptPath is empty. -2 if the script is already loaded. -3 if setup to load the script or modify the global lua state fails. -4 if the script fails to load. - virtual int LoadScript(const std::string &scriptPath, bool loadAsEnabledScript = true); - - /// - /// Reloads the all of the scripts on this object. This will also reload scripts for the original preset in PresetMan so future objects spawned will use the new scripts. - /// - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int ReloadScripts() final; - - /// - /// Gets whether or not the object has a script name, and there were no errors when initializing its Lua scripts. If there were, the object would need to be reloaded. - /// - /// Whether or not the object's scripts have been successfully initialized. - bool ObjectScriptsInitialized() const { return !m_ScriptObjectName.empty() && m_ScriptObjectName != "ERROR"; } - - /// - /// Checks if this MO has any scripts on it. - /// - /// Whether or not this MO has any scripts on it. - bool HasAnyScripts() const { return !m_AllLoadedScripts.empty(); } - - /// - /// Checks if the script at the given path is one of the scripts on this MO. - /// - /// The path to the script to check. - /// Whether or not the script is on this MO. - bool HasScript(const std::string &scriptPath) const { return m_AllLoadedScripts.find(scriptPath) != m_AllLoadedScripts.end(); } - - /// - /// Checks if the script at the given path is one of the enabled scripts on this MO. - /// - /// The path to the script to check. - /// Whether or not the script is enabled on this MO. - bool ScriptEnabled(const std::string &scriptPath) const { auto scriptPathIterator = m_AllLoadedScripts.find(scriptPath); return scriptPathIterator != m_AllLoadedScripts.end() && scriptPathIterator->second == true; } - - /// - /// Enables or dsiableds the script at the given path on this MO. - /// - /// The path to the script to enable or disable - /// Whether to enable the script, or disable it. - /// Whether or not the script was successfully eanbled/disabled. - bool EnableOrDisableScript(const std::string &scriptPath, bool enableScript); - - /// - /// Enables or disables all scripts on this MovableObject. - /// - /// Whether to enable (true) or disable (false) all scripts on this MovableObject. - void EnableOrDisableAllScripts(bool enableScripts); - - /// - /// Runs the given function in all scripts that have it, with the given arguments, with the ability to not run on disabled scripts and to cease running if there's an error. - /// The first argument to the function will always be 'self'. If either argument list is not empty, its entries will be passed into the Lua function in order, with entity arguments first. - /// - /// The name of the function to run. - /// Whether to run the function on disabled scripts. Defaults to false. - /// Whether to stop if there's an error running any script, or simply print it to the console and continue. Defaults to false. - /// Optional vector of entity pointers that should be passed into the Lua function. Their internal Lua states will not be accessible. Defaults to empty. - /// Optional vector of strings, that should be passed into the Lua function. Entries must be surrounded with escaped quotes (i.e.`\"`) they'll be passed in as-is, allowing them to act as booleans, etc.. Defaults to empty. - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int RunScriptedFunctionInAppropriateScripts(const std::string &functionName, bool runOnDisabledScripts = false, bool stopOnError = false, const std::vector &functionEntityArguments = std::vector(), const std::vector &functionLiteralArguments = std::vector(), const std::vector &functionObjectArguments = std::vector()); - - /// - /// Cleans up and destroys the script state of this object, calling the Destroy callback in lua - /// - virtual void DestroyScriptState(); + /// + /// Loads the script at the given script path onto the object, checking for appropriately named functions within it. + /// If the script contains a Create function and this MO's scripts are running, the Create function will be run immediately. + /// + /// The path to the script to load. + /// Whether or not the script should load as enabled. Defaults to true. + /// 0 on success. -1 if scriptPath is empty. -2 if the script is already loaded. -3 if setup to load the script or modify the global lua state fails. -4 if the script fails to load. + virtual int LoadScript(const std::string& scriptPath, bool loadAsEnabledScript = true); + + /// + /// Reloads the all of the scripts on this object. This will also reload scripts for the original preset in PresetMan so future objects spawned will use the new scripts. + /// + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + int ReloadScripts() final; + + /// + /// Gets whether or not the object has a script name, and there were no errors when initializing its Lua scripts. If there were, the object would need to be reloaded. + /// + /// Whether or not the object's scripts have been successfully initialized. + bool ObjectScriptsInitialized() const { return !m_ScriptObjectName.empty() && m_ScriptObjectName != "ERROR"; } + + /// + /// Checks if this MO has any scripts on it. + /// + /// Whether or not this MO has any scripts on it. + bool HasAnyScripts() const { return !m_AllLoadedScripts.empty(); } + + /// + /// Checks if the script at the given path is one of the scripts on this MO. + /// + /// The path to the script to check. + /// Whether or not the script is on this MO. + bool HasScript(const std::string& scriptPath) const { return m_AllLoadedScripts.find(scriptPath) != m_AllLoadedScripts.end(); } + + /// + /// Checks if the script at the given path is one of the enabled scripts on this MO. + /// + /// The path to the script to check. + /// Whether or not the script is enabled on this MO. + bool ScriptEnabled(const std::string& scriptPath) const { + auto scriptPathIterator = m_AllLoadedScripts.find(scriptPath); + return scriptPathIterator != m_AllLoadedScripts.end() && scriptPathIterator->second == true; + } + + /// + /// Enables or dsiableds the script at the given path on this MO. + /// + /// The path to the script to enable or disable + /// Whether to enable the script, or disable it. + /// Whether or not the script was successfully eanbled/disabled. + bool EnableOrDisableScript(const std::string& scriptPath, bool enableScript); + + /// + /// Enables or disables all scripts on this MovableObject. + /// + /// Whether to enable (true) or disable (false) all scripts on this MovableObject. + void EnableOrDisableAllScripts(bool enableScripts); + + /// + /// Runs the given function in all scripts that have it, with the given arguments, with the ability to not run on disabled scripts and to cease running if there's an error. + /// The first argument to the function will always be 'self'. If either argument list is not empty, its entries will be passed into the Lua function in order, with entity arguments first. + /// + /// The name of the function to run. + /// Whether to run the function on disabled scripts. Defaults to false. + /// Whether to stop if there's an error running any script, or simply print it to the console and continue. Defaults to false. + /// Optional vector of entity pointers that should be passed into the Lua function. Their internal Lua states will not be accessible. Defaults to empty. + /// Optional vector of strings, that should be passed into the Lua function. Entries must be surrounded with escaped quotes (i.e.`\"`) they'll be passed in as-is, allowing them to act as booleans, etc.. Defaults to empty. + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + int RunScriptedFunctionInAppropriateScripts(const std::string& functionName, bool runOnDisabledScripts = false, bool stopOnError = false, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector(), const std::vector& functionObjectArguments = std::vector()); + + /// + /// Cleans up and destroys the script state of this object, calling the Destroy callback in lua + /// + virtual void DestroyScriptState(); #pragma endregion + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMOType + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the MO type code of this MO. Either Actor, Item, or Generic. + // Arguments: None. + // Return value: An int describing the MO Type code of this MovableObject. + + int GetMOType() const { return m_MOType; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMass + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the mass value of this MovableObject. + // Arguments: None. + // Return value: A float describing the mass value in Kilograms (kg). + + virtual float GetMass() const { return m_Mass; } + + /// + /// Gets the previous position vector of this MovableObject, prior to this frame. + /// + /// A Vector describing the previous position vector. + const Vector& GetPrevPos() const { return m_PrevPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the velocity vector of this MovableObject. + // Arguments: None. + // Return value: A Vector describing the current velocity vector. + + const Vector& GetVel() const { return m_Vel; } + + /// + /// Gets the previous velocity vector of this MovableObject, prior to this frame. + /// + /// A Vector describing the previous velocity vector. + const Vector& GetPrevVel() const { return m_PrevVel; } + + /// + /// Gets the amount of distance this MO has travelled since its creation, in pixels. + /// + /// The amount of distance this MO has travelled, in pixels. + float GetDistanceTravelled() const { return m_DistanceTravelled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAngularVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current angular velocity of this MovableObject. Positive is + // a counter-clockwise rotation. + // Arguments: None. + // Return value: The angular velocity in radians per second. + + virtual float GetAngularVel() const { return 0.0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRadius + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the largest radius of this in pixels. + // Arguments: None. + // Return value: The radius from its center to the edge of its graphical representation. + + virtual float GetRadius() const { return 1.0f; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetDiameter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the largest diameter of this in pixels. + // Arguments: None. + // Return value: The largest diameter across its graphical representation. + + virtual float GetDiameter() const { return 2.0F; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current scale of this MOSRotating. This is mostly for fun. + // Arguments: None. + // Return value: The normalized scale. + + float GetScale() const { return m_Scale; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGlobalAccScalar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets How this is affected by global effects, from +1.0 to -1.0. + // Something with a negative value will 'float' upward. + // Arguments: None. + // Return value: The global acceleration scalar. + + float GetGlobalAccScalar() const { return m_GlobalAccScalar; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetGlobalAccScalar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets How this is affected by global effects, from +1.0 to -1.0. + // Something with a negative value will 'float' upward. + // Arguments: The global acceleration scalar. + // Return value: None. + + void SetGlobalAccScalar(float newValue) { m_GlobalAccScalar = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAirResistance + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: How much this is affected by air resistance when traveling over a + // second, 0 to 1.0, with 0 as default + // Arguments: None. + // Return value: The air resistance coefficient. + + float GetAirResistance() const { return m_AirResistance; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAirResistance + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets how much this is affected by air resistance when traveling over a + // second, 0 to 1.0, with 0 as default + // Arguments: The air resistance coefficient. + // Return value: None. + + void SetAirResistance(float newValue) { m_AirResistance = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAirThreshold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: At which threshold of velocity, in m/s, the effect of AirResistance + // kicks in. + // Arguments: None. + // Return value: The air threshold speed. + + float GetAirThreshold() const { return m_AirThreshold; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAirThreshold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets at which threshold of velocity, in m/s, the effect of AirResistance + // kicks in. + // Arguments: The air threshold speed. + // Return value: None. + + void SetAirThreshold(float newValue) { m_AirThreshold = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAge + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets real time age of this MovableObject. + // Arguments: None. + // Return value: A unsigned long describing the current age in ms. + + unsigned long GetAge() const { return m_AgeTimer.GetElapsedSimTimeMS(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLifetime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the amount of time this MovableObject will exist from creation. + // Arguments: None. + // Return value: A unsigned long describing the current lifetime in ms. 0 means unlimited. + + unsigned long GetLifetime() const { return m_Lifetime; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the MOID of this MovableObject for this frame. + // Arguments: None. + // Return value: An int specifying the MOID that this MovableObject is + // assigned for the current frame only. + + MOID GetID() const { return m_MOID; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRootID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the MOID of the MovableObject which is the root MO of this MO for + // this frame. If same as what GetID returns, then this is owned by + // MovableMan. + // Arguments: None. + // Return value: An int specifying the MOID of the MO that this MovableObject + // is owned by for the current frame only. + + MOID GetRootID() const { return m_RootMOID; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMOIDFootprint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how many total (subsequent) MOID's this MO and all its children + // are taking up this frame. ie if this MO has no children, this will + // likely be 1. Note this is only valid for this frame! + // Arguments: None. + // Return value: The number of MOID indices this MO and all its children are taking up. + + int GetMOIDFootprint() const { return m_MOIDFootprint; } + + /// + /// Returns whether or not this MovableObject has ever been added to MovableMan. Does not account for removal from MovableMan. + /// + /// Whether or not this MovableObject has ever been added to MovableMan. + bool HasEverBeenAddedToMovableMan() const { return m_HasEverBeenAddedToMovableMan; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetSharpness + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the sharpness factor of this MO. + // Arguments: None. + // Return value: The sharpness factor of this MO. 1.0 means normal sharpness, no alter- + // ation to any of the impulses. + + float GetSharpness() const { return m_Sharpness; } + + /// + /// Placeholder method to allow for ease of use with Attachables. Returns nullptr for classes that aren't derived from Attachable. + /// + /// Nothing. + virtual MOSRotating* GetParent() { return nullptr; } + + /// + /// Placeholder method to allow for ease of use with Attachables. Returns nullptr for classes that aren't derived from Attachable. + /// + /// Nothing. + virtual const MOSRotating* GetParent() const { return nullptr; } + + /// + /// Returns a pointer to this MO, this is to enable Attachables to get their root nodes. + /// + /// A pointer to this MovableObject. + virtual MovableObject* GetRootParent() { return this; } + + /// + /// Returns a pointer to this MO, this is to enable Attachables to get their root nodes. + /// + /// A pointer to this MovableObject. + virtual const MovableObject* GetRootParent() const { return this; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the altitide of this' pos (or appropriate low point) over the + // terrain, in pixels. + // Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. + // The accuracy within which measurement is acceptable. Higher number + // here means less calculation. + // Return value: The rough altitude over the terrain, in pixels. + + virtual float GetAltitude(int max = 0, int accuracy = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetAboveHUDPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absoltue position of the top of this' HUD stack. + // Arguments: None. + // Return value: A Vector with the absolute position of this' HUD stack top point. + + virtual Vector GetAboveHUDPos() const { return m_Pos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IntersectionWarning + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this may have started to intersect the terrain since the + // last frame, e g due to flipping. + // Arguments: None. + // Return value: Whether this may have started to intersect the terrain since last frame. + + bool IntersectionWarning() const { return m_CheckTerrIntersection; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HitsMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets whether this MovableObject is set to collide with other + // MovableObject:s during its travel. + // Arguments: None. + // Return value: Whether this hits other MO's during its travel, or not. + + bool HitsMOs() const { return m_HitsMOs; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetsHitByMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets whether this MovableObject is set to be able to get hit by other + // MovableObject:s during their travel. + // Arguments: None. + // Return value: Whether this can get hit by MO's, or not. + + bool GetsHitByMOs() const { return m_GetsHitByMOs; } + + /// + /// Sets the team of this MovableObject. + /// + /// The new team to assign. + void SetTeam(int team) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetIgnoresTeamHits + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this will collide with any other MO of the same team. + // Arguments: Whether this can hit or get hit by other MOs of the same team. + // Return value: None. + + void SetIgnoresTeamHits(bool ignoreTeam = true) { m_IgnoresTeamHits = ignoreTeam; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IgnoresTeamHits + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this will collide with any other MO of the same team. + // Arguments: None. + // Return value: Whether this can hit or get hit by other MOs of the same team. + + bool IgnoresTeamHits() const { return m_IgnoresTeamHits; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IgnoresWhichTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells which team this would be ignoring hits with, if we're ignoring + // hits at all. + // Arguments: None. + // Return value: Which team this ignores hits with, if any. + + int IgnoresWhichTeam() const { return m_IgnoresTeamHits ? m_Team : Activity::NoTeam; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetIgnoresAtomGroupHits + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this will collide with any other MO that uses an + // AtomGroup as a physical representation. This also overrides the + // IgnoresAGHitsWhenSlowerThan property. + // Arguments: Whether this can hit or get hit by other MOs which use AGs. + // Return value: None. + + void SetIgnoresAtomGroupHits(bool ignoreAG = true) { + m_IgnoresAtomGroupHits = ignoreAG; + if (ignoreAG) + m_IgnoresAGHitsWhenSlowerThan = -1; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IgnoresAtomGroupHits + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this will collide with any MO that uses an AtomGroup + // as physical representation. (as opposed to single-atom ones) + // Arguments: None. + // Return value: Whether this can hit or get hit by other MOs that use AGs. + + bool IgnoresAtomGroupHits() const { return m_IgnoresAtomGroupHits; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IgnoreTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this will collide with any Terrain + // Arguments: None. + // Return value: Whether this can hit terrain. + + bool IgnoreTerrain() const { return m_IgnoreTerrain; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetIgnoreTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this will collide with any Terrain + // Arguments: Whether this can hit terrain. + // Return value: None. + + void SetIgnoreTerrain(bool ignores) { m_IgnoreTerrain = ignores; } + + /// + /// Gets whether this MO ignores collisions with actors. + /// + /// Whether this MO ignores collisions with actors. + bool GetIgnoresActorHits() const { return m_IgnoresActorHits; } + + /// + /// Sets whether this MO ignores collisions with actors. + /// + /// Whether this MO will ignore collisions with actors. + void SetIgnoresActorHits(bool value) { m_IgnoresActorHits = value; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: GetMaterial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the main material of this MovableObject. + // Arguments: None. + // Return value: The the material of this MovableObject. + + virtual Material const* GetMaterial() const = 0; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: GetDrawPriority + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the drawing priority of this MovableObject, if two things were + // overlap when copying to the terrain, the higher priority MO would + // end up getting drawn. + // Arguments: None. + // Return value: The the priority of this MovableObject. Higher number, the higher + // priority. + + virtual int GetDrawPriority() const = 0; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetScreenEffect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the screen effect this has loaded, which can be applied to post + // rendering. Ownership is NOT transferred! + // Arguments: None. + // Return value: The 32bpp screen effect BITMAP. Ownership is NOT transferred! + + BITMAP* GetScreenEffect() const { return m_pScreenEffect; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetScreenEffectHash + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the hash of the path of this object's screen effect file. Used to + // transfer glow effects over network. The hash itself is calculated during + // load. + // Arguments: None. + // Return value: This effect's unique hash. + + size_t GetScreenEffectHash() const { return m_ScreenEffectHash; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetMass + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the mass of this MovableObject. + // Arguments: A float specifying the new mass value in Kilograms (kg). + // Return value: None. + + virtual void SetMass(const float newMass) { m_Mass = newMass; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPrevPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the position at the start of the sim update. + // Arguments: A Vector specifying the new 'prev' pos. + // Return value: None. + + void SetPrevPos(const Vector& newPrevPos) { m_PrevPos = newPrevPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the velocity vector of this MovableObject. + // Arguments: A Vector specifying the new velocity vector. + // Return value: None. + + void SetVel(const Vector& newVel) { m_Vel = newVel; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetRotAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current absolute angle of rotation of this MovableObject. + // Arguments: The new absolute angle in radians. + // Return value: None. + + void SetRotAngle(float newAngle) override {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetEffectRotAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current absolute angle of rotation of this MovableObject's effect. + // Arguments: The new absolute angle in radians. + // Return value: None. + + void SetEffectRotAngle(float newAngle) { m_EffectRotAngle = newAngle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetEffectRotAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current absolute angle of rotation of this MovableObject's effect. + // Arguments: None. + // Return value: The absolute angle in radians. + + float GetEffectRotAngle() const { return m_EffectRotAngle; } + + /// + /// Gets the starting strength of this MovableObject's effect. + /// + /// The starting strength of the effect, 0-255. + int GetEffectStartStrength() const { return m_EffectStartStrength; } + + /// + /// Gets the stopping strength of this MovableObject's effect. + /// + /// The stopping strength of the effect, 0-255. + int GetEffectStopStrength() const { return m_EffectStopStrength; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetAngularVel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current angular velocity of this MovableObject. Positive is + // a counter clockwise rotation. + // Arguments: The new angular velocity in radians per second. + // Return value: None. + + virtual void SetAngularVel(float newRotVel) {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current scale of this MOSRotating. This is mostly for fun. + // Arguments: The new normalized scale. + // Return value: None. + + void SetScale(float newScale) { m_Scale = newScale; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLifetime + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the amount of time this MovableObject will exist. + // Arguments: A unsigned long specifying amount of time in ms. 0 means unlimited life. + // Return value: None. + + void SetLifetime(const int newLifetime = 0) { m_Lifetime = newLifetime; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAge + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this' age timer to a specific value, in ms. + // Arguments: The new age of this, in MS. + // Return value: None. + + void SetAge(double newAge = 0) { m_AgeTimer.SetElapsedSimTimeMS(newAge); } + + /// + /// Sets the MOID of this MovableObject to be g_NoMOID (255) for this frame. + /// + virtual void SetAsNoID() { m_MOID = g_NoMOID; } + + /// + /// Sets this MovableObject as having been added to MovableMan. Should only really be done in MovableMan::Add/Remove Actor/Item/Particle. + /// + /// Whether or not this MovableObject has been added to MovableMan. + void SetAsAddedToMovableMan(bool addedToMovableMan = true) { + if (addedToMovableMan) { + m_HasEverBeenAddedToMovableMan = true; + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetSharpness + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the sharpness factor of this MO. + // Arguments: The sharpness factor of this MO. 1.0 means normal sharpness, no alter- + // ation to any of the impulses. + // Return value: None. + + void SetSharpness(const float sharpness) { m_Sharpness = sharpness; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetToHitMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this MovableObject to collide with other MovableObjects during + // travel. + // Arguments: Whether to hit other MO's during travel, or not. + // Return value: None. + + void SetToHitMOs(bool hitMOs = true) { m_HitsMOs = hitMOs; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetToGetHitByMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this MovableObject to be able to be collided with by other + // MovableObjects during their travel. + // Arguments: Whether this should get hit by other MO's during travel, or not. + // Return value: None. + + void SetToGetHitByMOs(bool getHitByMOs = true) { m_GetsHitByMOs = getHitByMOs; } + + /// + /// Gets the MO this MO is set not to hit even when MO hitting is enabled on this MO. + /// + /// The MO this MO is set not to hit. + const MovableObject* GetWhichMOToNotHit() const { return m_pMOToNotHit; } + + /// + /// Sets this MO to not hit a specific other MO and all its children even when MO hitting is enabled on this MO. + /// + /// A pointer to the MO to not be hitting. Null pointer means don't ignore anyhting. Ownership is NOT transferred! + /// How long, in seconds, to ignore the specified MO. A negative number means forever. + virtual void SetWhichMOToNotHit(MovableObject* moToNotHit = nullptr, float forHowLong = -1) { + m_pMOToNotHit = moToNotHit; + m_MOIgnoreTimer.Reset(); + m_MOIgnoreTimer.SetSimTimeLimitS(forHowLong); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetWrapDoubleDrawing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Enables or disables double drawing of this across wrapping seams. + // Arguments: Wheter to enable or not. + // Return value: None. + + void SetWrapDoubleDrawing(bool wrapDraw = true) { m_WrapDoubleDraw = wrapDraw; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetToSettle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Marks this MovableObject for settling onto the terrain at the end of + // the MovableMan update. + // Arguments: Whether to mark this MO for settling or not. + // Return value: None. + + void SetToSettle(bool toSettle = true) { m_ToSettle = toSettle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetToDelete + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Marks this MovableObject for deletion at the end of the MovableMan + // update. + // Arguments: Whether to mark this MO for deletion or not. + // Return value: None. + + void SetToDelete(bool toDelete = true) { m_ToDelete = toDelete; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsSetToDelete + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells if this MovableObject is marked for deletion at the end of the + // update. + // Arguments: None. + // Return value: Whether this is marked for deletion or not. + + bool IsSetToDelete() const { return m_ToDelete; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsMissionCritical + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is mission critical and should therefore NEVER be + // settled or otherwise destroyed during teh course of a mission. + // Arguments: None. + // Return value: Whetehr this should be immune to settling and destruction. + + bool IsMissionCritical() const { return m_MissionCritical; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMissionCritical + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this is mission critical and should therefore NEVER be + // settled or otherwise destroyed during teh course of a mission. + // Arguments: Whether this should be immune to settling and destruction. + // Return value: None. + + void SetMissionCritical(bool missionCritical) { m_MissionCritical = missionCritical; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CanBeSquished + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this can be squished by getting pushed into the ground. + // Arguments: None. + // Return value: Whetehr this should be immune to squishing or not. + + bool CanBeSquished() const { return m_CanBeSquished; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetHUDVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this Actor's HUD is drawn or not. + // Arguments: None. + // Return value: Whether this' HUD gets drawn or not. + + void SetHUDVisible(bool visible) { m_HUDVisible = visible; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetHUDVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this Actor's HUD is drawn or not. + // Arguments: None. + // Return value: Whether this' HUD gets drawn or not. + + bool GetHUDVisible() const { return m_HUDVisible; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsTooFast + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is moving or rotating stupidly fast in a way + // that will screw up the simulation. + // Arguments: None. + // Return value: Whether this is either moving or rotating too fast. + + virtual bool IsTooFast() const { return m_Vel.MagnitudeIsGreaterThan(500.0F); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: FixTooFast + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Slows the speed of anyhting that is deemed to be too fast to within + // acceptable rates. + // Arguments: None. + // Return value: None. + + virtual void FixTooFast() { + if (IsTooFast()) { + m_Vel.SetMagnitude(450.0F); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsGeneric + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is an Generic or not. + // Arguments: None. + // Return value: Whether this MovableObject is of Type Generic or not. + + bool IsGeneric() const { return m_MOType == TypeGeneric; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is an Actor or not. + // Arguments: None. + // Return value: Whether this MovableObject is of Type Actor or not. + + bool IsActor() const { return m_MOType == TypeActor; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is a Device or not. + // Arguments: None. + // Return value: Whether this MovableObject is of Type Device (Held or Thrown) or not. + + bool IsDevice() const { return m_MOType == TypeHeldDevice || m_MOType == TypeThrownDevice; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsHeldDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is a HeldDevice or not. + // Arguments: None. + // Return value: Whether this MovableObject is of Type HeldDevice or not. + + // LEGACY CRAP + bool IsHeldDevice() const { return m_MOType == TypeHeldDevice || m_MOType == TypeThrownDevice; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsThrownDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is a ThrownDevice or not. + // Arguments: None. + // Return value: Whether this MovableObject is of Type ThrownDevice or not. + + bool IsThrownDevice() const { return m_MOType == TypeThrownDevice; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsGold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is made of Gold or not. + // Arguments: None. + // Return value: Whether this MovableObject is of Gold or not. + + bool IsGold() const { return m_MOType == TypeGeneric && GetMaterial()->GetIndex() == c_GoldMaterialID; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDrawnAfterParent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MovableObject is to be drawn after + // (in front of) or before (behind) the parent. + // Arguments: None. + // Return value: Whether it's to be drawn after parent or not. + + virtual bool IsDrawnAfterParent() const { return true; } + + /// + /// Whether a set of X, Y coordinates overlap us (in world space). + /// + /// The given X coordinate, in world space. + /// The given Y coordinate, in world space. + /// Whether the given coordinate overlap us. + virtual bool HitTestAtPixel(int pixelX, int pixelY) const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically named object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The Preset name of the object to look for. + // Return value: Whetehr the object was found carried by this. + + virtual bool HasObject(std::string objectName) const { return m_PresetName == objectName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasObjectInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is or carries a specifically grouped object in its + // inventory. Also looks through the inventories of potential passengers, + // as applicable. + // Arguments: The name of the group to look for. + // Return value: Whetehr the object in the group was found carried by this. + + virtual bool HasObjectInGroup(std::string groupName) const { return const_cast(this)->IsInGroup(groupName); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds force to this MovableObject for the next time Update() is called. + // Arguments: An Vector with the external force vector that will be added to this + // MovableObject and affect its path next Update(). In N or kg * m/s^2. + // A Vector with the offset, in METERS, of where the force is being + // applied relative to the center of this MovableObject. + // Return value: None.A + + void AddForce(const Vector& force, const Vector& offset = Vector()) { m_Forces.push_back(std::make_pair(force, offset)); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddAbsForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds force to this MovableObject for the next time Update() is called. + // Arguments: An Vector with the external force vector that will be added to this + // MovableObject and affect its path next Update(). In N or kg * m/s^2. + // A Vector with the absolute world coordinates, in PIXELS, of where the + // force is being applied to the center of this MovableObject. + // Return value: None. + + void AddAbsForce(const Vector& force, const Vector& absPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddImpulseForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds impulse force (or instant momentum) to this MovableObject for + // the next time Update() is called. + // Arguments: An Vector with the impulse force vector that will directly be added + // to this MovableObject's momentum next Update(). In kg * m/s. + // A Vector with the offset, in METERS, of where the impulse is being + // applied relative to the center of this MovableObject. + // Return value: None. + + void AddImpulseForce(const Vector& impulse, const Vector& offset = Vector()) { -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMOType -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the MO type code of this MO. Either Actor, Item, or Generic. -// Arguments: None. -// Return value: An int describing the MO Type code of this MovableObject. - - int GetMOType() const { return m_MOType; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMass -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the mass value of this MovableObject. -// Arguments: None. -// Return value: A float describing the mass value in Kilograms (kg). - - virtual float GetMass() const { return m_Mass; } - - - /// - /// Gets the previous position vector of this MovableObject, prior to this frame. - /// - /// A Vector describing the previous position vector. - const Vector & GetPrevPos() const { return m_PrevPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the velocity vector of this MovableObject. -// Arguments: None. -// Return value: A Vector describing the current velocity vector. - - const Vector & GetVel() const { return m_Vel; } - - - /// - /// Gets the previous velocity vector of this MovableObject, prior to this frame. - /// - /// A Vector describing the previous velocity vector. - const Vector & GetPrevVel() const { return m_PrevVel; } - - /// - /// Gets the amount of distance this MO has travelled since its creation, in pixels. - /// - /// The amount of distance this MO has travelled, in pixels. - float GetDistanceTravelled() const { return m_DistanceTravelled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAngularVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current angular velocity of this MovableObject. Positive is -// a counter-clockwise rotation. -// Arguments: None. -// Return value: The angular velocity in radians per second. - - virtual float GetAngularVel() const { return 0.0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRadius -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the largest radius of this in pixels. -// Arguments: None. -// Return value: The radius from its center to the edge of its graphical representation. - - virtual float GetRadius() const { return 1.0f; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetDiameter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the largest diameter of this in pixels. -// Arguments: None. -// Return value: The largest diameter across its graphical representation. - - virtual float GetDiameter() const { return 2.0F; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetScale -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current scale of this MOSRotating. This is mostly for fun. -// Arguments: None. -// Return value: The normalized scale. - - float GetScale() const { return m_Scale; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGlobalAccScalar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets How this is affected by global effects, from +1.0 to -1.0. -// Something with a negative value will 'float' upward. -// Arguments: None. -// Return value: The global acceleration scalar. - - float GetGlobalAccScalar() const { return m_GlobalAccScalar; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetGlobalAccScalar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets How this is affected by global effects, from +1.0 to -1.0. -// Something with a negative value will 'float' upward. -// Arguments: The global acceleration scalar. -// Return value: None. - - void SetGlobalAccScalar(float newValue) { m_GlobalAccScalar = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAirResistance -////////////////////////////////////////////////////////////////////////////////////////// -// Description: How much this is affected by air resistance when traveling over a -// second, 0 to 1.0, with 0 as default -// Arguments: None. -// Return value: The air resistance coefficient. - - float GetAirResistance() const { return m_AirResistance; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAirResistance -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets how much this is affected by air resistance when traveling over a -// second, 0 to 1.0, with 0 as default -// Arguments: The air resistance coefficient. -// Return value: None. - - void SetAirResistance(float newValue) { m_AirResistance = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAirThreshold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: At which threshold of velocity, in m/s, the effect of AirResistance -// kicks in. -// Arguments: None. -// Return value: The air threshold speed. - - float GetAirThreshold() const { return m_AirThreshold; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAirThreshold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets at which threshold of velocity, in m/s, the effect of AirResistance -// kicks in. -// Arguments: The air threshold speed. -// Return value: None. - - void SetAirThreshold(float newValue) { m_AirThreshold = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAge -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets real time age of this MovableObject. -// Arguments: None. -// Return value: A unsigned long describing the current age in ms. - - unsigned long GetAge() const { return m_AgeTimer.GetElapsedSimTimeMS(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLifetime -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the amount of time this MovableObject will exist from creation. -// Arguments: None. -// Return value: A unsigned long describing the current lifetime in ms. 0 means unlimited. - - unsigned long GetLifetime() const { return m_Lifetime; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the MOID of this MovableObject for this frame. -// Arguments: None. -// Return value: An int specifying the MOID that this MovableObject is -// assigned for the current frame only. - - MOID GetID() const { return m_MOID; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRootID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the MOID of the MovableObject which is the root MO of this MO for -// this frame. If same as what GetID returns, then this is owned by -// MovableMan. -// Arguments: None. -// Return value: An int specifying the MOID of the MO that this MovableObject -// is owned by for the current frame only. - - MOID GetRootID() const { return m_RootMOID; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMOIDFootprint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how many total (subsequent) MOID's this MO and all its children -// are taking up this frame. ie if this MO has no children, this will -// likely be 1. Note this is only valid for this frame! -// Arguments: None. -// Return value: The number of MOID indices this MO and all its children are taking up. - - int GetMOIDFootprint() const { return m_MOIDFootprint; } - - /// - /// Returns whether or not this MovableObject has ever been added to MovableMan. Does not account for removal from MovableMan. - /// - /// Whether or not this MovableObject has ever been added to MovableMan. - bool HasEverBeenAddedToMovableMan() const { return m_HasEverBeenAddedToMovableMan; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetSharpness -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the sharpness factor of this MO. -// Arguments: None. -// Return value: The sharpness factor of this MO. 1.0 means normal sharpness, no alter- -// ation to any of the impulses. - - float GetSharpness() const { return m_Sharpness; } - - - /// - /// Placeholder method to allow for ease of use with Attachables. Returns nullptr for classes that aren't derived from Attachable. - /// - /// Nothing. - virtual MOSRotating * GetParent() { return nullptr; } - - /// - /// Placeholder method to allow for ease of use with Attachables. Returns nullptr for classes that aren't derived from Attachable. - /// - /// Nothing. - virtual const MOSRotating * GetParent() const { return nullptr; } - - /// - /// Returns a pointer to this MO, this is to enable Attachables to get their root nodes. - /// - /// A pointer to this MovableObject. - virtual MovableObject * GetRootParent() { return this; } - - /// - /// Returns a pointer to this MO, this is to enable Attachables to get their root nodes. - /// - /// A pointer to this MovableObject. - virtual const MovableObject * GetRootParent() const { return this; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the altitide of this' pos (or appropriate low point) over the -// terrain, in pixels. -// Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. -// The accuracy within which measurement is acceptable. Higher number -// here means less calculation. -// Return value: The rough altitude over the terrain, in pixels. - - virtual float GetAltitude(int max = 0, int accuracy = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetAboveHUDPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absoltue position of the top of this' HUD stack. -// Arguments: None. -// Return value: A Vector with the absolute position of this' HUD stack top point. - - virtual Vector GetAboveHUDPos() const { return m_Pos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IntersectionWarning -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this may have started to intersect the terrain since the -// last frame, e g due to flipping. -// Arguments: None. -// Return value: Whether this may have started to intersect the terrain since last frame. - - bool IntersectionWarning() const { return m_CheckTerrIntersection; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HitsMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets whether this MovableObject is set to collide with other -// MovableObject:s during its travel. -// Arguments: None. -// Return value: Whether this hits other MO's during its travel, or not. - - bool HitsMOs() const { return m_HitsMOs; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetsHitByMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets whether this MovableObject is set to be able to get hit by other -// MovableObject:s during their travel. -// Arguments: None. -// Return value: Whether this can get hit by MO's, or not. - - bool GetsHitByMOs() const { return m_GetsHitByMOs; } - - /// - /// Sets the team of this MovableObject. - /// - /// The new team to assign. - void SetTeam(int team) override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetIgnoresTeamHits -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this will collide with any other MO of the same team. -// Arguments: Whether this can hit or get hit by other MOs of the same team. -// Return value: None. - - void SetIgnoresTeamHits(bool ignoreTeam = true) { m_IgnoresTeamHits = ignoreTeam; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IgnoresTeamHits -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this will collide with any other MO of the same team. -// Arguments: None. -// Return value: Whether this can hit or get hit by other MOs of the same team. - - bool IgnoresTeamHits() const { return m_IgnoresTeamHits; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IgnoresWhichTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells which team this would be ignoring hits with, if we're ignoring -// hits at all. -// Arguments: None. -// Return value: Which team this ignores hits with, if any. - - int IgnoresWhichTeam() const { return m_IgnoresTeamHits ? m_Team : Activity::NoTeam; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetIgnoresAtomGroupHits -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this will collide with any other MO that uses an -// AtomGroup as a physical representation. This also overrides the -// IgnoresAGHitsWhenSlowerThan property. -// Arguments: Whether this can hit or get hit by other MOs which use AGs. -// Return value: None. - - void SetIgnoresAtomGroupHits(bool ignoreAG = true) { m_IgnoresAtomGroupHits = ignoreAG; if (ignoreAG) m_IgnoresAGHitsWhenSlowerThan = -1; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IgnoresAtomGroupHits -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this will collide with any MO that uses an AtomGroup -// as physical representation. (as opposed to single-atom ones) -// Arguments: None. -// Return value: Whether this can hit or get hit by other MOs that use AGs. - - bool IgnoresAtomGroupHits() const { return m_IgnoresAtomGroupHits; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IgnoreTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this will collide with any Terrain -// Arguments: None. -// Return value: Whether this can hit terrain. - - bool IgnoreTerrain() const { return m_IgnoreTerrain; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetIgnoreTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this will collide with any Terrain -// Arguments: Whether this can hit terrain. -// Return value: None. - - void SetIgnoreTerrain(bool ignores) { m_IgnoreTerrain = ignores; } - - /// - /// Gets whether this MO ignores collisions with actors. - /// - /// Whether this MO ignores collisions with actors. - bool GetIgnoresActorHits() const { return m_IgnoresActorHits; } - - /// - /// Sets whether this MO ignores collisions with actors. - /// - /// Whether this MO will ignore collisions with actors. - void SetIgnoresActorHits(bool value) { m_IgnoresActorHits = value; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: GetMaterial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the main material of this MovableObject. -// Arguments: None. -// Return value: The the material of this MovableObject. - - virtual Material const * GetMaterial() const = 0; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: GetDrawPriority -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the drawing priority of this MovableObject, if two things were -// overlap when copying to the terrain, the higher priority MO would -// end up getting drawn. -// Arguments: None. -// Return value: The the priority of this MovableObject. Higher number, the higher -// priority. - - virtual int GetDrawPriority() const = 0; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetScreenEffect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the screen effect this has loaded, which can be applied to post -// rendering. Ownership is NOT transferred! -// Arguments: None. -// Return value: The 32bpp screen effect BITMAP. Ownership is NOT transferred! - - BITMAP * GetScreenEffect() const { return m_pScreenEffect; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetScreenEffectHash -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the hash of the path of this object's screen effect file. Used to -// transfer glow effects over network. The hash itself is calculated during -// load. -// Arguments: None. -// Return value: This effect's unique hash. - - size_t GetScreenEffectHash() const { return m_ScreenEffectHash; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetMass -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the mass of this MovableObject. -// Arguments: A float specifying the new mass value in Kilograms (kg). -// Return value: None. - - virtual void SetMass(const float newMass) { m_Mass = newMass; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPrevPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the position at the start of the sim update. -// Arguments: A Vector specifying the new 'prev' pos. -// Return value: None. - - void SetPrevPos(const Vector &newPrevPos) {m_PrevPos = newPrevPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the velocity vector of this MovableObject. -// Arguments: A Vector specifying the new velocity vector. -// Return value: None. - - void SetVel(const Vector &newVel) {m_Vel = newVel; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetRotAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current absolute angle of rotation of this MovableObject. -// Arguments: The new absolute angle in radians. -// Return value: None. - - void SetRotAngle(float newAngle) override {} +#ifndef RELEASE_BUILD + RTEAssert(impulse.MagnitudeIsLessThan(500000.0F), "HUEG IMPULSE FORCE"); + RTEAssert(offset.MagnitudeIsLessThan(5000.0F), "HUGE IMPULSE FORCE OFFSET"); +#endif -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetEffectRotAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current absolute angle of rotation of this MovableObject's effect. -// Arguments: The new absolute angle in radians. -// Return value: None. - - void SetEffectRotAngle(float newAngle) { m_EffectRotAngle = newAngle; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetEffectRotAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current absolute angle of rotation of this MovableObject's effect. -// Arguments: None. -// Return value: The absolute angle in radians. - - float GetEffectRotAngle() const { return m_EffectRotAngle; } - - /// - /// Gets the starting strength of this MovableObject's effect. - /// - /// The starting strength of the effect, 0-255. - int GetEffectStartStrength() const { return m_EffectStartStrength; } - - /// - /// Gets the stopping strength of this MovableObject's effect. - /// - /// The stopping strength of the effect, 0-255. - int GetEffectStopStrength() const { return m_EffectStopStrength; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetAngularVel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current angular velocity of this MovableObject. Positive is -// a counter clockwise rotation. -// Arguments: The new angular velocity in radians per second. -// Return value: None. - - virtual void SetAngularVel(float newRotVel) {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetScale -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current scale of this MOSRotating. This is mostly for fun. -// Arguments: The new normalized scale. -// Return value: None. - - void SetScale(float newScale) { m_Scale = newScale; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLifetime -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the amount of time this MovableObject will exist. -// Arguments: A unsigned long specifying amount of time in ms. 0 means unlimited life. -// Return value: None. - - void SetLifetime(const int newLifetime = 0) { m_Lifetime = newLifetime; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAge -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this' age timer to a specific value, in ms. -// Arguments: The new age of this, in MS. -// Return value: None. - - void SetAge(double newAge = 0) { m_AgeTimer.SetElapsedSimTimeMS(newAge); } - - - /// - /// Sets the MOID of this MovableObject to be g_NoMOID (255) for this frame. - /// - virtual void SetAsNoID() { m_MOID = g_NoMOID; } - - /// - /// Sets this MovableObject as having been added to MovableMan. Should only really be done in MovableMan::Add/Remove Actor/Item/Particle. - /// - /// Whether or not this MovableObject has been added to MovableMan. - void SetAsAddedToMovableMan(bool addedToMovableMan = true) { if (addedToMovableMan) { m_HasEverBeenAddedToMovableMan = true; } } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetSharpness -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the sharpness factor of this MO. -// Arguments: The sharpness factor of this MO. 1.0 means normal sharpness, no alter- -// ation to any of the impulses. -// Return value: None. - - void SetSharpness(const float sharpness) { m_Sharpness = sharpness; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetToHitMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this MovableObject to collide with other MovableObjects during -// travel. -// Arguments: Whether to hit other MO's during travel, or not. -// Return value: None. - - void SetToHitMOs(bool hitMOs = true) { m_HitsMOs = hitMOs; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetToGetHitByMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this MovableObject to be able to be collided with by other -// MovableObjects during their travel. -// Arguments: Whether this should get hit by other MO's during travel, or not. -// Return value: None. - - void SetToGetHitByMOs(bool getHitByMOs = true) { m_GetsHitByMOs = getHitByMOs; } - - - /// - /// Gets the MO this MO is set not to hit even when MO hitting is enabled on this MO. - /// - /// The MO this MO is set not to hit. - const MovableObject * GetWhichMOToNotHit() const { return m_pMOToNotHit; } - - /// - /// Sets this MO to not hit a specific other MO and all its children even when MO hitting is enabled on this MO. - /// - /// A pointer to the MO to not be hitting. Null pointer means don't ignore anyhting. Ownership is NOT transferred! - /// How long, in seconds, to ignore the specified MO. A negative number means forever. - virtual void SetWhichMOToNotHit(MovableObject *moToNotHit = nullptr, float forHowLong = -1) { m_pMOToNotHit = moToNotHit; m_MOIgnoreTimer.Reset(); m_MOIgnoreTimer.SetSimTimeLimitS(forHowLong); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetWrapDoubleDrawing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Enables or disables double drawing of this across wrapping seams. -// Arguments: Wheter to enable or not. -// Return value: None. - - void SetWrapDoubleDrawing(bool wrapDraw = true) { m_WrapDoubleDraw = wrapDraw; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetToSettle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Marks this MovableObject for settling onto the terrain at the end of -// the MovableMan update. -// Arguments: Whether to mark this MO for settling or not. -// Return value: None. - - void SetToSettle(bool toSettle = true) { m_ToSettle = toSettle; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetToDelete -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Marks this MovableObject for deletion at the end of the MovableMan -// update. -// Arguments: Whether to mark this MO for deletion or not. -// Return value: None. - - void SetToDelete(bool toDelete = true) { m_ToDelete = toDelete; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsSetToDelete -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells if this MovableObject is marked for deletion at the end of the -// update. -// Arguments: None. -// Return value: Whether this is marked for deletion or not. - - bool IsSetToDelete() const { return m_ToDelete; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsMissionCritical -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is mission critical and should therefore NEVER be -// settled or otherwise destroyed during teh course of a mission. -// Arguments: None. -// Return value: Whetehr this should be immune to settling and destruction. - - bool IsMissionCritical() const { return m_MissionCritical; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMissionCritical -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this is mission critical and should therefore NEVER be -// settled or otherwise destroyed during teh course of a mission. -// Arguments: Whether this should be immune to settling and destruction. -// Return value: None. - - void SetMissionCritical(bool missionCritical) { m_MissionCritical = missionCritical; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CanBeSquished -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this can be squished by getting pushed into the ground. -// Arguments: None. -// Return value: Whetehr this should be immune to squishing or not. - - bool CanBeSquished() const { return m_CanBeSquished; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetHUDVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this Actor's HUD is drawn or not. -// Arguments: None. -// Return value: Whether this' HUD gets drawn or not. - - void SetHUDVisible(bool visible) { m_HUDVisible = visible; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetHUDVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this Actor's HUD is drawn or not. -// Arguments: None. -// Return value: Whether this' HUD gets drawn or not. - - bool GetHUDVisible() const { return m_HUDVisible; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsTooFast -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is moving or rotating stupidly fast in a way -// that will screw up the simulation. -// Arguments: None. -// Return value: Whether this is either moving or rotating too fast. - - virtual bool IsTooFast() const { return m_Vel.MagnitudeIsGreaterThan(500.0F); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: FixTooFast -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Slows the speed of anyhting that is deemed to be too fast to within -// acceptable rates. -// Arguments: None. -// Return value: None. - - virtual void FixTooFast() { if (IsTooFast()) { m_Vel.SetMagnitude(450.0F); } } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsGeneric -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is an Generic or not. -// Arguments: None. -// Return value: Whether this MovableObject is of Type Generic or not. - - bool IsGeneric() const { return m_MOType == TypeGeneric; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is an Actor or not. -// Arguments: None. -// Return value: Whether this MovableObject is of Type Actor or not. - - bool IsActor() const { return m_MOType == TypeActor; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is a Device or not. -// Arguments: None. -// Return value: Whether this MovableObject is of Type Device (Held or Thrown) or not. - - bool IsDevice() const { return m_MOType == TypeHeldDevice || m_MOType == TypeThrownDevice; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsHeldDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is a HeldDevice or not. -// Arguments: None. -// Return value: Whether this MovableObject is of Type HeldDevice or not. - -// LEGACY CRAP - bool IsHeldDevice() const { return m_MOType == TypeHeldDevice || m_MOType == TypeThrownDevice; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsThrownDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is a ThrownDevice or not. -// Arguments: None. -// Return value: Whether this MovableObject is of Type ThrownDevice or not. - - bool IsThrownDevice() const { return m_MOType == TypeThrownDevice; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsGold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is made of Gold or not. -// Arguments: None. -// Return value: Whether this MovableObject is of Gold or not. - - bool IsGold() const { return m_MOType == TypeGeneric && GetMaterial()->GetIndex() == c_GoldMaterialID; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDrawnAfterParent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MovableObject is to be drawn after -// (in front of) or before (behind) the parent. -// Arguments: None. -// Return value: Whether it's to be drawn after parent or not. - - virtual bool IsDrawnAfterParent() const { return true; } - - /// - /// Whether a set of X, Y coordinates overlap us (in world space). - /// - /// The given X coordinate, in world space. - /// The given Y coordinate, in world space. - /// Whether the given coordinate overlap us. - virtual bool HitTestAtPixel(int pixelX, int pixelY) const { return false; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically named object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The Preset name of the object to look for. -// Return value: Whetehr the object was found carried by this. - - virtual bool HasObject(std::string objectName) const { return m_PresetName == objectName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasObjectInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is or carries a specifically grouped object in its -// inventory. Also looks through the inventories of potential passengers, -// as applicable. -// Arguments: The name of the group to look for. -// Return value: Whetehr the object in the group was found carried by this. - - virtual bool HasObjectInGroup(std::string groupName) const { return const_cast(this)->IsInGroup(groupName); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds force to this MovableObject for the next time Update() is called. -// Arguments: An Vector with the external force vector that will be added to this -// MovableObject and affect its path next Update(). In N or kg * m/s^2. -// A Vector with the offset, in METERS, of where the force is being -// applied relative to the center of this MovableObject. -// Return value: None.A - - void AddForce(const Vector &force, const Vector &offset = Vector()) - { m_Forces.push_back(std::make_pair(force, offset)); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddAbsForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds force to this MovableObject for the next time Update() is called. -// Arguments: An Vector with the external force vector that will be added to this -// MovableObject and affect its path next Update(). In N or kg * m/s^2. -// A Vector with the absolute world coordinates, in PIXELS, of where the -// force is being applied to the center of this MovableObject. -// Return value: None. - - void AddAbsForce(const Vector &force, const Vector &absPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddImpulseForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds impulse force (or instant momentum) to this MovableObject for -// the next time Update() is called. -// Arguments: An Vector with the impulse force vector that will directly be added -// to this MovableObject's momentum next Update(). In kg * m/s. -// A Vector with the offset, in METERS, of where the impulse is being -// applied relative to the center of this MovableObject. -// Return value: None. - - void AddImpulseForce(const Vector &impulse, const Vector &offset = Vector()) { - -#ifndef RELEASE_BUILD - RTEAssert(impulse.MagnitudeIsLessThan(500000.0F), "HUEG IMPULSE FORCE"); - RTEAssert(offset.MagnitudeIsLessThan(5000.0F), "HUGE IMPULSE FORCE OFFSET"); -#endif - - m_ImpulseForces.push_back({impulse, offset}); - } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddAbsImpulseForce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds impulse force (or instant momentum) to this MovableObject for -// the next time Update() is called. -// Arguments: An Vector with the impulse force vector that will directly be added -// to this MovableObject's momentum next Update(). In kg * m/s. -// A Vector with the absolute world coordinates, in PIXELS, of where the -// force is being applied to the center of this MovableObject. -// Return value: None. - - void AddAbsImpulseForce(const Vector &impulse, const Vector &absPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ClearForces -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out all the forces this MO has accumulated during this frame. -// Arguments: None. -// Return value: None. - - void ClearForces() { m_Forces.clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ClearImpulseForces -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out all the impulses this MO has accumulated during this frame. -// Arguments: None. -// Return value: None. - - void ClearImpulseForces() { m_ImpulseForces.clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPinStrength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the impulse force threshold which has to be exceeded to -// 'shake loose' this from a 'pinned' state. Pinned MOs don't get moved -// by travel algos. If 0, this isn't pinned. -// Arguments: None. -// Return value: The impulse threshold in kg * (m/s). 0 means no pinning - - float GetPinStrength() const { return m_PinStrength; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPinStrength -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets a impulse force threshold which has to be exceeded to -// 'shake loose' this from a 'pinned' state. Pinned MOs don't get moved -// by travel algos. If 0, this isn't pinned. -// Arguments: The impulse threshold in kg * (m/s). 0 means no pinning -// Return value: None. - - void SetPinStrength(float pinStrength) { m_PinStrength = pinStrength; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ResetAllTimers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resest all the timers used by this. Can be emitters, etc. This is to -// prevent backed up emissions to come out all at once while this has been -// held dormant in an inventory. -// Arguments: None. -// Return value: None. - - virtual void ResetAllTimers() {} - - /// - /// Does the calculations necessary to detect whether this MovableObject is at rest or not. IsAtRest() retrieves the answer. - /// - virtual void RestDetection(); - - /// - /// Forces this MovableObject out of resting conditions. - /// - virtual void NotResting() { m_RestTimer.Reset(); m_ToSettle = false; m_VelOscillations = 0; } - - /// - /// Indicates whether this MovableObject has been at rest with no movement for longer than its RestThreshold. - /// - virtual bool IsAtRest(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsUpdated -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates wheter this MovableObject has been updated yet during this -// frame. -// Arguments: None. -// Return value: Wheter or not the MovableObject has been updated yet during this frame. - - bool IsUpdated() const { return m_IsUpdated; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NewFrame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tell this MovableObject that a new frame has started. -// Arguments: None. -// Return value: None. - - void NewFrame() { m_IsUpdated = false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ToSettle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is marked for settling at the end of the -// MovableMan update. -// Arguments: None. -// Return value: Whether this MO is marked for settling ontot the terrain or not. - - bool ToSettle() const { return !m_MissionCritical && m_ToSettle; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ToDelete -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO is marked for deletion at the end of the -// MovableMan update. -// Arguments: None. -// Return value: Whether this MO is marked for deletion or not. - - bool ToDelete() const { return m_ToDelete; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DidWrap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this MO moved across the scene wrap seam during the -// last update. -// Arguments: None. -// Return value: Whether this MO wrapped or not. - - bool DidWrap() { return m_DidWrap; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure v. method: CollideAtPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the collision response when another MO's Atom collides with -// this MO's physical representation. The effects will be applied -// directly to this MO, and also represented in the passed in HitData. -// Arguments: Reference to the HitData struct which describes the collision. This -// will be modified to represent the results of the collision. -// Return value: Whether the collision has been deemed valid. If false, then disregard -// any impulses in the Hitdata. - - virtual bool CollideAtPoint(HitData &hitData) = 0; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: OnMOHit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits another MO. -// This is called by the owned Atom/AtomGroup of this MovableObject during -// travel. -// Arguments: The HitData describing the collision in detail. -// Return value: Wheter the MovableObject should immediately halt any travel going on -// after this hit. - - bool OnMOHit(HitData &hd); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure v. method: OnBounce -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// bounces off of something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. -// Arguments: The HitData describing the collision in detail. -// Return value: Wheter the MovableObject should immediately halt any travel going on -// after this bounce. - - virtual bool OnBounce(HitData &hd) = 0; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure v. method: OnSink -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Defines what should happen when this MovableObject hits and then -// sink into something. This is called by the owned Atom/AtomGroup -// of this MovableObject during travel. -// Arguments: The HitData describing the collision in detail. -// Return value: Wheter the MovableObject should immediately halt any travel going on -// after this sinkage. - - virtual bool OnSink(HitData &hd) = 0; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: MoveOutOfTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether any of the Atom:s in this MovableObject are on top of -// terrain pixels, and if so, attempt to move this out so none of this' -// Atoms are on top of the terrain any more. -// Arguments: Only consider materials stronger than this in the terrain for -// intersections. -// Return value: Whether any intersection was successfully resolved. Will return true -// even if there wasn't any intersections to begin with. - - virtual bool MoveOutOfTerrain(unsigned char strongerThan = g_MaterialAir) { return true; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: RotateOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Rotates a vector offset from this MORotating's position according to -// the rotate angle and flipping. -// Arguments: A const reference the offset Vector to rotate. -// Return value: A new vector that is the result of the rotation. - - virtual Vector RotateOffset(const Vector &offset) const { return offset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ApplyForces -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gathers and applies the global and accumulated forces. Then it clears -// out the force list.Note that this does NOT apply the accumulated -// impulses (impulse forces)! -// Arguments: None. -// Return value: None. - - virtual void ApplyForces(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ApplyImpulses -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gathers and applies the accumulated impulse forces. Then it clears -// out the impulse list.Note that this does NOT apply the accumulated -// regular forces (non-impulse forces)! -// Arguments: None. -// Return value: None. - - virtual void ApplyImpulses(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetForcesCount() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the number of Forces vectors to apply. -// Arguments: None. -// Return value: Number of entries in Forces list. - - int GetForcesCount() { return m_Forces.size(); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetForceVector() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns force vector in newtons of the specified Force record. -// Arguments: Force record index to get data from. -// Return value: Force vector in newtons of the specified Force record. - - Vector GetForceVector(int n) { if (n > 0 && n < m_Forces.size()) return m_Forces[n].first; else return Vector(0, 0); } - - /// - /// Gets the total sum of all forces applied to this MovableObject in a single Vector. - /// - /// The total sum of all forces applied to this MovableObject. - virtual Vector GetTotalForce(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetForceOffset() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns offset vector in METERS (not pixels) of the specified Force record. -// Arguments: Force record index to get data from. -// Return value: Offset vector in meters of the specified Force record. - - Vector GetForceOffset(int n) { if (n > 0 && n < m_Forces.size()) return m_Forces[n].second; else return Vector(0, 0); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetForceVector() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets force vector in newtons of the specified Force record. -// Arguments: Force record index to get data from. New Vector force value in newtons. -// Return value: None. - - void SetForceVector(int n, Vector v) { if (n > 0 && n < m_Forces.size()) m_Forces[n].first = v; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetForceOffset() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets offset vector in METERS (not pixels) of the specified Force record. -// Arguments: Force record index to get data from. New Vector offset value in meters. -// Return value: None. - - void SetForceOffset(int n, Vector v) { if (n > 0 && n < m_Forces.size()) m_Forces[n].second = v; } - - /// - /// Gets the pairs of impulse forces and their offsets that have to be applied. - /// - /// A constant reference to the deque of impulses for this MovableObject. - const std::deque > &GetImpulses() { return m_ImpulseForces; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetImpulsesCount() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the number of ImpulseForces vectors to apply. -// Arguments: None. -// Return value: Number of entries in ImpulseForces list. - - int GetImpulsesCount() { return m_ImpulseForces.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetImpulseVector() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns Impulse vector in newtons of the specified Impulse record. -// Arguments: Impulse record index to get data from. -// Return value: Impulse vector in newtons of the specified Impulse record. - - Vector GetImpulseVector(int n) { if (n > 0 && n < m_ImpulseForces.size()) return m_ImpulseForces[n].first; else return Vector(0, 0); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetImpulseOffset() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns offset vector in METERS (not pixels) of the specified Impulse record. -// Arguments: Impulse record index to get data from. -// Return value: Offset vector in meters of the specified Impulse record. - - Vector GetImpulseOffset(int n) { if (n > 0 && n < m_ImpulseForces.size()) return m_ImpulseForces[n].second; else return Vector(0, 0); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetImpulseVector() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns offset vector in METERS (not pixels) of the specified Impulse record. -// Arguments: Impulse record index to get data from. -// Return value: Offset vector in meters of the specified Impulse record. - - void SetImpulseVector(int n, Vector v) { if (n > 0 && n < m_ImpulseForces.size()) m_ImpulseForces[n].first = v; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetImpulseOffset() -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets offset vector in METERS (not pixels) of the specified Impulse record. -// Arguments: Impulse record index to get data from. New Vector offset value in meters. -// Return value: None. - - void SetImpulseOffset(int n, Vector v) { if (n > 0 && n < m_ImpulseForces.size()) m_ImpulseForces[n].second = v; } - - /// - /// Gets the number of Sim updates that run between each script update for this MovableObject. - /// - /// The number of Sim updates that run between each script update for this MovableObject. - int GetSimUpdatesBetweenScriptedUpdates() const { return m_SimUpdatesBetweenScriptedUpdates; } - - /// - /// Sets the number of Sim updates that run between each script update for this MovableObject. - /// - /// The new number of Sim updates that run between each script update for this MovableObject. - void SetSimUpdatesBetweenScriptedUpdates(int newSimUpdatesBetweenScriptedUpdates) { m_SimUpdatesBetweenScriptedUpdates = std::max(1, newSimUpdatesBetweenScriptedUpdates); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done before Travel(). Always call before -// calling Travel. -// Arguments: None. -// Return value: None. - - virtual void PreTravel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Travel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Travels this MovableObject, using its physical representation. -// Arguments: None. -// Return value: None. - - virtual void Travel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PostTravel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does stuff that needs to be done after Travel(). Always call after -// calling Travel. -// Arguments: None. -// Return value: None. - - virtual void PostTravel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PreControllerUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - virtual void PreControllerUpdate() { }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this MovableObject. Supposed to be done every frame. This also -// applies and clear the accumulated impulse forces (impulses), and the -// transferred forces of MOs attached to this. -// Arguments: None. -// Return value: None. - - void Update() override; - - void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - /// - /// Updates this MovableObject's Lua scripts. - /// - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - virtual int UpdateScripts(); - - /// - /// Gets a const reference to this MOSRotating's map of string values. - /// - /// A const reference to this MOSRotating's map of string values. - const std::unordered_map & GetStringValueMap() const { return m_StringValueMap; } - - /// - /// Gets a const reference to this MOSRotating's map of number values. - /// - /// A const reference to this MOSRotating's map of number values. - const std::unordered_map & GetNumberValueMap() const { return m_NumberValueMap; } - - /// - /// Returns the string value associated with the specified key or "" if it does not exist. - /// - /// Key to retrieve value. - /// The value associated with the key. - const std::string & GetStringValue(const std::string &key) const; - - /// - /// Returns an encoded string value associated with the specified key or "" if it does not exist. - /// - /// Key to retrieve value. - /// The value associated with the key. - std::string GetEncodedStringValue(const std::string &key) const; - - /// - /// Returns the number value associated with the specified key or 0 if it does not exist. - /// - /// Key to retrieve value. - /// The value associated with the key. - double GetNumberValue(const std::string &key) const; - - /// - /// Returns the entity value associated with the specified key or nullptr if it does not exist. - /// - /// Key to retrieve value. - /// The value associated with the key. - Entity * GetObjectValue(const std::string &key) const; - - /// - /// Sets the string value associated with the specified key. - /// - /// Key to retrieve value. - /// The new value to be associated with the key. - void SetStringValue(const std::string &key, const std::string &value); - - /// - /// Sets the string value associated with the specified key. - /// - /// Key to retrieve value. - /// The new value to be associated with the key. - void SetEncodedStringValue(const std::string &key, const std::string &value); - - /// - /// Sets the number value associated with the specified key. - /// - /// Key to retrieve value. - /// The new value to be associated with the key. - void SetNumberValue(const std::string &key, double value); - - /// - /// Sets the entity value associated with the specified key. - /// - /// Key to retrieve value. - /// The new value to be associated with the key. - void SetObjectValue(const std::string &key, Entity *value); - - /// - /// Remove the string value associated with the specified key. - /// - /// The key to remove. - void RemoveStringValue(const std::string &key); - - /// - /// Remove the number value associated with the specified key. - /// - /// The key to remove. - void RemoveNumberValue(const std::string &key); - - /// - /// Remove the entity value associated with the specified key. - /// - /// The key to remove. - void RemoveObjectValue(const std::string &key); - - /// - /// Checks whether the string value associated with the specified key exists. - /// - /// The key to check. - /// Whether or not there is an associated value for this key. - bool StringValueExists(const std::string &key) const; - - /// - /// Checks whether the number value associated with the specified key exists. - /// - /// The key to check. - /// Whether or not there is an associated value for this key. - bool NumberValueExists(const std::string &key) const; - - /// - /// Checks whether the entity value associated with the specified key exists. - /// - /// The key to check. - /// Whether or not there is an associated value for this key. - bool ObjectValueExists(const std::string &key) const; - - /// - /// Event listener to be run while this MovableObject's PieMenu is opened. - /// - /// The PieMenu this event listener needs to listen to. This will always be this' m_PieMenu and only exists for std::bind. - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - virtual int WhilePieMenuOpenListener(const PieMenu *pieMenu); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this' and its its childrens' MOID's and foorprint. Should -// be done every frame. -// Arguments: None. -// Return value: None. - - void UpdateMOID(std::vector &MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawMOIDIfOverlapping -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the MOID representation of this to the SceneMan's MOID layer if -// this is found to potentially overlap another MovableObject. -// Arguments: The MovableObject to check this for overlap against. -// Return value: Whether it was drawn or not. - - virtual bool DrawMOIDIfOverlapping(MovableObject *pOverlapMO) { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this' current graphical HUD overlay representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the draw bitmap's upper left corner in the Scene. -// Which player's screen this is being drawn to. May affect what HUD elements -// get drawn etc. -// Return value: None. - - virtual void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) { return; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRestThreshold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns current rest threshold for this MO -// Arguments: None -// Return value: Rest threshold of this MO - - int GetRestThreshold() const { return m_RestThreshold; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetRestThreshold -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets current rest threshold for this MO -// Arguments: New rest threshold value -// Return value: None - - void SetRestThreshold(int newRestThreshold) { m_RestThreshold = newRestThreshold; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Static method: GetNextID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the next unique id for MO's and increments unique ID counter -// Arguments: None. -// Return value: Returns the next unique id. - - static unsigned long int GetNextUniqueID() { return ++m_UniqueIDCounter; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Static method: GetUniqueID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns this MO's unique persistent ID -// Arguments: None. -// Return value: Returns this MO's unique persistent ID - - unsigned long int const GetUniqueID() const { return m_UniqueID; } - - /// - /// Gets the preset name and unique ID of this MO, often useful for error messages. - /// - /// A string containing the unique ID and preset name of this MO. - std::string GetPresetNameAndUniqueID() const { return m_PresetName + ", UID: " + std::to_string(m_UniqueID); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DamageOnCollision -////////////////////////////////////////////////////////////////////////////////////////// -// Description: If not zero applyies specified ammount of damage points to actors on -// collision even without penetration. -// Arguments: None -// Return value: Amount of damage to apply. - - float DamageOnCollision() const { return m_DamageOnCollision; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetDamageOnCollision -////////////////////////////////////////////////////////////////////////////////////////// -// Description: If not zero applyies specified ammount of damage points to actors on -// collision even without penetration. -// Arguments: Amount of damage to apply. -// Return value: None. - - void SetDamageOnCollision(float value) { m_DamageOnCollision = value; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DamageOnPenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: If not zero applies specified ammount of damage points to actors on -// collision if penetration occured. -// Arguments: None -// Return value: Amount of damage to apply. - - float DamageOnPenetration() const { return m_DamageOnPenetration; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetDamageOnPenetration -////////////////////////////////////////////////////////////////////////////////////////// -// Description: If not zero applies specified ammount of damage points to actors on -// collision if penetration occured. -// Arguments: Amount of damage to apply. -// Return value: None. - - void SetDamageOnPenetration(float value) { m_DamageOnPenetration = value; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: WoundDamageMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns damage multiplier transferred to wound inflicted by this object on penetration -// Arguments: None -// Return value: Damage multiplier to apply to wound. - - float WoundDamageMultiplier() const { return m_WoundDamageMultiplier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetWoundDamageMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets damage multiplier transferred to wound inflicted by this object on penetration -// Arguments: New damage multiplier to apply to wound. -// Return value: None. - - void SetWoundDamageMultiplier(float value) { m_WoundDamageMultiplier = value; } - - /// - /// Gets whether or not this MovableObject should apply wound damage when it collides with another MovableObject. - /// - /// Whether or not this MovableObject should apply wound damage when it collides with another MovableObject. - bool GetApplyWoundDamageOnCollision() const { return m_ApplyWoundDamageOnCollision; } - - /// - /// Sets whether or not this MovableObject should apply wound damage when it collides with another MovableObject. - /// - /// Whether or not this MovableObject should apply wound damage on collision. - void SetApplyWoundDamageOnCollision(bool applyWoundDamageOnCollision) { m_ApplyWoundDamageOnCollision = applyWoundDamageOnCollision; } - - /// - /// Gets whether or not this MovableObject should apply burst wound damage when it collides with another MovableObject. - /// - /// Whether or not this MovableObject should apply burst wound damage when it collides with another MovableObject. - bool GetApplyWoundBurstDamageOnCollision() const { return m_ApplyWoundBurstDamageOnCollision; } - - /// - /// Sets whether or not this MovableObject should apply burst wound damage when it collides with another MovableObject. - /// - /// Whether or not this MovableObject should apply burst wound damage on collision. - void SetApplyWoundBurstDamageOnCollision(bool applyWoundBurstDamageOnCollision) { m_ApplyWoundBurstDamageOnCollision = applyWoundBurstDamageOnCollision; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Puts all MOIDs associated with this MO and all it's descendants into MOIDs vector -// Arguments: Vector to store MOIDs -// Return value: None. - - virtual void GetMOIDs(std::vector &MOIDs) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HitWhatMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the ID of the MO hit at the previously taken Travel -// This will only potentially return non-g_NoMOID if this object's Atom is set to -// hit MO's and the MO hit isn't marked to be ignored. -// Arguments: None. -// Return value: The ID of the non-ignored MO, if any, that this object's Atom or AtomGroup is now -// intersecting because of the last Travel taken. - - MOID HitWhatMOID() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetHitWhatMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the ID of the MO hit at the previously taken Travel -// This will only potentially return non-g_NoMOID if this object's Atom is set to -// hit MO's and the MO hit isn't marked to be ignored. -// Arguments: The ID of the non-ignored MO, if any, that this object's Atom or AtomGroup is now -// intersecting because of the last Travel taken. -// Return value: None. - - void SetHitWhatMOID(MOID id); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HitWhatMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the unique ID of the particle hit at the previously taken Travel -// Arguments: None. -// Return value: Unique ID of the particle hit at the previously taken Travel - - long int HitWhatParticleUniqueID() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HitWhatMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the unique ID of the particle hit at the previously taken Travel -// Arguments: Unique ID of the particle hit at the previously taken Travel. -// Return value: None. - - void SetHitWhatParticleUniqueID(long int id); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HitWhatTerrMaterial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the terrain material the previously taken Tarvel -// hit, if any. -// Arguments: None. -// Return value: The ID of the material, if any, that this MO hit during the last Travel. - - unsigned char HitWhatTerrMaterial() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetHitWhatTerrMaterial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the terrain material the previously taken Tarvel hit, if any. -// Arguments: The ID of the material, if any, that this MO hit during the last Travel. -// Return value: None. - - void SetHitWhatTerrMaterial(unsigned char matID); - - /// - /// Gets whether this MO's RootParent can GetHitByMOs and is currently traveling. - /// - /// Whether this MO's RootParent can GetHitByMOs and is currently traveling. - bool GetTraveling() const { return GetRootParent()->m_IsTraveling; } - - /// - /// Sets whether this MO's RootParent is currently traveling. - /// - /// Whether this MO's RootParent is currently traveling. - void SetTraveling(bool newValue) { GetRootParent()->m_IsTraveling = newValue; } - - /// - /// Draws this MovableObject's graphical and material representations to the specified SLTerrain's respective layers. - /// - /// The SLTerrain to draw this MovableObject to. Ownership is NOT transferred! - /// Whether the object was successfully drawn to the terrain. - bool DrawToTerrain(SLTerrain *terrain); - - /// - /// Used to get the Lua state that handles our scripts. - /// - /// Our lua state. Can potentially be nullptr if we're not setup yet. - LuaStateWrapper* GetLuaState() { return m_ThreadedLuaState; } - - /// - /// Method to be run when the game is saved via ActivityMan::SaveCurrentGame. Not currently used in metagame or editor saving. - /// - virtual void OnSave() { RunScriptedFunctionInAppropriateScripts("OnSave"); } - - /// - /// Requests a synced update for the MO this frame. - /// - virtual void RequestSyncedUpdate() { m_RequestedSyncedUpdate = true; } - - /// - /// Resets the requested update flag. - /// - virtual void ResetRequestedSyncedUpdateFlag() { m_RequestedSyncedUpdate = false; } - - /// - /// Returns whether this MO has requested a synced update this frame. - /// - /// Whether this MO has requested a synced update this frame. - virtual bool HasRequestedSyncedUpdate() { return m_RequestedSyncedUpdate; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - /// - /// Does necessary work to setup a script object name for this object, allowing it to be accessed in Lua, then runs all of the MO's scripts' Create functions in Lua. - /// - /// 0 on success, -2 if it fails to setup the script object in Lua, and -3 if it fails to run any Create function. - int InitializeObjectScripts(); - - /// - /// Runs the given function for the given script, with the given arguments. The first argument to the function will always be 'self'. - /// If either argument list is not empty, its entries will be passed into the Lua function in order, with entity arguments first. - /// - /// The path to the script to run. - /// The name of the function to run. - /// Optional vector of entity pointers that should be passed into the Lua function. Their internal Lua states will not be accessible. Defaults to empty. - /// Optional vector of strings, that should be passed into the Lua function. Entries must be surrounded with escaped quotes (i.e.`\"`) they'll be passed in as-is, allowing them to act as booleans, etc.. Defaults to empty. - /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int RunFunctionOfScript(const std::string &scriptPath, const std::string &functionName, const std::vector &functionEntityArguments = std::vector(), const std::vector &functionLiteralArguments = std::vector()); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: UpdateChildMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this MO register itself and all its attached children in the -// MOID register and get ID:s for itself and its children for this frame. -// Arguments: The MOID index to register itself and its children in. -// The MOID of the root MO of this MO, ie the highest parent of this MO. -// 0 means that this MO is the root, ie it is owned by MovableMan. -// Whether this MO should make a new MOID to use for itself, or to use -// the same as the last one in the index (presumably its parent), -// Return value: None. - - virtual void UpdateChildMOIDs(std::vector &MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true) {} - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: RegMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this MO register itself in the MOID register and get ID:s for -// itself and its children for this frame. -// BITMAP of choice. -// Arguments: The MOID index to register itself and its children in. -// The MOID of the root MO of this MO, ie the highest parent of this MO. -// 0 means that this MO is the root, ie it is owned by MovableMan. -// Whether this MO should make a new MOID to use for itself, or to use -// the same as the last one in the index (presumably its parent), -// Return value: None. - - void RegMOID(std::vector &MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true); - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MovableObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Copy constructor method used to instantiate a MovableObject object -// identical to an already existing one. -// Arguments: A MovableObject object which is passed in by reference. - - - // Member variables - static Entity::ClassInfo m_sClass; - // Global counter with unique ID's - static std::atomic m_UniqueIDCounter; - // The type of MO this is, either Actor, Item, or Particle - int m_MOType; - float m_Mass; // In metric kilograms (kg). - Vector m_Vel; // In meters per second (m/s). - Vector m_PrevPos; // Previous frame's position. - Vector m_PrevVel; // Previous frame's velocity. - float m_DistanceTravelled; //!< An estimate of how many pixels this MO has travelled since its creation. - float m_Scale; // The scale that this MovableObject's representation will be drawn in. 1.0 being 1:1; - // How this is affected by global effects, from +1.0 to -1.0. Something with a negative value will 'float' upward - float m_GlobalAccScalar; - // How much this is affected by air resistance when traveling over a second, 0 to 1.0, with 0 as default - float m_AirResistance; - // At which threshold of velocity, in m/s, the effect of AirResistance kicks in - float m_AirThreshold; - // The impulse force in kg * (m/s) needed to unpin this. Pinned MO's don't travel at all. - float m_PinStrength; - // The threshold in ms as to how long this MO should wait after being at rest - // to get flagged to be copied to the terrain. - int m_RestThreshold; - // The forces acting on this MovableObject, the first vector being the force in - // In kg * m/s^2 (Newtons), and the second one being the offset the force is being - // applied from the m_Pos, IN METERS (not pixels!). - std::deque > m_Forces; - std::deque > m_ImpulseForces; // First in kg * m/s, second vector in meters. - Timer m_AgeTimer; - Timer m_RestTimer; - - unsigned long m_Lifetime; - // The sharpness factor that gets added to single pixel hit impulses in - // applicable situations. - float m_Sharpness; - // This is to be set each frame that this may be intersecting the terrain, like when it has been flipped - bool m_CheckTerrIntersection; - // Whether or not this MovableObject will test for collisions against other MOs. - bool m_HitsMOs; - // Another MovableObject that this should not be hitting even if it is set to hit MOs. - MovableObject *m_pMOToNotHit; - // For how long to not hit specific MO above - Timer m_MOIgnoreTimer; - // Whether or not this MovableObject can get hit by other MOs. - bool m_GetsHitByMOs; - // Whether this ignores collisions with other MOs of the same Team as this. - bool m_IgnoresTeamHits; - // This currently ignores hits with other AtomGroup MOs. - bool m_IgnoresAtomGroupHits; - // This will flip the IgnoreAtomGroupHits on or off depending on whether this MO is travelling slower than the threshold here, in m/s - // This is disabled if set to negative value, and 0 means AG hits are never ignored - float m_IgnoresAGHitsWhenSlowerThan; - // Wehther this ignores collisions with actors - bool m_IgnoresActorHits; - // This is mission critical, which means it should NEVER be settled or destroyed by gibbing - bool m_MissionCritical; - // Whether this can be destroyed by being squished into the terrain - bool m_CanBeSquished; - // Whether or not this MovableObject has been updated yet this frame. - bool m_IsUpdated; - // Whether wrap drawing double across wrapping seams is enabled or not - bool m_WrapDoubleDraw; - // Whether the position of this object wrapped around the world this frame, or not. - // This is just run-time data, don't need to be saved. - bool m_DidWrap; - // This is only valid the same frame it was assigned! - MOID m_MOID; - // This is only valid the same frame it was assigned! - // MOID of the root MO, same as this' m_MOID if this is owned by MovableMan. - MOID m_RootMOID; - // How many total (subsequent) MOID's this MO and all its children are taking up this frame. - // ie if this MO has no children, this will likely be 1. - int m_MOIDFootprint; - // Whether or not this object has ever been added to MovableMan. Does not take into account the object being removed from MovableMan, though in practice it usually will, cause objects are usually only removed when they're deleted. - bool m_HasEverBeenAddedToMovableMan; - // A set of ID:s of MO:s that already have collided with this MO during this frame. - std::set m_AlreadyHitBy; - int m_VelOscillations; //!< A counter for oscillations in translational velocity, in order to detect settling. - // Mark to have the MovableMan copy this the terrain layers at the end - // of update. - bool m_ToSettle; - // Mark to delete at the end of MovableMan update - bool m_ToDelete; - // To draw this guy's HUD or not - bool m_HUDVisible; - - bool m_IsTraveling; //!< Prevents self-intersection while traveling. - - LuaStateWrapper *m_ThreadedLuaState; //!< The lua state that will runs our lua scripts. - bool m_ForceIntoMasterLuaState; //!< This is awful, and only exists for automovers because they mangle global state all over the place. TODO - change automovers to use messages. - - struct LuaFunction { - bool m_ScriptIsEnabled; //!< Whether this function is in an enabled script. - std::unique_ptr m_LuaFunction; //!< The lua function itself. - }; - - std::string m_ScriptObjectName; //!< The name of this object for script usage. - std::unordered_map m_AllLoadedScripts; //!< A map of script paths to the enabled state of the given script. - std::unordered_map> m_FunctionsAndScripts; //!< A map of function names to vectors of Lua functions. Used to maintain script execution order and avoid extraneous Lua calls. - - volatile bool m_RequestedSyncedUpdate; //!< For optimisation purposes, scripts explicitly request a synced update if they want one. - - std::unordered_map m_StringValueMap; // m_NumberValueMap; // m_ObjectValueMap; // - /// Clears all the member variables of this MovableObject, effectively resetting the members of this abstraction level only. - /// - void Clear(); - - /// - /// Handles reading for custom values, dealing with the various types of custom values. - /// - /// A Reader lined up to the custom value type to be read. - void ReadCustomValueProperty(Reader& reader); - - /// - /// Returns the script state to use for a given script path. - /// This will be locked to our thread and safe to use - ensure that it'll be unlocked after use! - /// - /// The path to the script to check for thread safety. - /// A LuaFunction, to use as an early-out check instead of redundantly hashing and checking the filepath string. - /// A script state. - LuaStateWrapper & GetAndLockStateForScript(const std::string &scriptPath, const LuaFunction *function = nullptr); - - // Disallow the use of some implicit methods. - MovableObject(const MovableObject &reference) = delete; - MovableObject& operator=(const MovableObject& ref) = delete; -}; + m_ImpulseForces.push_back({impulse, offset}); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddAbsImpulseForce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds impulse force (or instant momentum) to this MovableObject for + // the next time Update() is called. + // Arguments: An Vector with the impulse force vector that will directly be added + // to this MovableObject's momentum next Update(). In kg * m/s. + // A Vector with the absolute world coordinates, in PIXELS, of where the + // force is being applied to the center of this MovableObject. + // Return value: None. + + void AddAbsImpulseForce(const Vector& impulse, const Vector& absPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ClearForces + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out all the forces this MO has accumulated during this frame. + // Arguments: None. + // Return value: None. + + void ClearForces() { m_Forces.clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ClearImpulseForces + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out all the impulses this MO has accumulated during this frame. + // Arguments: None. + // Return value: None. + + void ClearImpulseForces() { m_ImpulseForces.clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPinStrength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the impulse force threshold which has to be exceeded to + // 'shake loose' this from a 'pinned' state. Pinned MOs don't get moved + // by travel algos. If 0, this isn't pinned. + // Arguments: None. + // Return value: The impulse threshold in kg * (m/s). 0 means no pinning + + float GetPinStrength() const { return m_PinStrength; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPinStrength + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets a impulse force threshold which has to be exceeded to + // 'shake loose' this from a 'pinned' state. Pinned MOs don't get moved + // by travel algos. If 0, this isn't pinned. + // Arguments: The impulse threshold in kg * (m/s). 0 means no pinning + // Return value: None. + + void SetPinStrength(float pinStrength) { m_PinStrength = pinStrength; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. + // Arguments: None. + // Return value: None. + + virtual void ResetAllTimers() {} + + /// + /// Does the calculations necessary to detect whether this MovableObject is at rest or not. IsAtRest() retrieves the answer. + /// + virtual void RestDetection(); + + /// + /// Forces this MovableObject out of resting conditions. + /// + virtual void NotResting() { + m_RestTimer.Reset(); + m_ToSettle = false; + m_VelOscillations = 0; + } + + /// + /// Indicates whether this MovableObject has been at rest with no movement for longer than its RestThreshold. + /// + virtual bool IsAtRest(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsUpdated + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates wheter this MovableObject has been updated yet during this + // frame. + // Arguments: None. + // Return value: Wheter or not the MovableObject has been updated yet during this frame. + + bool IsUpdated() const { return m_IsUpdated; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NewFrame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tell this MovableObject that a new frame has started. + // Arguments: None. + // Return value: None. + + void NewFrame() { m_IsUpdated = false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ToSettle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is marked for settling at the end of the + // MovableMan update. + // Arguments: None. + // Return value: Whether this MO is marked for settling ontot the terrain or not. + + bool ToSettle() const { return !m_MissionCritical && m_ToSettle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ToDelete + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO is marked for deletion at the end of the + // MovableMan update. + // Arguments: None. + // Return value: Whether this MO is marked for deletion or not. + + bool ToDelete() const { return m_ToDelete; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DidWrap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this MO moved across the scene wrap seam during the + // last update. + // Arguments: None. + // Return value: Whether this MO wrapped or not. + + bool DidWrap() { return m_DidWrap; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure v. method: CollideAtPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the collision response when another MO's Atom collides with + // this MO's physical representation. The effects will be applied + // directly to this MO, and also represented in the passed in HitData. + // Arguments: Reference to the HitData struct which describes the collision. This + // will be modified to represent the results of the collision. + // Return value: Whether the collision has been deemed valid. If false, then disregard + // any impulses in the Hitdata. + + virtual bool CollideAtPoint(HitData& hitData) = 0; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: OnMOHit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits another MO. + // This is called by the owned Atom/AtomGroup of this MovableObject during + // travel. + // Arguments: The HitData describing the collision in detail. + // Return value: Wheter the MovableObject should immediately halt any travel going on + // after this hit. + + bool OnMOHit(HitData& hd); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure v. method: OnBounce + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // bounces off of something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. + // Arguments: The HitData describing the collision in detail. + // Return value: Wheter the MovableObject should immediately halt any travel going on + // after this bounce. + + virtual bool OnBounce(HitData& hd) = 0; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure v. method: OnSink + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Defines what should happen when this MovableObject hits and then + // sink into something. This is called by the owned Atom/AtomGroup + // of this MovableObject during travel. + // Arguments: The HitData describing the collision in detail. + // Return value: Wheter the MovableObject should immediately halt any travel going on + // after this sinkage. + + virtual bool OnSink(HitData& hd) = 0; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: MoveOutOfTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether any of the Atom:s in this MovableObject are on top of + // terrain pixels, and if so, attempt to move this out so none of this' + // Atoms are on top of the terrain any more. + // Arguments: Only consider materials stronger than this in the terrain for + // intersections. + // Return value: Whether any intersection was successfully resolved. Will return true + // even if there wasn't any intersections to begin with. + + virtual bool MoveOutOfTerrain(unsigned char strongerThan = g_MaterialAir) { return true; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RotateOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Rotates a vector offset from this MORotating's position according to + // the rotate angle and flipping. + // Arguments: A const reference the offset Vector to rotate. + // Return value: A new vector that is the result of the rotation. + + virtual Vector RotateOffset(const Vector& offset) const { return offset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ApplyForces + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gathers and applies the global and accumulated forces. Then it clears + // out the force list.Note that this does NOT apply the accumulated + // impulses (impulse forces)! + // Arguments: None. + // Return value: None. + + virtual void ApplyForces(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ApplyImpulses + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gathers and applies the accumulated impulse forces. Then it clears + // out the impulse list.Note that this does NOT apply the accumulated + // regular forces (non-impulse forces)! + // Arguments: None. + // Return value: None. + + virtual void ApplyImpulses(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetForcesCount() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the number of Forces vectors to apply. + // Arguments: None. + // Return value: Number of entries in Forces list. + + int GetForcesCount() { return m_Forces.size(); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetForceVector() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns force vector in newtons of the specified Force record. + // Arguments: Force record index to get data from. + // Return value: Force vector in newtons of the specified Force record. + + Vector GetForceVector(int n) { + if (n > 0 && n < m_Forces.size()) + return m_Forces[n].first; + else + return Vector(0, 0); + } + + /// + /// Gets the total sum of all forces applied to this MovableObject in a single Vector. + /// + /// The total sum of all forces applied to this MovableObject. + virtual Vector GetTotalForce(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetForceOffset() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns offset vector in METERS (not pixels) of the specified Force record. + // Arguments: Force record index to get data from. + // Return value: Offset vector in meters of the specified Force record. + + Vector GetForceOffset(int n) { + if (n > 0 && n < m_Forces.size()) + return m_Forces[n].second; + else + return Vector(0, 0); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetForceVector() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets force vector in newtons of the specified Force record. + // Arguments: Force record index to get data from. New Vector force value in newtons. + // Return value: None. + + void SetForceVector(int n, Vector v) { + if (n > 0 && n < m_Forces.size()) + m_Forces[n].first = v; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetForceOffset() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets offset vector in METERS (not pixels) of the specified Force record. + // Arguments: Force record index to get data from. New Vector offset value in meters. + // Return value: None. + + void SetForceOffset(int n, Vector v) { + if (n > 0 && n < m_Forces.size()) + m_Forces[n].second = v; + } + + /// + /// Gets the pairs of impulse forces and their offsets that have to be applied. + /// + /// A constant reference to the deque of impulses for this MovableObject. + const std::deque>& GetImpulses() { return m_ImpulseForces; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetImpulsesCount() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the number of ImpulseForces vectors to apply. + // Arguments: None. + // Return value: Number of entries in ImpulseForces list. + + int GetImpulsesCount() { return m_ImpulseForces.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetImpulseVector() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns Impulse vector in newtons of the specified Impulse record. + // Arguments: Impulse record index to get data from. + // Return value: Impulse vector in newtons of the specified Impulse record. + + Vector GetImpulseVector(int n) { + if (n > 0 && n < m_ImpulseForces.size()) + return m_ImpulseForces[n].first; + else + return Vector(0, 0); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetImpulseOffset() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns offset vector in METERS (not pixels) of the specified Impulse record. + // Arguments: Impulse record index to get data from. + // Return value: Offset vector in meters of the specified Impulse record. + + Vector GetImpulseOffset(int n) { + if (n > 0 && n < m_ImpulseForces.size()) + return m_ImpulseForces[n].second; + else + return Vector(0, 0); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetImpulseVector() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns offset vector in METERS (not pixels) of the specified Impulse record. + // Arguments: Impulse record index to get data from. + // Return value: Offset vector in meters of the specified Impulse record. + + void SetImpulseVector(int n, Vector v) { + if (n > 0 && n < m_ImpulseForces.size()) + m_ImpulseForces[n].first = v; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetImpulseOffset() + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets offset vector in METERS (not pixels) of the specified Impulse record. + // Arguments: Impulse record index to get data from. New Vector offset value in meters. + // Return value: None. + + void SetImpulseOffset(int n, Vector v) { + if (n > 0 && n < m_ImpulseForces.size()) + m_ImpulseForces[n].second = v; + } + + /// + /// Gets the number of Sim updates that run between each script update for this MovableObject. + /// + /// The number of Sim updates that run between each script update for this MovableObject. + int GetSimUpdatesBetweenScriptedUpdates() const { return m_SimUpdatesBetweenScriptedUpdates; } + + /// + /// Sets the number of Sim updates that run between each script update for this MovableObject. + /// + /// The new number of Sim updates that run between each script update for this MovableObject. + void SetSimUpdatesBetweenScriptedUpdates(int newSimUpdatesBetweenScriptedUpdates) { m_SimUpdatesBetweenScriptedUpdates = std::max(1, newSimUpdatesBetweenScriptedUpdates); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done before Travel(). Always call before + // calling Travel. + // Arguments: None. + // Return value: None. + + virtual void PreTravel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Travel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Travels this MovableObject, using its physical representation. + // Arguments: None. + // Return value: None. + + virtual void Travel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PostTravel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does stuff that needs to be done after Travel(). Always call after + // calling Travel. + // Arguments: None. + // Return value: None. + + virtual void PostTravel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PreControllerUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Update called prior to controller update. Ugly hack. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + virtual void PreControllerUpdate(){}; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. This also + // applies and clear the accumulated impulse forces (impulses), and the + // transferred forces of MOs attached to this. + // Arguments: None. + // Return value: None. + + void Update() override; + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + /// + /// Updates this MovableObject's Lua scripts. + /// + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + virtual int UpdateScripts(); + + /// + /// Gets a const reference to this MOSRotating's map of string values. + /// + /// A const reference to this MOSRotating's map of string values. + const std::unordered_map& GetStringValueMap() const { return m_StringValueMap; } + + /// + /// Gets a const reference to this MOSRotating's map of number values. + /// + /// A const reference to this MOSRotating's map of number values. + const std::unordered_map& GetNumberValueMap() const { return m_NumberValueMap; } + + /// + /// Returns the string value associated with the specified key or "" if it does not exist. + /// + /// Key to retrieve value. + /// The value associated with the key. + const std::string& GetStringValue(const std::string& key) const; + + /// + /// Returns an encoded string value associated with the specified key or "" if it does not exist. + /// + /// Key to retrieve value. + /// The value associated with the key. + std::string GetEncodedStringValue(const std::string& key) const; + + /// + /// Returns the number value associated with the specified key or 0 if it does not exist. + /// + /// Key to retrieve value. + /// The value associated with the key. + double GetNumberValue(const std::string& key) const; + + /// + /// Returns the entity value associated with the specified key or nullptr if it does not exist. + /// + /// Key to retrieve value. + /// The value associated with the key. + Entity* GetObjectValue(const std::string& key) const; + + /// + /// Sets the string value associated with the specified key. + /// + /// Key to retrieve value. + /// The new value to be associated with the key. + void SetStringValue(const std::string& key, const std::string& value); + + /// + /// Sets the string value associated with the specified key. + /// + /// Key to retrieve value. + /// The new value to be associated with the key. + void SetEncodedStringValue(const std::string& key, const std::string& value); + + /// + /// Sets the number value associated with the specified key. + /// + /// Key to retrieve value. + /// The new value to be associated with the key. + void SetNumberValue(const std::string& key, double value); + + /// + /// Sets the entity value associated with the specified key. + /// + /// Key to retrieve value. + /// The new value to be associated with the key. + void SetObjectValue(const std::string& key, Entity* value); + + /// + /// Remove the string value associated with the specified key. + /// + /// The key to remove. + void RemoveStringValue(const std::string& key); + + /// + /// Remove the number value associated with the specified key. + /// + /// The key to remove. + void RemoveNumberValue(const std::string& key); + + /// + /// Remove the entity value associated with the specified key. + /// + /// The key to remove. + void RemoveObjectValue(const std::string& key); + + /// + /// Checks whether the string value associated with the specified key exists. + /// + /// The key to check. + /// Whether or not there is an associated value for this key. + bool StringValueExists(const std::string& key) const; + + /// + /// Checks whether the number value associated with the specified key exists. + /// + /// The key to check. + /// Whether or not there is an associated value for this key. + bool NumberValueExists(const std::string& key) const; + + /// + /// Checks whether the entity value associated with the specified key exists. + /// + /// The key to check. + /// Whether or not there is an associated value for this key. + bool ObjectValueExists(const std::string& key) const; + + /// + /// Event listener to be run while this MovableObject's PieMenu is opened. + /// + /// The PieMenu this event listener needs to listen to. This will always be this' m_PieMenu and only exists for std::bind. + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + virtual int WhilePieMenuOpenListener(const PieMenu* pieMenu); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this' and its its childrens' MOID's and foorprint. Should + // be done every frame. + // Arguments: None. + // Return value: None. + + void UpdateMOID(std::vector& MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawMOIDIfOverlapping + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the MOID representation of this to the SceneMan's MOID layer if + // this is found to potentially overlap another MovableObject. + // Arguments: The MovableObject to check this for overlap against. + // Return value: Whether it was drawn or not. + + virtual bool DrawMOIDIfOverlapping(MovableObject* pOverlapMO) { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this' current graphical HUD overlay representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the draw bitmap's upper left corner in the Scene. + // Which player's screen this is being drawn to. May affect what HUD elements + // get drawn etc. + // Return value: None. + + virtual void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) { return; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRestThreshold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns current rest threshold for this MO + // Arguments: None + // Return value: Rest threshold of this MO + + int GetRestThreshold() const { return m_RestThreshold; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetRestThreshold + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets current rest threshold for this MO + // Arguments: New rest threshold value + // Return value: None + + void SetRestThreshold(int newRestThreshold) { m_RestThreshold = newRestThreshold; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Static method: GetNextID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the next unique id for MO's and increments unique ID counter + // Arguments: None. + // Return value: Returns the next unique id. + + static unsigned long int GetNextUniqueID() { return ++m_UniqueIDCounter; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Static method: GetUniqueID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns this MO's unique persistent ID + // Arguments: None. + // Return value: Returns this MO's unique persistent ID + + unsigned long int const GetUniqueID() const { return m_UniqueID; } + + /// + /// Gets the preset name and unique ID of this MO, often useful for error messages. + /// + /// A string containing the unique ID and preset name of this MO. + std::string GetPresetNameAndUniqueID() const { return m_PresetName + ", UID: " + std::to_string(m_UniqueID); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DamageOnCollision + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: If not zero applyies specified ammount of damage points to actors on + // collision even without penetration. + // Arguments: None + // Return value: Amount of damage to apply. + + float DamageOnCollision() const { return m_DamageOnCollision; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetDamageOnCollision + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: If not zero applyies specified ammount of damage points to actors on + // collision even without penetration. + // Arguments: Amount of damage to apply. + // Return value: None. + + void SetDamageOnCollision(float value) { m_DamageOnCollision = value; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DamageOnPenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: If not zero applies specified ammount of damage points to actors on + // collision if penetration occured. + // Arguments: None + // Return value: Amount of damage to apply. + + float DamageOnPenetration() const { return m_DamageOnPenetration; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetDamageOnPenetration + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: If not zero applies specified ammount of damage points to actors on + // collision if penetration occured. + // Arguments: Amount of damage to apply. + // Return value: None. + + void SetDamageOnPenetration(float value) { m_DamageOnPenetration = value; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: WoundDamageMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns damage multiplier transferred to wound inflicted by this object on penetration + // Arguments: None + // Return value: Damage multiplier to apply to wound. + + float WoundDamageMultiplier() const { return m_WoundDamageMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetWoundDamageMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets damage multiplier transferred to wound inflicted by this object on penetration + // Arguments: New damage multiplier to apply to wound. + // Return value: None. + + void SetWoundDamageMultiplier(float value) { m_WoundDamageMultiplier = value; } + + /// + /// Gets whether or not this MovableObject should apply wound damage when it collides with another MovableObject. + /// + /// Whether or not this MovableObject should apply wound damage when it collides with another MovableObject. + bool GetApplyWoundDamageOnCollision() const { return m_ApplyWoundDamageOnCollision; } + + /// + /// Sets whether or not this MovableObject should apply wound damage when it collides with another MovableObject. + /// + /// Whether or not this MovableObject should apply wound damage on collision. + void SetApplyWoundDamageOnCollision(bool applyWoundDamageOnCollision) { m_ApplyWoundDamageOnCollision = applyWoundDamageOnCollision; } + + /// + /// Gets whether or not this MovableObject should apply burst wound damage when it collides with another MovableObject. + /// + /// Whether or not this MovableObject should apply burst wound damage when it collides with another MovableObject. + bool GetApplyWoundBurstDamageOnCollision() const { return m_ApplyWoundBurstDamageOnCollision; } + + /// + /// Sets whether or not this MovableObject should apply burst wound damage when it collides with another MovableObject. + /// + /// Whether or not this MovableObject should apply burst wound damage on collision. + void SetApplyWoundBurstDamageOnCollision(bool applyWoundBurstDamageOnCollision) { m_ApplyWoundBurstDamageOnCollision = applyWoundBurstDamageOnCollision; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Puts all MOIDs associated with this MO and all it's descendants into MOIDs vector + // Arguments: Vector to store MOIDs + // Return value: None. + + virtual void GetMOIDs(std::vector& MOIDs) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HitWhatMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the ID of the MO hit at the previously taken Travel + // This will only potentially return non-g_NoMOID if this object's Atom is set to + // hit MO's and the MO hit isn't marked to be ignored. + // Arguments: None. + // Return value: The ID of the non-ignored MO, if any, that this object's Atom or AtomGroup is now + // intersecting because of the last Travel taken. + + MOID HitWhatMOID() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetHitWhatMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the ID of the MO hit at the previously taken Travel + // This will only potentially return non-g_NoMOID if this object's Atom is set to + // hit MO's and the MO hit isn't marked to be ignored. + // Arguments: The ID of the non-ignored MO, if any, that this object's Atom or AtomGroup is now + // intersecting because of the last Travel taken. + // Return value: None. + + void SetHitWhatMOID(MOID id); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HitWhatMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the unique ID of the particle hit at the previously taken Travel + // Arguments: None. + // Return value: Unique ID of the particle hit at the previously taken Travel + + long int HitWhatParticleUniqueID() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HitWhatMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the unique ID of the particle hit at the previously taken Travel + // Arguments: Unique ID of the particle hit at the previously taken Travel. + // Return value: None. + + void SetHitWhatParticleUniqueID(long int id); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HitWhatTerrMaterial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the terrain material the previously taken Tarvel + // hit, if any. + // Arguments: None. + // Return value: The ID of the material, if any, that this MO hit during the last Travel. + + unsigned char HitWhatTerrMaterial() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetHitWhatTerrMaterial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the terrain material the previously taken Tarvel hit, if any. + // Arguments: The ID of the material, if any, that this MO hit during the last Travel. + // Return value: None. + + void SetHitWhatTerrMaterial(unsigned char matID); + + /// + /// Gets whether this MO's RootParent can GetHitByMOs and is currently traveling. + /// + /// Whether this MO's RootParent can GetHitByMOs and is currently traveling. + bool GetTraveling() const { return GetRootParent()->m_IsTraveling; } + + /// + /// Sets whether this MO's RootParent is currently traveling. + /// + /// Whether this MO's RootParent is currently traveling. + void SetTraveling(bool newValue) { GetRootParent()->m_IsTraveling = newValue; } + + /// + /// Draws this MovableObject's graphical and material representations to the specified SLTerrain's respective layers. + /// + /// The SLTerrain to draw this MovableObject to. Ownership is NOT transferred! + /// Whether the object was successfully drawn to the terrain. + bool DrawToTerrain(SLTerrain* terrain); + + /// + /// Used to get the Lua state that handles our scripts. + /// + /// Our lua state. Can potentially be nullptr if we're not setup yet. + LuaStateWrapper* GetLuaState() { return m_ThreadedLuaState; } + + /// + /// Method to be run when the game is saved via ActivityMan::SaveCurrentGame. Not currently used in metagame or editor saving. + /// + virtual void OnSave() { RunScriptedFunctionInAppropriateScripts("OnSave"); } + + /// + /// Requests a synced update for the MO this frame. + /// + virtual void RequestSyncedUpdate() { m_RequestedSyncedUpdate = true; } + + /// + /// Resets the requested update flag. + /// + virtual void ResetRequestedSyncedUpdateFlag() { m_RequestedSyncedUpdate = false; } + + /// + /// Returns whether this MO has requested a synced update this frame. + /// + /// Whether this MO has requested a synced update this frame. + virtual bool HasRequestedSyncedUpdate() { return m_RequestedSyncedUpdate; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Does necessary work to setup a script object name for this object, allowing it to be accessed in Lua, then runs all of the MO's scripts' Create functions in Lua. + /// + /// 0 on success, -2 if it fails to setup the script object in Lua, and -3 if it fails to run any Create function. + int InitializeObjectScripts(); + + /// + /// Runs the given function for the given script, with the given arguments. The first argument to the function will always be 'self'. + /// If either argument list is not empty, its entries will be passed into the Lua function in order, with entity arguments first. + /// + /// The path to the script to run. + /// The name of the function to run. + /// Optional vector of entity pointers that should be passed into the Lua function. Their internal Lua states will not be accessible. Defaults to empty. + /// Optional vector of strings, that should be passed into the Lua function. Entries must be surrounded with escaped quotes (i.e.`\"`) they'll be passed in as-is, allowing them to act as booleans, etc.. Defaults to empty. + /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. + int RunFunctionOfScript(const std::string& scriptPath, const std::string& functionName, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector()); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: UpdateChildMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this MO register itself and all its attached children in the + // MOID register and get ID:s for itself and its children for this frame. + // Arguments: The MOID index to register itself and its children in. + // The MOID of the root MO of this MO, ie the highest parent of this MO. + // 0 means that this MO is the root, ie it is owned by MovableMan. + // Whether this MO should make a new MOID to use for itself, or to use + // the same as the last one in the index (presumably its parent), + // Return value: None. + + virtual void UpdateChildMOIDs(std::vector& MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true) {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RegMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this MO register itself in the MOID register and get ID:s for + // itself and its children for this frame. + // BITMAP of choice. + // Arguments: The MOID index to register itself and its children in. + // The MOID of the root MO of this MO, ie the highest parent of this MO. + // 0 means that this MO is the root, ie it is owned by MovableMan. + // Whether this MO should make a new MOID to use for itself, or to use + // the same as the last one in the index (presumably its parent), + // Return value: None. + + void RegMOID(std::vector& MOIDIndex, MOID rootMOID = g_NoMOID, bool makeNewMOID = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MovableObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Copy constructor method used to instantiate a MovableObject object + // identical to an already existing one. + // Arguments: A MovableObject object which is passed in by reference. + + // Member variables + static Entity::ClassInfo m_sClass; + // Global counter with unique ID's + static std::atomic m_UniqueIDCounter; + // The type of MO this is, either Actor, Item, or Particle + int m_MOType; + float m_Mass; // In metric kilograms (kg). + Vector m_Vel; // In meters per second (m/s). + Vector m_PrevPos; // Previous frame's position. + Vector m_PrevVel; // Previous frame's velocity. + float m_DistanceTravelled; //!< An estimate of how many pixels this MO has travelled since its creation. + float m_Scale; // The scale that this MovableObject's representation will be drawn in. 1.0 being 1:1; + // How this is affected by global effects, from +1.0 to -1.0. Something with a negative value will 'float' upward + float m_GlobalAccScalar; + // How much this is affected by air resistance when traveling over a second, 0 to 1.0, with 0 as default + float m_AirResistance; + // At which threshold of velocity, in m/s, the effect of AirResistance kicks in + float m_AirThreshold; + // The impulse force in kg * (m/s) needed to unpin this. Pinned MO's don't travel at all. + float m_PinStrength; + // The threshold in ms as to how long this MO should wait after being at rest + // to get flagged to be copied to the terrain. + int m_RestThreshold; + // The forces acting on this MovableObject, the first vector being the force in + // In kg * m/s^2 (Newtons), and the second one being the offset the force is being + // applied from the m_Pos, IN METERS (not pixels!). + std::deque> m_Forces; + std::deque> m_ImpulseForces; // First in kg * m/s, second vector in meters. + Timer m_AgeTimer; + Timer m_RestTimer; + + unsigned long m_Lifetime; + // The sharpness factor that gets added to single pixel hit impulses in + // applicable situations. + float m_Sharpness; + // This is to be set each frame that this may be intersecting the terrain, like when it has been flipped + bool m_CheckTerrIntersection; + // Whether or not this MovableObject will test for collisions against other MOs. + bool m_HitsMOs; + // Another MovableObject that this should not be hitting even if it is set to hit MOs. + MovableObject* m_pMOToNotHit; + // For how long to not hit specific MO above + Timer m_MOIgnoreTimer; + // Whether or not this MovableObject can get hit by other MOs. + bool m_GetsHitByMOs; + // Whether this ignores collisions with other MOs of the same Team as this. + bool m_IgnoresTeamHits; + // This currently ignores hits with other AtomGroup MOs. + bool m_IgnoresAtomGroupHits; + // This will flip the IgnoreAtomGroupHits on or off depending on whether this MO is travelling slower than the threshold here, in m/s + // This is disabled if set to negative value, and 0 means AG hits are never ignored + float m_IgnoresAGHitsWhenSlowerThan; + // Wehther this ignores collisions with actors + bool m_IgnoresActorHits; + // This is mission critical, which means it should NEVER be settled or destroyed by gibbing + bool m_MissionCritical; + // Whether this can be destroyed by being squished into the terrain + bool m_CanBeSquished; + // Whether or not this MovableObject has been updated yet this frame. + bool m_IsUpdated; + // Whether wrap drawing double across wrapping seams is enabled or not + bool m_WrapDoubleDraw; + // Whether the position of this object wrapped around the world this frame, or not. + // This is just run-time data, don't need to be saved. + bool m_DidWrap; + // This is only valid the same frame it was assigned! + MOID m_MOID; + // This is only valid the same frame it was assigned! + // MOID of the root MO, same as this' m_MOID if this is owned by MovableMan. + MOID m_RootMOID; + // How many total (subsequent) MOID's this MO and all its children are taking up this frame. + // ie if this MO has no children, this will likely be 1. + int m_MOIDFootprint; + // Whether or not this object has ever been added to MovableMan. Does not take into account the object being removed from MovableMan, though in practice it usually will, cause objects are usually only removed when they're deleted. + bool m_HasEverBeenAddedToMovableMan; + // A set of ID:s of MO:s that already have collided with this MO during this frame. + std::set m_AlreadyHitBy; + int m_VelOscillations; //!< A counter for oscillations in translational velocity, in order to detect settling. + // Mark to have the MovableMan copy this the terrain layers at the end + // of update. + bool m_ToSettle; + // Mark to delete at the end of MovableMan update + bool m_ToDelete; + // To draw this guy's HUD or not + bool m_HUDVisible; + + bool m_IsTraveling; //!< Prevents self-intersection while traveling. + + LuaStateWrapper* m_ThreadedLuaState; //!< The lua state that will runs our lua scripts. + bool m_ForceIntoMasterLuaState; //!< This is awful, and only exists for automovers because they mangle global state all over the place. TODO - change automovers to use messages. + + struct LuaFunction { + bool m_ScriptIsEnabled; //!< Whether this function is in an enabled script. + std::unique_ptr m_LuaFunction; //!< The lua function itself. + }; + + std::string m_ScriptObjectName; //!< The name of this object for script usage. + std::unordered_map m_AllLoadedScripts; //!< A map of script paths to the enabled state of the given script. + std::unordered_map> m_FunctionsAndScripts; //!< A map of function names to vectors of Lua functions. Used to maintain script execution order and avoid extraneous Lua calls. + + volatile bool m_RequestedSyncedUpdate; //!< For optimisation purposes, scripts explicitly request a synced update if they want one. + + std::unordered_map m_StringValueMap; // m_NumberValueMap; // m_ObjectValueMap; // + /// Clears all the member variables of this MovableObject, effectively resetting the members of this abstraction level only. + /// + void Clear(); + + /// + /// Handles reading for custom values, dealing with the various types of custom values. + /// + /// A Reader lined up to the custom value type to be read. + void ReadCustomValueProperty(Reader& reader); + + /// + /// Returns the script state to use for a given script path. + /// This will be locked to our thread and safe to use - ensure that it'll be unlocked after use! + /// + /// The path to the script to check for thread safety. + /// A LuaFunction, to use as an early-out check instead of redundantly hashing and checking the filepath string. + /// A script state. + LuaStateWrapper& GetAndLockStateForScript(const std::string& scriptPath, const LuaFunction* function = nullptr); + + // Disallow the use of some implicit methods. + MovableObject(const MovableObject& reference) = delete; + MovableObject& operator=(const MovableObject& ref) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/PEmitter.cpp b/Source/Entities/PEmitter.cpp index 9d66a8ae7..81bcc656a 100644 --- a/Source/Entities/PEmitter.cpp +++ b/Source/Entities/PEmitter.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -21,14 +20,13 @@ namespace RTE { ConcreteClassInfo(PEmitter, MOSParticle, 100); - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Clear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Clears all the member variables of this PEmitter, effectively - // resetting the members of this abstraction level only. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this PEmitter, effectively + // resetting the members of this abstraction level only. - void PEmitter::Clear() - { + void PEmitter::Clear() { m_EmissionList.clear(); m_EmissionSound.Reset(); m_BurstSound.Reset(); @@ -59,28 +57,24 @@ namespace RTE { m_LoudnessOnEmit = 1.0f; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the Emission object ready for use. - int PEmitter::Create() - { + int PEmitter::Create() { if (MOSParticle::Create() < 0) return -1; return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Creates a PEmitter to be identical to another, by deep copy. - int PEmitter::Create(const PEmitter &reference) - { + int PEmitter::Create(const PEmitter& reference) { MOSParticle::Create(reference); for (auto itr = reference.m_EmissionList.begin(); itr != reference.m_EmissionList.end(); ++itr) { @@ -110,7 +104,6 @@ namespace RTE { return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: ReadProperty ////////////////////////////////////////////////////////////////////////////////////////// @@ -119,16 +112,15 @@ namespace RTE { // is called. If the property isn't recognized by any of the base classes, // false is returned, and the reader's position is untouched. - int PEmitter::ReadProperty(const std::string_view &propName, Reader &reader) - { + int PEmitter::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return MOSParticle::ReadProperty(propName, reader)); - + MatchProperty("AddEmission", - { - Emission emission; - reader >> emission; - m_EmissionList.push_back(emission); - }); + { + Emission emission; + reader >> emission; + m_EmissionList.push_back(emission); + }); MatchProperty("EmissionSound", { reader >> m_EmissionSound; }); MatchProperty("BurstSound", { reader >> m_BurstSound; }); MatchProperty("EndSound", { reader >> m_EndSound; }); @@ -136,25 +128,25 @@ namespace RTE { MatchProperty("EmissionCount", { reader >> m_EmitCount; }); MatchProperty("EmissionCountLimit", { reader >> m_EmitCountLimit; }); MatchProperty("ParticlesPerMinute", - { - float ppm; - reader >> ppm; - // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility - for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) - (*eItr).m_PPM = ppm / m_EmissionList.size(); - }); + { + float ppm; + reader >> ppm; + // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility + for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) + (*eItr).m_PPM = ppm / m_EmissionList.size(); + }); MatchProperty("NegativeThrottleMultiplier", { reader >> m_NegativeThrottleMultiplier; }); MatchProperty("PositiveThrottleMultiplier", { reader >> m_PositiveThrottleMultiplier; }); MatchProperty("Throttle", { reader >> m_Throttle; }); MatchProperty("EmissionsIgnoreThis", { reader >> m_EmissionsIgnoreThis; }); MatchProperty("BurstSize", - { - int burstSize; - reader >> burstSize; - // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility - for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) - (*eItr).m_BurstSize = std::ceil((float)burstSize / (float)m_EmissionList.size()); - }); + { + int burstSize; + reader >> burstSize; + // Go through all emissions and set the rate so that it emulates the way it used to work, for mod backwards compatibility + for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) + (*eItr).m_BurstSize = std::ceil((float)burstSize / (float)m_EmissionList.size()); + }); MatchProperty("BurstScale", { reader >> m_BurstScale; }); MatchProperty("BurstSpacing", { reader >> m_BurstSpacing; }); MatchProperty("BurstTriggered", { reader >> m_BurstTriggered; }); @@ -165,23 +157,20 @@ namespace RTE { MatchProperty("SustainBurstSound", { reader >> m_SustainBurstSound; }); MatchProperty("BurstSoundFollowsEmitter", { reader >> m_BurstSoundFollowsEmitter; }); MatchProperty("LoudnessOnEmit", { reader >> m_LoudnessOnEmit; }); - + EndPropertyList; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Save ////////////////////////////////////////////////////////////////////////////////////////// // Description: Saves the complete state of this PEmitter with a Writer for // later recreation with Create(Reader &reader); - int PEmitter::Save(Writer &writer) const - { + int PEmitter::Save(Writer& writer) const { MOSParticle::Save(writer); - for (auto itr = m_EmissionList.begin(); itr != m_EmissionList.end(); ++itr) - { + for (auto itr = m_EmissionList.begin(); itr != m_EmissionList.end(); ++itr) { writer.NewProperty("AddEmission"); writer << *itr; } @@ -229,14 +218,12 @@ namespace RTE { return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the PEmitter object. - void PEmitter::Destroy(bool notInherited) - { + void PEmitter::Destroy(bool notInherited) { // Stop playback of sounds gracefully if (m_EmissionSound.IsBeingPlayed()) m_EndSound.Play(m_Pos); @@ -254,55 +241,46 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Method: ResetEmissionTimers ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Reset the timers of all emissions so they will start/stop at the + // Description: Reset the timers of all emissions so they will start/stop at the // correct relative offsets from now. - void PEmitter::ResetEmissionTimers() - { + void PEmitter::ResetEmissionTimers() { m_LastEmitTmr.Reset(); for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) (*eItr).ResetEmissionTimers(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: EnableEmission ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets this PEmitter to start emitting at the set rate, or to stop. - void PEmitter::EnableEmission(bool enable) - { - if (!m_EmitEnabled && enable) - { + void PEmitter::EnableEmission(bool enable) { + if (!m_EmitEnabled && enable) { m_LastEmitTmr.Reset(); // Reset counter m_EmitCount = 0; // Reset animation - //m_Frame = 0; + // m_Frame = 0; } m_EmitEnabled = enable; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: EstimateImpulse ////////////////////////////////////////////////////////////////////////////////////////// // Description: Calculates the forces this emitter applies on any parent. - float PEmitter::EstimateImpulse(bool burst) - { + float PEmitter::EstimateImpulse(bool burst) { // Calculate the impulse generated by the emissions, once and store the result - if ((!burst && m_AvgImpulse < 0) || (burst && m_AvgBurstImpulse < 0)) - { + if ((!burst && m_AvgImpulse < 0) || (burst && m_AvgBurstImpulse < 0)) { float impulse = 0; float velMin, velMax, velRange, spread; // Go through all emissions and emit them according to their respective rates - for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) - { + for (auto eItr = m_EmissionList.begin(); eItr != m_EmissionList.end(); ++eItr) { // Only check emissions that push the emitter - if (eItr->PushesEmitter()) - { + if (eItr->PushesEmitter()) { double emissions = eItr->GetRate() * g_TimerMan.GetDeltaTimeSecs() / 60.0f; if (burst) emissions *= eItr->GetBurstSize(); @@ -310,7 +288,7 @@ namespace RTE { velMin = std::min(eItr->GetMinVelocity(), eItr->GetMaxVelocity()); velMax = std::max(eItr->GetMinVelocity(), eItr->GetMaxVelocity()); velRange = (velMax - velMin) * 0.5; - spread = std::max(static_cast(c_PI)-eItr->GetSpread(), .0f) / c_PI; // A large spread will cause the forces to cancel eachother out + spread = std::max(static_cast(c_PI) - eItr->GetSpread(), .0f) / c_PI; // A large spread will cause the forces to cancel eachother out // Add to accumulative recoil impulse generated, F = m * a. impulse += (velMin + velRange) * spread * eItr->m_pEmission->GetMass() * emissions; @@ -321,7 +299,6 @@ namespace RTE { m_AvgBurstImpulse = impulse; else m_AvgImpulse = impulse; - } // Scale the emission rate up or down according to the appropriate throttle multiplier. @@ -333,7 +310,6 @@ namespace RTE { return m_AvgImpulse * throttleFactor; } - /* ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: GibThis @@ -354,23 +330,20 @@ namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates this PEmitter. Supposed to be done every frame. - void PEmitter::Update() - { + void PEmitter::Update() { MOSParticle::Update(); if (m_BurstSoundFollowsEmitter) { m_BurstSound.SetPosition(m_Pos); } - if (m_EmitEnabled) - { - if (!m_WasEmitting) - { + if (m_EmitEnabled) { + if (!m_WasEmitting) { // Start playing the sound m_EmissionSound.Play(m_Pos); // Reset the timers of all emissions so they will start/stop at the correct relative offsets from now - for (Emission& emission : m_EmissionList) { + for (Emission& emission: m_EmissionList) { emission.ResetEmissionTimers(); } } @@ -380,14 +353,13 @@ namespace RTE { // Get the parent root of this PEmitter // TODO: Potentially get this once outside instead, like in attach/detach") - MovableObject *pRootParent = GetRootParent(); + MovableObject* pRootParent = GetRootParent(); // Scale the emission rate up or down according to the appropriate throttle multiplier. float throttleFactor = GetThrottleFactor(); m_FlashScale = throttleFactor; // Check burst triggering against whether the spacing is fulfilled - if (m_BurstTriggered && (m_BurstSpacing <= 0 || m_BurstTimer.IsPastSimMS(m_BurstSpacing))) - { + if (m_BurstTriggered && (m_BurstSpacing <= 0 || m_BurstTimer.IsPastSimMS(m_BurstSpacing))) { // Play burst sound m_BurstSound.Play(m_Pos); // Start timing until next burst @@ -400,21 +372,18 @@ namespace RTE { int emissions = 0; float velMin, velRange, spread; double currentPPM, SPE; - MovableObject *pParticle = 0; + MovableObject* pParticle = 0; Vector parentVel, emitVel, pushImpulses; // Go through all emissions and emit them according to their respective rates - for (Emission &emission : m_EmissionList) - { + for (Emission& emission: m_EmissionList) { // Make sure the emissions only happen between the start time and end time - if (emission.IsEmissionTime()) - { + if (emission.IsEmissionTime()) { // Apply the throttle factor to the emission rate currentPPM = emission.GetRate() * throttleFactor; emissions = 0; // Only do all this if the PPM is acutally above zero - if (currentPPM > 0) - { + if (currentPPM > 0) { // Calculate secs per emission SPE = 60.0 / currentPPM; @@ -437,17 +406,16 @@ namespace RTE { emitVel.Reset(); parentVel = pRootParent->GetVel() * emission.InheritsVelocity(); - for (int i = 0; i < emissions; ++i) - { + for (int i = 0; i < emissions; ++i) { velMin = emission.GetMinVelocity() * (m_BurstTriggered ? m_BurstScale : 1.0); velRange = emission.GetMaxVelocity() - emission.GetMinVelocity() * (m_BurstTriggered ? m_BurstScale : 1.0); spread = emission.GetSpread() * (m_BurstTriggered ? m_BurstScale : 1.0); // Make a copy after the reference particle - pParticle = dynamic_cast(emission.GetEmissionParticlePreset()->Clone()); + pParticle = dynamic_cast(emission.GetEmissionParticlePreset()->Clone()); // Set up its position and velocity according to the parameters of this. // Emission point offset not set if (m_EmissionOffset.IsZero()) - pParticle->SetPos(m_Pos/*Vector(m_Pos.m_X + 5 * NormalRand(), m_Pos.m_Y + 5 * NormalRand())*/); + pParticle->SetPos(m_Pos /*Vector(m_Pos.m_X + 5 * NormalRand(), m_Pos.m_Y + 5 * NormalRand())*/); else pParticle->SetPos(m_Pos + RotateOffset(m_EmissionOffset)); // TODO: Optimize making the random angles!") @@ -456,7 +424,9 @@ namespace RTE { emitVel = RotateOffset(emitVel); pParticle->SetVel(parentVel + emitVel); - if (pParticle->GetLifetime() != 0) { pParticle->SetLifetime(std::max(static_cast(pParticle->GetLifetime() * (1.0F + (emission.GetLifeVariation() * RandomNormalNum()))), 1)); } + if (pParticle->GetLifetime() != 0) { + pParticle->SetLifetime(std::max(static_cast(pParticle->GetLifetime() * (1.0F + (emission.GetLifeVariation() * RandomNormalNum()))), 1)); + } pParticle->SetTeam(m_Team); pParticle->SetIgnoresTeamHits(true); @@ -494,28 +464,27 @@ namespace RTE { m_WasEmitting = true; } // Do stuff to stop emission - else if (m_WasEmitting) - { + else if (m_WasEmitting) { m_EmissionSound.Stop(); - if (!m_SustainBurstSound) { m_BurstSound.Stop(); } + if (!m_SustainBurstSound) { + m_BurstSound.Stop(); + } m_EndSound.Play(m_Pos); m_WasEmitting = false; } } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws this PEmitter's current graphical representation to a // BITMAP of choice. - void PEmitter::Draw(BITMAP *pTargetBitmap, - const Vector &targetPos, - DrawMode mode, - bool onlyPhysical) const - { + void PEmitter::Draw(BITMAP* pTargetBitmap, + const Vector& targetPos, + DrawMode mode, + bool onlyPhysical) const { MOSParticle::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/PEmitter.h b/Source/Entities/PEmitter.h index 3749780ef..8395f77cb 100644 --- a/Source/Entities/PEmitter.h +++ b/Source/Entities/PEmitter.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -18,32 +17,27 @@ #include "Emission.h" #include "SoundContainer.h" -namespace RTE -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: PEmitter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A particle MO that creates and emits particle MOs. -// Parent(s): MOSParticle. -// Class history: 02/29/2004 PEmitter created. - -class PEmitter : public MOSParticle { - +namespace RTE { ////////////////////////////////////////////////////////////////////////////////////////// - // Public member variable, method and friend function declarations + // Class: PEmitter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A particle MO that creates and emits particle MOs. + // Parent(s): MOSParticle. + // Class history: 02/29/2004 PEmitter created. -public: + class PEmitter : public MOSParticle { - friend struct EntityLuaBindings; + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations - // Concrete allocation and cloning definitions - EntityAllocation(PEmitter); - SerializableOverrideMethods; - ClassInfoGetters; + public: + friend struct EntityLuaBindings; + // Concrete allocation and cloning definitions + EntityAllocation(PEmitter); + SerializableOverrideMethods; + ClassInfoGetters; ////////////////////////////////////////////////////////////////////////////////////////// // Constructor: PEmitter @@ -54,545 +48,527 @@ class PEmitter : public MOSParticle { PEmitter() { Clear(); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~PEmitter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a PEmitter object before deletion + // from system memory. + // Arguments: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Destructor: ~PEmitter - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Destructor method used to clean up a PEmitter object before deletion - // from system memory. - // Arguments: None. - - ~PEmitter() override { Destroy(true); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Makes the PEmitter object ready for use. - // Arguments: None. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create() override; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Creates a PEmitter to be identical to another, by deep copy. - // Arguments: A reference to the PEmitter to deep copy. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create(const PEmitter &reference); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Reset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Resets the entire PEmitter, including its inherited members, to their - // default settings or values. - // Arguments: None. - // Return value: None. - - void Reset() override { Clear(); MOSParticle::Reset(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Destroy - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Destroys and resets (through Clear()) the SceneLayer object. - // Arguments: Whether to only destroy the members defined in this derived class, or - // to destroy all inherited members also. - // Return value: None. - - void Destroy(bool notInherited = false) override; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: IsEmitting - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Indicates whether this PEmitter is currently enabled and emitting. - // Arguments: None. - // Return value: Whether it's emitting or not. - - bool IsEmitting() const { return m_EmitEnabled; } - - /// - /// Returns whether this emitter was emitting last frame. - /// - /// Whether this emitter was emitting last frame. - bool WasEmitting() const { return m_WasEmitting; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: ResetEmissionTimers - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Reset the timers of all emissions so they will start/stop at the - // correct relative offsets from now. - // Arguments: None. - // Return value: None. - - void ResetEmissionTimers(); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: EnableEmission - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets this PEmitter to start emitting at the set rate, or to stop. - // Arguments: Whether to enable or disable emission. - // Return value: None. - - void EnableEmission(bool enable = true); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: EstimateImpulse - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Calculates the forces this emitter applies on any parent. - // Arguments: Whether to calculate a burst update or not. - // Return value: The approximate impulse generated by the emitter. - - float EstimateImpulse(bool burst = false); - - - /* - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetEmitRate - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the rate at which this PEmitter emits its particles. - // Arguments: None. - // Return value: A float with the rate in #/min. - - float GetEmitRate() const { return m_PPM; } - + ~PEmitter() override { Destroy(true); } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetBurstCount - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the number of particles that will be emitted in one shot upon - // a triggered burst of this PEmitter. - // Arguments: None. - // Return value: The number of emitted particles a burst should have. 0 means burst - // are disabled. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the PEmitter object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. - int GetBurstCount() const { return m_BurstSize; } - */ + int Create() override; - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetBurstScale - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the scale factor that will be applied to the regular spread and - // emission velocity to get the burst particle parameters. - // Arguments: None. - // Return value: The scale factor. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a PEmitter to be identical to another, by deep copy. + // Arguments: A reference to the PEmitter to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. - float GetBurstScale() const { return m_BurstScale; } + int Create(const PEmitter& reference); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire PEmitter, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetEmitAngle - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the angle of direction that the emitted particles will be shot at. - // Arguments: None. - // Return value: A float with the angle in radians. + void Reset() override { + Clear(); + MOSParticle::Reset(); + } - float GetEmitAngle() const { return m_EmitAngle.GetRadAngle(); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneLayer object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + void Destroy(bool notInherited = false) override; - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetEmitVector - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: A vector in the direction, including the rotation of the emitter, that - // the emitted particles will be shot at. - // Arguments: None. - // Return value: A unit vector. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEmitting + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this PEmitter is currently enabled and emitting. + // Arguments: None. + // Return value: Whether it's emitting or not. - Vector GetEmitVector() const { return Vector(1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } + bool IsEmitting() const { return m_EmitEnabled; } + /// + /// Returns whether this emitter was emitting last frame. + /// + /// Whether this emitter was emitting last frame. + bool WasEmitting() const { return m_WasEmitting; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetRecoilVector - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: A vector in the opposite direction, including the rotation of the - // emitter, that the emitted particles will be shot at. - // Arguments: None. - // Return value: A unit vector. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResetEmissionTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reset the timers of all emissions so they will start/stop at the + // correct relative offsets from now. + // Arguments: None. + // Return value: None. - Vector GetRecoilVector() const { return Vector(-1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } + void ResetEmissionTimers(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableEmission + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this PEmitter to start emitting at the set rate, or to stop. + // Arguments: Whether to enable or disable emission. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetBurstSpacing - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the BurstSpacing for this emitter. - // Arguments: None. - // Return value: The BurstSpacing in ms. + void EnableEmission(bool enable = true); - float GetBurstSpacing() const { return m_BurstSpacing; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EstimateImpulse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the forces this emitter applies on any parent. + // Arguments: Whether to calculate a burst update or not. + // Return value: The approximate impulse generated by the emitter. - /* - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetEmitSpread - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the angle spread of velocity of the emitted MO's to each side of - // the angle of emission of this PEmitter. - // Arguments: None. - // Return value: A float with the spread in r's. PI/2 would mean that MO's fly out to - // one side only, with the m_EmitAngle defining the middle of that half - // circle. + float EstimateImpulse(bool burst = false); - float GetEmitSpread() const { return m_Spread; } + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitRate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rate at which this PEmitter emits its particles. + // Arguments: None. + // Return value: A float with the rate in #/min. + float GetEmitRate() const { return m_PPM; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetEmitVelMin - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the min end of the range the velocity of a particle being emitted - // by this PEmitter can have. - // Arguments: None. - // Return value: A float with the min vel possible for an emitted particle. - float GetEmitVelMin() const { return m_MinVelocity; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBurstCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of particles that will be emitted in one shot upon + // a triggered burst of this PEmitter. + // Arguments: None. + // Return value: The number of emitted particles a burst should have. 0 means burst + // are disabled. + int GetBurstCount() const { return m_BurstSize; } + */ - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetEmitVelMax - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the max end of the range the velocity of a particle being emitted - // by this PEmitter can have. - // Arguments: None. - // Return value: A float with the max vel possible for an emitted particle. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBurstScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the scale factor that will be applied to the regular spread and + // emission velocity to get the burst particle parameters. + // Arguments: None. + // Return value: The scale factor. - float GetEmitVelMax() const { return m_MaxVelocity; } - */ + float GetBurstScale() const { return m_BurstScale; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetThrottle - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the normalized throttle scalar which controls how to affect the - // emission rate as per the emisison rate range. Depricated for Lua, use - // the Throttle property instead. - // Arguments: None. - // Return value: A float with the normalized throttle scalar. 1.0 means max throttle, - // 0 means normal, -1.0 means least emission rate. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the angle of direction that the emitted particles will be shot at. + // Arguments: None. + // Return value: A float with the angle in radians. - float GetThrottle() const { return m_Throttle; } + float GetEmitAngle() const { return m_EmitAngle.GetRadAngle(); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitVector + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A vector in the direction, including the rotation of the emitter, that + // the emitted particles will be shot at. + // Arguments: None. + // Return value: A unit vector. - /// - /// Gets the adjusted throttle multiplier that is factored into the emission rate of this PEmitter. - /// - /// The throttle strength as a multiplier. - float GetThrottleFactor() const { return LERP(-1.0f, 1.0f, m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, m_Throttle); } + Vector GetEmitVector() const { return Vector(1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } - /// - /// Gets the throttle value that will achieve a given throttle factor that is factored into the emission rate of this AEmitter. - /// - /// The throttle value that will achieve the given throttle factor. - float GetThrottleForThrottleFactor(float throttleFactor) const { return LERP(m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, -1.0f, 1.0f, throttleFactor); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRecoilVector + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A vector in the opposite direction, including the rotation of the + // emitter, that the emitted particles will be shot at. + // Arguments: None. + // Return value: A unit vector. - /* - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetEmitRate - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the rate at which this PEmitter emits its particles. - // Arguments: A float with the rate in #/min. - // Return value: None. + Vector GetRecoilVector() const { return Vector(-1, 0).RadRotate(m_HFlipped ? c_PI + m_Rotation.GetRadAngle() - m_EmitAngle.GetRadAngle() : m_Rotation.GetRadAngle() + m_EmitAngle.GetRadAngle()); } - void SetEmitRate(const float rate) { m_PPM = rate; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBurstSpacing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the BurstSpacing for this emitter. + // Arguments: None. + // Return value: The BurstSpacing in ms. + float GetBurstSpacing() const { return m_BurstSpacing; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetBurstCount - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the number of particles that will be emitted in one shot upon - // a triggered burst of this PEmitter. - // Arguments: The number of emitted particles a burst should have. 0 means burst - // are disabled. - // Return value: None. + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitSpread + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the angle spread of velocity of the emitted MO's to each side of + // the angle of emission of this PEmitter. + // Arguments: None. + // Return value: A float with the spread in r's. PI/2 would mean that MO's fly out to + // one side only, with the m_EmitAngle defining the middle of that half + // circle. - void SetBurstCount(const int count) { m_BurstSize = count; } - */ + float GetEmitSpread() const { return m_Spread; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetBurstScale - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the scale factor that will be applied to the regular spread and - // emission velocity to get the burst particle parameters. - // Arguments: The scale factor. - // Return value: None. - void SetBurstScale(const float scale) { m_BurstScale = scale; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitVelMin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the min end of the range the velocity of a particle being emitted + // by this PEmitter can have. + // Arguments: None. + // Return value: A float with the min vel possible for an emitted particle. + float GetEmitVelMin() const { return m_MinVelocity; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetBurstSpacing - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the BurstSpacing for this emitter. - // Arguments: The BurstSpacing in ms. - // Return value: None. - void SetBurstSpacing(const float spacing) { m_BurstSpacing = spacing; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEmitVelMax + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the max end of the range the velocity of a particle being emitted + // by this PEmitter can have. + // Arguments: None. + // Return value: A float with the max vel possible for an emitted particle. + float GetEmitVelMax() const { return m_MaxVelocity; } + */ - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetFlashScale - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the display scale factor of the flash effect. This is purely - // visual. - // Arguments: The scale factor of the flash draw. - // Return value: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetThrottle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the normalized throttle scalar which controls how to affect the + // emission rate as per the emisison rate range. Depricated for Lua, use + // the Throttle property instead. + // Arguments: None. + // Return value: A float with the normalized throttle scalar. 1.0 means max throttle, + // 0 means normal, -1.0 means least emission rate. - void SetFlashScale(float flashScale = 1.0f) { m_FlashScale = flashScale; } + float GetThrottle() const { return m_Throttle; } + /// + /// Gets the adjusted throttle multiplier that is factored into the emission rate of this PEmitter. + /// + /// The throttle strength as a multiplier. + float GetThrottleFactor() const { return LERP(-1.0f, 1.0f, m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, m_Throttle); } - /// - /// Gets the display scale factor of the flash effect. This is purely visual. - /// - /// The scale factor of the flash draw. - float GetFlashScale() const { return m_FlashScale; } + /// + /// Gets the throttle value that will achieve a given throttle factor that is factored into the emission rate of this AEmitter. + /// + /// The throttle value that will achieve the given throttle factor. + float GetThrottleForThrottleFactor(float throttleFactor) const { return LERP(m_NegativeThrottleMultiplier, m_PositiveThrottleMultiplier, -1.0f, 1.0f, throttleFactor); } + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitRate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the rate at which this PEmitter emits its particles. + // Arguments: A float with the rate in #/min. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetEmitAngle - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the angle of direction that the emitted particles will be shot at. - // Arguments: A float with the angle in radians. - // Return value: None. + void SetEmitRate(const float rate) { m_PPM = rate; } - void SetEmitAngle(const float angle) { m_EmitAngle.SetRadAngle(angle); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the number of particles that will be emitted in one shot upon + // a triggered burst of this PEmitter. + // Arguments: The number of emitted particles a burst should have. 0 means burst + // are disabled. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetThrottle - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the normalized throttle scalar which controls how to affect the - // emission rate as per the emisison rate range. - // Arguments: A float with the normalized throttle scalar. 1.0 means max throttle, - // 0 means normal, -1.0 means least emission rate. - // Return value: None. + void SetBurstCount(const int count) { m_BurstSize = count; } + */ - void SetThrottle(float throttle) { m_Throttle = throttle > 1.0f ? 1.0f : (throttle < -1.0f ? -1.0f : throttle); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the scale factor that will be applied to the regular spread and + // emission velocity to get the burst particle parameters. + // Arguments: The scale factor. + // Return value: None. - /* - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetEmitSpread - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the angle spread of velocity of the emitted MO's to each side of - // angle of emission of this PEmitter. - // Arguments: A float with the spread in r's. PI/2 would mean that MO's fly out to - // one side only, with the m_EmitAngle defining the middle of that half - // circle. - // Return value: None. + void SetBurstScale(const float scale) { m_BurstScale = scale; } - void SetEmitSpread(const float spread) { m_Spread = spread; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBurstSpacing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the BurstSpacing for this emitter. + // Arguments: The BurstSpacing in ms. + // Return value: None. + void SetBurstSpacing(const float spacing) { m_BurstSpacing = spacing; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetEmitVelMin - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the min end of the range the velocity of a particle being emitted - // by this PEmitter can have. - // Arguments: A float with the min vel possible for an emitted particle. - // Return value: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFlashScale + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the display scale factor of the flash effect. This is purely + // visual. + // Arguments: The scale factor of the flash draw. + // Return value: None. - void SetEmitVelMin(const float minVel) { m_MinVelocity = minVel; } + void SetFlashScale(float flashScale = 1.0f) { m_FlashScale = flashScale; } + /// + /// Gets the display scale factor of the flash effect. This is purely visual. + /// + /// The scale factor of the flash draw. + float GetFlashScale() const { return m_FlashScale; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetEmitVelMax - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the max end of the range the velocity of a particle being emitted - // by this PEmitter can have. - // Arguments: A float with the max vel possible for an emitted particle. - // Return value: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the angle of direction that the emitted particles will be shot at. + // Arguments: A float with the angle in radians. + // Return value: None. - void SetEmitVelMax(const float maxVel) { m_MaxVelocity = maxVel; } - */ + void SetEmitAngle(const float angle) { m_EmitAngle.SetRadAngle(angle); } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: TriggerBurst - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Triggers a one-shot burst of emissions in the number that has - // previously been set. The burst will happen during the next Update of - // this PEmitter. - // Arguments: None. - // Return value: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetThrottle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the normalized throttle scalar which controls how to affect the + // emission rate as per the emisison rate range. + // Arguments: A float with the normalized throttle scalar. 1.0 means max throttle, + // 0 means normal, -1.0 means least emission rate. + // Return value: None. - void TriggerBurst() { m_BurstTriggered = true; } + void SetThrottle(float throttle) { m_Throttle = throttle > 1.0f ? 1.0f : (throttle < -1.0f ? -1.0f : throttle); } + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitSpread + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the angle spread of velocity of the emitted MO's to each side of + // angle of emission of this PEmitter. + // Arguments: A float with the spread in r's. PI/2 would mean that MO's fly out to + // one side only, with the m_EmitAngle defining the middle of that half + // circle. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: CanTriggerBurst - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Checks if it is possible to trigger a one-shot burst of emissions during - // the next Update of this PEmitter. - // Arguments: None. - // Return value: If it is possible to trigger a burst. + void SetEmitSpread(const float spread) { m_Spread = spread; } - bool CanTriggerBurst() { if (m_BurstSpacing <= 0 || m_BurstTimer.IsPastSimMS(m_BurstSpacing)) return true; return false; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitVelMin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the min end of the range the velocity of a particle being emitted + // by this PEmitter can have. + // Arguments: A float with the min vel possible for an emitted particle. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: IsSetToBurst - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Indicates whether this PEmitter is set to burst next update or not. - // Arguments: None. - // Return value: Whether a burst is gonna happen or not.. + void SetEmitVelMin(const float minVel) { m_MinVelocity = minVel; } - bool IsSetToBurst() const { return m_BurstTriggered; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEmitVelMax + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the max end of the range the velocity of a particle being emitted + // by this PEmitter can have. + // Arguments: A float with the max vel possible for an emitted particle. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: AlarmOnEmit - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Registers a new AlarmEvent if this emitter has a loudness above zero. - // Arguments: Team that will ignore this AlarmEvent. - // Return value: None. + void SetEmitVelMax(const float maxVel) { m_MaxVelocity = maxVel; } + */ - void AlarmOnEmit(int Team) const { if (m_LoudnessOnEmit > 0) g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, Team, m_LoudnessOnEmit)); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TriggerBurst + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Triggers a one-shot burst of emissions in the number that has + // previously been set. The burst will happen during the next Update of + // this PEmitter. + // Arguments: None. + // Return value: None. + void TriggerBurst() { m_BurstTriggered = true; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: ResetAllTimers - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Resest all the timers used by this. Can be emitters, etc. This is to - // prevent backed up emissions to come out all at once while this has been - // held dormant in an inventory. - // Arguments: None. - // Return value: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CanTriggerBurst + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if it is possible to trigger a one-shot burst of emissions during + // the next Update of this PEmitter. + // Arguments: None. + // Return value: If it is possible to trigger a burst. - void ResetAllTimers() override { m_BurstTimer.Reset(); m_LastEmitTmr.Reset(); } + bool CanTriggerBurst() { + if (m_BurstSpacing <= 0 || m_BurstTimer.IsPastSimMS(m_BurstSpacing)) + return true; + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsSetToBurst + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this PEmitter is set to burst next update or not. + // Arguments: None. + // Return value: Whether a burst is gonna happen or not.. - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Update - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Updates this MovableObject. Supposed to be done every frame. - // Arguments: None. - // Return value: None. + bool IsSetToBurst() const { return m_BurstTriggered; } - void Update() override; - void PostUpdate() override { MOSParticle::PostUpdate(); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AlarmOnEmit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers a new AlarmEvent if this emitter has a loudness above zero. + // Arguments: Team that will ignore this AlarmEvent. + // Return value: None. + void AlarmOnEmit(int Team) const { + if (m_LoudnessOnEmit > 0) + g_MovableMan.RegisterAlarmEvent(AlarmEvent(m_Pos, Team, m_LoudnessOnEmit)); + } - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Draw - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Draws this PEmitter's current graphical representation to a - // BITMAP of choice. - // Arguments: A pointer to a BITMAP to draw on. - // The absolute position of the target bitmap's upper left corner in the Scene. - // In which mode to draw in. See the DrawMode enumeration for the modes. - // Whether to not draw any extra 'ghost' items of this MovableObject, - // indicator arrows or hovering HUD text and so on. - // Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; - - /// - /// Gets the number of emissions left before emitter is disabled. - /// - /// The number of emissions left before emitter is disabled. - long GetEmitCountLimit() const { return m_EmitCountLimit; } - - /// - /// Sets the number of emissions left before emitter is disabled. - /// - /// New number of emissions left. - void SetEmitCountLimit(long newValue) { m_EmitCountLimit = newValue; } - - /// - /// Returns whether this emitter just started emitting this frame. - /// - /// Whether this emitter just started emitting this frame. - bool JustStartedEmitting() const { return !m_WasEmitting && m_EmitEnabled; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ResetAllTimers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resest all the timers used by this. Can be emitters, etc. This is to + // prevent backed up emissions to come out all at once while this has been + // held dormant in an inventory. + // Arguments: None. + // Return value: None. - ////////////////////////////////////////////////////////////////////////////////////////// - // Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - - // The list of MO instances that get emitted - std::vector m_EmissionList; - // Sounds - SoundContainer m_EmissionSound; - SoundContainer m_BurstSound; - SoundContainer m_EndSound; - // Whether emitting is currently enabled or not. - bool m_EmitEnabled; - // Whether or not the it was emitting last frame or not. - bool m_WasEmitting; - // The number of emissions emitted since emission was last enabled - long m_EmitCount; - // The max number of emissions to emit per emit being enabled - long m_EmitCountLimit; - float m_NegativeThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is negative. Relative to the absolute throttle value. - float m_PositiveThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is positive. Relative to the absolute throttle value. - // The normalized throttle which controls the MSPE between 1.0 * m_MSPERange and -1.0 * m_MSPERange. 0 means emit the regular m_PPM amount. - float m_Throttle; - // Whether or not this' emissions ignore hits with itself, even if they are set to hit other MOs. - bool m_EmissionsIgnoreThis; - // The scale factor that will be applied to the regular spread and emission - // velocity to get the the burst particle parameters. - float m_BurstScale; - // Indicates that a burst is set to happen during the next Update. - bool m_BurstTriggered; - // The shortest possible time between bursts, in ms - float m_BurstSpacing; - // Measures the shortest possible time between bursts - Timer m_BurstTimer; - // The angle of the direction the emitted particles will head in. - // The m_Roataion of this PEmitter will be added to this angle. - Matrix m_EmitAngle; - // Offset of the emission point from this' sprite center, which gets rotated with this - Vector m_EmissionOffset; - // Timer for timing how long ago the last particle was emitted. 0 means no limit. - Timer m_LastEmitTmr; - // Flash offset. - // Vector m_FlashOff; nah dont need it - // Flash display scale - float m_FlashScale; - // How large impulse this emitter generates when bursting - float m_AvgBurstImpulse; - // How large impulse this emitter generates when firing - float m_AvgImpulse; - // How far this is audiable (in screens) when emitting as a jetpack or craft engine - float m_LoudnessOnEmit; - // Whether to only display flash on bursts, and not on any emission frame. - bool m_FlashOnlyOnBurst; - // Whether the burst sound should always play until completion, or whether it stops when this emitter stops emitting - bool m_SustainBurstSound; - // Whether the burst sound follows the emitter - bool m_BurstSoundFollowsEmitter; + void ResetAllTimers() override { + m_BurstTimer.Reset(); + m_LastEmitTmr.Reset(); + } - ////////////////////////////////////////////////////////////////////////////////////////// - // Private member variable and method declarations + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this MovableObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. -private: + void Update() override; + void PostUpdate() override { MOSParticle::PostUpdate(); } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this PEmitter's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // indicator arrows or hovering HUD text and so on. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + + /// + /// Gets the number of emissions left before emitter is disabled. + /// + /// The number of emissions left before emitter is disabled. + long GetEmitCountLimit() const { return m_EmitCountLimit; } + + /// + /// Sets the number of emissions left before emitter is disabled. + /// + /// New number of emissions left. + void SetEmitCountLimit(long newValue) { m_EmitCountLimit = newValue; } + + /// + /// Returns whether this emitter just started emitting this frame. + /// + /// Whether this emitter just started emitting this frame. + bool JustStartedEmitting() const { return !m_WasEmitting && m_EmitEnabled; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Clear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Clears all the member variables of this PEmitter, effectively - // resetting the members of this abstraction level only. - // Arguments: None. - // Return value: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + + // The list of MO instances that get emitted + std::vector m_EmissionList; + // Sounds + SoundContainer m_EmissionSound; + SoundContainer m_BurstSound; + SoundContainer m_EndSound; + // Whether emitting is currently enabled or not. + bool m_EmitEnabled; + // Whether or not the it was emitting last frame or not. + bool m_WasEmitting; + // The number of emissions emitted since emission was last enabled + long m_EmitCount; + // The max number of emissions to emit per emit being enabled + long m_EmitCountLimit; + float m_NegativeThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is negative. Relative to the absolute throttle value. + float m_PositiveThrottleMultiplier; //!< The multiplier applied to the emission rate when throttle is positive. Relative to the absolute throttle value. + // The normalized throttle which controls the MSPE between 1.0 * m_MSPERange and -1.0 * m_MSPERange. 0 means emit the regular m_PPM amount. + float m_Throttle; + // Whether or not this' emissions ignore hits with itself, even if they are set to hit other MOs. + bool m_EmissionsIgnoreThis; + // The scale factor that will be applied to the regular spread and emission + // velocity to get the the burst particle parameters. + float m_BurstScale; + // Indicates that a burst is set to happen during the next Update. + bool m_BurstTriggered; + // The shortest possible time between bursts, in ms + float m_BurstSpacing; + // Measures the shortest possible time between bursts + Timer m_BurstTimer; + // The angle of the direction the emitted particles will head in. + // The m_Roataion of this PEmitter will be added to this angle. + Matrix m_EmitAngle; + // Offset of the emission point from this' sprite center, which gets rotated with this + Vector m_EmissionOffset; + // Timer for timing how long ago the last particle was emitted. 0 means no limit. + Timer m_LastEmitTmr; + // Flash offset. + // Vector m_FlashOff; nah dont need it + // Flash display scale + float m_FlashScale; + // How large impulse this emitter generates when bursting + float m_AvgBurstImpulse; + // How large impulse this emitter generates when firing + float m_AvgImpulse; + // How far this is audiable (in screens) when emitting as a jetpack or craft engine + float m_LoudnessOnEmit; + // Whether to only display flash on bursts, and not on any emission frame. + bool m_FlashOnlyOnBurst; + // Whether the burst sound should always play until completion, or whether it stops when this emitter stops emitting + bool m_SustainBurstSound; + // Whether the burst sound follows the emitter + bool m_BurstSoundFollowsEmitter; - void Clear(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this PEmitter, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. - // Disallow the use of some implicit methods. - PEmitter(const PEmitter &reference) = delete; - PEmitter & operator=(const PEmitter &rhs) = delete; + void Clear(); -}; + // Disallow the use of some implicit methods. + PEmitter(const PEmitter& reference) = delete; + PEmitter& operator=(const PEmitter& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/PieMenu.cpp b/Source/Entities/PieMenu.cpp index 324610846..d25f8bbbb 100644 --- a/Source/Entities/PieMenu.cpp +++ b/Source/Entities/PieMenu.cpp @@ -17,35 +17,31 @@ namespace RTE { ConcreteClassInfo(PieMenu, Entity, 20); const std::unordered_map PieMenu::c_IconSeparatorModeMap = { - {"Line", IconSeparatorMode::Line}, - {"Circle", IconSeparatorMode::Circle}, - {"Square", IconSeparatorMode::Square} - }; + {"Line", IconSeparatorMode::Line}, + {"Circle", IconSeparatorMode::Circle}, + {"Square", IconSeparatorMode::Square}}; const std::unordered_map PieMenu::c_ControlStateDirections = { - {ControlState::PRESS_UP, Directions::Up}, - {ControlState::PRESS_DOWN, Directions::Down}, - {ControlState::PRESS_LEFT, Directions::Left}, - {ControlState::PRESS_RIGHT, Directions::Right} - }; + {ControlState::PRESS_UP, Directions::Up}, + {ControlState::PRESS_DOWN, Directions::Down}, + {ControlState::PRESS_LEFT, Directions::Left}, + {ControlState::PRESS_RIGHT, Directions::Right}}; const std::unordered_map PieMenu::c_OppositeDirections = { - {Directions::Up, Directions::Down}, - {Directions::Down, Directions::Up}, - {Directions::Left, Directions::Right}, - {Directions::Right, Directions::Left} - }; + {Directions::Up, Directions::Down}, + {Directions::Down, Directions::Up}, + {Directions::Left, Directions::Right}, + {Directions::Right, Directions::Left}}; const std::unordered_map PieMenu::c_CounterClockwiseDirections = { - {Directions::Up, Directions::Left}, - {Directions::Down, Directions::Right}, - {Directions::Left, Directions::Down}, - {Directions::Right, Directions::Up} - }; + {Directions::Up, Directions::Left}, + {Directions::Down, Directions::Right}, + {Directions::Left, Directions::Down}, + {Directions::Right, Directions::Up}}; - BITMAP * PieMenu::s_CursorBitmap = nullptr; + BITMAP* PieMenu::s_CursorBitmap = nullptr; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::Clear() { m_LargeFont = nullptr; @@ -97,21 +93,27 @@ namespace RTE { m_BGPieSlicesWithSubPieMenuBitmapNeedsRedrawing = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int PieMenu::Create() { - if (!s_CursorBitmap) { s_CursorBitmap = ContentFile("Base.rte/GUIs/PieMenus/PieCursor.png").GetAsBitmap(); } + if (!s_CursorBitmap) { + s_CursorBitmap = ContentFile("Base.rte/GUIs/PieMenus/PieCursor.png").GetAsBitmap(); + } - if (!m_LargeFont) { m_LargeFont = g_FrameMan.GetLargeFont(); } + if (!m_LargeFont) { + m_LargeFont = g_FrameMan.GetLargeFont(); + } - if (!m_BGBitmap) { RecreateBackgroundBitmaps(); } + if (!m_BGBitmap) { + RecreateBackgroundBitmaps(); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PieMenu::Create(const PieMenu &reference) { + int PieMenu::Create(const PieMenu& reference) { Entity::Create(reference); m_LargeFont = reference.m_LargeFont; @@ -140,7 +142,7 @@ namespace RTE { for (int i = 0; i < m_PieQuadrants.size(); i++) { m_PieQuadrants[i].Create(reference.m_PieQuadrants[i], &reference, this); - for (const PieSlice *pieSlice : m_PieQuadrants[i].GetFlattenedPieSlices()) { + for (const PieSlice* pieSlice: m_PieQuadrants[i].GetFlattenedPieSlices()) { if (pieSlice->GetOriginalSource() != this) { m_PieQuadrants[i].RemovePieSlice(pieSlice); } @@ -158,21 +160,23 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::Destroy(bool notInherited) { - if (!notInherited) { Entity::Destroy(); } + if (!notInherited) { + Entity::Destroy(); + } destroy_bitmap(m_BGBitmap); destroy_bitmap(m_BGRotationBitmap); destroy_bitmap(m_BGPieSlicesWithSubPieMenuBitmap); Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PieMenu::ReadProperty(const std::string_view &propName, Reader &reader) { + int PieMenu::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("IconSeparatorMode", { std::string iconSeparatorModeString = reader.ReadPropValue(); auto itr = c_IconSeparatorModeMap.find(iconSeparatorModeString); @@ -181,7 +185,7 @@ namespace RTE { } else { try { m_IconSeparatorMode = static_cast(std::stoi(iconSeparatorModeString)); - } catch (const std::invalid_argument &) { + } catch (const std::invalid_argument&) { reader.ReportError("IconSeparatorMode " + iconSeparatorModeString + " is invalid."); } } @@ -197,7 +201,7 @@ namespace RTE { if (m_CurrentPieSlices.size() == 4 * PieQuadrant::c_PieQuadrantSlotCount) { reader.ReportError("Pie menus cannot have more than " + std::to_string(4 * PieQuadrant::c_PieQuadrantSlotCount) + " slices. Use sub-pie menus to better organize your pie slices."); } - if (!AddPieSlice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)), this)) { + if (!AddPieSlice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)), this)) { reader.ReportError("Tried to add pie slice but that direction was full. Set direction to None if you don't care where the pie slice ends up."); } }); @@ -205,9 +209,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PieMenu::Save(Writer &writer) const { + int PieMenu::Save(Writer& writer) const { Entity::Save(writer); writer.NewPropertyWithValue("IconSeparatorMode", static_cast(m_IconSeparatorMode)); @@ -219,20 +223,24 @@ namespace RTE { writer.NewPropertyWithValue("BackgroundBorderColor", m_BackgroundBorderColor); writer.NewPropertyWithValue("SelectedItemBackgroundColor", m_SelectedItemBackgroundColor); - for (const PieSlice *pieSlice : m_CurrentPieSlices) { - if (pieSlice->GetOriginalSource() == m_Owner) { writer.NewPropertyWithValue("AddPieSlice", pieSlice); } + for (const PieSlice* pieSlice: m_CurrentPieSlices) { + if (pieSlice->GetOriginalSource() == m_Owner) { + writer.NewPropertyWithValue("AddPieSlice", pieSlice); + } } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::SetOwner(Actor *newOwner) { + void PieMenu::SetOwner(Actor* newOwner) { RTEAssert((newOwner == nullptr) ? true : (newOwner->GetPieMenu() == this || IsSubPieMenu()), "Tried to set Pie Menu owning Actor to Actor with different Pie Menu."); if (m_Owner) { - for (PieSlice *pieSlice : m_CurrentPieSlices) { - if (pieSlice->GetOriginalSource() == m_Owner) { pieSlice->SetOriginalSource(newOwner); } + for (PieSlice* pieSlice: m_CurrentPieSlices) { + if (pieSlice->GetOriginalSource() == m_Owner) { + pieSlice->SetOriginalSource(newOwner); + } } if (!IsSubPieMenu()) { RemoveWhilePieMenuOpenListener(m_Owner); @@ -244,9 +252,9 @@ namespace RTE { m_Owner = newOwner; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Controller * PieMenu::GetController() const { + Controller* PieMenu::GetController() const { if (m_MenuController) { return m_MenuController; } @@ -257,14 +265,15 @@ namespace RTE { return m_Owner->GetController(); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - void PieMenu::SetPos(const Vector &newPos) { - if (g_SceneMan.ShortestDistance(m_CenterPos, newPos, g_SceneMan.SceneWrapsX()).GetMagnitude() > 2.0F) { m_CenterPos = newPos; } + void PieMenu::SetPos(const Vector& newPos) { + if (g_SceneMan.ShortestDistance(m_CenterPos, newPos, g_SceneMan.SceneWrapsX()).GetMagnitude() > 2.0F) { + m_CenterPos = newPos; + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::SetEnabled(bool enable, bool playSounds) { m_MenuMode = MenuMode::Normal; @@ -277,7 +286,7 @@ namespace RTE { PrepareAnalogCursorForEnableOrDisable(enable); if (playSounds) { - SoundContainer *soundToPlay = enable ? g_GUISound.PieMenuEnterSound() : g_GUISound.PieMenuExitSound(); + SoundContainer* soundToPlay = enable ? g_GUISound.PieMenuEnterSound() : g_GUISound.PieMenuExitSound(); soundToPlay->Play(); } @@ -295,26 +304,26 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const PieSlice * PieMenu::GetActivatedPieSlice() const { + const PieSlice* PieMenu::GetActivatedPieSlice() const { if (m_ActiveSubPieMenu) { return m_ActiveSubPieMenu->GetActivatedPieSlice(); } return m_ActivatedPieSlice; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// PieSlice::SliceType PieMenu::GetPieCommand() const { - const PieSlice *activatedSlice = m_ActiveSubPieMenu ? m_ActiveSubPieMenu->GetActivatedPieSlice() : m_ActivatedPieSlice; + const PieSlice* activatedSlice = m_ActiveSubPieMenu ? m_ActiveSubPieMenu->GetActivatedPieSlice() : m_ActivatedPieSlice; return (activatedSlice == nullptr) ? PieSlice::SliceType::NoType : activatedSlice->GetType(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PieSlice * PieMenu::GetFirstPieSliceByPresetName(const std::string &presetName) const { - for (PieSlice *pieSlice : m_CurrentPieSlices) { + PieSlice* PieMenu::GetFirstPieSliceByPresetName(const std::string& presetName) const { + for (PieSlice* pieSlice: m_CurrentPieSlices) { if (pieSlice->GetPresetName() == presetName) { return pieSlice; } @@ -322,10 +331,10 @@ namespace RTE { return nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PieSlice * PieMenu::GetFirstPieSliceByType(PieSlice::SliceType pieSliceType) const { - for (PieSlice *pieSlice : m_CurrentPieSlices) { + PieSlice* PieMenu::GetFirstPieSliceByType(PieSlice::SliceType pieSliceType) const { + for (PieSlice* pieSlice: m_CurrentPieSlices) { if (pieSlice->GetType() == pieSliceType) { return pieSlice; } @@ -333,9 +342,9 @@ namespace RTE { return nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieMenu::AddPieSlice(PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource, bool allowQuadrantOverflow) { + bool PieMenu::AddPieSlice(PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource, bool allowQuadrantOverflow) { Directions pieSliceDirection = pieSliceToAdd->GetDirection(); if (pieSliceDirection != Directions::Any && !m_PieQuadrants.at(pieSliceDirection).m_Enabled) { pieSliceToAdd->SetDirection(Directions::Any); @@ -344,8 +353,8 @@ namespace RTE { bool sliceWasAdded = false; if (pieSliceDirection == Directions::Any) { - PieQuadrant *leastFullPieQuadrant = nullptr; - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { + PieQuadrant* leastFullPieQuadrant = nullptr; + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { if (pieQuadrant.m_Enabled && (!leastFullPieQuadrant || pieQuadrant.GetFlattenedPieSlices().size() < leastFullPieQuadrant->GetFlattenedPieSlices().size())) { leastFullPieQuadrant = &pieQuadrant; } @@ -372,10 +381,10 @@ namespace RTE { return sliceWasAdded; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieMenu::AddPieSliceIfPresetNameIsUnique(PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource, bool allowQuadrantOverflow) { - const std::string &pieSlicePresetName = pieSliceToAdd->GetPresetName(); + bool PieMenu::AddPieSliceIfPresetNameIsUnique(PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource, bool allowQuadrantOverflow) { + const std::string& pieSlicePresetName = pieSliceToAdd->GetPresetName(); if (pieSlicePresetName == "None") { return AddPieSlice(dynamic_cast(pieSliceToAdd->Clone()), pieSliceOriginalSource, allowQuadrantOverflow); @@ -383,7 +392,7 @@ namespace RTE { bool pieSliceAlreadyExists = onlyCheckPieSlicesWithSameOriginalSource ? false : GetFirstPieSliceByPresetName(pieSlicePresetName) != nullptr; if (!pieSliceAlreadyExists) { - for (const PieSlice *pieSlice : m_CurrentPieSlices) { + for (const PieSlice* pieSlice: m_CurrentPieSlices) { if (pieSlice->GetOriginalSource() == pieSliceOriginalSource && pieSlice->GetPresetName() == pieSlicePresetName) { pieSliceAlreadyExists = true; break; @@ -398,14 +407,14 @@ namespace RTE { return AddPieSlice(dynamic_cast(pieSliceToAdd->Clone()), pieSliceOriginalSource, allowQuadrantOverflow); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PieSlice * PieMenu::RemovePieSlice(const PieSlice *pieSliceToRemove) { - PieSlice *removedPieSlice = nullptr; + PieSlice* PieMenu::RemovePieSlice(const PieSlice* pieSliceToRemove) { + PieSlice* removedPieSlice = nullptr; if (Directions sliceDirection = pieSliceToRemove->GetDirection(); sliceDirection > Directions::None) { if (sliceDirection == Directions::Any) { - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { removedPieSlice = pieQuadrant.RemovePieSlice(pieSliceToRemove); if (removedPieSlice) { break; @@ -415,7 +424,7 @@ namespace RTE { removedPieSlice = m_PieQuadrants.at(sliceDirection).RemovePieSlice(pieSliceToRemove); } if (removedPieSlice) { - if (PieMenu *removedPieSliceSubPieMenu = removedPieSlice->GetSubPieMenu()) { + if (PieMenu* removedPieSliceSubPieMenu = removedPieSlice->GetSubPieMenu()) { removedPieSliceSubPieMenu->SetEnabled(false); removedPieSliceSubPieMenu->SetOwner(nullptr); } @@ -426,66 +435,66 @@ namespace RTE { return removedPieSlice; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieMenu::RemovePieSlicesByPresetName(const std::string &presetNameToRemoveBy) { + bool PieMenu::RemovePieSlicesByPresetName(const std::string& presetNameToRemoveBy) { bool anyPieSlicesRemoved = false; - std::vector pieSlicesToRemove; - for (const PieSlice *pieSlice : m_CurrentPieSlices) { + std::vector pieSlicesToRemove; + for (const PieSlice* pieSlice: m_CurrentPieSlices) { if (pieSlice->GetPresetName() == presetNameToRemoveBy) { pieSlicesToRemove.emplace_back(pieSlice); anyPieSlicesRemoved = true; } } - for (const PieSlice *pieSliceToRemove : pieSlicesToRemove) { + for (const PieSlice* pieSliceToRemove: pieSlicesToRemove) { delete RemovePieSlice(pieSliceToRemove); } return anyPieSlicesRemoved; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool PieMenu::RemovePieSlicesByType(PieSlice::SliceType pieSliceTypeToRemoveBy) { bool anyPieSlicesRemoved = false; - std::vector pieSlicesToRemove; - for (const PieSlice *pieSlice : m_CurrentPieSlices) { + std::vector pieSlicesToRemove; + for (const PieSlice* pieSlice: m_CurrentPieSlices) { if (pieSlice->GetType() == pieSliceTypeToRemoveBy) { pieSlicesToRemove.emplace_back(pieSlice); anyPieSlicesRemoved = true; } } - for (const PieSlice *pieSliceToRemove : pieSlicesToRemove) { + for (const PieSlice* pieSliceToRemove: pieSlicesToRemove) { delete RemovePieSlice(pieSliceToRemove); } return anyPieSlicesRemoved; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieMenu::RemovePieSlicesByOriginalSource(const Entity *originalSource) { + bool PieMenu::RemovePieSlicesByOriginalSource(const Entity* originalSource) { bool anyPieSlicesRemoved = false; - std::vector pieSlicesToRemove; - for (const PieSlice *pieSlice : m_CurrentPieSlices) { + std::vector pieSlicesToRemove; + for (const PieSlice* pieSlice: m_CurrentPieSlices) { if (pieSlice->GetOriginalSource() == originalSource) { pieSlicesToRemove.emplace_back(pieSlice); anyPieSlicesRemoved = true; } } - for (const PieSlice *pieSliceToRemove : pieSlicesToRemove) { + for (const PieSlice* pieSliceToRemove: pieSlicesToRemove) { delete RemovePieSlice(pieSliceToRemove); } return anyPieSlicesRemoved; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PieSlice * PieMenu::ReplacePieSlice(const PieSlice *pieSliceToReplace, PieSlice *replacementPieSlice) { + PieSlice* PieMenu::ReplacePieSlice(const PieSlice* pieSliceToReplace, PieSlice* replacementPieSlice) { if (pieSliceToReplace == nullptr) { return nullptr; } @@ -493,9 +502,9 @@ namespace RTE { return RemovePieSlice(pieSliceToReplace); } - PieSlice *replacedPieSlice = nullptr; + PieSlice* replacedPieSlice = nullptr; - auto DoPieSliceReplacementInPieQuadrant = [&replacedPieSlice, &pieSliceToReplace, &replacementPieSlice](PieQuadrant &pieQuadrant) { + auto DoPieSliceReplacementInPieQuadrant = [&replacedPieSlice, &pieSliceToReplace, &replacementPieSlice](PieQuadrant& pieQuadrant) { if (pieSliceToReplace == pieQuadrant.m_MiddlePieSlice.get()) { replacedPieSlice = pieQuadrant.m_MiddlePieSlice.release(); pieQuadrant.m_MiddlePieSlice = std::unique_ptr(replacementPieSlice); @@ -517,13 +526,13 @@ namespace RTE { if (Directions sliceDirection = pieSliceToReplace->GetDirection(); sliceDirection > Directions::None) { if (sliceDirection == Directions::Any) { - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { if (pieQuadrant.ContainsPieSlice(pieSliceToReplace)) { DoPieSliceReplacementInPieQuadrant(pieQuadrant); break; } } - } else if (PieQuadrant &pieQuadrant = m_PieQuadrants[sliceDirection]; pieQuadrant.ContainsPieSlice(pieSliceToReplace)) { + } else if (PieQuadrant& pieQuadrant = m_PieQuadrants[sliceDirection]; pieQuadrant.ContainsPieSlice(pieSliceToReplace)) { DoPieSliceReplacementInPieQuadrant(pieQuadrant); } } @@ -550,19 +559,19 @@ namespace RTE { } return replacedPieSlice; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::Update() { - const Controller *controller = GetController(); + void PieMenu::Update() { + const Controller* controller = GetController(); m_ActivatedPieSlice = nullptr; if (m_Owner) { SetPos(m_Owner->GetCPUPos()); } else if (m_AffectedObject) { - const Actor *affectedObjectAsActor = dynamic_cast(m_AffectedObject); + const Actor* affectedObjectAsActor = dynamic_cast(m_AffectedObject); SetPos(affectedObjectAsActor ? affectedObjectAsActor->GetCPUPos() : m_AffectedObject->GetPos()); } @@ -579,11 +588,15 @@ namespace RTE { return; } - if (m_AffectedObject && !g_MovableMan.ValidMO(m_AffectedObject)) { m_AffectedObject = nullptr; } + if (m_AffectedObject && !g_MovableMan.ValidMO(m_AffectedObject)) { + m_AffectedObject = nullptr; + } if (m_MenuMode == MenuMode::Normal) { if (IsEnabled()) { - for (const auto &[listenerObject, listenerFunction] : m_WhilePieMenuOpenListeners) { listenerFunction(); } + for (const auto& [listenerObject, listenerFunction]: m_WhilePieMenuOpenListeners) { + listenerFunction(); + } bool anyInput = false; bool skipInputBecauseActiveSubPieMenuWasJustDisabled = false; @@ -607,7 +620,7 @@ namespace RTE { bool shouldClearHoveredSlice = controller->IsState(ControlState::PIE_MENU_ACTIVE_ANALOG); // If a keyboard-only sub-PieMenu is exited by going off the sides, the parent PieMenu should handle input so the next PieSlice can be naturally stepped to. if (activeSubPieMenuDirection != Directions::None) { - for (const auto &[controlState, controlStateDirection] : c_ControlStateDirections) { + for (const auto& [controlState, controlStateDirection]: c_ControlStateDirections) { if (controlStateDirection == c_OppositeDirections.at(activeSubPieMenuDirection) && controller->IsState(controlState)) { shouldClearHoveredSlice = true; break; @@ -638,17 +651,23 @@ namespace RTE { } } - if (m_HoveredPieSlice && m_EnabledState != EnabledState::Disabled && !m_ActiveSubPieMenu) { UpdateSliceActivation(); } + if (m_HoveredPieSlice && m_EnabledState != EnabledState::Disabled && !m_ActiveSubPieMenu) { + UpdateSliceActivation(); + } - if (!IsSubPieMenu()) { SetEnabled(controller->IsState(ControlState::PIE_MENU_ACTIVE)); } + if (!IsSubPieMenu()) { + SetEnabled(controller->IsState(ControlState::PIE_MENU_ACTIVE)); + } } - if (m_BGBitmapNeedsRedrawing && m_EnabledState != EnabledState::Disabled) { UpdatePredrawnMenuBackgroundBitmap(); } + if (m_BGBitmapNeedsRedrawing && m_EnabledState != EnabledState::Disabled) { + UpdatePredrawnMenuBackgroundBitmap(); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::Draw(BITMAP *targetBitmap, const Vector &targetPos) const { + void PieMenu::Draw(BITMAP* targetBitmap, const Vector& targetPos) const { Vector drawPos; CalculateDrawPosition(targetBitmap, targetPos, drawPos); @@ -663,13 +682,17 @@ namespace RTE { if (m_EnabledState == EnabledState::Enabled) { DrawPieIcons(targetBitmap, drawPos); - if (m_CursorInVisiblePosition) { DrawPieCursorAndPieSliceDescriptions(targetBitmap, drawPos); } + if (m_CursorInVisiblePosition) { + DrawPieCursorAndPieSliceDescriptions(targetBitmap, drawPos); + } } - if (m_ActiveSubPieMenu) { m_ActiveSubPieMenu->Draw(targetBitmap, targetPos); } + if (m_ActiveSubPieMenu) { + m_ActiveSubPieMenu->Draw(targetBitmap, targetPos); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::UpdateWobbling() { float innerRadiusChange = static_cast(m_EnableDisableAnimationTimer.GetElapsedRealTimeMS()) / 6.0F; @@ -687,7 +710,7 @@ namespace RTE { m_EnableDisableAnimationTimer.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::UpdateEnablingAndDisablingProgress() { m_BGBitmapNeedsRedrawing = true; @@ -703,23 +726,25 @@ namespace RTE { if (IsSubPieMenu() || m_EnableDisableAnimationTimer.IsPastRealMS(c_EnablingDelay)) { m_EnabledState = EnabledState::Disabled; m_CurrentInnerRadius = 0; - if (Actor *affectedObjectAsActor = dynamic_cast(m_AffectedObject)) { affectedObjectAsActor->FlashWhite(); } + if (Actor* affectedObjectAsActor = dynamic_cast(m_AffectedObject)) { + affectedObjectAsActor->FlashWhite(); + } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieMenu::HandleAnalogInput(const Vector &input) { - const Controller *controller = GetController(); - const PieSlice *pieSliceToSelect = nullptr; + bool PieMenu::HandleAnalogInput(const Vector& input) { + const Controller* controller = GetController(); + const PieSlice* pieSliceToSelect = nullptr; if (input.MagnitudeIsGreaterThan(0.5F)) { m_CursorInVisiblePosition = true; float normalizedCursorAngle = NormalizeAngleBetween0And2PI(input.GetAbsRadAngle()); m_CursorAngle = normalizedCursorAngle; - for (const PieSlice *pieSlice : m_CurrentPieSlices) { + for (const PieSlice* pieSlice: m_CurrentPieSlices) { float absolutePieSliceStartAngle = pieSlice->GetStartAngle() + GetRotAngle(); if (AngleWithinRange(m_CursorAngle, absolutePieSliceStartAngle, absolutePieSliceStartAngle + (PieQuadrant::c_PieSliceSlotSize * static_cast(pieSlice->GetSlotCount())))) { pieSliceToSelect = pieSlice; @@ -736,10 +761,10 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool PieMenu::HandleDigitalInput() { - const Controller *controller = GetController(); + const Controller* controller = GetController(); if (!controller) { return false; } @@ -752,16 +777,16 @@ namespace RTE { auto GetPieQuadrantContainingHoveredSlice = [this]() { if (m_HoveredPieSlice) { - for (const PieQuadrant &pieQuadrant : m_PieQuadrants) { + for (const PieQuadrant& pieQuadrant: m_PieQuadrants) { if (pieQuadrant.ContainsPieSlice(m_HoveredPieSlice)) { return &pieQuadrant; } } } - return static_cast(nullptr); + return static_cast(nullptr); }; - auto MoveToPieQuadrant = [this](const PieQuadrant &pieQuadrant, MoveToPieQuadrantMode moveToPieQuadrantMode = MoveToPieQuadrantMode::Middle) { + auto MoveToPieQuadrant = [this](const PieQuadrant& pieQuadrant, MoveToPieQuadrantMode moveToPieQuadrantMode = MoveToPieQuadrantMode::Middle) { if (pieQuadrant.GetFlattenedPieSlices().empty()) { SetHoveredPieSlice(nullptr); m_CursorInVisiblePosition = true; @@ -775,8 +800,8 @@ namespace RTE { } }; - auto StepToNeighbouringPieSlice = [this, &MoveToPieQuadrant](const PieQuadrant *hoveredPieSlicePieQuadrant, Directions controlStateDirection, bool counterClockwiseMovement) { - std::vector flattenedPieSlices = hoveredPieSlicePieQuadrant->GetFlattenedPieSlices(true); + auto StepToNeighbouringPieSlice = [this, &MoveToPieQuadrant](const PieQuadrant* hoveredPieSlicePieQuadrant, Directions controlStateDirection, bool counterClockwiseMovement) { + std::vector flattenedPieSlices = hoveredPieSlicePieQuadrant->GetFlattenedPieSlices(true); auto hoveredSliceIterator = std::find(flattenedPieSlices.begin(), flattenedPieSlices.end(), m_HoveredPieSlice); if ((counterClockwiseMovement && hoveredSliceIterator == flattenedPieSlices.end() - 1) || (!counterClockwiseMovement && hoveredSliceIterator == flattenedPieSlices.begin())) { if (m_PieQuadrants.at(controlStateDirection).m_Enabled) { @@ -789,12 +814,12 @@ namespace RTE { } }; - for (const auto &[controlState, controlStateDirection] : c_ControlStateDirections) { + for (const auto& [controlState, controlStateDirection]: c_ControlStateDirections) { if (controller->IsState(controlState)) { - const PieQuadrant &pieQuadrantAtControlStateDirection = m_PieQuadrants.at(controlStateDirection); + const PieQuadrant& pieQuadrantAtControlStateDirection = m_PieQuadrants.at(controlStateDirection); if (!m_HoveredPieSlice && pieQuadrantAtControlStateDirection.m_Enabled) { MoveToPieQuadrant(pieQuadrantAtControlStateDirection); - } else if (const PieQuadrant *hoveredPieSlicePieQuadrant = GetPieQuadrantContainingHoveredSlice()) { + } else if (const PieQuadrant* hoveredPieSlicePieQuadrant = GetPieQuadrantContainingHoveredSlice()) { if (controlStateDirection == c_OppositeDirections.at(hoveredPieSlicePieQuadrant->m_Direction)) { if (IsSubPieMenu()) { SetEnabled(false); @@ -812,13 +837,13 @@ namespace RTE { } } else { bool hoveredPieSliceIsInPieQuadrantRightSide = (m_HoveredPieSlice == hoveredPieSlicePieQuadrant->m_RightPieSlices[0].get() || m_HoveredPieSlice == hoveredPieSlicePieQuadrant->m_RightPieSlices[1].get()); - std::vector flattenedPieSlices = hoveredPieSlicePieQuadrant->GetFlattenedPieSlices(true); + std::vector flattenedPieSlices = hoveredPieSlicePieQuadrant->GetFlattenedPieSlices(true); auto hoveredPieSliceIterator = std::find(flattenedPieSlices.begin(), flattenedPieSlices.end(), m_HoveredPieSlice); SetHoveredPieSlice(*(hoveredPieSliceIterator + (hoveredPieSliceIsInPieQuadrantRightSide ? 1 : -1)), true); } } else { bool counterClockwiseMovement = controlStateDirection == c_CounterClockwiseDirections.at(hoveredPieSlicePieQuadrant->m_Direction); - const std::array, PieQuadrant::c_PieQuadrantSlotCount / 2> &pieSlicesToMovePieQuadrantsFor = counterClockwiseMovement ? hoveredPieSlicePieQuadrant->m_RightPieSlices : hoveredPieSlicePieQuadrant->m_LeftPieSlices; + const std::array, PieQuadrant::c_PieQuadrantSlotCount / 2>& pieSlicesToMovePieQuadrantsFor = counterClockwiseMovement ? hoveredPieSlicePieQuadrant->m_RightPieSlices : hoveredPieSlicePieQuadrant->m_LeftPieSlices; if (pieQuadrantAtControlStateDirection.m_Enabled && (m_HoveredPieSlice == pieSlicesToMovePieQuadrantsFor[0].get() || m_HoveredPieSlice == pieSlicesToMovePieQuadrantsFor[1].get())) { MoveToPieQuadrant(pieQuadrantAtControlStateDirection); } else { @@ -834,10 +859,10 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::UpdateSliceActivation() { - const Controller *controller = GetController(); + const Controller* controller = GetController(); if (controller && (controller->IsState(ControlState::PRESS_PRIMARY) || (m_HoveredPieSlice != m_AlreadyActivatedPieSlice && controller->IsState(ControlState::RELEASE_SECONDARY)))) { m_HoverTimer.Reset(); m_ActivatedPieSlice = m_HoveredPieSlice->IsEnabled() ? m_HoveredPieSlice : m_ActivatedPieSlice; @@ -846,7 +871,7 @@ namespace RTE { if (m_HoveredPieSlice->GetSubPieMenu() && controller->IsState(ControlState::RELEASE_SECONDARY)) { g_GUISound.UserErrorSound()->Play(); } else { - SoundContainer *soundToPlay = m_HoveredPieSlice->IsEnabled() ? g_GUISound.SlicePickedSound() : g_GUISound.DisabledPickedSound(); + SoundContainer* soundToPlay = m_HoveredPieSlice->IsEnabled() ? g_GUISound.SlicePickedSound() : g_GUISound.DisabledPickedSound(); soundToPlay->Play(); } } @@ -866,29 +891,38 @@ namespace RTE { m_ActiveSubPieMenu->m_HoverTimer.SetRealTimeLimitMS(2000); m_ActiveSubPieMenu->m_HoverTimer.Reset(); } else if (m_ActivatedPieSlice && m_ActivatedPieSlice->GetLuabindFunctionObjectWrapper() && m_ActivatedPieSlice->GetLuabindFunctionObjectWrapper()->GetLuabindObject()) { - if (const MovableObject *scriptTarget = m_Owner ? m_Owner : m_AffectedObject) { - g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(m_ActivatedPieSlice->GetLuabindFunctionObjectWrapper(), "", "", { scriptTarget, this, m_ActivatedPieSlice }); + if (const MovableObject* scriptTarget = m_Owner ? m_Owner : m_AffectedObject) { + g_LuaMan.GetMasterScriptState().RunScriptFunctionObject(m_ActivatedPieSlice->GetLuabindFunctionObjectWrapper(), "", "", {scriptTarget, this, m_ActivatedPieSlice}); } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::UpdatePredrawnMenuBackgroundBitmap() { int centerX = IsSubPieMenu() ? 0 : m_BGBitmap->w / 2; int centerY = IsSubPieMenu() ? 0 : m_BGBitmap->h / 2; - if (m_DirectionIfSubPieMenu == Directions::Up || m_DirectionIfSubPieMenu == Directions::Left) { centerX = m_BGBitmap->w; } - if (m_DirectionIfSubPieMenu == Directions::Up || m_DirectionIfSubPieMenu == Directions::Right) { centerY = m_BGBitmap->h; } - if (m_DirectionIfSubPieMenu == Directions::Down) { centerX = -2; centerY = -2; } - if (m_DirectionIfSubPieMenu == Directions::Left) { centerY = -2; } + if (m_DirectionIfSubPieMenu == Directions::Up || m_DirectionIfSubPieMenu == Directions::Left) { + centerX = m_BGBitmap->w; + } + if (m_DirectionIfSubPieMenu == Directions::Up || m_DirectionIfSubPieMenu == Directions::Right) { + centerY = m_BGBitmap->h; + } + if (m_DirectionIfSubPieMenu == Directions::Down) { + centerX = -2; + centerY = -2; + } + if (m_DirectionIfSubPieMenu == Directions::Left) { + centerY = -2; + } float subPieMenuRotationOffset = IsSubPieMenu() ? c_QuarterPI : 0; bool pieMenuNeedsToBeDrawnRotated = GetRotAngle() - subPieMenuRotationOffset != 0; - BITMAP *bitmapToDrawTo = pieMenuNeedsToBeDrawnRotated ? m_BGRotationBitmap : m_BGBitmap; + BITMAP* bitmapToDrawTo = pieMenuNeedsToBeDrawnRotated ? m_BGRotationBitmap : m_BGBitmap; bool hasPieSliceWithSubPieMenu = false; - for (const PieSlice *pieSlice : m_CurrentPieSlices) { + for (const PieSlice* pieSlice: m_CurrentPieSlices) { if (pieSlice->GetSubPieMenu()) { hasPieSliceWithSubPieMenu = true; break; @@ -922,22 +956,22 @@ namespace RTE { m_BGPieSlicesWithSubPieMenuBitmapNeedsRedrawing = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::CalculateDrawPosition(const BITMAP *targetBitmap, const Vector &targetPos, Vector &drawPos) const { + void PieMenu::CalculateDrawPosition(const BITMAP* targetBitmap, const Vector& targetPos, Vector& drawPos) const { drawPos = m_CenterPos - targetPos; if (!targetPos.IsZero()) { - const Box *nearestBox = nullptr; + const Box* nearestBox = nullptr; Box screenBox(targetPos, static_cast(targetBitmap->w), static_cast(targetBitmap->h)); std::list wrappedBoxes; bool withinAnyBox = false; float distance = std::numeric_limits::max(); float shortestDist = std::numeric_limits::max(); - //TODO under what conditions would the pie menu not be on the screen and, if that's the case, would we still want to draw it? Try to remove this in next pass of PieMenu changes, or replace it with more standard wrapping handling. - // Note - offscreen piemenu is used for signaling selectable actors so it's currently desirable. Strategic mode won't want that clutter, so this can probably change then. + // TODO under what conditions would the pie menu not be on the screen and, if that's the case, would we still want to draw it? Try to remove this in next pass of PieMenu changes, or replace it with more standard wrapping handling. + // Note - offscreen piemenu is used for signaling selectable actors so it's currently desirable. Strategic mode won't want that clutter, so this can probably change then. g_SceneMan.WrapBox(screenBox, wrappedBoxes); - for (const Box &wrappedBox : wrappedBoxes) { + for (const Box& wrappedBox: wrappedBoxes) { if (wrappedBox.IsWithinBox(m_CenterPos)) { nearestBox = &wrappedBox; withinAnyBox = true; @@ -971,18 +1005,22 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::DrawPieIcons(BITMAP *targetBitmap, const Vector &drawPos) const { - for (const PieSlice *pieSlice : m_CurrentPieSlices) { - BITMAP *pieSliceIcon = pieSlice->GetAppropriateIcon(pieSlice == m_HoveredPieSlice); + void PieMenu::DrawPieIcons(BITMAP* targetBitmap, const Vector& drawPos) const { + for (const PieSlice* pieSlice: m_CurrentPieSlices) { + BITMAP* pieSliceIcon = pieSlice->GetAppropriateIcon(pieSlice == m_HoveredPieSlice); if (pieSliceIcon) { float pieSliceRotation = NormalizeAngleBetween0And2PI(pieSlice->GetMidAngle() + GetRotAngle()); Vector pieSliceCenteringOffset(1.0F - static_cast(pieSliceIcon->w / 2), 1.0F - static_cast(pieSliceIcon->h / 2)); - if (GetRotAngle() == 0 && pieSlice == m_PieQuadrants[Directions::Right].m_MiddlePieSlice.get()) { pieSliceCenteringOffset.SetX(pieSliceCenteringOffset.GetX() - 1.0F); } - if (GetRotAngle() == 0 && pieSlice == m_PieQuadrants[Directions::Down].m_MiddlePieSlice.get()) { pieSliceCenteringOffset.SetY(pieSliceCenteringOffset.GetY() - 1.0F); } + if (GetRotAngle() == 0 && pieSlice == m_PieQuadrants[Directions::Right].m_MiddlePieSlice.get()) { + pieSliceCenteringOffset.SetX(pieSliceCenteringOffset.GetX() - 1.0F); + } + if (GetRotAngle() == 0 && pieSlice == m_PieQuadrants[Directions::Down].m_MiddlePieSlice.get()) { + pieSliceCenteringOffset.SetY(pieSliceCenteringOffset.GetY() - 1.0F); + } Vector pieSliceIconOffset = Vector(static_cast(m_CurrentInnerRadius + (m_BackgroundThickness / 2) + (pieSlice->GetSubPieMenu() && m_IconSeparatorMode == IconSeparatorMode::Line ? 2 : 0)), 0).RadRotate(pieSliceRotation) + pieSliceCenteringOffset; @@ -999,9 +1037,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::DrawPieCursorAndPieSliceDescriptions(BITMAP *targetBitmap, const Vector &drawPos) const { + void PieMenu::DrawPieCursorAndPieSliceDescriptions(BITMAP* targetBitmap, const Vector& drawPos) const { int nonLineSeparatorCorrection = m_IconSeparatorMode != IconSeparatorMode::Line ? -(m_BackgroundSeparatorSize) : 0; Vector cursorPos = Vector(static_cast(m_CurrentInnerRadius + nonLineSeparatorCorrection), 0.0F).RadRotate(m_CursorAngle); pivot_sprite(targetBitmap, s_CursorBitmap, drawPos.GetFloorIntX() + cursorPos.GetFloorIntX(), drawPos.GetFloorIntY() + cursorPos.GetFloorIntY(), s_CursorBitmap->w / 2, s_CursorBitmap->h / 2, ftofix((m_CursorAngle / c_PI) * -128.0F)); @@ -1022,38 +1060,48 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::RepopulateAndRealignCurrentPieSlices() { m_CurrentPieSlices.clear(); - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { pieQuadrant.RealignPieSlices(); - if (pieQuadrant.m_MiddlePieSlice) { m_CurrentPieSlices.emplace_back(pieQuadrant.m_MiddlePieSlice.get()); } + if (pieQuadrant.m_MiddlePieSlice) { + m_CurrentPieSlices.emplace_back(pieQuadrant.m_MiddlePieSlice.get()); + } } - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { - if (pieQuadrant.m_LeftPieSlices[0]) { m_CurrentPieSlices.emplace_back(pieQuadrant.m_LeftPieSlices[0].get()); } + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { + if (pieQuadrant.m_LeftPieSlices[0]) { + m_CurrentPieSlices.emplace_back(pieQuadrant.m_LeftPieSlices[0].get()); + } } - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { - if (pieQuadrant.m_RightPieSlices[0]) { m_CurrentPieSlices.emplace_back(pieQuadrant.m_RightPieSlices[0].get()); } + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { + if (pieQuadrant.m_RightPieSlices[0]) { + m_CurrentPieSlices.emplace_back(pieQuadrant.m_RightPieSlices[0].get()); + } } - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { - if (pieQuadrant.m_LeftPieSlices[1]) { m_CurrentPieSlices.emplace_back(pieQuadrant.m_LeftPieSlices[1].get()); } + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { + if (pieQuadrant.m_LeftPieSlices[1]) { + m_CurrentPieSlices.emplace_back(pieQuadrant.m_LeftPieSlices[1].get()); + } } - for (PieQuadrant &pieQuadrant : m_PieQuadrants) { - if (pieQuadrant.m_RightPieSlices[1]) { m_CurrentPieSlices.emplace_back(pieQuadrant.m_RightPieSlices[1].get()); } + for (PieQuadrant& pieQuadrant: m_PieQuadrants) { + if (pieQuadrant.m_RightPieSlices[1]) { + m_CurrentPieSlices.emplace_back(pieQuadrant.m_RightPieSlices[1].get()); + } } ExpandPieSliceIntoEmptySpaceIfPossible(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::ExpandPieSliceIntoEmptySpaceIfPossible() { - const std::unordered_map nextDirectionForGivenDirection{ {Directions::Right, Directions::Up}, {Directions::Up, Directions::Left}, {Directions::Left, Directions::Down}, {Directions::Down, Directions::Right} }; + const std::unordered_map nextDirectionForGivenDirection{{Directions::Right, Directions::Up}, {Directions::Up, Directions::Left}, {Directions::Left, Directions::Down}, {Directions::Down, Directions::Right}}; - for (const PieQuadrant &pieQuadrant : m_PieQuadrants) { + for (const PieQuadrant& pieQuadrant: m_PieQuadrants) { if (pieQuadrant.m_Enabled) { - const std::unique_ptr &leftMostPieSlice = !pieQuadrant.m_LeftPieSlices[1] ? pieQuadrant.m_LeftPieSlices[0] : pieQuadrant.m_LeftPieSlices[1]; - PieQuadrant &neighbouringPieQuadrant = m_PieQuadrants.at(nextDirectionForGivenDirection.at(pieQuadrant.m_Direction)); + const std::unique_ptr& leftMostPieSlice = !pieQuadrant.m_LeftPieSlices[1] ? pieQuadrant.m_LeftPieSlices[0] : pieQuadrant.m_LeftPieSlices[1]; + PieQuadrant& neighbouringPieQuadrant = m_PieQuadrants.at(nextDirectionForGivenDirection.at(pieQuadrant.m_Direction)); if (leftMostPieSlice && leftMostPieSlice->GetSlotCount() == 1 && neighbouringPieQuadrant.m_Enabled && neighbouringPieQuadrant.m_SlotsForPieSlices[0] == nullptr) { leftMostPieSlice->SetSlotCount(leftMostPieSlice->GetSlotCount() + 1); @@ -1065,7 +1113,7 @@ namespace RTE { m_BGPieSlicesWithSubPieMenuBitmapNeedsRedrawing = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::RecreateBackgroundBitmaps() { if (m_BGBitmap) { @@ -1094,16 +1142,16 @@ namespace RTE { m_BGPieSlicesWithSubPieMenuBitmapNeedsRedrawing = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::DrawBackgroundPieSliceSeparators(BITMAP *backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float subPieMenuRotationOffset) const { + void PieMenu::DrawBackgroundPieSliceSeparators(BITMAP* backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float subPieMenuRotationOffset) const { switch (m_IconSeparatorMode) { case IconSeparatorMode::Line: - for (const PieQuadrant &pieQuadrant : m_PieQuadrants) { + for (const PieQuadrant& pieQuadrant: m_PieQuadrants) { float currentAngle = c_DirectionsToRadiansMap.at(pieQuadrant.m_Direction) - c_QuarterPI + subPieMenuRotationOffset; bool pieQuadrantIsEmpty = !pieQuadrant.m_Enabled || pieQuadrant.GetFlattenedPieSlices().empty(); for (int currentSlot = 0; currentSlot < PieQuadrant::c_PieQuadrantSlotCount;) { - if (const PieSlice *pieSliceInSlot = pieQuadrant.m_SlotsForPieSlices.at(currentSlot)) { + if (const PieSlice* pieSliceInSlot = pieQuadrant.m_SlotsForPieSlices.at(currentSlot)) { // We don't draw lines if the current slot is the first slot, since a line will be drawn by the previous PieQuadrant's last PieSlice, or if it's a 2-size, since that means it's spreading over PieQuadrants and a line will be drawn at the next PieSlice's start. if (currentSlot > 0 || pieSliceInSlot->GetSlotCount() != 2) { currentAngle = pieSliceInSlot->GetStartAngle() + subPieMenuRotationOffset; @@ -1113,13 +1161,15 @@ namespace RTE { continue; } } else { - if (!pieQuadrantIsEmpty && currentSlot == 0) { DrawBackgroundPieSliceSeparator(backgroundBitmapToDrawTo, pieCircleCenterX, pieCircleCenterY, currentAngle, false, false); } + if (!pieQuadrantIsEmpty && currentSlot == 0) { + DrawBackgroundPieSliceSeparator(backgroundBitmapToDrawTo, pieCircleCenterX, pieCircleCenterY, currentAngle, false, false); + } currentAngle += PieQuadrant::c_PieSliceSlotSize; } currentSlot++; } } - for (const PieSlice *pieSlice : m_CurrentPieSlices) { + for (const PieSlice* pieSlice: m_CurrentPieSlices) { if (!pieSlice->GetSubPieMenu()) { Vector floodfillPosition = Vector(static_cast(m_CurrentInnerRadius + (m_BackgroundThickness / 2)), 0).RadRotate(pieSlice->GetMidAngle() + subPieMenuRotationOffset); floodfill(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX + floodfillPosition.GetFloorIntX(), pieCircleCenterY + floodfillPosition.GetFloorIntY(), ColorKeys::g_MaskColor); @@ -1128,8 +1178,10 @@ namespace RTE { break; case IconSeparatorMode::Circle: case IconSeparatorMode::Square: - for (const PieSlice *pieSlice : m_CurrentPieSlices) { - if (pieSlice->GetType() != PieSlice::SliceType::NoType) { DrawBackgroundPieSliceSeparator(backgroundBitmapToDrawTo, pieCircleCenterX, pieCircleCenterY, pieSlice->GetMidAngle() + subPieMenuRotationOffset, pieSlice == m_HoveredPieSlice && pieSlice->IsEnabled(), pieSlice->GetSubPieMenu()); } + for (const PieSlice* pieSlice: m_CurrentPieSlices) { + if (pieSlice->GetType() != PieSlice::SliceType::NoType) { + DrawBackgroundPieSliceSeparator(backgroundBitmapToDrawTo, pieCircleCenterX, pieCircleCenterY, pieSlice->GetMidAngle() + subPieMenuRotationOffset, pieSlice == m_HoveredPieSlice && pieSlice->IsEnabled(), pieSlice->GetSubPieMenu()); + } } break; default: @@ -1137,9 +1189,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieMenu::DrawBackgroundPieSliceSeparator(BITMAP *backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float rotAngle, bool isHoveredPieSlice, bool pieSliceHasSubPieMenu, bool drawHalfSizedSeparator) const { + void PieMenu::DrawBackgroundPieSliceSeparator(BITMAP* backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float rotAngle, bool isHoveredPieSlice, bool pieSliceHasSubPieMenu, bool drawHalfSizedSeparator) const { Vector separatorOffset; int backgroundSeparatorSize = m_BackgroundSeparatorSize; @@ -1147,27 +1199,39 @@ namespace RTE { case IconSeparatorMode::Line: separatorOffset.SetXY(static_cast(m_CurrentInnerRadius + m_BackgroundThickness + backgroundSeparatorSize), 0).RadRotate(rotAngle); line(backgroundBitmapToDrawTo, pieCircleCenterX, pieCircleCenterY, pieCircleCenterX + separatorOffset.GetCeilingIntX(), pieCircleCenterY + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); - if (!drawHalfSizedSeparator) { line(backgroundBitmapToDrawTo, pieCircleCenterX + 1, pieCircleCenterY, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); } + if (!drawHalfSizedSeparator) { + line(backgroundBitmapToDrawTo, pieCircleCenterX + 1, pieCircleCenterY, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); + } line(backgroundBitmapToDrawTo, pieCircleCenterX, pieCircleCenterY + 1, pieCircleCenterX + separatorOffset.GetCeilingIntX(), pieCircleCenterY + 1 + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); - if (!drawHalfSizedSeparator) { line(backgroundBitmapToDrawTo, pieCircleCenterX + 1, pieCircleCenterY + 1, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + 1 + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); } + if (!drawHalfSizedSeparator) { + line(backgroundBitmapToDrawTo, pieCircleCenterX + 1, pieCircleCenterY + 1, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + 1 + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); + } if (pieSliceHasSubPieMenu) { separatorOffset.SetXY(static_cast(m_CurrentInnerRadius + m_BackgroundThickness + backgroundSeparatorSize + c_PieSliceWithSubPieMenuExtraThickness), 0).RadRotate(rotAngle); line(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX, pieCircleCenterY, pieCircleCenterX + separatorOffset.GetCeilingIntX(), pieCircleCenterY + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); - if (!drawHalfSizedSeparator) { line(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX + 1, pieCircleCenterY, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); } + if (!drawHalfSizedSeparator) { + line(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX + 1, pieCircleCenterY, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); + } line(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX, pieCircleCenterY + 1, pieCircleCenterX + separatorOffset.GetCeilingIntX(), pieCircleCenterY + 1 + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); - if (!drawHalfSizedSeparator) { line(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX + 1, pieCircleCenterY + 1, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + 1 + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); } + if (!drawHalfSizedSeparator) { + line(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX + 1, pieCircleCenterY + 1, pieCircleCenterX + 1 + separatorOffset.GetCeilingIntX(), pieCircleCenterY + 1 + separatorOffset.GetCeilingIntY(), m_BackgroundBorderColor); + } } if (isHoveredPieSlice) { separatorOffset.SetXY(static_cast(m_CurrentInnerRadius + (m_BackgroundThickness / 2)), 0).RadRotate(rotAngle - (PieQuadrant::c_PieSliceSlotSize / 2.0F)); floodfill(backgroundBitmapToDrawTo, pieCircleCenterX + separatorOffset.GetFloorIntX(), pieCircleCenterY + separatorOffset.GetFloorIntY(), m_SelectedItemBackgroundColor); - if (pieSliceHasSubPieMenu) { floodfill(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX + separatorOffset.GetFloorIntX(), pieCircleCenterY + separatorOffset.GetFloorIntY(), m_SelectedItemBackgroundColor); } + if (pieSliceHasSubPieMenu) { + floodfill(m_BGPieSlicesWithSubPieMenuBitmap, pieCircleCenterX + separatorOffset.GetFloorIntX(), pieCircleCenterY + separatorOffset.GetFloorIntY(), m_SelectedItemBackgroundColor); + } } break; case IconSeparatorMode::Circle: case IconSeparatorMode::Square: - if (drawHalfSizedSeparator) { backgroundSeparatorSize /= 2; } + if (drawHalfSizedSeparator) { + backgroundSeparatorSize /= 2; + } separatorOffset.SetXY(static_cast(m_CurrentInnerRadius) + (static_cast(m_BackgroundThickness) / 2.0F), 0).RadRotate(rotAngle); if (pieSliceHasSubPieMenu) { if (m_IconSeparatorMode == IconSeparatorMode::Circle) { @@ -1191,9 +1255,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieMenu::SetHoveredPieSlice(const PieSlice *pieSliceToSelect, bool moveCursorIconToSlice) { + bool PieMenu::SetHoveredPieSlice(const PieSlice* pieSliceToSelect, bool moveCursorIconToSlice) { if (pieSliceToSelect == m_HoveredPieSlice) { return false; } @@ -1208,7 +1272,7 @@ namespace RTE { m_CursorAngle = GetRotAngle() + m_HoveredPieSlice->GetMidAngle(); } - SoundContainer *soundToPlay = pieSliceToSelect->IsEnabled() ? g_GUISound.HoverChangeSound() : g_GUISound.HoverDisabledSound(); + SoundContainer* soundToPlay = pieSliceToSelect->IsEnabled() ? g_GUISound.HoverChangeSound() : g_GUISound.HoverDisabledSound(); soundToPlay->Play(); } else { m_CursorInVisiblePosition = false; @@ -1216,15 +1280,15 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieMenu::PreparePieSliceSubPieMenuForUse(const PieSlice *pieSliceWithSubPieMenu) const { - PieMenu *subPieMenu = pieSliceWithSubPieMenu->GetSubPieMenu(); + bool PieMenu::PreparePieSliceSubPieMenuForUse(const PieSlice* pieSliceWithSubPieMenu) const { + PieMenu* subPieMenu = pieSliceWithSubPieMenu->GetSubPieMenu(); subPieMenu->m_ActivatedPieSlice = nullptr; if (!subPieMenu || subPieMenu->IsSubPieMenu()) { return false; } - for (const PieQuadrant &pieQuadrant : m_PieQuadrants) { + for (const PieQuadrant& pieQuadrant: m_PieQuadrants) { if (pieQuadrant.ContainsPieSlice(pieSliceWithSubPieMenu)) { subPieMenu->m_DirectionIfSubPieMenu = pieQuadrant.m_Direction; break; @@ -1232,38 +1296,42 @@ namespace RTE { } float subPieMenuRotAngle = NormalizeAngleBetween0And2PI(pieSliceWithSubPieMenu->GetMidAngle() - c_DirectionsToRadiansMap.at(subPieMenu->m_DirectionIfSubPieMenu) + GetRotAngle()); - if (subPieMenuRotAngle < 0.0001F) { subPieMenuRotAngle = 0; } + if (subPieMenuRotAngle < 0.0001F) { + subPieMenuRotAngle = 0; + } subPieMenu->SetRotAngle(subPieMenuRotAngle); subPieMenu->SetFullInnerRadius(m_FullInnerRadius + std::max(m_BackgroundThickness * 2, m_BackgroundSeparatorSize * 3) + c_PieSliceWithSubPieMenuExtraThickness); - for (PieQuadrant &pieQuadrant : subPieMenu->m_PieQuadrants) { - if (pieQuadrant.m_Direction != subPieMenu->m_DirectionIfSubPieMenu) { pieQuadrant.m_Enabled = false; } + for (PieQuadrant& pieQuadrant: subPieMenu->m_PieQuadrants) { + if (pieQuadrant.m_Direction != subPieMenu->m_DirectionIfSubPieMenu) { + pieQuadrant.m_Enabled = false; + } } - std::vector existingPieSlices = subPieMenu->GetPieSlices(); - std::vector pieSlicesToReadd; + std::vector existingPieSlices = subPieMenu->GetPieSlices(); + std::vector pieSlicesToReadd; pieSlicesToReadd.reserve(existingPieSlices.size()); - for (const PieSlice *existingPieSlice : existingPieSlices) { + for (const PieSlice* existingPieSlice: existingPieSlices) { pieSlicesToReadd.emplace_back(subPieMenu->RemovePieSlice(existingPieSlice)); pieSlicesToReadd.back()->SetDirection(Directions::Any); } - for (PieSlice *pieSlice : pieSlicesToReadd) { + for (PieSlice* pieSlice: pieSlicesToReadd) { subPieMenu->AddPieSlice(pieSlice, subPieMenu); } return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieMenu::PrepareAnalogCursorForEnableOrDisable(bool enable) const { - if (Controller *controller = GetController(); controller && (controller->IsMouseControlled() || controller->IsGamepadControlled())) { + if (Controller* controller = GetController(); controller && (controller->IsMouseControlled() || controller->IsGamepadControlled())) { if (!IsSubPieMenu()) { g_UInputMan.SetMouseValueMagnitude(0, controller->GetPlayer()); controller->m_AnalogCursor.Reset(); } else if (enable) { controller->SetAnalogCursorAngleLimits(GetRotAngle() + c_DirectionsToRadiansMap.at(m_DirectionIfSubPieMenu) - c_QuarterPI + (PieQuadrant::c_PieSliceSlotSize / 2.0F), GetRotAngle() + c_DirectionsToRadiansMap.at(m_DirectionIfSubPieMenu) + c_QuarterPI - (PieQuadrant::c_PieSliceSlotSize / 2.0F)); if (!controller->m_AnalogCursor.IsZero()) { - float mouseAngleToSet = GetRotAngle() + (m_HoveredPieSlice ? m_HoveredPieSlice->GetMidAngle() : c_DirectionsToRadiansMap.at(m_DirectionIfSubPieMenu)); + float mouseAngleToSet = GetRotAngle() + (m_HoveredPieSlice ? m_HoveredPieSlice->GetMidAngle() : c_DirectionsToRadiansMap.at(m_DirectionIfSubPieMenu)); g_UInputMan.SetMouseValueAngle(mouseAngleToSet, controller->GetPlayer()); g_UInputMan.SetMouseValueMagnitude(0.75F, controller->GetPlayer()); controller->m_AnalogCursor.SetAbsRadAngle(mouseAngleToSet); @@ -1274,4 +1342,4 @@ namespace RTE { } } } -} +} // namespace RTE diff --git a/Source/Entities/PieMenu.h b/Source/Entities/PieMenu.h index fe5b941b2..44ea5d8ff 100644 --- a/Source/Entities/PieMenu.h +++ b/Source/Entities/PieMenu.h @@ -20,16 +20,17 @@ namespace RTE { friend class PieSlice; public: - EntityAllocation(PieMenu) - SerializableOverrideMethods - ClassInfoGetters + SerializableOverrideMethods + ClassInfoGetters #pragma region Creation - /// - /// Constructor method used to instantiate a PieMenu object in system memory. Create() should be called before using the object. - /// - PieMenu() { Clear(); } + /// + /// Constructor method used to instantiate a PieMenu object in system memory. Create() should be called before using the object. + /// + PieMenu() { + Clear(); + } /// /// Makes the PieMenu object ready for use. @@ -42,14 +43,17 @@ namespace RTE { /// /// The Actor which should act as the owner for this PieMenu. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(Actor *owner) { SetOwner(owner); return Create(); } + int Create(Actor* owner) { + SetOwner(owner); + return Create(); + } /// /// Creates a PieMenu to be identical to another, by deep copy. /// /// A reference to the Attachable to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const PieMenu &reference); + int Create(const PieMenu& reference); #pragma endregion #pragma region Destruction @@ -67,7 +71,10 @@ namespace RTE { /// /// Resets the entire PieMenu, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -75,37 +82,37 @@ namespace RTE { /// Gets the owner Actor of this PieMenu. Ownership is NOT transferred! /// /// The owner Actor of this PieMenu. Ownership is NOT transferred! - const Actor * GetOwner() const { return m_Owner; } + const Actor* GetOwner() const { return m_Owner; } /// /// Sets the owner Actor of this PieMenu, ensuring this is that Actor's PieMenu, and updates PieSlice sources accordingly. Ownership is NOT transferred! /// /// The new owner Actor for this PieMenu. Ownership is NOT transferred! - void SetOwner(Actor *newOwner); + void SetOwner(Actor* newOwner); /// /// Gets the currently in-use Controller for this PieMenu - either the menu Controller if there's one set, or the owning Actor's Controller. Ownership IS NOT transferred! /// /// The currently in-use Controller for this PieMenu. - Controller * GetController() const; + Controller* GetController() const; /// /// Sets the menu Controller used by this PieMenu, separate from any Controller on its owner Actor. Ownership is NOT transferred! /// /// The new Controller for this PieMenu. Ownership is NOT transferred! - void SetMenuController(Controller *menuController) { m_MenuController = menuController; } + void SetMenuController(Controller* menuController) { m_MenuController = menuController; } /// /// Gets the currently affected MovableObject. Ownership is NOT transferred! /// /// The MovableObject this PieMenu affects. Ownership is NOT transferred! - const MovableObject * GetAffectedObject() const { return m_AffectedObject; } + const MovableObject* GetAffectedObject() const { return m_AffectedObject; } /// /// Sets the MovableObject this PieMenu should affect. Ownership is NOT transferred! /// /// The new MovableObject affected by this PieMenu. Ownership is NOT transferred! - void SetAffectedObject(MovableObject *affectedObject) { m_AffectedObject = affectedObject; } + void SetAffectedObject(MovableObject* affectedObject) { m_AffectedObject = affectedObject; } /// /// Gets whether this PieMenu is a sub-PieMenu, i.e. it's owned by a PieSlice. @@ -117,19 +124,19 @@ namespace RTE { /// Gets the absolute center position of this PieMenu. /// /// A Vector describing the current absolute position of this PieMenu in pixels. - const Vector & GetPos() const { return m_CenterPos; } + const Vector& GetPos() const { return m_CenterPos; } /// /// Sets the absolute center position of this PieMenu in the scene. /// /// A Vector describing the new absolute position of this PieMenu in pixels, in the scene. - void SetPos(const Vector &newPos); + void SetPos(const Vector& newPos); /// /// Gets the absolute rotation of this PieMenu. /// /// A Matrix describing the current absolute rotation of this PieMenu. - const Matrix & GetRotation() const { return m_Rotation; } + const Matrix& GetRotation() const { return m_Rotation; } /// /// Gets the absolute rotation of this PieMenu in radians. @@ -141,7 +148,7 @@ namespace RTE { /// Sets the absolute rotation of this PieMenu. /// /// A Matrix describing the new rotation of this PieMenu. - void SetRotation(const Matrix &newRotation) { m_Rotation = newRotation; } + void SetRotation(const Matrix& newRotation) { m_Rotation = newRotation; } /// /// Sets the absolute rotation of this PieMenu to the specified rad angle. @@ -159,7 +166,15 @@ namespace RTE { /// Sets the full inner radius of this PieMenu and recreates the background bitmap if it's changed. /// /// The new full inner radius of this PieMenu. - void SetFullInnerRadius(int fullInnerRadius) { if (m_FullInnerRadius != fullInnerRadius) { if (m_CurrentInnerRadius == m_FullInnerRadius) { m_CurrentInnerRadius = fullInnerRadius; } m_FullInnerRadius = fullInnerRadius; RecreateBackgroundBitmaps(); } } + void SetFullInnerRadius(int fullInnerRadius) { + if (m_FullInnerRadius != fullInnerRadius) { + if (m_CurrentInnerRadius == m_FullInnerRadius) { + m_CurrentInnerRadius = fullInnerRadius; + } + m_FullInnerRadius = fullInnerRadius; + RecreateBackgroundBitmaps(); + } + } /// /// Gets whether or not the PieMenu is enabled or in the process of being enabled, and is not in wobble mode. @@ -215,12 +230,22 @@ namespace RTE { /// /// Sets this PieMenu to normal MenuMode. /// - void SetAnimationModeToNormal() { if (m_MenuMode != MenuMode::Normal) { m_MenuMode = MenuMode::Normal; m_EnabledState = EnabledState::Disabled; } } + void SetAnimationModeToNormal() { + if (m_MenuMode != MenuMode::Normal) { + m_MenuMode = MenuMode::Normal; + m_EnabledState = EnabledState::Disabled; + } + } /// /// Plays the disabling animation, regardless of whether the PieMenu was enabled or not. /// - void DoDisableAnimation() { m_CurrentInnerRadius = m_FullInnerRadius; m_MenuMode = MenuMode::Normal; m_EnableDisableAnimationTimer.Reset(); m_EnabledState = EnabledState::Disabling; } + void DoDisableAnimation() { + m_CurrentInnerRadius = m_FullInnerRadius; + m_MenuMode = MenuMode::Normal; + m_EnableDisableAnimationTimer.Reset(); + m_EnabledState = EnabledState::Disabling; + } /// /// Plays an animation of the background circle expanding and contracting continuously. The PieMenu is effectively disabled while doing this. @@ -232,7 +257,11 @@ namespace RTE { /// Makes the background circle freeze at a certain radius until SetEnabled is called. The PieMenu is effectively disabled while doing this. /// /// The radius to make the background circle freeze at. - void FreezeAtRadius(int radius) { m_MenuMode = MenuMode::Freeze; m_CurrentInnerRadius = radius; m_BGBitmapNeedsRedrawing = true; } + void FreezeAtRadius(int radius) { + m_MenuMode = MenuMode::Freeze; + m_CurrentInnerRadius = radius; + m_BGBitmapNeedsRedrawing = true; + } #pragma endregion #pragma region PieSlice Handling @@ -240,7 +269,7 @@ namespace RTE { /// Gets the activated PieSlice for this PieMenu in the last update. If there is a sub-PieMenu open for this PieMenu, it gets that activated PieSlice instead. /// /// The activated PieSlice for this PieMenu. - const PieSlice * GetActivatedPieSlice() const; + const PieSlice* GetActivatedPieSlice() const; /// /// Gets the command issued by this PieMenu in the last update, i.e. the PieSlice SliceType of the currently activated PieSlice, or None if no slice was activated. @@ -252,21 +281,21 @@ namespace RTE { /// Gets a const reference to the vector containing pointers to all the PieSlices in this PieMenu. /// /// A const reference to the vector containing pointers to all the PieSlices in this PieMenu. - const std::vector & GetPieSlices() const { return m_CurrentPieSlices; } + const std::vector& GetPieSlices() const { return m_CurrentPieSlices; } /// /// Gets the first found PieSlice with the passed in preset name, if there is one. Ownership is NOT transferred! /// /// The preset name to look for. /// The first found PieSlice with the passed in preset name, or nullptr if there are no PieSlices with that preset name in this PieMenu. - PieSlice * GetFirstPieSliceByPresetName(const std::string &presetName) const; + PieSlice* GetFirstPieSliceByPresetName(const std::string& presetName) const; /// /// Gets the first found PieSlice with the passed in PieSlice SliceType, if there is one. Ownership is NOT transferred! /// /// The type of PieSlice to look for. /// The first found PieSlice with the passed in PieSlice SliceType, or nullptr if there are no PieSlices with that SliceType in this PieMenu. - PieSlice * GetFirstPieSliceByType(PieSlice::SliceType pieSliceType) const; + PieSlice* GetFirstPieSliceByType(PieSlice::SliceType pieSliceType) const; /// /// Adds a PieSlice to the PieMenu, setting its original source to the specified sliceSource. Ownership IS transferred! @@ -278,7 +307,7 @@ namespace RTE { /// The source of the added PieSlice. Should be nullptr for slices not added by Entities. /// Whether the new PieSlice can be placed in PieQuadrants other than the one specified by its Direction, if that PieQuadrant is full. /// Whether or not the PieSlice was added successfully. - bool AddPieSlice(PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource, bool allowQuadrantOverflow = false); + bool AddPieSlice(PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource, bool allowQuadrantOverflow = false); /// /// Adds a PieSlice to the PieMenu, with the same conditions as AddPieSlice above, but only if no PieSlice exists in this PieMenu with the same PresetName (optionally with the same original source). Ownership IS transferred! @@ -288,21 +317,21 @@ namespace RTE { /// Whether all PieSlices in the PieMenu should be checked to see if there are no duplicates, or only those with the same original source. /// Whether the new PieSlice can be placed in PieQuadrants other than the one specified by its Direction, if that PieQuadrant is full. /// Whether or not the PieSlice was added successfully. - bool AddPieSliceIfPresetNameIsUnique(PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource = false, bool allowQuadrantOverflow = false); + bool AddPieSliceIfPresetNameIsUnique(PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource = false, bool allowQuadrantOverflow = false); /// /// Removes and returns the passed in PieSlice from this PieMenu if it's in the PieMenu. Ownership IS transferred to the caller! /// /// The PieSlice to remove from this PieMenu. Ownership IS transferred to the caller! /// The removed PieSlice, if it was in the PieMenu. - PieSlice * RemovePieSlice(const PieSlice *pieSliceToRemove); + PieSlice* RemovePieSlice(const PieSlice* pieSliceToRemove); /// /// Removes any PieSlices in this PieMenu whose preset name matches the passed in preset name. /// /// The preset name to check against. /// Whether or not any PieSlices were removed from this PieMenu. - bool RemovePieSlicesByPresetName(const std::string &presetNameToRemoveBy); + bool RemovePieSlicesByPresetName(const std::string& presetNameToRemoveBy); /// /// Removes any PieSlices in this PieMenu whose PieSlice SliceType matches the passed in PieSlice SliceType. @@ -316,7 +345,7 @@ namespace RTE { /// /// The original source whose PieSlices should be removed. /// Whether or not any PieSlices were removed from this PieMenu. - bool RemovePieSlicesByOriginalSource(const Entity *originalSource); + bool RemovePieSlicesByOriginalSource(const Entity* originalSource); /// /// Replaces the first PieSlice with the second, ensuring original source, direction, middle slice eligibility, angles and slot count are maintained. @@ -325,7 +354,7 @@ namespace RTE { /// The PieSlice that will be replaced. /// The PieSlice that will replace the existing one. If this is nullptr, the existing one will just be removed. /// The removed PieSlice, if there is one. Ownership IS transferred! - PieSlice * ReplacePieSlice(const PieSlice *pieSliceToReplace, PieSlice *replacementPieSlice); + PieSlice* ReplacePieSlice(const PieSlice* pieSliceToReplace, PieSlice* replacementPieSlice); #pragma endregion #pragma region Updating @@ -339,7 +368,7 @@ namespace RTE { /// /// A pointer to a BITMAP to draw on. Generally a screen BITMAP. /// The absolute position of the target bitmap's upper left corner in the scene. - void Draw(BITMAP *targetBitmap, const Vector &targetPos = Vector()) const; + void Draw(BITMAP* targetBitmap, const Vector& targetPos = Vector()) const; #pragma endregion #pragma region Event Handling @@ -348,37 +377,57 @@ namespace RTE { /// /// The MovableObject listening. /// The function to be run on the MovableObject. - void AddWhilePieMenuOpenListener(const MovableObject *listeningObject, const std::function &listenerFunction) { if (listeningObject) { m_WhilePieMenuOpenListeners.try_emplace(listeningObject, listenerFunction); } } + void AddWhilePieMenuOpenListener(const MovableObject* listeningObject, const std::function& listenerFunction) { + if (listeningObject) { + m_WhilePieMenuOpenListeners.try_emplace(listeningObject, listenerFunction); + } + } /// /// Removes the passed in MovableObject and its listening function as a listener for when this PieMenu is opened. /// /// The MovableObject whose listening function should be removed. /// Whether or not the MovableObject was found and removed as a listener. - bool RemoveWhilePieMenuOpenListener(const MovableObject *objectToRemove) { return m_WhilePieMenuOpenListeners.erase(objectToRemove) == 1; } + bool RemoveWhilePieMenuOpenListener(const MovableObject* objectToRemove) { return m_WhilePieMenuOpenListeners.erase(objectToRemove) == 1; } #pragma endregion private: - /// /// Enumeration for enabled states when enabling/disabling the PieMenu. /// - enum class EnabledState { Enabling, Enabled, Disabling, Disabled }; + enum class EnabledState { + Enabling, + Enabled, + Disabling, + Disabled + }; /// /// Enumeration for the modes a PieMenu can have. /// - enum class MenuMode { Normal, Wobble, Freeze }; + enum class MenuMode { + Normal, + Wobble, + Freeze + }; /// /// Enumeration for the different item separator modes available to the PieMenu. /// - enum class IconSeparatorMode { Line, Circle, Square }; + enum class IconSeparatorMode { + Line, + Circle, + Square + }; /// /// Enumeration for helping keyboard PieMenu navigation. Specifies the ways the cursor should move from one PieQuadrant to another. /// - enum class MoveToPieQuadrantMode { Start, Middle, End }; + enum class MoveToPieQuadrantMode { + Start, + Middle, + End + }; static constexpr int c_EnablingDelay = 50; //!< Time in ms for how long it takes to enable/disable. static constexpr int c_DefaultFullRadius = 58; //!< The radius the menu should have when fully enabled, in pixels. @@ -390,13 +439,13 @@ namespace RTE { static const std::unordered_map c_CounterClockwiseDirections; //!< A map of Directions to the Direction that is CCW from them, for moving between PieQuadrants with the keyboard. static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - static BITMAP *s_CursorBitmap; //!< A static pointer to the bitmap to use as the cursor in any menu. + static BITMAP* s_CursorBitmap; //!< A static pointer to the bitmap to use as the cursor in any menu. - GUIFont *m_LargeFont; //!< A pointer to the large font from FrameMan. Not owned here. + GUIFont* m_LargeFont; //!< A pointer to the large font from FrameMan. Not owned here. - Actor *m_Owner; //!< The owner Actor of this PieMenu. Note that PieMenus do not necessarily need to have a owner. - Controller *m_MenuController; //!< The Controller which controls this PieMenu. Separate from the Controller of the owner or affected object (if there is one). - MovableObject *m_AffectedObject; //!< The MovableObject this PieMenu affects, if any. Only applies if there's no owner. + Actor* m_Owner; //!< The owner Actor of this PieMenu. Note that PieMenus do not necessarily need to have a owner. + Controller* m_MenuController; //!< The Controller which controls this PieMenu. Separate from the Controller of the owner or affected object (if there is one). + MovableObject* m_AffectedObject; //!< The MovableObject this PieMenu affects, if any. Only applies if there's no owner. Directions m_DirectionIfSubPieMenu; //!< The direction this sub-PieMenu is facing in. None if this is not a sub-PieMenu of another PieMenu. MenuMode m_MenuMode; //!< The mode this PieMenu is in. See MenuMode enum for more details. Vector m_CenterPos; //!< The center position of this PieMenu in the scene. @@ -417,22 +466,22 @@ namespace RTE { int m_SelectedItemBackgroundColor; //!< The color used for drawing selected PieMenu items' backgrounds. std::array m_PieQuadrants; //!< The array of PieQuadrants that make up this PieMenu. Quadrants may be individually enabled or disabled, affecting what's drawn. - const PieSlice *m_HoveredPieSlice; //!< The PieSlice currently being hovered over. - const PieSlice *m_ActivatedPieSlice; //!< The currently activated PieSlice, if there is one, or 0 if there's not. - const PieSlice *m_AlreadyActivatedPieSlice; //!< The PieSlice that was most recently activated by pressing primary. Used to avoid duplicate activation when disabling. - std::vector m_CurrentPieSlices; //!< All the PieSlices in this PieMenu in INI order. Not owned here, just pointing to the ones above. + const PieSlice* m_HoveredPieSlice; //!< The PieSlice currently being hovered over. + const PieSlice* m_ActivatedPieSlice; //!< The currently activated PieSlice, if there is one, or 0 if there's not. + const PieSlice* m_AlreadyActivatedPieSlice; //!< The PieSlice that was most recently activated by pressing primary. Used to avoid duplicate activation when disabling. + std::vector m_CurrentPieSlices; //!< All the PieSlices in this PieMenu in INI order. Not owned here, just pointing to the ones above. - PieMenu *m_ActiveSubPieMenu; //!< The currently active sub-PieMenu, if any. + PieMenu* m_ActiveSubPieMenu; //!< The currently active sub-PieMenu, if any. - std::unordered_map> m_WhilePieMenuOpenListeners; //!< Unordered map of MovableObject pointers to functions to be called while the PieMenu is open. Pointers are NOT owned. + std::unordered_map> m_WhilePieMenuOpenListeners; //!< Unordered map of MovableObject pointers to functions to be called while the PieMenu is open. Pointers are NOT owned. int m_CurrentInnerRadius; //!< The current radius of the innermost circle of the pie menu, in pixels. bool m_CursorInVisiblePosition; //!< Whether or not this PieMenu's cursor is in a visible position and should be shown. float m_CursorAngle; //!< Position of the cursor on the circle, in radians, counterclockwise from straight out to the right. - BITMAP *m_BGBitmap; //!< The intermediary bitmap used to first draw the PieMenu background, which will be blitted to the final draw target surface. - BITMAP *m_BGRotationBitmap; //!< The intermediary bitmap used to allow the PieMenu background to rotate, which will be pivoted onto the BG bitmap. - BITMAP *m_BGPieSlicesWithSubPieMenuBitmap; //!< The intermediary bitmap used to support handling PieSlices with sub-PieMenus, which will be drawn onto the BG bitmap. + BITMAP* m_BGBitmap; //!< The intermediary bitmap used to first draw the PieMenu background, which will be blitted to the final draw target surface. + BITMAP* m_BGRotationBitmap; //!< The intermediary bitmap used to allow the PieMenu background to rotate, which will be pivoted onto the BG bitmap. + BITMAP* m_BGPieSlicesWithSubPieMenuBitmap; //!< The intermediary bitmap used to support handling PieSlices with sub-PieMenus, which will be drawn onto the BG bitmap. bool m_BGBitmapNeedsRedrawing; //!< Whether the BG bitmap should be redrawn during the next Update call. bool m_BGPieSlicesWithSubPieMenuBitmapNeedsRedrawing; //!< Whether the BG bitmap for PieSlices with sub-PieMenus should be redrawn when the BGBitmap is redrawn. @@ -452,7 +501,7 @@ namespace RTE { /// /// The analog input vector. /// Whether or not enough input was received to do something. - bool HandleAnalogInput(const Vector &input); + bool HandleAnalogInput(const Vector& input); /// /// Handles the digital input when updating. @@ -478,21 +527,21 @@ namespace RTE { /// A pointer to the BITMAP to draw on. Generally a screen BITMAP. /// The absolute position of the target bitmap's upper left corner in the scene. /// Out parameter, a Vector to be filled in with the position at which the PieMenu should be drawn. - void CalculateDrawPosition(const BITMAP *targetBitmap, const Vector &targetPos, Vector &drawPos) const; + void CalculateDrawPosition(const BITMAP* targetBitmap, const Vector& targetPos, Vector& drawPos) const; /// /// Handles drawing icons for PieSlices' visual representation in the PieMenu. /// /// A pointer to the BITMAP to draw on. Generally a screen BITMAP. /// The seam corrected position at which the PieMenu is being drawn. - void DrawPieIcons(BITMAP *targetBitmap, const Vector &drawPos) const; + void DrawPieIcons(BITMAP* targetBitmap, const Vector& drawPos) const; /// /// Handles drawing the cursor and description text for selected PieSlices. /// /// A pointer to the BITMAP to draw on. Generally a screen BITMAP. /// The seam corrected position at which the PieMenu is being drawn. - void DrawPieCursorAndPieSliceDescriptions(BITMAP *targetBitmap, const Vector &drawPos) const; + void DrawPieCursorAndPieSliceDescriptions(BITMAP* targetBitmap, const Vector& drawPos) const; #pragma endregion /// @@ -517,7 +566,7 @@ namespace RTE { /// The center X position of the circle being separated. /// The center Y position of the circle being separated. /// The rotation offset used if this is a sub-PieMenu. - void DrawBackgroundPieSliceSeparators(BITMAP *backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float subPieMenuRotationOffset) const; + void DrawBackgroundPieSliceSeparators(BITMAP* backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float subPieMenuRotationOffset) const; /// /// Draws a background separator, based on this PieMenu's IconSeparatorMode, to the passed in bitmap. @@ -529,7 +578,7 @@ namespace RTE { /// Whether the separator is being drawn for the PieMenu's hovered PieSlice. /// Whether the PieSlice whose separator is being drawn has a sub-PieMenu. /// Whether to draw a half-sized separator or a full-sized one. Defaults to drawing a full-sized one. - void DrawBackgroundPieSliceSeparator(BITMAP *backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float rotAngle, bool isHoveredPieSlice, bool pieSliceHasSubPieMenu, bool drawHalfSizedSeparator = false) const; + void DrawBackgroundPieSliceSeparator(BITMAP* backgroundBitmapToDrawTo, int pieCircleCenterX, int pieCircleCenterY, float rotAngle, bool isHoveredPieSlice, bool pieSliceHasSubPieMenu, bool drawHalfSizedSeparator = false) const; /// /// Sets the passed in PieSlice as the hovered PieSlice of this PieMenu. If nullptr is passed in, no PieSlice will be hovered. @@ -537,14 +586,14 @@ namespace RTE { /// The PieSlice to consider hovered, if any. Has to be a PieSlice currently in this PieMenu. /// Whether to also move the cursor icon to the center of the new hovered PieSlice and set it to be drawn (generally for non-mouse inputs). Defaults to false. /// Whether or not the PieSlice to set as hovered was different from the already hovered PieSlice. - bool SetHoveredPieSlice(const PieSlice *pieSliceToSetAsHovered, bool moveCursorToPieSlice = false); + bool SetHoveredPieSlice(const PieSlice* pieSliceToSetAsHovered, bool moveCursorToPieSlice = false); /// /// Prepares the passed in PieSlice's sub-PieMenu for use by setting flags, moving PieSlices around, and disabling PieQuadrants as appropriate. /// /// The PieSlice with a sub-PieMenu that needs to be prepared. /// Whether the sub-PieMenu was prepared. PieMenus with the SubPieMenu flag already set will not have action taken on them. - bool PreparePieSliceSubPieMenuForUse(const PieSlice *pieSliceWithSubPieMenu) const; + bool PreparePieSliceSubPieMenuForUse(const PieSlice* pieSliceWithSubPieMenu) const; /// /// If the Controller for this PieMenu is mouse or gamepad controlled, sets up analog cursor angle limits and positions for when the pie menu is enabled or disabled. Also used when a sub-PieMenu of this PieMenu is disabled. @@ -558,8 +607,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - PieMenu(const PieMenu &reference) = delete; - PieMenu & operator=(const PieMenu &rhs) = delete; + PieMenu(const PieMenu& reference) = delete; + PieMenu& operator=(const PieMenu& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Entities/PieSlice.cpp b/Source/Entities/PieSlice.cpp index 6ce6d176d..912933374 100644 --- a/Source/Entities/PieSlice.cpp +++ b/Source/Entities/PieSlice.cpp @@ -8,7 +8,7 @@ namespace RTE { ConcreteClassInfo(PieSlice, Entity, 80); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieSlice::Clear() { m_Type = SliceType::NoType; @@ -31,20 +31,22 @@ namespace RTE { m_DrawFlippedToMatchAbsoluteAngle = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int PieSlice::Create() { if (Entity::Create() < 0) { return -1; } - if (!HasIcon()) { m_Icon = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Blank")->Clone())); } + if (!HasIcon()) { + m_Icon = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Blank")->Clone())); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PieSlice::Create(const PieSlice &reference) { + int PieSlice::Create(const PieSlice& reference) { Entity::Create(reference); m_Type = reference.m_Type; @@ -52,7 +54,7 @@ namespace RTE { m_CanBeMiddleSlice = reference.m_CanBeMiddleSlice; m_Enabled = reference.m_Enabled; - m_Icon = std::unique_ptr(dynamic_cast(reference.m_Icon->Clone())); + m_Icon = std::unique_ptr(dynamic_cast(reference.m_Icon->Clone())); m_FunctionName = reference.m_FunctionName; if (reference.m_LuabindFunctionObject) { @@ -60,7 +62,9 @@ namespace RTE { ReloadScripts(); } - if (reference.m_SubPieMenu) { SetSubPieMenu(dynamic_cast(reference.m_SubPieMenu->Clone())); } + if (reference.m_SubPieMenu) { + SetSubPieMenu(dynamic_cast(reference.m_SubPieMenu->Clone())); + } m_StartAngle = reference.m_StartAngle; m_SlotCount = reference.m_SlotCount; @@ -71,11 +75,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PieSlice::ReadProperty(const std::string_view &propName, Reader &reader) { + int PieSlice::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("Type", { m_Type = static_cast(std::stoi(reader.ReadPropValue())); }); MatchProperty("Direction", { if (std::string directionString = reader.ReadPropValue(); c_DirectionNameToDirectionsMap.find(directionString) != c_DirectionNameToDirectionsMap.end()) { @@ -87,15 +91,17 @@ namespace RTE { reader.ReportError("Direction " + directionString + " is invalid (Out of Bounds)."); } m_Direction = static_cast(direction); - } catch (const std::invalid_argument &) { + } catch (const std::invalid_argument&) { reader.ReportError("Direction " + directionString + " is invalid."); } } - if (m_Direction == Directions::None) { reader.ReportError("Pie Slices cannot have direction None."); } + if (m_Direction == Directions::None) { + reader.ReportError("Pie Slices cannot have direction None."); + } }); MatchProperty("CanBeMiddleSlice", { reader >> m_CanBeMiddleSlice; }); MatchProperty("Enabled", { reader >> m_Enabled; }); - MatchProperty("Icon", { SetIcon(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("Icon", { SetIcon(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); MatchProperty("ScriptPath", { std::string scriptPath; reader >> scriptPath; @@ -110,33 +116,41 @@ namespace RTE { ReloadScripts(); } }); - MatchProperty("SubPieMenu", { SetSubPieMenu(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("SubPieMenu", { SetSubPieMenu(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); MatchProperty("DrawFlippedToMatchAbsoluteAngle", { reader >> m_DrawFlippedToMatchAbsoluteAngle; }); EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PieSlice::Save(Writer &writer) const { + int PieSlice::Save(Writer& writer) const { Entity::Save(writer); - if (m_Type != SliceType::NoType) { writer.NewPropertyWithValue("Type", m_Type); } - if (m_Direction != Directions::Any) { writer.NewPropertyWithValue("Direction", static_cast(m_Direction)); } - if (!m_Enabled) { writer.NewPropertyWithValue("Enabled", m_Enabled); } + if (m_Type != SliceType::NoType) { + writer.NewPropertyWithValue("Type", m_Type); + } + if (m_Direction != Directions::Any) { + writer.NewPropertyWithValue("Direction", static_cast(m_Direction)); + } + if (!m_Enabled) { + writer.NewPropertyWithValue("Enabled", m_Enabled); + } writer.NewPropertyWithValue("Icon", m_Icon.get()); if (m_LuabindFunctionObject && !m_FunctionName.empty()) { writer.NewPropertyWithValue("ScriptPath", m_LuabindFunctionObject->GetFilePath()); writer.NewPropertyWithValue("FunctionName", m_FunctionName); } - if (m_SubPieMenu) { writer.NewPropertyWithValue("SubPieMenu", m_SubPieMenu.get()); } + if (m_SubPieMenu) { + writer.NewPropertyWithValue("SubPieMenu", m_SubPieMenu.get()); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BITMAP * RTE::PieSlice::GetAppropriateIcon(bool sliceIsSelected) const { + BITMAP* RTE::PieSlice::GetAppropriateIcon(bool sliceIsSelected) const { if (int iconFrameCount = m_Icon->GetFrameCount(); iconFrameCount > 0) { if (!IsEnabled() && iconFrameCount > 2) { return m_Icon->GetBitmaps8()[2]; @@ -149,45 +163,45 @@ namespace RTE { return nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PieMenu *PieSlice::GetSubPieMenu() const { + PieMenu* PieSlice::GetSubPieMenu() const { return m_SubPieMenu.get(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieSlice::SetSubPieMenu(PieMenu *newSubPieMenu) { + void PieSlice::SetSubPieMenu(PieMenu* newSubPieMenu) { m_SubPieMenu = std::unique_ptr(newSubPieMenu); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PieSlice::ReloadScripts() { + int PieSlice::ReloadScripts() { int status = 0; if (m_LuabindFunctionObject) { std::string filePath = m_LuabindFunctionObject->GetFilePath(); - std::unordered_map scriptFileFunctions; + std::unordered_map scriptFileFunctions; - status = g_LuaMan.GetMasterScriptState().RunScriptFileAndRetrieveFunctions(filePath, { m_FunctionName }, scriptFileFunctions, true); + status = g_LuaMan.GetMasterScriptState().RunScriptFileAndRetrieveFunctions(filePath, {m_FunctionName}, scriptFileFunctions, true); if (scriptFileFunctions.find(m_FunctionName) != scriptFileFunctions.end()) { m_LuabindFunctionObject = std::unique_ptr(scriptFileFunctions.at(m_FunctionName)); } } - return status; - } + return status; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieSlice::RecalculateMidAngle() { + void PieSlice::RecalculateMidAngle() { m_MidAngle = m_StartAngle + (static_cast(m_SlotCount) * PieQuadrant::c_PieSliceSlotSize / 2.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieSlice::PieMenuCustomDeleter::operator()(PieMenu *pieMenu) const { + void PieSlice::PieMenuCustomDeleter::operator()(PieMenu* pieMenu) const { pieMenu->Destroy(true); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/PieSlice.h b/Source/Entities/PieSlice.h index 5ad43a25a..e32822764 100644 --- a/Source/Entities/PieSlice.h +++ b/Source/Entities/PieSlice.h @@ -15,7 +15,6 @@ namespace RTE { class PieSlice : public Entity { public: - EntityAllocation(PieSlice); SerializableOverrideMethods; ClassInfoGetters; @@ -85,7 +84,7 @@ namespace RTE { /// /// A reference to the PieSlice to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const PieSlice &reference); + int Create(const PieSlice& reference); #pragma endregion #pragma region Destruction @@ -123,7 +122,11 @@ namespace RTE { /// Sets the Direction of this PieSlice. /// /// The new Direction of this PieSlice. - void SetDirection(Directions newDirection) { if (newDirection != Directions::None) { m_Direction = newDirection; } } + void SetDirection(Directions newDirection) { + if (newDirection != Directions::None) { + m_Direction = newDirection; + } + } /// /// Gets whether or not this PieSlice can be the middle PieSlice of a PieQuadrant. @@ -141,13 +144,13 @@ namespace RTE { /// Gets the original Entity source of this PieSlice, if there is one. /// /// A pointer to the original Entity source of this PieSlice, if there is one. - const Entity * GetOriginalSource() const { return m_OriginalSource; } + const Entity* GetOriginalSource() const { return m_OriginalSource; } /// /// Sets the original Entity source of this PieSlice. /// /// A pointer to the original Entity source of this PieSlice. - void SetOriginalSource(const Entity *originalSource) { m_OriginalSource = originalSource; } + void SetOriginalSource(const Entity* originalSource) { m_OriginalSource = originalSource; } /// /// Gets whether or not this PieSlice is enabled. @@ -172,19 +175,19 @@ namespace RTE { /// /// Whether or not this PieSlice is selected, which may affect which icon is appropriate. /// The icon for this PieSlice. - BITMAP * GetAppropriateIcon(bool sliceIsSelected = false) const; + BITMAP* GetAppropriateIcon(bool sliceIsSelected = false) const; /// /// Sets the new Icon for this PieSlice. Ownership IS transferred. /// /// The new Icon for this PieSlice. - void SetIcon(Icon *newIcon) { m_Icon = std::unique_ptr(newIcon); } + void SetIcon(Icon* newIcon) { m_Icon = std::unique_ptr(newIcon); } /// /// Gets the LuabindObjectWrapper for the function this PieSlice should run when activated. /// /// The LuabindObjectWrapper this PieSlice should run when activated. - const LuabindObjectWrapper * GetLuabindFunctionObjectWrapper() const { return m_LuabindFunctionObject.get(); } + const LuabindObjectWrapper* GetLuabindFunctionObjectWrapper() const { return m_LuabindFunctionObject.get(); } /// /// Gets the file path of the Lua file this PieSlice should run when activated, if any. @@ -196,32 +199,38 @@ namespace RTE { /// Sets the file path of the scripted file this PieSlice should run when activated. /// /// The file path of the Lua file this PieSlice should run when activated. - void SetScriptPath(const std::string &newScriptPath) { m_LuabindFunctionObject = std::make_unique(nullptr, newScriptPath); ReloadScripts(); } + void SetScriptPath(const std::string& newScriptPath) { + m_LuabindFunctionObject = std::make_unique(nullptr, newScriptPath); + ReloadScripts(); + } /// /// Gets the name of the Lua function to run when this PieSlice is activated. /// /// The name of the Lua function this PieSlice should execute when activated. - const std::string & GetFunctionName() const { return m_FunctionName; } + const std::string& GetFunctionName() const { return m_FunctionName; } /// /// Sets the name of the Lua function to run when this PieSlice is activated as a scripted pie menu option. /// /// The name of the Lua function to run when this PieSlice is activated. - void SetFunctionName(const std::string &newFunctionName) { m_FunctionName = newFunctionName; ReloadScripts(); } + void SetFunctionName(const std::string& newFunctionName) { + m_FunctionName = newFunctionName; + ReloadScripts(); + } - //TODO Ideally this would be done with a weak_ptr but I'm not sure how it'll go with LuaMan. Try it out and see + // TODO Ideally this would be done with a weak_ptr but I'm not sure how it'll go with LuaMan. Try it out and see /// /// Gets the sub-PieMenu for this PieSlice if there is one. Ownership is NOT transferred. /// /// The sub-PieMenu for this PieSlice if there is one. Ownership is NOT transferred. - PieMenu * GetSubPieMenu() const; + PieMenu* GetSubPieMenu() const; /// /// Sets the sub-PieMenu for this PieSlice. Ownership IS transferred. /// /// The new sub-PieMenu for this PieSlice. Ownership IS transferred. - void SetSubPieMenu(PieMenu *newSubPieMenu); + void SetSubPieMenu(PieMenu* newSubPieMenu); #pragma endregion #pragma region Angle Getter and Setters @@ -235,7 +244,10 @@ namespace RTE { /// Sets the start angle this PieSlice's area should be at in its pie menu. /// /// The start angle to set for the PieSlice's area. - void SetStartAngle(float startAngle) { m_StartAngle = startAngle; RecalculateMidAngle(); } + void SetStartAngle(float startAngle) { + m_StartAngle = startAngle; + RecalculateMidAngle(); + } /// /// Gets the number of slots this PieSlice takes up. @@ -247,7 +259,10 @@ namespace RTE { /// Sets the number of slots this PieSlice takes up. /// /// The number of slots this PieSlice should take up. - void SetSlotCount(int slotCount) { m_SlotCount = std::max(1, slotCount); RecalculateMidAngle(); } + void SetSlotCount(int slotCount) { + m_SlotCount = std::max(1, slotCount); + RecalculateMidAngle(); + } /// /// Gets the mid angle this PieSlice's area is set to be at in its pie menu. @@ -281,12 +296,11 @@ namespace RTE { int ReloadScripts() final; private: - /// /// Custom deleter for PieMenu to avoid include problems with unique_ptr. /// struct PieMenuCustomDeleter { - void operator()(PieMenu *pieMenu) const; + void operator()(PieMenu* pieMenu) const; }; static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. @@ -294,7 +308,7 @@ namespace RTE { SliceType m_Type; //!< The slice type, also used to determine the icon. Directions m_Direction; //!< The desired direction/location of this on the PieMenu. bool m_CanBeMiddleSlice; //!< Whether or not this PieSlice is allowed to be the middle slice. Defaults to true and should usually stay that way. - const Entity *m_OriginalSource; //!< A pointer to the original source of this PieSlice, normally filled in when PieSlices are added to PieMenus by objects other than the PieMenu's owner, and nullptr otherwise. + const Entity* m_OriginalSource; //!< A pointer to the original source of this PieSlice, normally filled in when PieSlices are added to PieMenus by objects other than the PieMenu's owner, and nullptr otherwise. bool m_Enabled; //!< Whether this PieSlice is enabled or disabled and grayed out. std::unique_ptr m_Icon; //!< The icon of this PieSlice. @@ -321,8 +335,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - PieSlice(const PieSlice &reference) = delete; - PieSlice &operator=(const PieSlice &rhs) = delete; + PieSlice(const PieSlice& reference) = delete; + PieSlice& operator=(const PieSlice& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/Round.cpp b/Source/Entities/Round.cpp index 6d51e067c..05f810a35 100644 --- a/Source/Entities/Round.cpp +++ b/Source/Entities/Round.cpp @@ -6,7 +6,7 @@ namespace RTE { ConcreteClassInfo(Round, Entity, 500); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Round::Clear() { m_Particle = 0; @@ -23,7 +23,7 @@ namespace RTE { m_AIPenetration = -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Round::Create() { if (Entity::Create() < 0) { @@ -31,22 +31,26 @@ namespace RTE { } if (m_AILifeTime == 0) { - const MovableObject *bullet = GetNextParticle(); - if (bullet) { m_AILifeTime = bullet->GetLifetime(); } + const MovableObject* bullet = GetNextParticle(); + if (bullet) { + m_AILifeTime = bullet->GetLifetime(); + } + } + if (m_AIFireVel < 0) { + m_AIFireVel = m_FireVel; } - if (m_AIFireVel < 0) { m_AIFireVel = m_FireVel; } if (m_AIPenetration < 0) { - const MovableObject *bullet = GetNextParticle(); - m_AIPenetration = (bullet && dynamic_cast(bullet)) ? bullet->GetMass() * bullet->GetSharpness() * m_AIFireVel : 0; + const MovableObject* bullet = GetNextParticle(); + m_AIPenetration = (bullet && dynamic_cast(bullet)) ? bullet->GetMass() * bullet->GetSharpness() * m_AIFireVel : 0; } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Round::Create(const Round &reference) { + int Round::Create(const Round& reference) { Entity::Create(reference); m_Particle = reference.m_Particle; @@ -65,13 +69,13 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Round::ReadProperty(const std::string_view &propName, Reader &reader) { + int Round::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("Particle", { - m_Particle = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); + m_Particle = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); RTEAssert(m_Particle, "Stream suggests allocating an unallocable type in Round::Create!"); }); MatchProperty("ParticleCount", { reader >> m_ParticleCount; }); @@ -79,20 +83,19 @@ namespace RTE { MatchProperty("InheritsFirerVelocity", { reader >> m_InheritsFirerVelocity; }); MatchProperty("Separation", { reader >> m_Separation; }); MatchProperty("LifeVariation", { reader >> m_LifeVariation; }); - MatchProperty("Shell", { m_Shell = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); + MatchProperty("Shell", { m_Shell = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); MatchProperty("ShellVelocity", { reader >> m_ShellVel; }); MatchProperty("FireSound", { reader >> m_FireSound; }); MatchProperty("AILifeTime", { reader >> m_AILifeTime; }); MatchProperty("AIFireVel", { reader >> m_AIFireVel; }); MatchProperty("AIPenetration", { reader >> m_AIPenetration; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Round::Save(Writer &writer) const { + int Round::Save(Writer& writer) const { Entity::Save(writer); writer.NewProperty("Particle"); @@ -122,11 +125,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - MovableObject * Round::PopNextParticle() { - MovableObject *tempParticle = (m_ParticleCount > 0) ? dynamic_cast(m_Particle->Clone()) : 0; + MovableObject* Round::PopNextParticle() { + MovableObject* tempParticle = (m_ParticleCount > 0) ? dynamic_cast(m_Particle->Clone()) : 0; m_ParticleCount--; return tempParticle; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/Round.h b/Source/Entities/Round.h index 0bd6cef18..694044f0b 100644 --- a/Source/Entities/Round.h +++ b/Source/Entities/Round.h @@ -13,7 +13,6 @@ namespace RTE { class Round : public Entity { public: - EntityAllocation(Round); SerializableOverrideMethods; ClassInfoGetters; @@ -35,7 +34,7 @@ namespace RTE { /// /// A reference to the Round to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Round &reference); + int Create(const Round& reference); #pragma endregion #pragma region Destruction @@ -48,12 +47,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the Round object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Entity::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Entity::Destroy(); + } + Clear(); + } /// /// Resets the entire Round, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -73,13 +80,13 @@ namespace RTE { /// Gets the next particle contained in this Round. Ownership is NOT transferred! /// /// A pointer to the next particle, or 0 if this Round is empty. - const MovableObject * GetNextParticle() const { return (m_ParticleCount > 0) ? m_Particle : 0; } + const MovableObject* GetNextParticle() const { return (m_ParticleCount > 0) ? m_Particle : 0; } /// /// Gets the next particle contained in this Round, and removes it from the stack. Ownership IS transferred! /// /// A pointer to the next particle, or 0 if this Round is empty. - MovableObject * PopNextParticle(); + MovableObject* PopNextParticle(); /// /// Gets the velocity at which this round is to be fired. @@ -109,7 +116,7 @@ namespace RTE { /// Gets the shell casing preset of this Round. Ownership IS NOT transferred! /// /// A pointer to the shell casing preset, or 0 if this Round has no shell. - const MovableObject * GetShell() const { return m_Shell; } + const MovableObject* GetShell() const { return m_Shell; } /// /// Gets the maximum velocity at which this round's shell is to be ejected. @@ -127,7 +134,7 @@ namespace RTE { /// Gets the extra firing sound of this Round, which can be played in addition to the weapon's own firing sound. OWNERSHIP IS NOT TRANSFERRED! /// /// A sound with the firing sample of this round. - SoundContainer * GetFireSound() { return &m_FireSound; } + SoundContainer* GetFireSound() { return &m_FireSound; } #pragma endregion #pragma region AI Properties @@ -151,17 +158,16 @@ namespace RTE { #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - const MovableObject *m_Particle; //!< Round particle MovableObject preset instance. + const MovableObject* m_Particle; //!< Round particle MovableObject preset instance. int m_ParticleCount; //!< How many particle copies there are in this Round. float m_FireVel; //!< The velocity with which this Round is fired. bool m_InheritsFirerVelocity; //!< Whether or not this Round should inherit velocity from its firer. float m_Separation; //!< The range of separation between particles in this Round, in pixels. float m_LifeVariation; //!< The random variation in life time of each fired particle, in percentage of their life time. - const MovableObject *m_Shell; //!< Shell particle MovableObject preset instance. + const MovableObject* m_Shell; //!< Shell particle MovableObject preset instance. float m_ShellVel; //!< The maximum velocity with which this Round's shell/casing is launched. SoundContainer m_FireSound; //!< The extra firing audio of this Round being fired. @@ -171,15 +177,14 @@ namespace RTE { int m_AIPenetration; //!< For overriding the bullets ability to penetrate material when executing the AI shooting scripts. private: - /// /// Clears all the member variables of this Round, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - Round(const Round &reference) = delete; - Round & operator=(const Round &rhs) = delete; + Round(const Round& reference) = delete; + Round& operator=(const Round& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/SLBackground.cpp b/Source/Entities/SLBackground.cpp index c9420260a..680e6b7ee 100644 --- a/Source/Entities/SLBackground.cpp +++ b/Source/Entities/SLBackground.cpp @@ -7,7 +7,7 @@ namespace RTE { ConcreteClassInfo(SLBackground, SceneLayer, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SLBackground::Clear() { m_Bitmaps.clear(); @@ -32,7 +32,7 @@ namespace RTE { m_IgnoreAutoScale = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int SLBackground::Create() { SceneLayer::Create(); @@ -58,9 +58,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SLBackground::Create(const SLBackground &reference) { + int SLBackground::Create(const SLBackground& reference) { SceneLayer::Create(reference); // The main bitmap is created and owned by SceneLayer because it can be modified. We need to destroy it to avoid a leak because the bitmaps we'll be using here are owned by ContentFile static maps and are unmodifiable. @@ -90,15 +90,17 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SLBackground::ReadProperty(const std::string_view &propName, Reader &reader) { + int SLBackground::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return SceneLayer::ReadProperty(propName, reader)); - + MatchProperty("FrameCount", { reader >> m_FrameCount; }); MatchProperty("SpriteAnimMode", { m_SpriteAnimMode = static_cast(std::stoi(reader.ReadPropValue())); - if (m_SpriteAnimMode < SpriteAnimMode::NOANIM || m_SpriteAnimMode > SpriteAnimMode::ALWAYSPINGPONG) { reader.ReportError("Invalid SLBackground sprite animation mode!"); } + if (m_SpriteAnimMode < SpriteAnimMode::NOANIM || m_SpriteAnimMode > SpriteAnimMode::ALWAYSPINGPONG) { + reader.ReportError("Invalid SLBackground sprite animation mode!"); + } }); MatchProperty("SpriteAnimDuration", { reader >> m_SpriteAnimDuration; }); MatchProperty("IsAnimatedManually", { reader >> m_IsAnimatedManually; }); @@ -117,14 +119,13 @@ namespace RTE { MatchProperty("CanAutoScrollY", { reader >> m_CanAutoScrollY; }); MatchProperty("AutoScrollStepInterval", { reader >> m_AutoScrollStepInterval; }); MatchProperty("AutoScrollStep", { reader >> m_AutoScrollStep; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SLBackground::Save(Writer &writer) const { + int SLBackground::Save(Writer& writer) const { SceneLayer::Save(writer); writer.NewPropertyWithValue("FrameCount", m_FrameCount); @@ -144,7 +145,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SLBackground::InitScaleFactors() { if (!m_IgnoreAutoScale) { @@ -166,7 +167,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SLBackground::Update() { if (!m_IsAnimatedManually && m_SpriteAnimMode != SpriteAnimMode::NOANIM) { @@ -200,8 +201,12 @@ namespace RTE { if (IsAutoScrolling()) { if (m_AutoScrollStepTimer.GetElapsedSimTimeMS() > m_AutoScrollStepInterval) { - if (m_WrapX && m_CanAutoScrollX) { m_AutoScrollOffset.SetX(m_AutoScrollOffset.GetX() + m_AutoScrollStep.GetX()); } - if (m_WrapY && m_CanAutoScrollY) { m_AutoScrollOffset.SetY(m_AutoScrollOffset.GetY() + m_AutoScrollStep.GetY()); } + if (m_WrapX && m_CanAutoScrollX) { + m_AutoScrollOffset.SetX(m_AutoScrollOffset.GetX() + m_AutoScrollStep.GetX()); + } + if (m_WrapY && m_CanAutoScrollY) { + m_AutoScrollOffset.SetY(m_AutoScrollOffset.GetY() + m_AutoScrollStep.GetY()); + } WrapPosition(m_AutoScrollOffset); m_AutoScrollStepTimer.Reset(); } @@ -209,9 +214,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SLBackground::Draw(BITMAP *targetBitmap, Box &targetBox, bool offsetNeedsScrollRatioAdjustment) { + void SLBackground::Draw(BITMAP* targetBitmap, Box& targetBox, bool offsetNeedsScrollRatioAdjustment) { SceneLayer::Draw(targetBitmap, targetBox, !IsAutoScrolling()); int bitmapWidth = m_ScaledDimensions.GetFloorIntX(); @@ -225,13 +230,21 @@ namespace RTE { // Detect if non-wrapping layer dimensions can't cover the whole target area with its main bitmap. If so, fill in the gap with appropriate solid color sampled from the hanging edge. if (!m_WrapX && bitmapWidth <= targetBoxWidth) { - if (m_FillColorLeft != ColorKeys::g_MaskColor && m_Offset.GetFloorIntX() != 0) { rectfill(targetBitmap, targetBoxCornerX, targetBoxCornerY, targetBoxCornerX - m_Offset.GetFloorIntX(), targetBoxCornerY + targetBoxHeight, m_FillColorLeft); } - if (m_FillColorRight != ColorKeys::g_MaskColor) { rectfill(targetBitmap, targetBoxCornerX + bitmapWidth - m_Offset.GetFloorIntX(), targetBoxCornerY, targetBoxCornerX + targetBoxWidth, targetBoxCornerY + targetBoxHeight, m_FillColorRight); } + if (m_FillColorLeft != ColorKeys::g_MaskColor && m_Offset.GetFloorIntX() != 0) { + rectfill(targetBitmap, targetBoxCornerX, targetBoxCornerY, targetBoxCornerX - m_Offset.GetFloorIntX(), targetBoxCornerY + targetBoxHeight, m_FillColorLeft); + } + if (m_FillColorRight != ColorKeys::g_MaskColor) { + rectfill(targetBitmap, targetBoxCornerX + bitmapWidth - m_Offset.GetFloorIntX(), targetBoxCornerY, targetBoxCornerX + targetBoxWidth, targetBoxCornerY + targetBoxHeight, m_FillColorRight); + } } if (!m_WrapY && bitmapHeight <= targetBoxHeight) { - if (m_FillColorUp != ColorKeys::g_MaskColor && m_Offset.GetFloorIntY() != 0) { rectfill(targetBitmap, targetBoxCornerX, targetBoxCornerY, targetBoxCornerX + targetBoxWidth, targetBoxCornerY - m_Offset.GetFloorIntY(), m_FillColorUp); } - if (m_FillColorDown != ColorKeys::g_MaskColor) { rectfill(targetBitmap, targetBoxCornerX, targetBoxCornerY + bitmapHeight - m_Offset.GetFloorIntY(), targetBoxCornerX + targetBoxWidth, targetBoxCornerY + targetBoxHeight, m_FillColorDown); } + if (m_FillColorUp != ColorKeys::g_MaskColor && m_Offset.GetFloorIntY() != 0) { + rectfill(targetBitmap, targetBoxCornerX, targetBoxCornerY, targetBoxCornerX + targetBoxWidth, targetBoxCornerY - m_Offset.GetFloorIntY(), m_FillColorUp); + } + if (m_FillColorDown != ColorKeys::g_MaskColor) { + rectfill(targetBitmap, targetBoxCornerX, targetBoxCornerY + bitmapHeight - m_Offset.GetFloorIntY(), targetBoxCornerX + targetBoxWidth, targetBoxCornerY + targetBoxHeight, m_FillColorDown); + } } set_clip_rect(targetBitmap, 0, 0, targetBitmap->w - 1, targetBitmap->h - 1); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/SLBackground.h b/Source/Entities/SLBackground.h index ffc122589..c368521ed 100644 --- a/Source/Entities/SLBackground.h +++ b/Source/Entities/SLBackground.h @@ -13,7 +13,6 @@ namespace RTE { friend class NetworkServer; public: - EntityAllocation(SLBackground); SerializableOverrideMethods; ClassInfoGetters; @@ -35,7 +34,7 @@ namespace RTE { /// /// A reference to the SLBackground to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const SLBackground &reference); + int Create(const SLBackground& reference); #pragma endregion #pragma region Destruction @@ -48,7 +47,12 @@ namespace RTE { /// Destroys and resets (through Clear()) the SLBackground object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { SceneLayer::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + SceneLayer::Destroy(); + } + Clear(); + } #pragma endregion #pragma region Getters and Setters @@ -152,7 +156,7 @@ namespace RTE { /// Sets the auto-scroll step (pixels to advance per interval) values. /// /// A Vector with the new auto-scroll step values. - void SetAutoScrollStep(const Vector &newStep) { m_AutoScrollStep = newStep; } + void SetAutoScrollStep(const Vector& newStep) { m_AutoScrollStep = newStep; } /// /// Gets the auto-scroll step (pixels to advance per interval) value on the X axis. @@ -199,19 +203,23 @@ namespace RTE { /// The bitmap to draw to. /// The box on the target bitmap to limit drawing to, with the corner of box being where the scroll position lines up. /// Whether the offset of this SceneLayer or the passed in offset override need to be adjusted to scroll ratio. - void Draw(BITMAP *targetBitmap, Box &targetBox, bool offsetNeedsScrollRatioAdjustment = false) override; + void Draw(BITMAP* targetBitmap, Box& targetBox, bool offsetNeedsScrollRatioAdjustment = false) override; #pragma endregion private: - /// /// Enumeration for the different modes of SLBackground auto-scaling. /// - enum LayerAutoScaleMode { AutoScaleOff, FitScreen, AlwaysUpscaled, LayerAutoScaleModeCount }; + enum LayerAutoScaleMode { + AutoScaleOff, + FitScreen, + AlwaysUpscaled, + LayerAutoScaleModeCount + }; static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. - std::vector m_Bitmaps; //!< Vector containing all the BITMAPs of this SLBackground. Not owned. + std::vector m_Bitmaps; //!< Vector containing all the BITMAPs of this SLBackground. Not owned. int m_FrameCount; //!< The total number of frames in this SLBackground's animation. int m_Frame; //!< The frame that is currently being shown/drawn. @@ -242,8 +250,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - SLBackground(const SLBackground &reference) = delete; - SLBackground & operator=(const SLBackground &rhs) = delete; + SLBackground(const SLBackground& reference) = delete; + SLBackground& operator=(const SLBackground& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/SLTerrain.cpp b/Source/Entities/SLTerrain.cpp index f44a040fe..6bc50fe73 100644 --- a/Source/Entities/SLTerrain.cpp +++ b/Source/Entities/SLTerrain.cpp @@ -13,7 +13,7 @@ namespace RTE { ConcreteClassInfo(SLTerrain, SceneLayer, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SLTerrain::Clear() { m_Width = 0; @@ -29,7 +29,7 @@ namespace RTE { m_OrbitDirection = Directions::Up; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int SLTerrain::Create() { SceneLayer::Create(); @@ -37,36 +37,40 @@ namespace RTE { m_Width = m_BitmapFile.GetImageWidth(); m_Height = m_BitmapFile.GetImageHeight(); - if (!m_FGColorLayer.get()) { m_FGColorLayer = std::make_unique(); } - if (!m_BGColorLayer.get()) { m_BGColorLayer = std::make_unique(); } + if (!m_FGColorLayer.get()) { + m_FGColorLayer = std::make_unique(); + } + if (!m_BGColorLayer.get()) { + m_BGColorLayer = std::make_unique(); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SLTerrain::Create(const SLTerrain &reference) { + int SLTerrain::Create(const SLTerrain& reference) { SceneLayer::Create(reference); m_Width = reference.m_Width; m_Height = reference.m_Height; // Copy the layers but not the layer BITMAPs because they will be loaded later by LoadData. - m_FGColorLayer.reset(dynamic_cast(reference.m_FGColorLayer->Clone())); - m_BGColorLayer.reset(dynamic_cast(reference.m_BGColorLayer->Clone())); + m_FGColorLayer.reset(dynamic_cast(reference.m_FGColorLayer->Clone())); + m_BGColorLayer.reset(dynamic_cast(reference.m_BGColorLayer->Clone())); m_DefaultBGTextureFile = reference.m_DefaultBGTextureFile; m_TerrainFrostings.clear(); - for (TerrainFrosting *terrainFrosting : reference.m_TerrainFrostings) { + for (TerrainFrosting* terrainFrosting: reference.m_TerrainFrostings) { m_TerrainFrostings.emplace_back(terrainFrosting); } m_TerrainDebris.clear(); - for (TerrainDebris *terrainDebris : reference.m_TerrainDebris) { + for (TerrainDebris* terrainDebris: reference.m_TerrainDebris) { m_TerrainDebris.emplace_back(terrainDebris); } m_TerrainObjects.clear(); - for (TerrainObject *terrainObject : reference.m_TerrainObjects) { + for (TerrainObject* terrainObject: reference.m_TerrainObjects) { m_TerrainObjects.emplace_back(terrainObject); } @@ -75,11 +79,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SLTerrain::ReadProperty(const std::string_view &propName, Reader &reader) { + int SLTerrain::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return SceneLayer::ReadProperty(propName, reader)); - + MatchProperty("BackgroundTexture", { reader >> m_DefaultBGTextureFile; }); MatchProperty("FGColorLayer", { m_FGColorLayer = std::make_unique(); @@ -119,13 +123,13 @@ namespace RTE { reader.ReportError("Unknown OrbitDirection '" + orbitDirection + "'!"); } }); - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SLTerrain::Save(Writer &writer) const { + int SLTerrain::Save(Writer& writer) const { SceneLayer::Save(writer); // Only write the background texture info if the background itself is not saved out as a file already, since saved, pre-rendered bitmaps don't need texturing. @@ -139,13 +143,13 @@ namespace RTE { if (m_FGColorLayer->IsLoadedFromDisk()) { writer.NewPropertyWithValue("FGColorLayer", m_FGColorLayer.get()); } else { - for (const TerrainFrosting *terrainFrosting : m_TerrainFrostings) { + for (const TerrainFrosting* terrainFrosting: m_TerrainFrostings) { writer.NewPropertyWithValue("AddTerrainFrosting", terrainFrosting); } - for (const TerrainDebris *terrainDebris : m_TerrainDebris) { + for (const TerrainDebris* terrainDebris: m_TerrainDebris) { writer.NewPropertyWithValue("AddTerrainDebris", terrainDebris); } - for (const TerrainObject *terrainObject : m_TerrainObjects) { + for (const TerrainObject* terrainObject: m_TerrainObjects) { // Write out only what is needed to place a copy of this in the Terrain writer.NewProperty("PlaceTerrainObject"); writer.ObjectStart(terrainObject->GetClassName()); @@ -157,39 +161,39 @@ namespace RTE { writer.NewProperty("OrbitDirection"); switch (m_OrbitDirection) { - default: - case Directions::Up: - writer << "Up"; - break; - case Directions::Down: - writer << "Down"; - break; - case Directions::Left: - writer << "Left"; - break; - case Directions::Right: - writer << "Right"; - break; + default: + case Directions::Up: + writer << "Up"; + break; + case Directions::Down: + writer << "Down"; + break; + case Directions::Left: + writer << "Left"; + break; + case Directions::Right: + writer << "Right"; + break; } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: Break this down and refactor. void SLTerrain::TexturizeTerrain() { - BITMAP *defaultBGLayerTexture = m_DefaultBGTextureFile.GetAsBitmap(); + BITMAP* defaultBGLayerTexture = m_DefaultBGTextureFile.GetAsBitmap(); BITMAP* fgLayerTexture = m_FGColorLayer->GetBitmap(); BITMAP* bgLayerTexture = m_BGColorLayer->GetBitmap(); - const std::array &materialPalette = g_SceneMan.GetMaterialPalette(); - const std::array &materialMappings = g_PresetMan.GetDataModule(m_BitmapFile.GetDataModuleID())->GetAllMaterialMappings(); + const std::array& materialPalette = g_SceneMan.GetMaterialPalette(); + const std::array& materialMappings = g_PresetMan.GetDataModule(m_BitmapFile.GetDataModuleID())->GetAllMaterialMappings(); - std::array materialFGTextures; + std::array materialFGTextures; materialFGTextures.fill(nullptr); - std::array materialBGTextures; + std::array materialBGTextures; materialBGTextures.fill(nullptr); std::array materialColors; materialColors.fill(0); @@ -202,64 +206,64 @@ namespace RTE { // Go through each pixel on the main bitmap, which contains all the material pixels loaded from the bitmap. // Place texture pixels on the FG layer corresponding to the materials on the main material bitmap. std::for_each(std::execution::par_unseq, std::begin(rows), std::end(rows), - [&](int yPos) { - for (int xPos = 0; xPos < m_MainBitmap->w; ++xPos) { - int matIndex = _getpixel(m_MainBitmap, xPos, yPos); - - // Map any materials defined in this data module but initially collided with other material ID's and thus were displaced to other ID's. - if (materialMappings[matIndex] != 0) { - // Assign the mapping and put it onto the material bitmap too. - matIndex = materialMappings[matIndex]; - _putpixel(m_MainBitmap, xPos, yPos, matIndex); - } - - RTEAssert(matIndex >= 0 && matIndex < c_PaletteEntriesNumber, "Invalid material index!"); - - // Validate the material, or fallback to default material. - const Material* material = materialPalette[matIndex] ? materialPalette[matIndex] : materialPalette[MaterialColorKeys::g_MaterialOutOfBounds]; - - BITMAP* fgTexture = materialFGTextures[matIndex]; - BITMAP* bgTexture = materialBGTextures[matIndex]; - - // If haven't read a pixel of this material before, then get its texture so we can quickly access it. - if (!fgTexture && material->GetFGTexture()) { - fgTexture = materialFGTextures[matIndex] = material->GetFGTexture(); - } - - if (!bgTexture && material->GetBGTexture()) { - bgTexture = materialBGTextures[matIndex] = material->GetBGTexture(); - } - - int fgPixelColor = 0; - - // If actually no texture for the material, then use the material's solid color instead. - if (!fgTexture) { - if (materialColors[matIndex] == 0) { - materialColors[matIndex] = material->GetColor().GetIndex(); - } - fgPixelColor = materialColors[matIndex]; - } else { - fgPixelColor = _getpixel(fgTexture, xPos % fgTexture->w, yPos % fgTexture->h); - } - _putpixel(fgLayerTexture, xPos, yPos, fgPixelColor); - - int bgPixelColor = 0; - if (matIndex == 0) { - bgPixelColor = ColorKeys::g_MaskColor; - } else { - if (!bgTexture) { - bgPixelColor = _getpixel(defaultBGLayerTexture, xPos % defaultBGLayerTexture->w, yPos % defaultBGLayerTexture->h); - } else { - bgPixelColor = _getpixel(bgTexture, xPos % bgTexture->w, yPos% bgTexture->h); - } - } - - _putpixel(bgLayerTexture, xPos, yPos, bgPixelColor); - } - }); + [&](int yPos) { + for (int xPos = 0; xPos < m_MainBitmap->w; ++xPos) { + int matIndex = _getpixel(m_MainBitmap, xPos, yPos); + + // Map any materials defined in this data module but initially collided with other material ID's and thus were displaced to other ID's. + if (materialMappings[matIndex] != 0) { + // Assign the mapping and put it onto the material bitmap too. + matIndex = materialMappings[matIndex]; + _putpixel(m_MainBitmap, xPos, yPos, matIndex); + } + + RTEAssert(matIndex >= 0 && matIndex < c_PaletteEntriesNumber, "Invalid material index!"); + + // Validate the material, or fallback to default material. + const Material* material = materialPalette[matIndex] ? materialPalette[matIndex] : materialPalette[MaterialColorKeys::g_MaterialOutOfBounds]; + + BITMAP* fgTexture = materialFGTextures[matIndex]; + BITMAP* bgTexture = materialBGTextures[matIndex]; + + // If haven't read a pixel of this material before, then get its texture so we can quickly access it. + if (!fgTexture && material->GetFGTexture()) { + fgTexture = materialFGTextures[matIndex] = material->GetFGTexture(); + } + + if (!bgTexture && material->GetBGTexture()) { + bgTexture = materialBGTextures[matIndex] = material->GetBGTexture(); + } + + int fgPixelColor = 0; + + // If actually no texture for the material, then use the material's solid color instead. + if (!fgTexture) { + if (materialColors[matIndex] == 0) { + materialColors[matIndex] = material->GetColor().GetIndex(); + } + fgPixelColor = materialColors[matIndex]; + } else { + fgPixelColor = _getpixel(fgTexture, xPos % fgTexture->w, yPos % fgTexture->h); + } + _putpixel(fgLayerTexture, xPos, yPos, fgPixelColor); + + int bgPixelColor = 0; + if (matIndex == 0) { + bgPixelColor = ColorKeys::g_MaskColor; + } else { + if (!bgTexture) { + bgPixelColor = _getpixel(defaultBGLayerTexture, xPos % defaultBGLayerTexture->w, yPos % defaultBGLayerTexture->h); + } else { + bgPixelColor = _getpixel(bgTexture, xPos % bgTexture->w, yPos % bgTexture->h); + } + } + + _putpixel(bgLayerTexture, xPos, yPos, bgPixelColor); + } + }); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int SLTerrain::LoadData() { SceneLayer::LoadData(); @@ -279,13 +283,13 @@ namespace RTE { TexturizeTerrain(); - for (const TerrainFrosting *terrainFrosting : m_TerrainFrostings) { + for (const TerrainFrosting* terrainFrosting: m_TerrainFrostings) { terrainFrosting->FrostTerrain(this); } - for (TerrainDebris *terrainDebris : m_TerrainDebris) { + for (TerrainDebris* terrainDebris: m_TerrainDebris) { terrainDebris->ScatterOnTerrain(this); } - for (TerrainObject *terrainObject : m_TerrainObjects) { + for (TerrainObject* terrainObject: m_TerrainObjects) { terrainObject->PlaceOnTerrain(this); } CleanAir(); @@ -293,9 +297,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SLTerrain::SaveData(const std::string &pathBase, bool doAsyncSaves) { + int SLTerrain::SaveData(const std::string& pathBase, bool doAsyncSaves) { if (pathBase.empty()) { return -1; } @@ -305,7 +309,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int SLTerrain::ClearData() { RTEAssert(SceneLayer::ClearData() == 0, "Failed to clear material bitmap data of an SLTerrain!"); @@ -314,16 +318,16 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SLTerrain::IsAirPixel(const int pixelX, const int pixelY) const { int checkPixel = GetPixel(pixelX, pixelY); return checkPixel == MaterialColorKeys::g_MaterialAir || checkPixel == MaterialColorKeys::g_MaterialCavity; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool SLTerrain::IsBoxBuried(const Box &checkBox) const { + bool SLTerrain::IsBoxBuried(const Box& checkBox) const { bool buried = true; buried = buried && !IsAirPixel(checkBox.GetCorner().GetFloorIntX(), checkBox.GetCorner().GetFloorIntY()); buried = buried && !IsAirPixel(static_cast(checkBox.GetCorner().GetX() + checkBox.GetWidth()), checkBox.GetCorner().GetFloorIntY()); @@ -332,28 +336,30 @@ namespace RTE { return buried; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SLTerrain::CleanAir() { std::vector rows(m_MainBitmap->h); // we loop through h first, because we want each thread to have sequential memory that they're touching std::iota(std::begin(rows), std::end(rows), 0); std::for_each(std::execution::par_unseq, std::begin(rows), std::end(rows), - [&](int yPos) { - for (int xPos = 0; xPos < m_MainBitmap->w; ++xPos) { - int matPixel = _getpixel(m_MainBitmap, xPos, yPos); - if (matPixel == MaterialColorKeys::g_MaterialCavity) { - _putpixel(m_MainBitmap, xPos, yPos, MaterialColorKeys::g_MaterialAir); - matPixel = MaterialColorKeys::g_MaterialAir; - } - if (matPixel == MaterialColorKeys::g_MaterialAir) { _putpixel(m_FGColorLayer->GetBitmap(), xPos, yPos, ColorKeys::g_MaskColor); } - } - }); + [&](int yPos) { + for (int xPos = 0; xPos < m_MainBitmap->w; ++xPos) { + int matPixel = _getpixel(m_MainBitmap, xPos, yPos); + if (matPixel == MaterialColorKeys::g_MaterialCavity) { + _putpixel(m_MainBitmap, xPos, yPos, MaterialColorKeys::g_MaterialAir); + matPixel = MaterialColorKeys::g_MaterialAir; + } + if (matPixel == MaterialColorKeys::g_MaterialAir) { + _putpixel(m_FGColorLayer->GetBitmap(), xPos, yPos, ColorKeys::g_MaskColor); + } + } + }); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SLTerrain::CleanAirBox(const Box &box, bool wrapsX, bool wrapsY) { + void SLTerrain::CleanAirBox(const Box& box, bool wrapsX, bool wrapsY) { int width = m_MainBitmap->w; int height = m_MainBitmap->h; @@ -363,12 +369,20 @@ namespace RTE { int wrappedY = y; if (wrapsX) { - if (wrappedX < 0) { wrappedX += width; } - if (wrappedX >= width) { wrappedX -= width; } + if (wrappedX < 0) { + wrappedX += width; + } + if (wrappedX >= width) { + wrappedX -= width; + } } if (wrapsY) { - if (wrappedY < 0) { wrappedY += height; } - if (wrappedY >= height) { wrappedY -= height; } + if (wrappedY < 0) { + wrappedY += height; + } + if (wrappedY >= height) { + wrappedY -= height; + } } if (wrappedX >= 0 && wrappedX < width && wrappedY >= 0 && wrappedY < height) { int matPixel = _getpixel(m_MainBitmap, wrappedX, wrappedY); @@ -376,16 +390,18 @@ namespace RTE { _putpixel(m_MainBitmap, wrappedX, wrappedY, MaterialColorKeys::g_MaterialAir); matPixel = MaterialColorKeys::g_MaterialAir; } - if (matPixel == MaterialColorKeys::g_MaterialAir) { _putpixel(m_FGColorLayer->GetBitmap(), wrappedX, wrappedY, ColorKeys::g_MaskColor); } + if (matPixel == MaterialColorKeys::g_MaterialAir) { + _putpixel(m_FGColorLayer->GetBitmap(), wrappedX, wrappedY, ColorKeys::g_MaskColor); + } } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: OPTIMIZE THIS, IT'S A TIME HOG. MAYBE JSUT STAMP THE OUTLINE AND SAMPLE SOME RANDOM PARTICLES? - std::deque SLTerrain::EraseSilhouette(BITMAP *sprite, const Vector &pos, const Vector &pivot, const Matrix &rotation, float scale, bool makeMOPs, int skipMOP, int maxMOPs) { + std::deque SLTerrain::EraseSilhouette(BITMAP* sprite, const Vector& pos, const Vector& pivot, const Matrix& rotation, float scale, bool makeMOPs, int skipMOP, int maxMOPs) { RTEAssert(sprite, "Null BITMAP passed to SLTerrain::EraseSilhouette"); int maxWidth = static_cast(static_cast(sprite->w + std::abs(pivot.GetFloorIntX() - (sprite->w / 2))) * scale); @@ -393,11 +409,11 @@ namespace RTE { int maxDiameter = static_cast(std::sqrt(static_cast(maxWidth * maxWidth + maxHeight * maxHeight)) * 2.0F); int skipCount = skipMOP; - BITMAP *tempBitmap = g_SceneMan.GetIntermediateBitmapForSettlingIntoTerrain(maxDiameter); + BITMAP* tempBitmap = g_SceneMan.GetIntermediateBitmapForSettlingIntoTerrain(maxDiameter); clear_bitmap(tempBitmap); pivot_scaled_sprite(tempBitmap, sprite, tempBitmap->w / 2, tempBitmap->h / 2, pivot.GetFloorIntX(), pivot.GetFloorIntY(), ftofix(rotation.GetAllegroAngle()), ftofix(scale)); - std::deque dislodgedMOPixels; + std::deque dislodgedMOPixels; // Test intersection between color pixels of the test bitmap and non-air pixels of the terrain, then generate and collect MOPixels that represent the terrain overlap and clear the same pixels out of the terrain. for (int testY = 0; testY < tempBitmap->h; ++testY) { @@ -444,8 +460,8 @@ namespace RTE { // Only add PixelMO if we're not due to skip any. if (makeMOPs && matPixel != MaterialColorKeys::g_MaterialAir && colorPixel != ColorKeys::g_MaskColor && ++skipCount > skipMOP && dislodgedMOPixels.size() < maxMOPs) { skipCount = 0; - const Material *sceneMat = g_SceneMan.GetMaterialFromID(matPixel); - const Material *spawnMat = sceneMat->GetSpawnMaterial() ? g_SceneMan.GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; + const Material* sceneMat = g_SceneMan.GetMaterialFromID(matPixel); + const Material* spawnMat = sceneMat->GetSpawnMaterial() ? g_SceneMan.GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; std::unique_ptr terrainPixelAtom = std::make_unique(Vector(), spawnMat->GetIndex(), nullptr, colorPixel, 2); std::unique_ptr terrainPixel = std::make_unique(colorPixel, spawnMat->GetPixelDensity(), Vector(static_cast(terrX), static_cast(terrY)), Vector(), terrainPixelAtom.release(), 0); @@ -457,7 +473,9 @@ namespace RTE { } // Clear the terrain pixels. - if (matPixel != MaterialColorKeys::g_MaterialAir) { putpixel(m_MainBitmap, terrX, terrY, MaterialColorKeys::g_MaterialAir); } + if (matPixel != MaterialColorKeys::g_MaterialAir) { + putpixel(m_MainBitmap, terrX, terrY, MaterialColorKeys::g_MaterialAir); + } if (colorPixel != ColorKeys::g_MaskColor) { putpixel(m_FGColorLayer->GetBitmap(), terrX, terrY, ColorKeys::g_MaskColor); g_SceneMan.RegisterTerrainChange(terrX, terrY, 1, 1, ColorKeys::g_MaskColor, false); @@ -471,7 +489,7 @@ namespace RTE { return dislodgedMOPixels; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SLTerrain::Update() { SceneLayer::Update(); @@ -480,9 +498,9 @@ namespace RTE { m_BGColorLayer->SetOffset(m_Offset); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SLTerrain::Draw(BITMAP *targetBitmap, Box &targetBox, bool offsetNeedsScrollRatioAdjustment) { + void SLTerrain::Draw(BITMAP* targetBitmap, Box& targetBox, bool offsetNeedsScrollRatioAdjustment) { switch (m_LayerToDraw) { case LayerType::MaterialLayer: SceneLayer::Draw(targetBitmap, targetBox); @@ -498,4 +516,4 @@ namespace RTE { break; } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/SLTerrain.h b/Source/Entities/SLTerrain.h index 451188a5b..a1ff35a36 100644 --- a/Source/Entities/SLTerrain.h +++ b/Source/Entities/SLTerrain.h @@ -17,7 +17,6 @@ namespace RTE { class SLTerrain : public SceneLayer { public: - EntityAllocation(SLTerrain); SerializableOverrideMethods; ClassInfoGetters; @@ -25,7 +24,11 @@ namespace RTE { /// /// Enumeration for the different type of layers in the SLTerrain. /// - enum class LayerType { ForegroundLayer, BackgroundLayer, MaterialLayer }; + enum class LayerType { + ForegroundLayer, + BackgroundLayer, + MaterialLayer + }; #pragma region Creation /// @@ -44,7 +47,7 @@ namespace RTE { /// /// A reference to the SLTerrain to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const SLTerrain &reference); + int Create(const SLTerrain& reference); #pragma endregion #pragma region Destruction @@ -57,7 +60,12 @@ namespace RTE { /// Destroys and resets (through Clear()) the SLTerrain object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { SceneLayer::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + SceneLayer::Destroy(); + } + Clear(); + } #pragma endregion #pragma region Data Handling @@ -79,7 +87,7 @@ namespace RTE { /// The filepath base to the where to save the Bitmap data. This means everything up to the extension. "FG" and "Mat" etc will be added. /// Whether or not to save asynchronously. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int SaveData(const std::string &pathBase, bool doAsyncSaves = true) override; + int SaveData(const std::string& pathBase, bool doAsyncSaves = true) override; /// /// Clears out any previously loaded bitmap data from memory. @@ -111,19 +119,19 @@ namespace RTE { /// Gets the foreground color bitmap of this SLTerrain. /// /// A pointer to the foreground color bitmap. - BITMAP * GetFGColorBitmap() { return m_FGColorLayer->GetBitmap(); } + BITMAP* GetFGColorBitmap() { return m_FGColorLayer->GetBitmap(); } /// /// Gets the background color bitmap of this SLTerrain. /// /// A pointer to the background color bitmap. - BITMAP * GetBGColorBitmap() { return m_BGColorLayer->GetBitmap(); } + BITMAP* GetBGColorBitmap() { return m_BGColorLayer->GetBitmap(); } /// /// Gets the material bitmap of this SLTerrain. /// /// A pointer to the material bitmap. - BITMAP * GetMaterialBitmap() { return m_MainBitmap; } + BITMAP* GetMaterialBitmap() { return m_MainBitmap; } /// /// Gets a specific pixel from the foreground color bitmap of this. LockBitmaps() must be called before using this method. @@ -186,7 +194,7 @@ namespace RTE { /// /// The box to check. /// Whether the box is completely buried, i.e. no corner sticks out in the Air or Cavity. - bool IsBoxBuried(const Box &checkBox) const; + bool IsBoxBuried(const Box& checkBox) const; #pragma endregion #pragma region Concrete Methods @@ -194,13 +202,13 @@ namespace RTE { /// Gets a deque of unwrapped boxes which show the areas where the material layer has had objects applied to it since last call to ClearUpdatedMaterialAreas(). /// /// Reference to the deque that has been filled with Boxes which are unwrapped and may be out of bounds of the scene! - std::deque & GetUpdatedMaterialAreas() { return m_UpdatedMaterialAreas; } + std::deque& GetUpdatedMaterialAreas() { return m_UpdatedMaterialAreas; } /// /// Adds a notification that an area of the material terrain has been updated. /// /// The Box defining the newly updated material area that can be unwrapped and may be out of bounds of the scene. - void AddUpdatedMaterialArea(const Box &newArea) { m_UpdatedMaterialAreas.emplace_back(newArea); } + void AddUpdatedMaterialArea(const Box& newArea) { m_UpdatedMaterialAreas.emplace_back(newArea); } /// /// Removes any color pixel in the color layer of this SLTerrain wherever there is an air material pixel in the material layer. @@ -213,7 +221,7 @@ namespace RTE { /// Box to clean. /// Whether the scene is X-wrapped. /// Whether the scene is Y-wrapped. - void CleanAirBox(const Box &box, bool wrapsX, bool wrapsY); + void CleanAirBox(const Box& box, bool wrapsX, bool wrapsY); /// /// Takes a BITMAP and scans through the pixels on this terrain for pixels which overlap with it. Erases them from the terrain and can optionally generate MOPixels based on the erased or 'dislodged' terrain pixels. @@ -227,7 +235,7 @@ namespace RTE { /// How many pixels to skip making MOPixels from, between each that gets made. 0 means every pixel turns into an MOPixel. /// The max number of MOPixels to make, if they are to be made. /// A deque filled with the MOPixels of the terrain that are now dislodged. This will be empty if makeMOPs is false. Note that ownership of all the MOPixels in the deque IS transferred! - std::deque EraseSilhouette(BITMAP *sprite, const Vector &pos, const Vector &pivot, const Matrix &rotation, float scale, bool makeMOPs = true, int skipMOP = 2, int maxMOPs = 150); + std::deque EraseSilhouette(BITMAP* sprite, const Vector& pos, const Vector& pivot, const Matrix& rotation, float scale, bool makeMOPs = true, int skipMOP = 2, int maxMOPs = 150); /// /// Returns the direction of the out-of-bounds "orbit" for this scene, where the brain must path to and where dropships/rockets come from. @@ -248,11 +256,10 @@ namespace RTE { /// The bitmap to draw to. /// The box on the target bitmap to limit drawing to, with the corner of box being where the scroll position lines up. /// Whether the offset of this SceneLayer or the passed in offset override need to be adjusted to scroll ratio. - void Draw(BITMAP *targetBitmap, Box &targetBox, bool offsetNeedsScrollRatioAdjustment = false) override; + void Draw(BITMAP* targetBitmap, Box& targetBox, bool offsetNeedsScrollRatioAdjustment = false) override; #pragma endregion private: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. int m_Width; //!< The width of this SLTerrain as determined by the main (material) bitmap, in pixels. @@ -265,9 +272,9 @@ namespace RTE { ContentFile m_DefaultBGTextureFile; //!< The background texture file that will be used to texturize Materials that have no defined background texture. - std::vector m_TerrainFrostings; //!< The TerrainFrostings that need to be placed on this SLTerrain. - std::vector m_TerrainDebris; //!< The TerrainDebris that need to be placed on this SLTerrain. - std::vector m_TerrainObjects; //!< The TerrainObjects that need to be placed on this SLTerrain. + std::vector m_TerrainFrostings; //!< The TerrainFrostings that need to be placed on this SLTerrain. + std::vector m_TerrainDebris; //!< The TerrainDebris that need to be placed on this SLTerrain. + std::vector m_TerrainObjects; //!< The TerrainObjects that need to be placed on this SLTerrain. std::deque m_UpdatedMaterialAreas; //!< List of areas of the material layer (main bitmap) which have been affected by new objects copied to it. These boxes are NOT wrapped, and can be out of bounds! @@ -284,8 +291,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - SLTerrain(const SLTerrain &reference) = delete; - SLTerrain & operator=(const SLTerrain &rhs) = delete; + SLTerrain(const SLTerrain& reference) = delete; + SLTerrain& operator=(const SLTerrain& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/Scene.cpp b/Source/Entities/Scene.cpp index 2046eee9a..91a11c0ab 100644 --- a/Source/Entities/Scene.cpp +++ b/Source/Entities/Scene.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -49,3112 +48,2831 @@ namespace RTE { -ConcreteClassInfo(Scene, Entity, 0); -const std::string Scene::Area::c_ClassName = "Area"; + ConcreteClassInfo(Scene, Entity, 0); + const std::string Scene::Area::c_ClassName = "Area"; -// Holds the path calculated by CalculateScenePath -thread_local std::list s_ScenePath; + // Holds the path calculated by CalculateScenePath + thread_local std::list s_ScenePath; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Area, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Area, effectively -// resetting the members of this abstraction level only. + void Scene::Area::Clear() { + m_BoxList.clear(); + m_Name.clear(); + } -void Scene::Area::Clear() -{ - m_BoxList.clear(); - m_Name.clear(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Area to be identical to another, by deep copy. + int Scene::Area::Create(const Area& reference) { + for (std::vector::const_iterator itr = reference.m_BoxList.begin(); itr != reference.m_BoxList.end(); ++itr) + m_BoxList.push_back(*itr); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Area to be identical to another, by deep copy. + m_Name = reference.m_Name; -int Scene::Area::Create(const Area &reference) -{ - for (std::vector::const_iterator itr = reference.m_BoxList.begin(); itr != reference.m_BoxList.end(); ++itr) - m_BoxList.push_back(*itr); + return 0; + } - m_Name = reference.m_Name; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Area object ready for use. - return 0; -} + int Scene::Area::Create() { + if (Serializable::Create() < 0) + return -1; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Area object ready for use. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. -int Scene::Area::Create() -{ - if (Serializable::Create() < 0) - return -1; + int Scene::Area::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Serializable::ReadProperty(propName, reader)); - return 0; -} + MatchProperty("AddBox", + Box box; + reader >> box; + m_BoxList.push_back(box);); + MatchProperty("Name", { reader >> m_Name; }); + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Area with a Writer for + // later recreation with Create(Reader &reader); -int Scene::Area::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Serializable::ReadProperty(propName, reader)); - - MatchProperty("AddBox", - Box box; - reader >> box; - m_BoxList.push_back(box); ); - MatchProperty("Name", { reader >> m_Name; }); + int Scene::Area::Save(Writer& writer) const { + Serializable::Save(writer); - EndPropertyList; -} + for (std::vector::const_iterator itr = m_BoxList.begin(); itr != m_BoxList.end(); ++itr) { + writer.NewProperty("AddBox"); + writer << *itr; + } + writer.NewProperty("Name"); + writer << m_Name; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Area with a Writer for -// later recreation with Create(Reader &reader); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: AddBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a Box to this' area coverage. -int Scene::Area::Save(Writer &writer) const -{ - Serializable::Save(writer); + bool Scene::Area::AddBox(const Box& newBox) { + if (newBox.IsEmpty()) + return false; - for (std::vector::const_iterator itr = m_BoxList.begin(); itr != m_BoxList.end(); ++itr) - { - writer.NewProperty("AddBox"); - writer << *itr; - } - writer.NewProperty("Name"); - writer << m_Name; + m_BoxList.push_back(newBox); + return true; + } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool Scene::Area::RemoveBox(const Box& boxToRemove) { + std::vector::iterator boxToRemoveIterator = std::find(m_BoxList.begin(), m_BoxList.end(), boxToRemove); + if (boxToRemoveIterator != m_BoxList.end()) { + m_BoxList.erase(boxToRemoveIterator); + return true; + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: AddBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a Box to this' area coverage. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool Scene::Area::AddBox(const Box &newBox) -{ - if (newBox.IsEmpty()) - return false; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: HasNoArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this really has no Area at all, ie it doesn't have any + // Box:es with both width and height. - m_BoxList.push_back(newBox); - return true; -} + bool Scene::Area::HasNoArea() const { + // If no boxes, then yeah we don't have any area + if (m_BoxList.empty()) + return true; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Search through the boxes to see if we find any with both width and height + for (std::vector::const_iterator itr = m_BoxList.begin(); itr != m_BoxList.end(); ++itr) { + if (!itr->IsEmpty()) + return false; + } -bool Scene::Area::RemoveBox(const Box &boxToRemove) { - std::vector::iterator boxToRemoveIterator = std::find(m_BoxList.begin(), m_BoxList.end(), boxToRemove); - if (boxToRemoveIterator != m_BoxList.end()) { - m_BoxList.erase(boxToRemoveIterator); - return true; - } - return false; -} + return true; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsInside + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether a point is anywhere inside this Area's coverage. + + bool Scene::Area::IsInside(const Vector& point) const { + std::list wrappedBoxes; + for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*aItr, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + if (wItr->IsWithinBox(point)) + return true; + } + } + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsInsideX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the + // X-axis only. + + bool Scene::Area::IsInsideX(float pointX) const { + std::list wrappedBoxes; + for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*aItr, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + if (wItr->IsWithinBoxX(pointX)) + return true; + } + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: HasNoArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this really has no Area at all, ie it doesn't have any -// Box:es with both width and height. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsInsideY + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the + // Y-axis only. + + bool Scene::Area::IsInsideY(float pointY) const { + std::list wrappedBoxes; + for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*aItr, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + if (wItr->IsWithinBoxY(pointY)) + return true; + } + } + return false; + } -bool Scene::Area::HasNoArea() const -{ - // If no boxes, then yeah we don't have any area - if (m_BoxList.empty()) - return true; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: MovePointInsideX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Moves a coordinate to the closest value which is within any of this + // Area's Box:es, in the X axis only. + + bool Scene::Area::MovePointInsideX(float& pointX, int direction) const { + if (HasNoArea() || IsInsideX(pointX)) + return false; + + float notFoundValue = 10000000; + float shortest = notFoundValue; + float shortestConstrained = notFoundValue; + float testDistance = 0; + std::list wrappedBoxes; + for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*aItr, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::const_iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + // Check against one edge of the box for the shortest distance + testDistance = g_SceneMan.ShortestDistanceX(pointX, (*wItr).GetCorner().m_X, false, direction); + // See if it's shorter than the shortest without constraints + if (fabs(testDistance) < fabs(shortest)) + shortest = testDistance; + // Also see if it's the shortest constrained distance + if (fabs(testDistance) < fabs(shortestConstrained) && (direction == 0 || (direction > 0 && testDistance > 0) || (direction < 0 && testDistance < 0))) + shortestConstrained = testDistance; + + // Then check against the other edge of the box + testDistance = g_SceneMan.ShortestDistanceX(pointX, (*wItr).GetCorner().m_X + (*wItr).GetWidth(), false, direction); + // See if it's shorter than the shortest without constraints + if (fabs(testDistance) < fabs(shortest)) + shortest = testDistance; + // Also see if it's the shortest constrained distance + if (fabs(testDistance) < fabs(shortestConstrained) && (direction == 0 || (direction > 0 && testDistance > 0) || (direction < 0 && testDistance < 0))) + shortestConstrained = testDistance; + } + } - // Search through the boxes to see if we find any with both width and height - for (std::vector::const_iterator itr = m_BoxList.begin(); itr != m_BoxList.end(); ++itr) - { - if (!itr->IsEmpty()) - return false; - } + // If we couldn't find any by adhering to the direction constraint, then use the shortest unconstrained found + if (shortestConstrained == notFoundValue) + pointX += shortest; + // Move the point the shortest distance we found, recognizing the direction constraints + else + pointX += shortestConstrained; - return true; -} + // Wrap it so it's inside the scene still + int x = pointX, crap = 0; + g_SceneMan.ForceBounds(x, crap); + pointX = x; + return true; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsInside -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether a point is anywhere inside this Area's coverage. - -bool Scene::Area::IsInside(const Vector &point) const -{ - std::list wrappedBoxes; - for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*aItr, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - if (wItr->IsWithinBox(point)) - return true; - } - } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetBoxInside + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the first Box encountered in this that contains a specific point. + + Box* Scene::Area::GetBoxInside(const Vector& point) { + std::list wrappedBoxes; + for (std::vector::iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*aItr, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::const_iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + // Return the BoxList box, not the inconsequential wrapped copy + if (wItr->IsWithinBox(point)) + return &(*aItr); + } + } + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RemoveBoxInside + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes the first Box encountered in this that contains a specific point. + + Box Scene::Area::RemoveBoxInside(const Vector& point) { + Box returnBox; + + std::list wrappedBoxes; + for (std::vector::iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*aItr, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + if (wItr->IsWithinBox(point)) { + // Remove the BoxList box, not the inconsequential wrapped copy + returnBox = (*aItr); + m_BoxList.erase(aItr); + return returnBox; + } + } + } + return returnBox; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsInsideX -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the -// X-axis only. - -bool Scene::Area::IsInsideX(float pointX) const -{ - std::list wrappedBoxes; - for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*aItr, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - if (wItr->IsWithinBoxX(pointX)) - return true; - } - } - return false; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetCenterPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a center point for this of all the boxes waeighted by their sizes. + // Arguments: None. + Vector Scene::Area::GetCenterPoint() const { + Vector areaCenter; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsInsideY -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the -// Y-axis only. - -bool Scene::Area::IsInsideY(float pointY) const -{ - std::list wrappedBoxes; - for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*aItr, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - if (wItr->IsWithinBoxY(pointY)) - return true; - } - } - return false; -} + if (!m_BoxList.empty()) { + if (m_BoxList.size() == 1) { + return m_BoxList[0].GetCenter(); + } + float totalWeight = 0; + for (std::vector::const_iterator itr = m_BoxList.begin(); itr != m_BoxList.end(); ++itr) { + // Doubly weighted + areaCenter += (*itr).GetCenter() * (*itr).GetArea() * 2; + totalWeight += (*itr).GetArea() * 2; + } + // Average center of the all the boxes, weighted by their respective areas + areaCenter /= totalWeight; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: MovePointInsideX -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Moves a coordinate to the closest value which is within any of this -// Area's Box:es, in the X axis only. - -bool Scene::Area::MovePointInsideX(float &pointX, int direction) const -{ - if (HasNoArea() || IsInsideX(pointX)) - return false; - - float notFoundValue = 10000000; - float shortest = notFoundValue; - float shortestConstrained = notFoundValue; - float testDistance = 0; - std::list wrappedBoxes; - for (std::vector::const_iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*aItr, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::const_iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - // Check against one edge of the box for the shortest distance - testDistance = g_SceneMan.ShortestDistanceX(pointX, (*wItr).GetCorner().m_X, false, direction); - // See if it's shorter than the shortest without constraints - if (fabs(testDistance) < fabs(shortest)) - shortest = testDistance; - // Also see if it's the shortest constrained distance - if (fabs(testDistance) < fabs(shortestConstrained) && (direction == 0 || (direction > 0 && testDistance > 0) || (direction < 0 && testDistance < 0))) - shortestConstrained = testDistance; - - // Then check against the other edge of the box - testDistance = g_SceneMan.ShortestDistanceX(pointX, (*wItr).GetCorner().m_X + (*wItr).GetWidth(), false, direction); - // See if it's shorter than the shortest without constraints - if (fabs(testDistance) < fabs(shortest)) - shortest = testDistance; - // Also see if it's the shortest constrained distance - if (fabs(testDistance) < fabs(shortestConstrained) && (direction == 0 || (direction > 0 && testDistance > 0) || (direction < 0 && testDistance < 0))) - shortestConstrained = testDistance; - } - } - - // If we couldn't find any by adhering to the direction constraint, then use the shortest unconstrained found - if (shortestConstrained == notFoundValue) - pointX += shortest; - // Move the point the shortest distance we found, recognizing the direction constraints - else - pointX += shortestConstrained; - - // Wrap it so it's inside the scene still - int x = pointX, crap = 0; - g_SceneMan.ForceBounds(x, crap); - pointX = x; - - return true; -} + return areaCenter; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRandomPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a random coordinate contained within any of this' Box:es. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetBoxInside -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the first Box encountered in this that contains a specific point. - -Box * Scene::Area::GetBoxInside(const Vector &point) -{ - std::list wrappedBoxes; - for (std::vector::iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*aItr, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::const_iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - // Return the BoxList box, not the inconsequential wrapped copy - if (wItr->IsWithinBox(point)) - return &(*aItr); - } - } - return 0; -} + Vector Scene::Area::GetRandomPoint() const { + // If no boxes, then can't return valid point + if (m_BoxList.empty()) + return Vector(); + // Randomly choose a box, and a point within it + return m_BoxList[RandomNum(0, m_BoxList.size() - 1)].GetRandomPoint(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: RemoveBoxInside -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes the first Box encountered in this that contains a specific point. - -Box Scene::Area::RemoveBoxInside(const Vector &point) -{ - Box returnBox; - - std::list wrappedBoxes; - for (std::vector::iterator aItr = m_BoxList.begin(); aItr != m_BoxList.end(); ++aItr) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*aItr, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - if (wItr->IsWithinBox(point)) - { - // Remove the BoxList box, not the inconsequential wrapped copy - returnBox = (*aItr); - m_BoxList.erase(aItr); - return returnBox; - } - } - } - return returnBox; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Scene, effectively + // resetting the members of this abstraction level only. + + void Scene::Clear() { + m_Location.Reset(); + m_LocationOffset.Reset(); + m_MetagamePlayable = false; // Let scenes be non-metagame playable by default, they need AI building plans anyway + m_Revealed = false; + m_OwnedByTeam = Activity::NoTeam; + m_RoundIncome = 1000; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + m_ResidentBrains[player] = 0; + m_BuildBudget[player] = 0; + m_BuildBudgetRatio[player] = 0; + } + m_AutoDesigned = true; + m_TotalInvestment = 0; + m_pTerrain = 0; + for (std::unique_ptr& pathFinder: m_pPathFinders) { + pathFinder.reset(); + } + m_PathfindingUpdated = false; + m_PartialPathUpdateTimer.Reset(); + + for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) + m_PlacedObjects[set].clear(); + m_BackLayerList.clear(); + m_Deployments.clear(); + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + m_UnseenPixelSize[team].Reset(); + m_apUnseenLayer[team] = 0; + m_SeenPixels[team].clear(); + m_CleanedPixels[team].clear(); + m_ScanScheduled[team] = false; + } + m_AreaList.clear(); + m_NavigatableAreas.clear(); + m_NavigatableAreasUpToDate = false; + m_Locked = false; + m_GlobalAcc.Reset(); + m_SelectedAssemblies.clear(); + m_AssembliesCounts.clear(); + m_pPreviewBitmap = 0; + m_MetasceneParent.clear(); + m_IsMetagameInternal = false; + m_IsSavedGameInternal = false; + } + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Scene object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetCenterPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a center point for this of all the boxes waeighted by their sizes. -// Arguments: None. + int Scene::Create() + { + if (Entity::Create() < 0) + return -1; -Vector Scene::Area::GetCenterPoint() const -{ - Vector areaCenter; + return 0; + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Scene object ready for use. + // Arguments: The Terrain to use. Ownership IS transferred! + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Scene::Create(SLTerrain* pNewTerrain) { + m_pTerrain = pNewTerrain; + // TODO: allow setting of other stuff too + m_GlobalAcc = Vector(0, 20); + + return 0; + } - if (!m_BoxList.empty()) { - if (m_BoxList.size() == 1) { - return m_BoxList[0].GetCenter(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a MOPixel to be identical to another, by deep copy. + + int Scene::Create(const Scene& reference) { + Entity::Create(reference); + + m_Location = reference.m_Location; + m_LocationOffset = reference.m_LocationOffset; + m_MetagamePlayable = reference.m_MetagamePlayable; + m_Revealed = reference.m_Revealed; + m_OwnedByTeam = reference.m_OwnedByTeam; + m_RoundIncome = reference.m_RoundIncome; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (reference.m_ResidentBrains[player]) + m_ResidentBrains[player] = dynamic_cast(reference.m_ResidentBrains[player]->Clone()); + m_BuildBudget[player] = reference.m_BuildBudget[player]; + m_BuildBudgetRatio[player] = reference.m_BuildBudgetRatio[player]; } + m_AutoDesigned = reference.m_AutoDesigned; + m_TotalInvestment = reference.m_TotalInvestment; + m_pTerrain = dynamic_cast(reference.m_pTerrain->Clone()); - float totalWeight = 0; - for (std::vector::const_iterator itr = m_BoxList.begin(); itr != m_BoxList.end(); ++itr) - { - // Doubly weighted - areaCenter += (*itr).GetCenter() * (*itr).GetArea() * 2; - totalWeight += (*itr).GetArea() * 2; - } - // Average center of the all the boxes, weighted by their respective areas - areaCenter /= totalWeight; - } - - return areaCenter; -} - + for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) { + for (std::list::const_iterator oItr = reference.m_PlacedObjects[set].begin(); oItr != reference.m_PlacedObjects[set].end(); ++oItr) + m_PlacedObjects[set].push_back(dynamic_cast((*oItr)->Clone())); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRandomPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a random coordinate contained within any of this' Box:es. + for (std::list::const_iterator lItr = reference.m_BackLayerList.begin(); lItr != reference.m_BackLayerList.end(); ++lItr) + m_BackLayerList.push_back(dynamic_cast((*lItr)->Clone())); -Vector Scene::Area::GetRandomPoint() const -{ - // If no boxes, then can't return valid point - if (m_BoxList.empty()) - return Vector(); + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + // If the Unseen layers are loaded, then copy them. If not, then copy the procedural param that is responsible for creating them + if (reference.m_apUnseenLayer[team]) + m_apUnseenLayer[team] = dynamic_cast(reference.m_apUnseenLayer[team]->Clone()); + else + m_UnseenPixelSize[team] = reference.m_UnseenPixelSize[team]; - // Randomly choose a box, and a point within it - return m_BoxList[RandomNum(0, m_BoxList.size() - 1)].GetRandomPoint(); -} + // Always copy the scan scheduling flags + m_ScanScheduled[team] = reference.m_ScanScheduled[team]; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Scene, effectively -// resetting the members of this abstraction level only. - -void Scene::Clear() -{ - m_Location.Reset(); - m_LocationOffset.Reset(); - m_MetagamePlayable = false; // Let scenes be non-metagame playable by default, they need AI building plans anyway - m_Revealed = false; - m_OwnedByTeam = Activity::NoTeam; - m_RoundIncome = 1000; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - m_ResidentBrains[player] = 0; - m_BuildBudget[player] = 0; - m_BuildBudgetRatio[player] = 0; - } - m_AutoDesigned = true; - m_TotalInvestment = 0; - m_pTerrain = 0; - for (std::unique_ptr &pathFinder : m_pPathFinders) { - pathFinder.reset(); - } - m_PathfindingUpdated = false; - m_PartialPathUpdateTimer.Reset(); - - for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) - m_PlacedObjects[set].clear(); - m_BackLayerList.clear(); - m_Deployments.clear(); - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - m_UnseenPixelSize[team].Reset(); - m_apUnseenLayer[team] = 0; - m_SeenPixels[team].clear(); - m_CleanedPixels[team].clear(); - m_ScanScheduled[team] = false; - } - m_AreaList.clear(); - m_NavigatableAreas.clear(); - m_NavigatableAreasUpToDate = false; - m_Locked = false; - m_GlobalAcc.Reset(); - m_SelectedAssemblies.clear(); - m_AssembliesCounts.clear(); - m_pPreviewBitmap = 0; - m_MetasceneParent.clear(); - m_IsMetagameInternal = false; - m_IsSavedGameInternal = false; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Scene object ready for use. + // Copy areas + for (std::list::const_iterator aItr = reference.m_AreaList.begin(); aItr != reference.m_AreaList.end(); ++aItr) + m_AreaList.push_back(*aItr); -int Scene::Create() -{ - if (Entity::Create() < 0) - return -1; + m_GlobalAcc = reference.m_GlobalAcc; - return 0; -} -*/ + // Deep copy of the bitmap + if (reference.m_pPreviewBitmap) { + // Copy the bitmap from the ContentFile, because we're going to be changing it! + BITMAP* pCopyFrom = reference.m_pPreviewBitmap; + // Destination + m_pPreviewBitmap = create_bitmap_ex(8, pCopyFrom->w, pCopyFrom->h); + RTEAssert(m_pPreviewBitmap, "Failed to allocate BITMAP in Scene::Create"); + m_PreviewBitmapFile = reference.m_PreviewBitmapFile; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Scene object ready for use. -// Arguments: The Terrain to use. Ownership IS transferred! -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. + // Copy! + blit(pCopyFrom, m_pPreviewBitmap, 0, 0, 0, 0, pCopyFrom->w, pCopyFrom->h); + } -int Scene::Create(SLTerrain *pNewTerrain) -{ - m_pTerrain = pNewTerrain; -// TODO: allow setting of other stuff too - m_GlobalAcc = Vector(0, 20); + m_MetasceneParent = reference.m_MetasceneParent; + m_IsMetagameInternal = reference.m_IsMetagameInternal; + m_IsSavedGameInternal = reference.m_IsSavedGameInternal; + return 0; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: LoadData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Actually loads previously specified/created data into memory. Has + // to be done before using this SceneLayer. + int Scene::LoadData(bool placeObjects, bool initPathfinding, bool placeUnits) { + RTEAssert(m_pTerrain, "Terrain not instantiated before trying to load its data!"); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a MOPixel to be identical to another, by deep copy. - -int Scene::Create(const Scene &reference) -{ - Entity::Create(reference); - - m_Location = reference.m_Location; - m_LocationOffset = reference.m_LocationOffset; - m_MetagamePlayable = reference.m_MetagamePlayable; - m_Revealed = reference.m_Revealed; - m_OwnedByTeam = reference.m_OwnedByTeam; - m_RoundIncome = reference.m_RoundIncome; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (reference.m_ResidentBrains[player]) - m_ResidentBrains[player] = dynamic_cast(reference.m_ResidentBrains[player]->Clone()); - m_BuildBudget[player] = reference.m_BuildBudget[player]; - m_BuildBudgetRatio[player] = reference.m_BuildBudgetRatio[player]; - } - m_AutoDesigned = reference.m_AutoDesigned; - m_TotalInvestment = reference.m_TotalInvestment; - m_pTerrain = dynamic_cast(reference.m_pTerrain->Clone()); - - for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) - { - for (std::list::const_iterator oItr = reference.m_PlacedObjects[set].begin(); oItr != reference.m_PlacedObjects[set].end(); ++oItr) - m_PlacedObjects[set].push_back(dynamic_cast((*oItr)->Clone())); - } - - for (std::list::const_iterator lItr = reference.m_BackLayerList.begin(); lItr != reference.m_BackLayerList.end(); ++lItr) - m_BackLayerList.push_back(dynamic_cast((*lItr)->Clone())); - - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - // If the Unseen layers are loaded, then copy them. If not, then copy the procedural param that is responsible for creating them - if (reference.m_apUnseenLayer[team]) - m_apUnseenLayer[team] = dynamic_cast(reference.m_apUnseenLayer[team]->Clone()); - else - m_UnseenPixelSize[team] = reference.m_UnseenPixelSize[team]; - - // Always copy the scan scheduling flags - m_ScanScheduled[team] = reference.m_ScanScheduled[team]; - } - - // Copy areas - for (std::list::const_iterator aItr = reference.m_AreaList.begin(); aItr != reference.m_AreaList.end(); ++aItr) - m_AreaList.push_back(*aItr); - - m_GlobalAcc = reference.m_GlobalAcc; - - // Deep copy of the bitmap - if (reference.m_pPreviewBitmap) - { - // Copy the bitmap from the ContentFile, because we're going to be changing it! - BITMAP *pCopyFrom = reference.m_pPreviewBitmap; - // Destination - m_pPreviewBitmap = create_bitmap_ex(8, pCopyFrom->w, pCopyFrom->h); - RTEAssert(m_pPreviewBitmap, "Failed to allocate BITMAP in Scene::Create"); - m_PreviewBitmapFile = reference.m_PreviewBitmapFile; - - // Copy! - blit(pCopyFrom, m_pPreviewBitmap, 0, 0, 0, 0, pCopyFrom->w, pCopyFrom->h); - } - - m_MetasceneParent = reference.m_MetasceneParent; - m_IsMetagameInternal = reference.m_IsMetagameInternal; - m_IsSavedGameInternal = reference.m_IsSavedGameInternal; - return 0; -} + /////////////////////////////////// + // Load Terrain's data + if (m_pTerrain->LoadData() < 0) { + RTEAbort("Loading Terrain " + m_pTerrain->GetPresetName() + "\'s data failed!"); + return -1; + } + for (SLBackground* backgroundLayer: m_BackLayerList) { + backgroundLayer->InitScaleFactors(); + } + /////////////////////////////////// + // Load Unseen layers before applying objects to the scene, + // so we can reveal around stuff that is getting placed for the appropriate team + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + // Specified to dynamically create the unseen layer? + if (!m_UnseenPixelSize[team].IsZero()) { + // Create the bitmap to make the unseen scene layer out of + BITMAP* pUnseenBitmap = create_bitmap_ex(8, GetWidth() / m_UnseenPixelSize[team].m_X, GetHeight() / m_UnseenPixelSize[team].m_Y); + clear_to_color(pUnseenBitmap, g_BlackColor); + // Replace any old unseen layer with the new one that is generated + delete m_apUnseenLayer[team]; + m_apUnseenLayer[team] = new SceneLayer(); + m_apUnseenLayer[team]->Create(pUnseenBitmap, true, Vector(), WrapsX(), WrapsY(), Vector(1.0, 1.0)); + m_apUnseenLayer[team]->SetScaleFactor(m_UnseenPixelSize[team]); + } + // If not dynamically generated, was it custom loaded? + else if (m_apUnseenLayer[team]) { + // Load unseen layer data from file + if (m_apUnseenLayer[team]->LoadData() < 0) { + g_ConsoleMan.PrintString("ERROR: Loading unseen layer " + m_apUnseenLayer[team]->GetPresetName() + "\'s data failed!"); + return -1; + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: LoadData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Actually loads previously specified/created data into memory. Has -// to be done before using this SceneLayer. - -int Scene::LoadData(bool placeObjects, bool initPathfinding, bool placeUnits) -{ - RTEAssert(m_pTerrain, "Terrain not instantiated before trying to load its data!"); - - /////////////////////////////////// - // Load Terrain's data - if (m_pTerrain->LoadData() < 0) - { - RTEAbort("Loading Terrain " + m_pTerrain->GetPresetName() + "\'s data failed!"); - return -1; - } - for (SLBackground *backgroundLayer : m_BackLayerList) { - backgroundLayer->InitScaleFactors(); - } - - /////////////////////////////////// - // Load Unseen layers before applying objects to the scene, - // so we can reveal around stuff that is getting placed for the appropriate team - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - // Specified to dynamically create the unseen layer? - if (!m_UnseenPixelSize[team].IsZero()) - { - // Create the bitmap to make the unseen scene layer out of - BITMAP *pUnseenBitmap = create_bitmap_ex(8, GetWidth() / m_UnseenPixelSize[team].m_X, GetHeight() / m_UnseenPixelSize[team].m_Y); - clear_to_color(pUnseenBitmap, g_BlackColor); - // Replace any old unseen layer with the new one that is generated - delete m_apUnseenLayer[team]; - m_apUnseenLayer[team] = new SceneLayer(); - m_apUnseenLayer[team]->Create(pUnseenBitmap, true, Vector(), WrapsX(), WrapsY(), Vector(1.0, 1.0)); - m_apUnseenLayer[team]->SetScaleFactor(m_UnseenPixelSize[team]); - } - // If not dynamically generated, was it custom loaded? - else if (m_apUnseenLayer[team]) - { - // Load unseen layer data from file - if (m_apUnseenLayer[team]->LoadData() < 0) - { - g_ConsoleMan.PrintString("ERROR: Loading unseen layer " + m_apUnseenLayer[team]->GetPresetName() + "\'s data failed!"); - return -1; - } - } - } - - m_SelectedAssemblies.clear(); - m_AssembliesCounts.clear(); - - ////////////////////////////////// - // Place all the specified Scene Objects that are set up to be placed on load - // But don't if we are only loading the scene bitmap layer data - if (placeObjects) - { - Actor * pBrains[Activity::MaxTeamCount]; - for (int i = Activity::TeamOne; i < Activity::MaxTeamCount; i++) - pBrains[i] = 0; - - // Indicates whether we need to process static brain deployments or mobile - // whichever comes first is selected and used everywhere - std::string activeBrainDeployment[Activity::MaxTeamCount]; - - // Lists of found brain deployment locations used to place brain - std::vector brainLocations[Activity::MaxTeamCount]; - - //for (std::list::iterator oItr = m_PlacedObjects[AIPLAN].begin(); oItr != m_PlacedObjects[AIPLAN].end(); ++oItr) // I'm using this to dump AI plans with ctrl+w - for (std::list::iterator oItr = m_PlacedObjects[PLACEONLOAD].begin(); oItr != m_PlacedObjects[PLACEONLOAD].end(); ++oItr) - { - // MovableObject:s get added to the MovableMan - MovableObject *pMO = dynamic_cast(*oItr); - if (pMO) - { - // PASSING OWNERSHIP INTO the Add* ones - we are clearing out this list! - if (Actor *actor = dynamic_cast(pMO)) { - bool shouldPlace = placeUnits || actor->IsInGroup("Bunker Systems"); - - // Because we don't save/load all data yet and do a bit of a hack with scene loading, we can potentially save a dead actor that still technically exists. - // If we find one of these, just skip them! - //shouldPlace = shouldPlace && dynamic_cast(pMO)->GetHealth() > 0.0F; - - if (shouldPlace) { - g_MovableMan.AddActor(dynamic_cast(pMO)); + m_SelectedAssemblies.clear(); + m_AssembliesCounts.clear(); + + ////////////////////////////////// + // Place all the specified Scene Objects that are set up to be placed on load + // But don't if we are only loading the scene bitmap layer data + if (placeObjects) { + Actor* pBrains[Activity::MaxTeamCount]; + for (int i = Activity::TeamOne; i < Activity::MaxTeamCount; i++) + pBrains[i] = 0; + + // Indicates whether we need to process static brain deployments or mobile + // whichever comes first is selected and used everywhere + std::string activeBrainDeployment[Activity::MaxTeamCount]; + + // Lists of found brain deployment locations used to place brain + std::vector brainLocations[Activity::MaxTeamCount]; + + // for (std::list::iterator oItr = m_PlacedObjects[AIPLAN].begin(); oItr != m_PlacedObjects[AIPLAN].end(); ++oItr) // I'm using this to dump AI plans with ctrl+w + for (std::list::iterator oItr = m_PlacedObjects[PLACEONLOAD].begin(); oItr != m_PlacedObjects[PLACEONLOAD].end(); ++oItr) { + // MovableObject:s get added to the MovableMan + MovableObject* pMO = dynamic_cast(*oItr); + if (pMO) { + // PASSING OWNERSHIP INTO the Add* ones - we are clearing out this list! + if (Actor* actor = dynamic_cast(pMO)) { + bool shouldPlace = placeUnits || actor->IsInGroup("Bunker Systems"); + + // Because we don't save/load all data yet and do a bit of a hack with scene loading, we can potentially save a dead actor that still technically exists. + // If we find one of these, just skip them! + // shouldPlace = shouldPlace && dynamic_cast(pMO)->GetHealth() > 0.0F; + + if (shouldPlace) { + g_MovableMan.AddActor(dynamic_cast(pMO)); + } else { + delete pMO; + pMO = nullptr; + } } else { - delete pMO; - pMO = nullptr; + g_MovableMan.AddMO(pMO); } } else { - g_MovableMan.AddMO(pMO); - } - } - else - { - // Deployment:s are translated into the appropriate loadout and put in place in the scene - Deployment *pDep = dynamic_cast(*oItr); - if (pDep) - { - Deployment * pDepCopy = dynamic_cast(pDep->Clone()); - if (pDepCopy) - { - pDepCopy->CloneID(pDep); - m_Deployments.push_back(pDepCopy); - } + // Deployment:s are translated into the appropriate loadout and put in place in the scene + Deployment* pDep = dynamic_cast(*oItr); + if (pDep) { + Deployment* pDepCopy = dynamic_cast(pDep->Clone()); + if (pDepCopy) { + pDepCopy->CloneID(pDep); + m_Deployments.push_back(pDepCopy); + } - if (placeUnits) - { - int team = pDep->GetTeam(); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) - team = 0; + if (placeUnits) { + int team = pDep->GetTeam(); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + team = 0; - // Select first brain deployemnt type as the only deployment type for this team + // Select first brain deployemnt type as the only deployment type for this team - bool toIgnore = false; - // Ignore brain deployment if it's not matching the previously selected deployment type, or save it's position if it does - if (pDep->IsInGroup("Brains") && pDep->GetPresetName() != "Brain Hideout") - { - if (activeBrainDeployment[team] == "") - activeBrainDeployment[team] = pDep->GetPresetName(); + bool toIgnore = false; + // Ignore brain deployment if it's not matching the previously selected deployment type, or save it's position if it does + if (pDep->IsInGroup("Brains") && pDep->GetPresetName() != "Brain Hideout") { + if (activeBrainDeployment[team] == "") + activeBrainDeployment[team] = pDep->GetPresetName(); - if (pDep->GetPresetName() != activeBrainDeployment[team]) - toIgnore = true; - else - brainLocations[team].push_back(pDep->GetPos()); - } + if (pDep->GetPresetName() != activeBrainDeployment[team]) + toIgnore = true; + else + brainLocations[team].push_back(pDep->GetPos()); + } - // Ignore brain hideouts, they are used only by metagame when applying build budget - if (pDep->GetPresetName() == "Brain Hideout") - toIgnore = true; + // Ignore brain hideouts, they are used only by metagame when applying build budget + if (pDep->GetPresetName() == "Brain Hideout") + toIgnore = true; - if (!toIgnore) - { - // Ownership IS transferred here; pass it along into the MovableMan - float cost = 0; - Actor *pActor = pDep->CreateDeployedActor(pDep->GetPlacedByPlayer(), cost); - if (pActor) - { - // Treat brain eployements the special way - if (pDep->GetPresetName() == activeBrainDeployment[team] && pActor->IsInGroup("Brains")) - { - // If it's the first created brain then place it, otherwise just delete - if (pBrains[team] == 0) - { + if (!toIgnore) { + // Ownership IS transferred here; pass it along into the MovableMan + float cost = 0; + Actor* pActor = pDep->CreateDeployedActor(pDep->GetPlacedByPlayer(), cost); + if (pActor) { + // Treat brain eployements the special way + if (pDep->GetPresetName() == activeBrainDeployment[team] && pActor->IsInGroup("Brains")) { + // If it's the first created brain then place it, otherwise just delete + if (pBrains[team] == 0) { + g_MovableMan.AddActor(pActor); + pBrains[team] = pActor; + } else { + delete pActor; + pActor = 0; + } + } else g_MovableMan.AddActor(pActor); - pBrains[team] = pActor; - } - else - { - delete pActor; - pActor = 0; - } } - else - g_MovableMan.AddActor(pActor); - } - // Just a simple Device in the Deployment? - else - { - // Get the Item/Device and add to scene, passing ownership - SceneObject *pObject = pDep->CreateDeployedObject(pDep->GetPlacedByPlayer(), cost); - pMO = dynamic_cast(pObject); - if (pMO) - g_MovableMan.AddMO(pMO); - else - { - delete pObject; - pObject = 0; + // Just a simple Device in the Deployment? + else { + // Get the Item/Device and add to scene, passing ownership + SceneObject* pObject = pDep->CreateDeployedObject(pDep->GetPlacedByPlayer(), cost); + pMO = dynamic_cast(pObject); + if (pMO) + g_MovableMan.AddMO(pMO); + else { + delete pObject; + pObject = 0; + } } } } } - } - // Has to be a TerrainObject then, so apply to terrain - else - { - //Place random BunkerAssembly instead of BunkerAssemblyScheme if this is a BunkerAssemblyScheme - TerrainObject *pTO = 0; - BunkerAssemblyScheme *pBAS = dynamic_cast(*oItr); - - if (pBAS) - { - const BunkerAssembly * pBAPreset = 0; - - // Try to select previousy selected assembly - if (pBAS->IsOneTypePerScene()) - { - auto itr = m_SelectedAssemblies.find(pBAS->GetModuleAndPresetName()); - if (itr != m_SelectedAssemblies.end()) - pBAPreset = (*itr).second; - } + // Has to be a TerrainObject then, so apply to terrain + else { + // Place random BunkerAssembly instead of BunkerAssemblyScheme if this is a BunkerAssemblyScheme + TerrainObject* pTO = 0; + BunkerAssemblyScheme* pBAS = dynamic_cast(*oItr); + + if (pBAS) { + const BunkerAssembly* pBAPreset = 0; + + // Try to select previousy selected assembly + if (pBAS->IsOneTypePerScene()) { + auto itr = m_SelectedAssemblies.find(pBAS->GetModuleAndPresetName()); + if (itr != m_SelectedAssemblies.end()) + pBAPreset = (*itr).second; + } + + // Find random bunker assembly and clone it + if (!pBAPreset) { + pBAPreset = dynamic_cast(g_PresetMan.GetRandomOfGroup(pBAS->GetPresetName(), "BunkerAssembly", -1)); + + if (pBAPreset) { + // Remember selected BunkerAssembly for this scheme to use it everywhere on the map. + if (pBAS->IsOneTypePerScene()) { + m_SelectedAssemblies.insert(std::pair(pBAS->GetModuleAndPresetName(), pBAPreset)); + + // Find out if this scheme has symmetric scheme, and this assembly have symmetric version + // so we could set them to be used when we need to create symmetric versions of this scheme + std::string symmetricScheme = pBAS->GetSymmetricSchemeName(); + std::string symmetricAssembly = pBAPreset->GetSymmetricAssemblyName(); - //Find random bunker assembly and clone it - if (!pBAPreset) - { - pBAPreset = dynamic_cast(g_PresetMan.GetRandomOfGroup(pBAS->GetPresetName(), "BunkerAssembly", -1)); - - if (pBAPreset) - { - // Remember selected BunkerAssembly for this scheme to use it everywhere on the map. - if (pBAS->IsOneTypePerScene()) - { - m_SelectedAssemblies.insert(std::pair(pBAS->GetModuleAndPresetName(), pBAPreset)); - - // Find out if this scheme has symmetric scheme, and this assembly have symmetric version - // so we could set them to be used when we need to create symmetric versions of this scheme - std::string symmetricScheme = pBAS->GetSymmetricSchemeName(); - std::string symmetricAssembly = pBAPreset->GetSymmetricAssemblyName(); - - if (symmetricScheme.size() > 0 && symmetricAssembly.size() > 0) - { - const BunkerAssembly * pBAPresetSymmetric = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssembly", symmetricAssembly)); - - if (pBAPresetSymmetric) - m_SelectedAssemblies.insert(std::pair(symmetricScheme, pBAPresetSymmetric)); + if (symmetricScheme.size() > 0 && symmetricAssembly.size() > 0) { + const BunkerAssembly* pBAPresetSymmetric = dynamic_cast(g_PresetMan.GetEntityPreset("BunkerAssembly", symmetricAssembly)); + + if (pBAPresetSymmetric) + m_SelectedAssemblies.insert(std::pair(symmetricScheme, pBAPresetSymmetric)); + } } } } + // Finally make a copy of found or selected assembly to put it on scene later + if (pBAPreset) { + pTO = dynamic_cast(pBAPreset->Clone()); + pTO->SetPos(pBAS->GetPos()); + pTO->SetTeam(pBAS->GetTeam()); + } } - // Finally make a copy of found or selected assembly to put it on scene later - if (pBAPreset) - { - pTO = dynamic_cast(pBAPreset->Clone()); - pTO->SetPos(pBAS->GetPos()); - pTO->SetTeam(pBAS->GetTeam()); + + // Try to read as terrain object if it's not Assembly Scheme + // NOT passing ownership here, so have to delete it ourselves + if (!pTO) + pTO = dynamic_cast(*oItr); + + // Add deployments placed by bunker assemblies, but not in metagame, + // as they are spawned and placed during ApplyBuildBudget + if (placeUnits && !g_MetaMan.GameInProgress()) { + BunkerAssembly* pBA = dynamic_cast(pTO); + if (pBA) { + std::vector deployments = pBA->GetDeployments(); + for (std::vector::iterator itr = deployments.begin(); itr != deployments.end(); ++itr) { + // Create a copy of deployment because assemblies own their placed objects and scenes own theirs + SceneObject* so = (SceneObject*)(*itr)->Clone(); + so->SetPos(so->GetPos() + pBA->GetPos() + pBA->GetBitmapOffset()); + so->SetTeam(pBA->GetTeam()); + so->SetPlacedByPlayer(pBA->GetPlacedByPlayer()); + m_PlacedObjects[PLACEONLOAD].push_back(so); + } + } } - } - // Try to read as terrain object if it's not Assembly Scheme - // NOT passing ownership here, so have to delete it ourselves - if (!pTO) - pTO = dynamic_cast(*oItr); - - // Add deployments placed by bunker assemblies, but not in metagame, - // as they are spawned and placed during ApplyBuildBudget - if (placeUnits && !g_MetaMan.GameInProgress()) - { - BunkerAssembly * pBA = dynamic_cast(pTO); - if (pBA) - { - std::vectordeployments = pBA->GetDeployments(); - for (std::vector::iterator itr = deployments.begin(); itr != deployments.end() ; ++itr) - { - // Create a copy of deployment because assemblies own their placed objects and scenes own theirs - SceneObject * so = (SceneObject *)(*itr)->Clone(); - so->SetPos(so->GetPos() + pBA->GetPos() + pBA->GetBitmapOffset()); - so->SetTeam(pBA->GetTeam()); - so->SetPlacedByPlayer(pBA->GetPlacedByPlayer()); - m_PlacedObjects[PLACEONLOAD].push_back(so); + // Finally place TerrainObject + if (pTO) { + const BITMAP* terrainObjectBitmap = pTO->GetFGColorBitmap() ? pTO->GetFGColorBitmap() : pTO->GetBGColorBitmap(); + + // First clear out the box of unseen layer for whichever team placed this + if (terrainObjectBitmap && pTO->GetPlacedByPlayer() != Players::NoPlayer && g_ActivityMan.GetActivity()) { + // Learn which team placed this thing so we can reveal for them only + int ownerTeam = pTO->GetTeam(); + if (ownerTeam != Activity::NoTeam && m_apUnseenLayer[ownerTeam] && m_apUnseenLayer[ownerTeam]->GetBitmap()) { + // Translate to the scaled unseen layer's coordinates + Vector scale = m_apUnseenLayer[ownerTeam]->GetScaleFactor(); + int scaledX = std::floor((pTO->GetPos().m_X - (float)(terrainObjectBitmap->w / 2)) / scale.m_X); + int scaledY = std::floor((pTO->GetPos().m_Y - (float)(terrainObjectBitmap->h / 2)) / scale.m_Y); + int scaledW = std::ceil(terrainObjectBitmap->w / scale.m_X); + int scaledH = std::ceil(terrainObjectBitmap->h / scale.m_Y); + // Fill the box with key color for the owner ownerTeam, revealing the area that this thing is on + rectfill(m_apUnseenLayer[ownerTeam]->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_MaskColor); + // Expand the box a little so the whole placed object is going to be hidden + scaledX -= 1; + scaledY -= 1; + scaledW += 2; + scaledH += 2; + // Fill the box with BLACK for all the other teams so they can't see the new developments here! + for (int t = Activity::TeamOne; t < Activity::MaxTeamCount; ++t) { + if (t != ownerTeam && m_apUnseenLayer[t] && m_apUnseenLayer[t]->GetBitmap()) + rectfill(m_apUnseenLayer[t]->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_BlackColor); + } + } } + // Now actually stamp the terrain object onto the terrain's scene layers + pTO->PlaceOnTerrain(m_pTerrain); + // delete pTO; + // pTO = 0; } - } - // Finally place TerrainObject - if (pTO) - { - const BITMAP *terrainObjectBitmap = pTO->GetFGColorBitmap() ? pTO->GetFGColorBitmap() : pTO->GetBGColorBitmap(); - - // First clear out the box of unseen layer for whichever team placed this - if (terrainObjectBitmap && pTO->GetPlacedByPlayer() != Players::NoPlayer && g_ActivityMan.GetActivity()) - { - // Learn which team placed this thing so we can reveal for them only - int ownerTeam = pTO->GetTeam(); - if (ownerTeam != Activity::NoTeam && m_apUnseenLayer[ownerTeam] && m_apUnseenLayer[ownerTeam]->GetBitmap()) - { - // Translate to the scaled unseen layer's coordinates - Vector scale = m_apUnseenLayer[ownerTeam]->GetScaleFactor(); - int scaledX = std::floor((pTO->GetPos().m_X - (float)(terrainObjectBitmap->w / 2)) / scale.m_X); - int scaledY = std::floor((pTO->GetPos().m_Y - (float)(terrainObjectBitmap->h / 2)) / scale.m_Y); - int scaledW = std::ceil(terrainObjectBitmap->w / scale.m_X); - int scaledH = std::ceil(terrainObjectBitmap->h / scale.m_Y); - // Fill the box with key color for the owner ownerTeam, revealing the area that this thing is on - rectfill(m_apUnseenLayer[ownerTeam]->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_MaskColor); - // Expand the box a little so the whole placed object is going to be hidden - scaledX -= 1; - scaledY -= 1; - scaledW += 2; - scaledH += 2; - // Fill the box with BLACK for all the other teams so they can't see the new developments here! - for (int t = Activity::TeamOne; t < Activity::MaxTeamCount; ++t) - { - if (t != ownerTeam && m_apUnseenLayer[t] && m_apUnseenLayer[t]->GetBitmap()) - rectfill(m_apUnseenLayer[t]->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_BlackColor); - } - } - } - // Now actually stamp the terrain object onto the terrain's scene layers - pTO->PlaceOnTerrain(m_pTerrain); - //delete pTO; - //pTO = 0; - } - - // Finally delete the object retreived from the list - delete (*oItr); - (*oItr) = 0; - } - } - } - // Finally select random brain location from the list of found brain deployments - for (int t = Activity::TeamOne; t < Activity::MaxTeamCount; t++) - { - if (pBrains[t]) - { - int team = pBrains[t]->GetTeam(); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) - team = 0; - if (brainLocations[team].size() > 0) - { - int selection = RandomNum(0, brainLocations[team].size() - 1); - pBrains[t]->SetPos(brainLocations[team].at(selection)); + // Finally delete the object retreived from the list + delete (*oItr); + (*oItr) = 0; + } + } + } + // Finally select random brain location from the list of found brain deployments + for (int t = Activity::TeamOne; t < Activity::MaxTeamCount; t++) { + if (pBrains[t]) { + int team = pBrains[t]->GetTeam(); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + team = 0; + if (brainLocations[team].size() > 0) { + int selection = RandomNum(0, brainLocations[team].size() - 1); + pBrains[t]->SetPos(brainLocations[team].at(selection)); + } } } - } - - // Clear out the list of things that were placed above.. the ownership of everything WAS transferred anyway - m_PlacedObjects[PLACEONLOAD].clear(); - //m_PlacedObjects[AIPLAN].clear(); // I'm using this to dump AI plans via CTRL+W - -// TODO: CLEAN AIR IN AN AFTER EACH OBJECT PLACED, becuase the items refuse to be placed in a hollowness otherwise? - // Clear the air out of objects placed - m_pTerrain->CleanAir(); - } - - ///////////////////////////////// - // Go through and init the teams on all remaining placed objects, so their flag icons etc are correct for the current Activity - for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) - { - for (std::list::iterator oItr = m_PlacedObjects[set].begin(); oItr != m_PlacedObjects[set].end(); ++oItr) - (*oItr)->SetTeam((*oItr)->GetTeam()); - } - /////////////////////////////// - // Pathfinding init - if (initPathfinding) - { - // Create the pathfinding stuff based on the current scene - int pathFinderGridNodeSize = g_SettingsMan.GetPathFinderGridNodeSize(); + // Clear out the list of things that were placed above.. the ownership of everything WAS transferred anyway + m_PlacedObjects[PLACEONLOAD].clear(); + // m_PlacedObjects[AIPLAN].clear(); // I'm using this to dump AI plans via CTRL+W - for (int i = 0; i < m_pPathFinders.size(); ++i) { - m_pPathFinders[i] = std::make_unique(pathFinderGridNodeSize); - } - ResetPathFinding(); - } + // TODO: CLEAN AIR IN AN AFTER EACH OBJECT PLACED, becuase the items refuse to be placed in a hollowness otherwise? + // Clear the air out of objects placed + m_pTerrain->CleanAir(); + } - return 0; -} + ///////////////////////////////// + // Go through and init the teams on all remaining placed objects, so their flag icons etc are correct for the current Activity + for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) { + for (std::list::iterator oItr = m_PlacedObjects[set].begin(); oItr != m_PlacedObjects[set].end(); ++oItr) + (*oItr)->SetTeam((*oItr)->GetTeam()); + } + /////////////////////////////// + // Pathfinding init + if (initPathfinding) { + // Create the pathfinding stuff based on the current scene + int pathFinderGridNodeSize = g_SettingsMan.GetPathFinderGridNodeSize(); + for (int i = 0; i < m_pPathFinders.size(); ++i) { + m_pPathFinders[i] = std::make_unique(pathFinderGridNodeSize); + } + ResetPathFinding(); + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ExpandAIPlanAssemblySchemes -////////////////////////////////////////////////////////////////////////////////////////// -// Description: -// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ExpandAIPlanAssemblySchemes + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: + // -int Scene::ExpandAIPlanAssemblySchemes() -{ - std::list newAIPlan; + int Scene::ExpandAIPlanAssemblySchemes() { + std::list newAIPlan; - for (std::list::iterator oItr = m_PlacedObjects[AIPLAN].begin(); oItr != m_PlacedObjects[AIPLAN].end(); ++oItr) - { - BunkerAssemblyScheme *pBAS = dynamic_cast(*oItr); + for (std::list::iterator oItr = m_PlacedObjects[AIPLAN].begin(); oItr != m_PlacedObjects[AIPLAN].end(); ++oItr) { + BunkerAssemblyScheme* pBAS = dynamic_cast(*oItr); - if (pBAS) - { - const BunkerAssembly * pBAPreset = 0; - //BunkerAssembly * pPA = 0; + if (pBAS) { + const BunkerAssembly* pBAPreset = 0; + // BunkerAssembly * pPA = 0; - // Try to select previousy selected assembly - if (pBAS->IsOneTypePerScene()) - { - auto itr = m_SelectedAssemblies.find(pBAS->GetModuleAndPresetName()); - if (itr != m_SelectedAssemblies.end()) - pBAPreset = (*itr).second; - } + // Try to select previousy selected assembly + if (pBAS->IsOneTypePerScene()) { + auto itr = m_SelectedAssemblies.find(pBAS->GetModuleAndPresetName()); + if (itr != m_SelectedAssemblies.end()) + pBAPreset = (*itr).second; + } - //Find random bunker assembly and clone it - if (!pBAPreset) - { - pBAPreset = dynamic_cast(g_PresetMan.GetRandomOfGroup(pBAS->GetPresetName(), "BunkerAssembly", -1)); + // Find random bunker assembly and clone it + if (!pBAPreset) { + pBAPreset = dynamic_cast(g_PresetMan.GetRandomOfGroup(pBAS->GetPresetName(), "BunkerAssembly", -1)); - // Remember selected BunkerAssembly for this scheme to use it everywhere on the map. - if (pBAS->IsOneTypePerScene()) - m_SelectedAssemblies.insert(std::pair(pBAS->GetModuleAndPresetName(), pBAPreset)); - } + // Remember selected BunkerAssembly for this scheme to use it everywhere on the map. + if (pBAS->IsOneTypePerScene()) + m_SelectedAssemblies.insert(std::pair(pBAS->GetModuleAndPresetName(), pBAPreset)); + } - // Add found assembly to the AI plan - if (pBAPreset) - { - BunkerAssembly * pBA = dynamic_cast(pBAPreset->Clone()); - pBA->SetPos(pBAS->GetPos()); - pBA->SetTeam(pBAS->GetTeam()); - pBA->SetPlacedByPlayer(pBAS->GetPlacedByPlayer()); - - newAIPlan.push_back(pBA); - - std::vectorpDeployments = pBA->GetDeployments(); - for (std::vector::iterator itr = pDeployments.begin(); itr != pDeployments.end() ; ++itr) - { - // Create a copy of deployment because assemblies own their placed objects and scenes own theirs - SceneObject * so = (SceneObject *)(*itr)->Clone(); - so->SetPos(so->GetPos() + pBA->GetPos() + pBA->GetBitmapOffset()); - so->SetTeam(pBA->GetTeam()); - so->SetPlacedByPlayer(pBA->GetPlacedByPlayer()); - newAIPlan.push_back(so); + // Add found assembly to the AI plan + if (pBAPreset) { + BunkerAssembly* pBA = dynamic_cast(pBAPreset->Clone()); + pBA->SetPos(pBAS->GetPos()); + pBA->SetTeam(pBAS->GetTeam()); + pBA->SetPlacedByPlayer(pBAS->GetPlacedByPlayer()); + + newAIPlan.push_back(pBA); + + std::vector pDeployments = pBA->GetDeployments(); + for (std::vector::iterator itr = pDeployments.begin(); itr != pDeployments.end(); ++itr) { + // Create a copy of deployment because assemblies own their placed objects and scenes own theirs + SceneObject* so = (SceneObject*)(*itr)->Clone(); + so->SetPos(so->GetPos() + pBA->GetPos() + pBA->GetBitmapOffset()); + so->SetTeam(pBA->GetTeam()); + so->SetPlacedByPlayer(pBA->GetPlacedByPlayer()); + newAIPlan.push_back(so); + } } + // Delete scheme as it was replaced by an assembly by now + delete (*oItr); + (*oItr) = 0; + } else { + // If it's not a scheme, then just put it in the new list + newAIPlan.push_back(*oItr); } - //Delete scheme as it was replaced by an assembly by now - delete (*oItr); - (*oItr) = 0; - } else { - // If it's not a scheme, then just put it in the new list - newAIPlan.push_back(*oItr); } - } - - // Copy new AI plan list to replace the original - m_PlacedObjects[AIPLAN].clear(); - for (std::list::iterator oItr = newAIPlan.begin(); oItr != newAIPlan.end(); ++oItr) - m_PlacedObjects[AIPLAN].push_back(*oItr); - return 0; -} + // Copy new AI plan list to replace the original + m_PlacedObjects[AIPLAN].clear(); + for (std::list::iterator oItr = newAIPlan.begin(); oItr != newAIPlan.end(); ++oItr) + m_PlacedObjects[AIPLAN].push_back(*oItr); + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SaveData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves currently loaded bitmap data in memory to disk. + int Scene::SaveData(std::string pathBase, bool doAsyncSaves) { + const std::string fullPathBase = g_PresetMan.GetFullModulePath(pathBase); + if (fullPathBase.empty()) + return -1; + if (!m_pTerrain) + return 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SaveData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves currently loaded bitmap data in memory to disk. - -int Scene::SaveData(std::string pathBase, bool doAsyncSaves) -{ - const std::string fullPathBase = g_PresetMan.GetFullModulePath(pathBase); - if (fullPathBase.empty()) - return -1; - - if (!m_pTerrain) - return 0; - - // Save Terrain's data - if (m_pTerrain->SaveData(fullPathBase, doAsyncSaves) < 0) - { - RTEAbort("Saving Terrain " + m_pTerrain->GetPresetName() + "\'s data failed!"); - return -1; - } - - // Don't bother saving background layers to disk, as they are never altered - - // Save unseen layers' data - char str[64]; - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - if (m_apUnseenLayer[team]) - { - std::snprintf(str, sizeof(str), "T%d", team); - // Save unseen layer data to disk - if (m_apUnseenLayer[team]->SaveData(fullPathBase + " US" + str + ".png", doAsyncSaves) < 0) - { - g_ConsoleMan.PrintString("ERROR: Saving unseen layer " + m_apUnseenLayer[team]->GetPresetName() + "\'s data failed!"); - return -1; - } - } - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SavePreview -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves preview bitmap for this scene. -// - -int Scene::SavePreview(const std::string &bitmapPath) { - // Do not save preview for MetaScenes! - if (!m_MetasceneParent.empty()) { - return -1; - } - - if (m_pPreviewBitmap && (m_pPreviewBitmap->w != c_ScenePreviewWidth || m_pPreviewBitmap->h != c_ScenePreviewHeight)) { - destroy_bitmap(m_pPreviewBitmap); - m_pPreviewBitmap = nullptr; - } - if (!m_pPreviewBitmap) { m_pPreviewBitmap = create_bitmap_ex(8, c_ScenePreviewWidth, c_ScenePreviewHeight); } - - ContentFile scenePreviewGradient("Base.rte/GUIs/PreviewSkyGradient.png"); - draw_sprite(m_pPreviewBitmap, scenePreviewGradient.GetAsBitmap(COLORCONV_NONE, true), 0, 0); - - int sceneWidth = m_pTerrain->GetBitmap()->w; - int sceneHeight = m_pTerrain->GetBitmap()->h; - BITMAP *previewBuffer = create_bitmap_ex(8, sceneWidth, sceneHeight); - clear_to_color(previewBuffer, ColorKeys::g_MaskColor); - - masked_blit(m_pTerrain->GetBGColorBitmap(), previewBuffer, 0, 0, 0, 0, sceneWidth, sceneHeight); - masked_blit(m_pTerrain->GetFGColorBitmap(), previewBuffer, 0, 0, 0, 0, sceneWidth, sceneHeight); - - for (SceneObject *sceneObject : m_PlacedObjects[PlacedObjectSets::PLACEONLOAD]) { - if (const TerrainObject *terrainObject = dynamic_cast(sceneObject)) { - Vector pos = terrainObject->GetPos() + terrainObject->GetBitmapOffset(); - BITMAP *terrainObjectBG = terrainObject->GetBGColorBitmap(); - BITMAP *terrainObjectFG = terrainObject->GetFGColorBitmap(); - - // Wrapped drawing - if (pos.GetFloorIntX() < 0) { - if (terrainObject->HasBGColorBitmap()) { masked_blit(terrainObjectBG, previewBuffer, 0, 0, pos.GetFloorIntX() + sceneWidth, pos.GetFloorIntY(), terrainObjectBG->w, terrainObjectBG->h); } - if (terrainObject->HasFGColorBitmap()) { masked_blit(terrainObjectFG, previewBuffer, 0, 0, pos.GetFloorIntX() + sceneWidth, pos.GetFloorIntY(), terrainObjectFG->w, terrainObjectFG->h); } - } else if (pos.GetFloorIntX() + terrainObject->GetBitmapWidth() >= sceneWidth) { - if (terrainObject->HasBGColorBitmap()) { masked_blit(terrainObjectBG, previewBuffer, 0, 0, pos.GetFloorIntX() - sceneWidth, pos.GetFloorIntY(), terrainObjectBG->w, terrainObjectBG->h); } - if (terrainObject->HasFGColorBitmap()) { masked_blit(terrainObjectFG, previewBuffer, 0, 0, pos.GetFloorIntX() - sceneWidth, pos.GetFloorIntY(), terrainObjectFG->w, terrainObjectFG->h); } - } - if (terrainObject->HasBGColorBitmap()) { masked_blit(terrainObjectBG, previewBuffer, 0, 0, pos.GetFloorIntX(), pos.GetFloorIntY(), terrainObjectBG->w, terrainObjectBG->h); } - if (terrainObject->HasFGColorBitmap()) { masked_blit(terrainObjectFG, previewBuffer, 0, 0, pos.GetFloorIntX(), pos.GetFloorIntY(), terrainObjectFG->w, terrainObjectFG->h); } + // Save Terrain's data + if (m_pTerrain->SaveData(fullPathBase, doAsyncSaves) < 0) { + RTEAbort("Saving Terrain " + m_pTerrain->GetPresetName() + "\'s data failed!"); + return -1; } - // TODO: Figure out how to draw the actual modules that compose an assembly that is part of the scheme. For now just disable. - /* - else if (const BunkerAssemblyScheme *assemblyScheme = dynamic_cast(sceneObject)) { - Vector pos = assemblyScheme->GetPos() + assemblyScheme->GetBitmapOffset(); - - // Wrapped drawing - if (pos.GetFloorIntX() < 0) { - rect(previewBuffer, pos.GetFloorIntX() + sceneWidth, pos.GetFloorIntY(), pos.GetFloorIntX() + sceneWidth + assemblyScheme->GetBitmapWidth(), pos.GetFloorIntY() + assemblyScheme->GetBitmapHeight(), 5); - } else if (pos.GetFloorIntX() + assemblyScheme->GetBitmapWidth() >= sceneWidth) { - rect(previewBuffer, pos.GetFloorIntX() - sceneWidth, pos.GetFloorIntY(), pos.GetFloorIntX() - sceneWidth + assemblyScheme->GetBitmapWidth(), pos.GetFloorIntY() + assemblyScheme->GetBitmapHeight(), 5); + // Don't bother saving background layers to disk, as they are never altered + + // Save unseen layers' data + char str[64]; + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + if (m_apUnseenLayer[team]) { + std::snprintf(str, sizeof(str), "T%d", team); + // Save unseen layer data to disk + if (m_apUnseenLayer[team]->SaveData(fullPathBase + " US" + str + ".png", doAsyncSaves) < 0) { + g_ConsoleMan.PrintString("ERROR: Saving unseen layer " + m_apUnseenLayer[team]->GetPresetName() + "\'s data failed!"); + return -1; + } } - rect(previewBuffer, pos.GetFloorIntX(), pos.GetFloorIntY(), pos.GetFloorIntX() + ((float)assemblyScheme->GetBitmapWidth()), pos.GetFloorIntY() + ((float)assemblyScheme->GetBitmapHeight()), 5); } - */ + + return 0; } - masked_stretch_blit(previewBuffer, m_pPreviewBitmap, 0, 0, previewBuffer->w, previewBuffer->h, 0, 0, m_pPreviewBitmap->w, m_pPreviewBitmap->h); - destroy_bitmap(previewBuffer); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SavePreview + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves preview bitmap for this scene. + // - if (g_FrameMan.SaveBitmapToPNG(m_pPreviewBitmap, bitmapPath.c_str()) == 0) { m_PreviewBitmapFile.SetDataPath(bitmapPath); } + int Scene::SavePreview(const std::string& bitmapPath) { + // Do not save preview for MetaScenes! + if (!m_MetasceneParent.empty()) { + return -1; + } - return 0; -} + if (m_pPreviewBitmap && (m_pPreviewBitmap->w != c_ScenePreviewWidth || m_pPreviewBitmap->h != c_ScenePreviewHeight)) { + destroy_bitmap(m_pPreviewBitmap); + m_pPreviewBitmap = nullptr; + } + if (!m_pPreviewBitmap) { + m_pPreviewBitmap = create_bitmap_ex(8, c_ScenePreviewWidth, c_ScenePreviewHeight); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ClearData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out any previously loaded bitmap data from memory. - -int Scene::ClearData() -{ - if (!m_pTerrain) - return 0; - - // Clear Terrain's data - if (m_pTerrain->ClearData() < 0) - { - RTEAbort("Clearing Terrain " + m_pTerrain->GetPresetName() + "\'s data failed!"); - return -1; - } - - // Clear unseen layers' data - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - if (m_apUnseenLayer[team]) - { - // Clear unseen layer data from memory - if (m_apUnseenLayer[team]->ClearData() < 0) - { - g_ConsoleMan.PrintString("ERROR: Clearing unseen layer " + m_apUnseenLayer[team]->GetPresetName() + "\'s data failed!"); - return -1; - } - } - } - - return 0; -} + ContentFile scenePreviewGradient("Base.rte/GUIs/PreviewSkyGradient.png"); + draw_sprite(m_pPreviewBitmap, scenePreviewGradient.GetAsBitmap(COLORCONV_NONE, true), 0, 0); + int sceneWidth = m_pTerrain->GetBitmap()->w; + int sceneHeight = m_pTerrain->GetBitmap()->h; + BITMAP* previewBuffer = create_bitmap_ex(8, sceneWidth, sceneHeight); + clear_to_color(previewBuffer, ColorKeys::g_MaskColor); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int Scene::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Entity::ReadProperty(propName, reader)); - - MatchProperty("LocationOnPlanet", { reader >> m_Location; }); - MatchProperty("MetagamePlayable", { reader >> m_MetagamePlayable; }); - MatchProperty("Revealed", { reader >> m_Revealed; }); - MatchProperty("MetasceneParent", { reader >> m_MetasceneParent; }); - MatchProperty("MetagameInternal", { reader >> m_IsMetagameInternal; }); - MatchProperty("ScriptSave", { reader >> m_IsSavedGameInternal; }); - MatchProperty("OwnedByTeam", { reader >> m_OwnedByTeam; }); - MatchProperty("RoundIncome", { reader >> m_RoundIncome; }); - MatchProperty("P1ResidentBrain", { m_ResidentBrains[Players::PlayerOne] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); - MatchProperty("P2ResidentBrain", { m_ResidentBrains[Players::PlayerTwo] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); - MatchProperty("P3ResidentBrain", { m_ResidentBrains[Players::PlayerThree] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); - MatchProperty("P4ResidentBrain", { m_ResidentBrains[Players::PlayerFour] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); - MatchProperty("P1BuildBudget", { reader >> m_BuildBudget[Players::PlayerOne]; }); - MatchProperty("P2BuildBudget", { reader >> m_BuildBudget[Players::PlayerTwo]; }); - MatchProperty("P3BuildBudget", { reader >> m_BuildBudget[Players::PlayerThree]; }); - MatchProperty("P4BuildBudget", { reader >> m_BuildBudget[Players::PlayerFour]; }); - MatchProperty("P1BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerOne]; }); - MatchProperty("P2BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerTwo]; }); - MatchProperty("P3BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerThree]; }); - MatchProperty("P4BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerFour]; }); - MatchProperty("AutoDesigned", { reader >> m_AutoDesigned; }); - MatchProperty("TotalInvestment", { reader >> m_TotalInvestment; }); - MatchProperty("PreviewBitmapFile", - reader >> m_PreviewBitmapFile; - m_pPreviewBitmap = m_PreviewBitmapFile.GetAsBitmap(COLORCONV_NONE, false); ); - MatchProperty("Terrain", - delete m_pTerrain; - m_pTerrain = new SLTerrain(); - reader >> m_pTerrain; ); - MatchForwards("PlaceSceneObject") - MatchProperty("PlaceMovableObject", - SceneObject *pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); - if (pSO) { - m_PlacedObjects[PLACEONLOAD].push_back(pSO); - } ); - MatchProperty("BlueprintObject", - SceneObject *pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); - if (pSO) { - m_PlacedObjects[BLUEPRINT].push_back(pSO); - } ); - MatchProperty("PlaceAIPlanObject", - SceneObject *pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); - if (pSO) { - m_PlacedObjects[AIPLAN].push_back(pSO); - } ); - MatchProperty("AddBackgroundLayer", - SLBackground *pLayer = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); - RTEAssert(pLayer, "Something went wrong with reading SceneLayer"); - if (pLayer) { - m_BackLayerList.push_back(pLayer); - } ); - MatchProperty("AllUnseenPixelSizeTeam1", - // Read the desired pixel dimensions of the dynamically generated unseen map - reader >> m_UnseenPixelSize[Activity::TeamOne]; ); - MatchProperty("AllUnseenPixelSizeTeam2", - // Read the desired pixel dimensions of the dynamically generated unseen map - reader >> m_UnseenPixelSize[Activity::TeamTwo]; ); - MatchProperty("AllUnseenPixelSizeTeam3", - // Read the desired pixel dimensions of the dynamically generated unseen map - reader >> m_UnseenPixelSize[Activity::TeamThree]; ); - MatchProperty("AllUnseenPixelSizeTeam4", - // Read the desired pixel dimensions of the dynamically generated unseen map - reader >> m_UnseenPixelSize[Activity::TeamFour]; ); - MatchProperty("UnseenLayerTeam1", - delete m_apUnseenLayer[Activity::TeamOne]; - m_apUnseenLayer[Activity::TeamOne] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); ); - MatchProperty("UnseenLayerTeam2", - delete m_apUnseenLayer[Activity::TeamTwo]; - m_apUnseenLayer[Activity::TeamTwo] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); ); - MatchProperty("UnseenLayerTeam3", - delete m_apUnseenLayer[Activity::TeamThree]; - m_apUnseenLayer[Activity::TeamThree] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); ); - MatchProperty("UnseenLayerTeam4", - delete m_apUnseenLayer[Activity::TeamFour]; - m_apUnseenLayer[Activity::TeamFour] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); ); - MatchProperty("ScanScheduledTeam1", { reader >> m_ScanScheduled[Activity::TeamOne]; }); - MatchProperty("ScanScheduledTeam2", { reader >> m_ScanScheduled[Activity::TeamTwo]; }); - MatchProperty("ScanScheduledTeam3", { reader >> m_ScanScheduled[Activity::TeamThree]; }); - MatchProperty("ScanScheduledTeam4", { reader >> m_ScanScheduled[Activity::TeamFour]; }); - MatchProperty("AddArea", - Area area; - reader >> area; - // This replaces any existing ones - SetArea(area); ); - MatchProperty("GlobalAcceleration", { reader >> m_GlobalAcc; }); - - EndPropertyList; -} + masked_blit(m_pTerrain->GetBGColorBitmap(), previewBuffer, 0, 0, 0, 0, sceneWidth, sceneHeight); + masked_blit(m_pTerrain->GetFGColorBitmap(), previewBuffer, 0, 0, 0, 0, sceneWidth, sceneHeight); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this Scene with a Writer for -// later recreation with Create(Reader &reader); + for (SceneObject* sceneObject: m_PlacedObjects[PlacedObjectSets::PLACEONLOAD]) { + if (const TerrainObject* terrainObject = dynamic_cast(sceneObject)) { + Vector pos = terrainObject->GetPos() + terrainObject->GetBitmapOffset(); + BITMAP* terrainObjectBG = terrainObject->GetBGColorBitmap(); + BITMAP* terrainObjectFG = terrainObject->GetFGColorBitmap(); -int Scene::Save(Writer &writer) const { - Entity::Save(writer); + // Wrapped drawing + if (pos.GetFloorIntX() < 0) { + if (terrainObject->HasBGColorBitmap()) { + masked_blit(terrainObjectBG, previewBuffer, 0, 0, pos.GetFloorIntX() + sceneWidth, pos.GetFloorIntY(), terrainObjectBG->w, terrainObjectBG->h); + } + if (terrainObject->HasFGColorBitmap()) { + masked_blit(terrainObjectFG, previewBuffer, 0, 0, pos.GetFloorIntX() + sceneWidth, pos.GetFloorIntY(), terrainObjectFG->w, terrainObjectFG->h); + } + } else if (pos.GetFloorIntX() + terrainObject->GetBitmapWidth() >= sceneWidth) { + if (terrainObject->HasBGColorBitmap()) { + masked_blit(terrainObjectBG, previewBuffer, 0, 0, pos.GetFloorIntX() - sceneWidth, pos.GetFloorIntY(), terrainObjectBG->w, terrainObjectBG->h); + } + if (terrainObject->HasFGColorBitmap()) { + masked_blit(terrainObjectFG, previewBuffer, 0, 0, pos.GetFloorIntX() - sceneWidth, pos.GetFloorIntY(), terrainObjectFG->w, terrainObjectFG->h); + } + } + if (terrainObject->HasBGColorBitmap()) { + masked_blit(terrainObjectBG, previewBuffer, 0, 0, pos.GetFloorIntX(), pos.GetFloorIntY(), terrainObjectBG->w, terrainObjectBG->h); + } + if (terrainObject->HasFGColorBitmap()) { + masked_blit(terrainObjectFG, previewBuffer, 0, 0, pos.GetFloorIntX(), pos.GetFloorIntY(), terrainObjectFG->w, terrainObjectFG->h); + } + } - bool doFullGameSave = !dynamic_cast(g_ActivityMan.GetActivity()); + // TODO: Figure out how to draw the actual modules that compose an assembly that is part of the scheme. For now just disable. + /* + else if (const BunkerAssemblyScheme *assemblyScheme = dynamic_cast(sceneObject)) { + Vector pos = assemblyScheme->GetPos() + assemblyScheme->GetBitmapOffset(); + + // Wrapped drawing + if (pos.GetFloorIntX() < 0) { + rect(previewBuffer, pos.GetFloorIntX() + sceneWidth, pos.GetFloorIntY(), pos.GetFloorIntX() + sceneWidth + assemblyScheme->GetBitmapWidth(), pos.GetFloorIntY() + assemblyScheme->GetBitmapHeight(), 5); + } else if (pos.GetFloorIntX() + assemblyScheme->GetBitmapWidth() >= sceneWidth) { + rect(previewBuffer, pos.GetFloorIntX() - sceneWidth, pos.GetFloorIntY(), pos.GetFloorIntX() - sceneWidth + assemblyScheme->GetBitmapWidth(), pos.GetFloorIntY() + assemblyScheme->GetBitmapHeight(), 5); + } + rect(previewBuffer, pos.GetFloorIntX(), pos.GetFloorIntY(), pos.GetFloorIntX() + ((float)assemblyScheme->GetBitmapWidth()), pos.GetFloorIntY() + ((float)assemblyScheme->GetBitmapHeight()), 5); + } + */ + } - writer.NewPropertyWithValue("LocationOnPlanet", m_Location); - writer.NewPropertyWithValue("MetagamePlayable", m_MetagamePlayable); - //Do not save preview if it's path is empty, for example in metagame - if (m_PreviewBitmapFile.GetDataPath().length() > 0 && m_MetasceneParent.length() == 0) { - writer.NewPropertyWithValue("PreviewBitmapFile", m_PreviewBitmapFile); - } - if (m_MetasceneParent.length() > 0) { - writer.NewPropertyWithValue("MetasceneParent", m_MetasceneParent); - } - writer.NewPropertyWithValue("MetagameInternal", m_IsMetagameInternal); - writer.NewPropertyWithValue("ScriptSave", m_IsSavedGameInternal); - writer.NewPropertyWithValue("Revealed", m_Revealed); - writer.NewPropertyWithValue("OwnedByTeam", m_OwnedByTeam); - writer.NewPropertyWithValue("RoundIncome", m_RoundIncome); + masked_stretch_blit(previewBuffer, m_pPreviewBitmap, 0, 0, previewBuffer->w, previewBuffer->h, 0, 0, m_pPreviewBitmap->w, m_pPreviewBitmap->h); + destroy_bitmap(previewBuffer); - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - std::string playerNumberString = "P" + std::to_string(player + 1); - writer.NewPropertyWithValue(playerNumberString + "BuildBudget", m_BuildBudget[player]); - writer.NewPropertyWithValue(playerNumberString + "BuildBudgetRatio", m_BuildBudgetRatio[player]); - if (m_ResidentBrains[player]) { - writer.NewProperty(playerNumberString + "ResidentBrain"); - SaveSceneObject(writer, m_ResidentBrains[player], false, doFullGameSave); + if (g_FrameMan.SaveBitmapToPNG(m_pPreviewBitmap, bitmapPath.c_str()) == 0) { + m_PreviewBitmapFile.SetDataPath(bitmapPath); } + + return 0; } - writer.NewPropertyWithValue("AutoDesigned", m_AutoDesigned); - writer.NewPropertyWithValue("TotalInvestment", m_TotalInvestment); - writer.NewPropertyWithValue("Terrain", m_pTerrain); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ClearData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out any previously loaded bitmap data from memory. - for (int set = PlacedObjectSets::PLACEONLOAD; set < PlacedObjectSets::PLACEDSETSCOUNT; ++set) { - for (const SceneObject *placedObject : m_PlacedObjects[set]) { - if (placedObject->GetPresetName().empty() || placedObject->GetPresetName() == "None") { - // We have no info about what we're placing. This is probably because it's some particle that was kicked off the terrain - // In future, we'll save all the data (uncomment out //writer << placedObject;), and will be able to save/load that stuff - // But for now, until we have a more effective writer that can remove redundant properties, we just skip this - continue; - } + int Scene::ClearData() { + if (!m_pTerrain) + return 0; - if (set == PlacedObjectSets::PLACEONLOAD) { - writer.NewProperty("PlaceSceneObject"); - } else if (set == PlacedObjectSets::BLUEPRINT) { - writer.NewProperty("BlueprintObject"); - } else if (set == PlacedObjectSets::AIPLAN) { - writer.NewProperty("PlaceAIPlanObject"); - } + // Clear Terrain's data + if (m_pTerrain->ClearData() < 0) { + RTEAbort("Clearing Terrain " + m_pTerrain->GetPresetName() + "\'s data failed!"); + return -1; + } - //writer << placedObject; - SaveSceneObject(writer, placedObject, false, doFullGameSave); - } - } - - for (std::list::const_iterator slItr = m_BackLayerList.begin(); slItr != m_BackLayerList.end(); ++slItr) - { - writer.NewProperty("AddBackgroundLayer"); - (*slItr)->SavePresetCopy(writer); - } - if (!m_UnseenPixelSize[Activity::TeamOne].IsZero()) - { - writer.NewProperty("AllUnseenPixelSizeTeam1"); - writer << m_UnseenPixelSize[Activity::TeamOne]; - } - if (!m_UnseenPixelSize[Activity::TeamTwo].IsZero()) - { - writer.NewProperty("AllUnseenPixelSizeTeam2"); - writer << m_UnseenPixelSize[Activity::TeamTwo]; - } - if (!m_UnseenPixelSize[Activity::TeamThree].IsZero()) - { - writer.NewProperty("AllUnseenPixelSizeTeam3"); - writer << m_UnseenPixelSize[Activity::TeamThree]; - } - if (!m_UnseenPixelSize[Activity::TeamFour].IsZero()) - { - writer.NewProperty("AllUnseenPixelSizeTeam4"); - writer << m_UnseenPixelSize[Activity::TeamFour]; - } - if (m_apUnseenLayer[Activity::TeamOne]) - { - writer.NewProperty("UnseenLayerTeam1"); - writer << m_apUnseenLayer[Activity::TeamOne]; - } - if (m_apUnseenLayer[Activity::TeamTwo]) - { - writer.NewProperty("UnseenLayerTeam2"); - writer << m_apUnseenLayer[Activity::TeamTwo]; - } - if (m_apUnseenLayer[Activity::TeamThree]) - { - writer.NewProperty("UnseenLayerTeam3"); - writer << m_apUnseenLayer[Activity::TeamThree]; - } - if (m_apUnseenLayer[Activity::TeamFour]) - { - writer.NewProperty("UnseenLayerTeam4"); - writer << m_apUnseenLayer[Activity::TeamFour]; - } - if (m_ScanScheduled[Activity::TeamOne]) - { - writer.NewProperty("ScanScheduledTeam1"); - writer << m_ScanScheduled[Activity::TeamOne]; - } - if (m_ScanScheduled[Activity::TeamTwo]) - { - writer.NewProperty("ScanScheduledTeam2"); - writer << m_ScanScheduled[Activity::TeamTwo]; - } - if (m_ScanScheduled[Activity::TeamThree]) - { - writer.NewProperty("ScanScheduledTeam3"); - writer << m_ScanScheduled[Activity::TeamThree]; - } - if (m_ScanScheduled[Activity::TeamFour]) - { - writer.NewProperty("ScanScheduledTeam4"); - writer << m_ScanScheduled[Activity::TeamFour]; - } - for (std::list::const_iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) - { - // Only write the area if it has any boxes/area at all - if (doFullGameSave || !(*aItr).HasNoArea()) { - writer.NewProperty("AddArea"); - writer << *aItr; + // Clear unseen layers' data + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + if (m_apUnseenLayer[team]) { + // Clear unseen layer data from memory + if (m_apUnseenLayer[team]->ClearData() < 0) { + g_ConsoleMan.PrintString("ERROR: Clearing unseen layer " + m_apUnseenLayer[team]->GetPresetName() + "\'s data failed!"); + return -1; + } + } } + + return 0; } - writer.NewProperty("GlobalAcceleration"); - writer << m_GlobalAcc; - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int Scene::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Entity::ReadProperty(propName, reader)); + + MatchProperty("LocationOnPlanet", { reader >> m_Location; }); + MatchProperty("MetagamePlayable", { reader >> m_MetagamePlayable; }); + MatchProperty("Revealed", { reader >> m_Revealed; }); + MatchProperty("MetasceneParent", { reader >> m_MetasceneParent; }); + MatchProperty("MetagameInternal", { reader >> m_IsMetagameInternal; }); + MatchProperty("ScriptSave", { reader >> m_IsSavedGameInternal; }); + MatchProperty("OwnedByTeam", { reader >> m_OwnedByTeam; }); + MatchProperty("RoundIncome", { reader >> m_RoundIncome; }); + MatchProperty("P1ResidentBrain", { m_ResidentBrains[Players::PlayerOne] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); + MatchProperty("P2ResidentBrain", { m_ResidentBrains[Players::PlayerTwo] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); + MatchProperty("P3ResidentBrain", { m_ResidentBrains[Players::PlayerThree] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); + MatchProperty("P4ResidentBrain", { m_ResidentBrains[Players::PlayerFour] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); }); + MatchProperty("P1BuildBudget", { reader >> m_BuildBudget[Players::PlayerOne]; }); + MatchProperty("P2BuildBudget", { reader >> m_BuildBudget[Players::PlayerTwo]; }); + MatchProperty("P3BuildBudget", { reader >> m_BuildBudget[Players::PlayerThree]; }); + MatchProperty("P4BuildBudget", { reader >> m_BuildBudget[Players::PlayerFour]; }); + MatchProperty("P1BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerOne]; }); + MatchProperty("P2BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerTwo]; }); + MatchProperty("P3BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerThree]; }); + MatchProperty("P4BuildBudgetRatio", { reader >> m_BuildBudgetRatio[Players::PlayerFour]; }); + MatchProperty("AutoDesigned", { reader >> m_AutoDesigned; }); + MatchProperty("TotalInvestment", { reader >> m_TotalInvestment; }); + MatchProperty("PreviewBitmapFile", + reader >> m_PreviewBitmapFile; + m_pPreviewBitmap = m_PreviewBitmapFile.GetAsBitmap(COLORCONV_NONE, false);); + MatchProperty("Terrain", + delete m_pTerrain; + m_pTerrain = new SLTerrain(); + reader >> m_pTerrain;); + MatchForwards("PlaceSceneObject") + MatchProperty( + "PlaceMovableObject", + SceneObject* pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); + if (pSO) { + m_PlacedObjects[PLACEONLOAD].push_back(pSO); + }); + MatchProperty( + "BlueprintObject", + SceneObject* pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); + if (pSO) { + m_PlacedObjects[BLUEPRINT].push_back(pSO); + }); + MatchProperty( + "PlaceAIPlanObject", + SceneObject* pSO = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); + if (pSO) { + m_PlacedObjects[AIPLAN].push_back(pSO); + }); + MatchProperty( + "AddBackgroundLayer", + SLBackground* pLayer = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader)); + RTEAssert(pLayer, "Something went wrong with reading SceneLayer"); + if (pLayer) { + m_BackLayerList.push_back(pLayer); + }); + MatchProperty("AllUnseenPixelSizeTeam1", + // Read the desired pixel dimensions of the dynamically generated unseen map + reader >> m_UnseenPixelSize[Activity::TeamOne];); + MatchProperty("AllUnseenPixelSizeTeam2", + // Read the desired pixel dimensions of the dynamically generated unseen map + reader >> m_UnseenPixelSize[Activity::TeamTwo];); + MatchProperty("AllUnseenPixelSizeTeam3", + // Read the desired pixel dimensions of the dynamically generated unseen map + reader >> m_UnseenPixelSize[Activity::TeamThree];); + MatchProperty("AllUnseenPixelSizeTeam4", + // Read the desired pixel dimensions of the dynamically generated unseen map + reader >> m_UnseenPixelSize[Activity::TeamFour];); + MatchProperty("UnseenLayerTeam1", + delete m_apUnseenLayer[Activity::TeamOne]; + m_apUnseenLayer[Activity::TeamOne] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader));); + MatchProperty("UnseenLayerTeam2", + delete m_apUnseenLayer[Activity::TeamTwo]; + m_apUnseenLayer[Activity::TeamTwo] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader));); + MatchProperty("UnseenLayerTeam3", + delete m_apUnseenLayer[Activity::TeamThree]; + m_apUnseenLayer[Activity::TeamThree] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader));); + MatchProperty("UnseenLayerTeam4", + delete m_apUnseenLayer[Activity::TeamFour]; + m_apUnseenLayer[Activity::TeamFour] = dynamic_cast(g_PresetMan.ReadReflectedPreset(reader));); + MatchProperty("ScanScheduledTeam1", { reader >> m_ScanScheduled[Activity::TeamOne]; }); + MatchProperty("ScanScheduledTeam2", { reader >> m_ScanScheduled[Activity::TeamTwo]; }); + MatchProperty("ScanScheduledTeam3", { reader >> m_ScanScheduled[Activity::TeamThree]; }); + MatchProperty("ScanScheduledTeam4", { reader >> m_ScanScheduled[Activity::TeamFour]; }); + MatchProperty("AddArea", + Area area; + reader >> area; + // This replaces any existing ones + SetArea(area);); + MatchProperty("GlobalAcceleration", { reader >> m_GlobalAcc; }); + + EndPropertyList; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this Scene with a Writer for + // later recreation with Create(Reader &reader); -void Scene::SaveSceneObject(Writer &writer, const SceneObject *sceneObjectToSave, bool isChildAttachable, bool saveFullData) const { - auto WriteHardcodedAttachableOrNone = [this, &writer, &saveFullData](const std::string &propertyName, const Attachable *harcodedAttachable) { - if (harcodedAttachable) { - writer.NewProperty(propertyName); - SaveSceneObject(writer, harcodedAttachable, true, saveFullData); - } else { - writer.NewPropertyWithValue(propertyName, "None"); - } - }; + int Scene::Save(Writer& writer) const { + Entity::Save(writer); - writer.ObjectStart(sceneObjectToSave->GetClassName()); - writer.NewPropertyWithValue("CopyOf", sceneObjectToSave->GetModuleAndPresetName()); + bool doFullGameSave = !dynamic_cast(g_ActivityMan.GetActivity()); - if (saveFullData) { - for (const std::string &group : *sceneObjectToSave->GetGroups()) { - writer.NewPropertyWithValue("AddToGroup", group); + writer.NewPropertyWithValue("LocationOnPlanet", m_Location); + writer.NewPropertyWithValue("MetagamePlayable", m_MetagamePlayable); + // Do not save preview if it's path is empty, for example in metagame + if (m_PreviewBitmapFile.GetDataPath().length() > 0 && m_MetasceneParent.length() == 0) { + writer.NewPropertyWithValue("PreviewBitmapFile", m_PreviewBitmapFile); + } + if (m_MetasceneParent.length() > 0) { + writer.NewPropertyWithValue("MetasceneParent", m_MetasceneParent); + } + writer.NewPropertyWithValue("MetagameInternal", m_IsMetagameInternal); + writer.NewPropertyWithValue("ScriptSave", m_IsSavedGameInternal); + writer.NewPropertyWithValue("Revealed", m_Revealed); + writer.NewPropertyWithValue("OwnedByTeam", m_OwnedByTeam); + writer.NewPropertyWithValue("RoundIncome", m_RoundIncome); + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + std::string playerNumberString = "P" + std::to_string(player + 1); + writer.NewPropertyWithValue(playerNumberString + "BuildBudget", m_BuildBudget[player]); + writer.NewPropertyWithValue(playerNumberString + "BuildBudgetRatio", m_BuildBudgetRatio[player]); + if (m_ResidentBrains[player]) { + writer.NewProperty(playerNumberString + "ResidentBrain"); + SaveSceneObject(writer, m_ResidentBrains[player], false, doFullGameSave); + } } - } - writer.NewPropertyWithValue("Position", sceneObjectToSave->GetPos()); - writer.NewPropertyWithValue("Team", sceneObjectToSave->GetTeam()); - if (!isChildAttachable) { - writer.NewPropertyWithValue("PlacedByPlayer", sceneObjectToSave->GetPlacedByPlayer()); - } - if (saveFullData) { - writer.NewPropertyWithValue("GoldValue", sceneObjectToSave->GetGoldValue()); - } + writer.NewPropertyWithValue("AutoDesigned", m_AutoDesigned); + writer.NewPropertyWithValue("TotalInvestment", m_TotalInvestment); + writer.NewPropertyWithValue("Terrain", m_pTerrain); + + for (int set = PlacedObjectSets::PLACEONLOAD; set < PlacedObjectSets::PLACEDSETSCOUNT; ++set) { + for (const SceneObject* placedObject: m_PlacedObjects[set]) { + if (placedObject->GetPresetName().empty() || placedObject->GetPresetName() == "None") { + // We have no info about what we're placing. This is probably because it's some particle that was kicked off the terrain + // In future, we'll save all the data (uncomment out //writer << placedObject;), and will be able to save/load that stuff + // But for now, until we have a more effective writer that can remove redundant properties, we just skip this + continue; + } - if (const Deployment *deploymentToSave = dynamic_cast(sceneObjectToSave); deploymentToSave && deploymentToSave->GetID() != 0) { - writer.NewPropertyWithValue("ID", deploymentToSave->GetID()); - } + if (set == PlacedObjectSets::PLACEONLOAD) { + writer.NewProperty("PlaceSceneObject"); + } else if (set == PlacedObjectSets::BLUEPRINT) { + writer.NewProperty("BlueprintObject"); + } else if (set == PlacedObjectSets::AIPLAN) { + writer.NewProperty("PlaceAIPlanObject"); + } - if (const MovableObject *movableObjectToSave = dynamic_cast(sceneObjectToSave); movableObjectToSave && saveFullData) { - writer.NewPropertyWithValue("HUDVisible", movableObjectToSave->GetHUDVisible()); - writer.NewPropertyWithValue("Velocity", movableObjectToSave->GetVel()); - writer.NewPropertyWithValue("LifeTime", movableObjectToSave->GetLifetime()); - writer.NewPropertyWithValue("Age", movableObjectToSave->GetAge()); - writer.NewPropertyWithValue("PinStrength", movableObjectToSave->GetPinStrength()); - } + // writer << placedObject; + SaveSceneObject(writer, placedObject, false, doFullGameSave); + } + } - if (const MOSprite *moSpriteToSave = dynamic_cast(sceneObjectToSave)) { - writer.NewPropertyWithValue("HFlipped", moSpriteToSave->IsHFlipped()); - if (saveFullData || dynamic_cast(moSpriteToSave)) { - writer.NewPropertyWithValue("Rotation", moSpriteToSave->GetRotMatrix()); + for (std::list::const_iterator slItr = m_BackLayerList.begin(); slItr != m_BackLayerList.end(); ++slItr) { + writer.NewProperty("AddBackgroundLayer"); + (*slItr)->SavePresetCopy(writer); } - if (saveFullData) { - writer.NewPropertyWithValue("AngularVel", moSpriteToSave->GetAngularVel()); + if (!m_UnseenPixelSize[Activity::TeamOne].IsZero()) { + writer.NewProperty("AllUnseenPixelSizeTeam1"); + writer << m_UnseenPixelSize[Activity::TeamOne]; + } + if (!m_UnseenPixelSize[Activity::TeamTwo].IsZero()) { + writer.NewProperty("AllUnseenPixelSizeTeam2"); + writer << m_UnseenPixelSize[Activity::TeamTwo]; + } + if (!m_UnseenPixelSize[Activity::TeamThree].IsZero()) { + writer.NewProperty("AllUnseenPixelSizeTeam3"); + writer << m_UnseenPixelSize[Activity::TeamThree]; + } + if (!m_UnseenPixelSize[Activity::TeamFour].IsZero()) { + writer.NewProperty("AllUnseenPixelSizeTeam4"); + writer << m_UnseenPixelSize[Activity::TeamFour]; + } + if (m_apUnseenLayer[Activity::TeamOne]) { + writer.NewProperty("UnseenLayerTeam1"); + writer << m_apUnseenLayer[Activity::TeamOne]; + } + if (m_apUnseenLayer[Activity::TeamTwo]) { + writer.NewProperty("UnseenLayerTeam2"); + writer << m_apUnseenLayer[Activity::TeamTwo]; + } + if (m_apUnseenLayer[Activity::TeamThree]) { + writer.NewProperty("UnseenLayerTeam3"); + writer << m_apUnseenLayer[Activity::TeamThree]; + } + if (m_apUnseenLayer[Activity::TeamFour]) { + writer.NewProperty("UnseenLayerTeam4"); + writer << m_apUnseenLayer[Activity::TeamFour]; + } + if (m_ScanScheduled[Activity::TeamOne]) { + writer.NewProperty("ScanScheduledTeam1"); + writer << m_ScanScheduled[Activity::TeamOne]; + } + if (m_ScanScheduled[Activity::TeamTwo]) { + writer.NewProperty("ScanScheduledTeam2"); + writer << m_ScanScheduled[Activity::TeamTwo]; + } + if (m_ScanScheduled[Activity::TeamThree]) { + writer.NewProperty("ScanScheduledTeam3"); + writer << m_ScanScheduled[Activity::TeamThree]; } + if (m_ScanScheduled[Activity::TeamFour]) { + writer.NewProperty("ScanScheduledTeam4"); + writer << m_ScanScheduled[Activity::TeamFour]; + } + for (std::list::const_iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) { + // Only write the area if it has any boxes/area at all + if (doFullGameSave || !(*aItr).HasNoArea()) { + writer.NewProperty("AddArea"); + writer << *aItr; + } + } + writer.NewProperty("GlobalAcceleration"); + writer << m_GlobalAcc; + + return 0; } - if (const MOSRotating *mosRotatingToSave = dynamic_cast(sceneObjectToSave)) { - if (saveFullData) { - const std::list &attachablesToSave = mosRotatingToSave->GetAttachableList(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // If this MOSRotating has any Attachables, we have to add a special behaviour property that'll delete them all so they can be re-read. This will allow us to handle Attachables with our limited serialization. - // Alternatively, if the MOSRotating has no Attachables but its preset does, we need to set the flag, because that means this is missing Attachables, and we don't want to magically regenerate them when a game is loaded. - if (!attachablesToSave.empty()) { - writer.NewPropertyWithValue("SpecialBehaviour_ClearAllAttachables", true); - } - else if (const MOSRotating *presetOfMOSRotatingToSave = dynamic_cast(g_PresetMan.GetEntityPreset(mosRotatingToSave->GetClassName(), mosRotatingToSave->GetPresetName(), mosRotatingToSave->GetModuleID())); presetOfMOSRotatingToSave && !presetOfMOSRotatingToSave->GetAttachableList().empty()) { - writer.NewPropertyWithValue("SpecialBehaviour_ClearAllAttachables", true); + void Scene::SaveSceneObject(Writer& writer, const SceneObject* sceneObjectToSave, bool isChildAttachable, bool saveFullData) const { + auto WriteHardcodedAttachableOrNone = [this, &writer, &saveFullData](const std::string& propertyName, const Attachable* harcodedAttachable) { + if (harcodedAttachable) { + writer.NewProperty(propertyName); + SaveSceneObject(writer, harcodedAttachable, true, saveFullData); + } else { + writer.NewPropertyWithValue(propertyName, "None"); } + }; - for (const Attachable *attachable : attachablesToSave) { - if (!mosRotatingToSave->AttachableIsHardcoded(attachable)) { - writer.NewProperty("AddAttachable"); - SaveSceneObject(writer, attachable, true, saveFullData); - } - } - for (const AEmitter *wound : mosRotatingToSave->GetWoundList()) { - writer.NewProperty("SpecialBehaviour_AddWound"); - SaveSceneObject(writer, wound, true, saveFullData); - } - } + writer.ObjectStart(sceneObjectToSave->GetClassName()); + writer.NewPropertyWithValue("CopyOf", sceneObjectToSave->GetModuleAndPresetName()); - for (auto &[key, value] : mosRotatingToSave->GetStringValueMap()) { - writer.NewProperty("AddCustomValue"); - writer.ObjectStart("StringValue"); - writer.NewPropertyWithValue(key, value); - writer.ObjectEnd(); - } - - for (auto &[key, value] : mosRotatingToSave->GetNumberValueMap()) { - writer.NewProperty("AddCustomValue"); - writer.ObjectStart("NumberValue"); - writer.NewPropertyWithValue(key, value); - writer.ObjectEnd(); - } - } - - if (const Attachable *attachableToSave = dynamic_cast(sceneObjectToSave); attachableToSave && saveFullData) { - writer.NewPropertyWithValue("ParentOffset", attachableToSave->GetParentOffset()); - writer.NewPropertyWithValue("DrawAfterParent", attachableToSave->IsDrawnAfterParent()); - writer.NewPropertyWithValue("DeleteWhenRemovedFromParent", attachableToSave->GetDeleteWhenRemovedFromParent()); - writer.NewPropertyWithValue("GibWhenRemovedFromParent", attachableToSave->GetGibWhenRemovedFromParent()); - writer.NewPropertyWithValue("JointStrength", attachableToSave->GetJointStrength()); - writer.NewPropertyWithValue("JointStiffness", attachableToSave->GetJointStiffness()); - writer.NewPropertyWithValue("JointOffset", attachableToSave->GetJointOffset()); - writer.NewPropertyWithValue("InheritsHFlipped", attachableToSave->InheritsHFlipped()); - writer.NewPropertyWithValue("InheritsRotAngle", attachableToSave->InheritsRotAngle()); - writer.NewPropertyWithValue("InheritedRotAngleOffset", attachableToSave->GetInheritedRotAngleOffset()); - writer.NewPropertyWithValue("InheritsFrame", attachableToSave->InheritsFrame()); - writer.NewPropertyWithValue("CollidesWithTerrainWhileAttached", attachableToSave->GetCollidesWithTerrainWhileAttached()); - - if (const AEmitter *aemitterToSave = dynamic_cast(sceneObjectToSave)) { - writer.NewPropertyWithValue("EmissionEnabled", aemitterToSave->IsEmitting()); - writer.NewPropertyWithValue("EmissionCount", aemitterToSave->GetEmitCount()); - writer.NewPropertyWithValue("EmissionCountLimit", aemitterToSave->GetEmitCountLimit()); - writer.NewPropertyWithValue("NegativeThrottleMultiplier", aemitterToSave->GetNegativeThrottleMultiplier()); - writer.NewPropertyWithValue("PositiveThrottleMultiplier", aemitterToSave->GetPositiveThrottleMultiplier()); - writer.NewPropertyWithValue("Throttle", aemitterToSave->GetThrottle()); - writer.NewPropertyWithValue("BurstScale", aemitterToSave->GetBurstScale()); - writer.NewPropertyWithValue("BurstDamage", aemitterToSave->GetBurstDamage()); - writer.NewPropertyWithValue("EmitterDamageMultiplier", aemitterToSave->GetEmitterDamageMultiplier()); - writer.NewPropertyWithValue("BurstSpacing", aemitterToSave->GetBurstSpacing()); - writer.NewPropertyWithValue("BurstTriggered", aemitterToSave->IsSetToBurst()); - writer.NewPropertyWithValue("EmissionAngle", aemitterToSave->GetEmitAngleMatrix()); - writer.NewPropertyWithValue("EmissionOffset", aemitterToSave->GetEmitOffset()); - writer.NewPropertyWithValue("EmissionDamage", aemitterToSave->GetEmitDamage()); - WriteHardcodedAttachableOrNone("Flash", aemitterToSave->GetFlash()); - } - - if (const AEJetpack *jetpackToSave = dynamic_cast(sceneObjectToSave)) { - writer.NewProperty("JetpackType"); - switch (jetpackToSave->GetJetpackType()) { - default: - case AEJetpack::JetpackType::Standard: - writer << "Standard"; - break; - case AEJetpack::JetpackType::JumpPack: - writer << "JumpPack"; - break; - } - - writer.NewPropertyWithValue("JumpTime", jetpackToSave->GetJetTimeTotal() / 1000.0f); // Convert to seconds - writer.NewPropertyWithValue("JumpReplenishRate", jetpackToSave->GetJetReplenishRate()); - writer.NewPropertyWithValue("MinimumFuelRatio", jetpackToSave->GetMinimumFuelRatio()); - writer.NewPropertyWithValue("JumpAngleRange", jetpackToSave->GetJetAngleRange()); - writer.NewPropertyWithValue("CanAdjustAngleWhileFiring", jetpackToSave->GetCanAdjustAngleWhileFiring()); - } - - if (const Arm *armToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("HeldDevice", armToSave->GetHeldDevice()); - } - - if (const Leg *legToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("Foot", legToSave->GetFoot()); - } - - if (const Turret *turretToSave = dynamic_cast(sceneObjectToSave)) { - for (const HeldDevice *heldDeviceToSave : turretToSave->GetMountedDevices()) { - WriteHardcodedAttachableOrNone("AddMountedDevice", heldDeviceToSave); + if (saveFullData) { + for (const std::string& group: *sceneObjectToSave->GetGroups()) { + writer.NewPropertyWithValue("AddToGroup", group); } } - if (const HeldDevice *heldDeviceToSave = dynamic_cast(sceneObjectToSave)) { - writer.NewPropertyWithValue("SpecialBehaviour_Activated", heldDeviceToSave->IsActivated()); - writer.NewPropertyWithValue("SpecialBehaviour_ActivationTimerElapsedSimTimeMS", heldDeviceToSave->GetActivationTimer().GetElapsedSimTimeMS()); + writer.NewPropertyWithValue("Position", sceneObjectToSave->GetPos()); + writer.NewPropertyWithValue("Team", sceneObjectToSave->GetTeam()); + if (!isChildAttachable) { + writer.NewPropertyWithValue("PlacedByPlayer", sceneObjectToSave->GetPlacedByPlayer()); } - - if (const HDFirearm *hdFirearmToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("Magazine", hdFirearmToSave->GetMagazine()); - WriteHardcodedAttachableOrNone("Flash", hdFirearmToSave->GetFlash()); + if (saveFullData) { + writer.NewPropertyWithValue("GoldValue", sceneObjectToSave->GetGoldValue()); } - if (const Magazine *magazineToSave = dynamic_cast(sceneObjectToSave)) { - writer.NewPropertyWithValue("RoundCount", magazineToSave->GetRoundCount()); + if (const Deployment* deploymentToSave = dynamic_cast(sceneObjectToSave); deploymentToSave && deploymentToSave->GetID() != 0) { + writer.NewPropertyWithValue("ID", deploymentToSave->GetID()); } - } - if (const Actor *actorToSave = dynamic_cast(sceneObjectToSave)) { - writer.NewPropertyWithValue("Health", actorToSave->GetHealth()); - writer.NewPropertyWithValue("MaxHealth", actorToSave->GetMaxHealth()); - if (saveFullData) { - writer.NewPropertyWithValue("Status", actorToSave->GetStatus()); - writer.NewPropertyWithValue("PlayerControllable", actorToSave->IsPlayerControllable()); + if (const MovableObject* movableObjectToSave = dynamic_cast(sceneObjectToSave); movableObjectToSave && saveFullData) { + writer.NewPropertyWithValue("HUDVisible", movableObjectToSave->GetHUDVisible()); + writer.NewPropertyWithValue("Velocity", movableObjectToSave->GetVel()); + writer.NewPropertyWithValue("LifeTime", movableObjectToSave->GetLifetime()); + writer.NewPropertyWithValue("Age", movableObjectToSave->GetAge()); + writer.NewPropertyWithValue("PinStrength", movableObjectToSave->GetPinStrength()); + } - int aiModeToSave = actorToSave->GetAIMode() == Actor::AIMode::AIMODE_SQUAD ? Actor::AIMode::AIMODE_GOTO : actorToSave->GetAIMode(); - if (aiModeToSave == Actor::AIMode::AIMODE_GOTO && (!actorToSave->GetMOMoveTarget() && g_SceneMan.ShortestDistance(actorToSave->GetMovePathEnd(), actorToSave->GetPos(), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(1.0F))) { - aiModeToSave = Actor::AIMode::AIMODE_SENTRY; + if (const MOSprite* moSpriteToSave = dynamic_cast(sceneObjectToSave)) { + writer.NewPropertyWithValue("HFlipped", moSpriteToSave->IsHFlipped()); + if (saveFullData || dynamic_cast(moSpriteToSave)) { + writer.NewPropertyWithValue("Rotation", moSpriteToSave->GetRotMatrix()); } - writer.NewPropertyWithValue("AIMode", aiModeToSave); - if (aiModeToSave == Actor::AIMode::AIMODE_GOTO) { - const std::string addWaypointPropertyName = "SpecialBehaviour_AddAISceneWaypoint"; - if (const MovableObject *actorToSaveMOMoveTarget = actorToSave->GetMOMoveTarget()) { - writer.NewPropertyWithValue(addWaypointPropertyName, actorToSaveMOMoveTarget->GetPos()); - } else { - writer.NewPropertyWithValue(addWaypointPropertyName, actorToSave->GetMovePathEnd()); - for (auto &[waypointPosition, waypointObject] : actorToSave->GetWaypointList()) { - writer.NewPropertyWithValue(addWaypointPropertyName, waypointPosition); - } - } + if (saveFullData) { + writer.NewPropertyWithValue("AngularVel", moSpriteToSave->GetAngularVel()); } } - if (actorToSave->GetDeploymentID()) { - writer.NewPropertyWithValue("DeploymentID", actorToSave->GetDeploymentID()); - } + if (const MOSRotating* mosRotatingToSave = dynamic_cast(sceneObjectToSave)) { + if (saveFullData) { + const std::list& attachablesToSave = mosRotatingToSave->GetAttachableList(); - for (const MovableObject *inventoryItem : *actorToSave->GetInventory()) { - writer.NewProperty("AddInventory"); - SaveSceneObject(writer, inventoryItem, true, saveFullData); - } + // If this MOSRotating has any Attachables, we have to add a special behaviour property that'll delete them all so they can be re-read. This will allow us to handle Attachables with our limited serialization. + // Alternatively, if the MOSRotating has no Attachables but its preset does, we need to set the flag, because that means this is missing Attachables, and we don't want to magically regenerate them when a game is loaded. + if (!attachablesToSave.empty()) { + writer.NewPropertyWithValue("SpecialBehaviour_ClearAllAttachables", true); + } else if (const MOSRotating* presetOfMOSRotatingToSave = dynamic_cast(g_PresetMan.GetEntityPreset(mosRotatingToSave->GetClassName(), mosRotatingToSave->GetPresetName(), mosRotatingToSave->GetModuleID())); presetOfMOSRotatingToSave && !presetOfMOSRotatingToSave->GetAttachableList().empty()) { + writer.NewPropertyWithValue("SpecialBehaviour_ClearAllAttachables", true); + } - if (saveFullData) { - if (const ADoor *aDoorToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("Door", aDoorToSave->GetDoor()); - } else if (const AHuman *aHumanToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("Head", aHumanToSave->GetHead()); - WriteHardcodedAttachableOrNone("Jetpack", aHumanToSave->GetJetpack()); - WriteHardcodedAttachableOrNone("FGArm", aHumanToSave->GetFGArm()); - WriteHardcodedAttachableOrNone("BGArm", aHumanToSave->GetBGArm()); - WriteHardcodedAttachableOrNone("FGLeg", aHumanToSave->GetFGLeg()); - WriteHardcodedAttachableOrNone("BGLeg", aHumanToSave->GetBGLeg()); - } else if (const ACrab *aCrabToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("Turret", aCrabToSave->GetTurret()); - WriteHardcodedAttachableOrNone("Jetpack", aCrabToSave->GetJetpack()); - WriteHardcodedAttachableOrNone("LeftFGLeg", aCrabToSave->GetLeftFGLeg()); - WriteHardcodedAttachableOrNone("LeftBGLeg", aCrabToSave->GetLeftBGLeg()); - WriteHardcodedAttachableOrNone("RightFGLeg", aCrabToSave->GetRightFGLeg()); - WriteHardcodedAttachableOrNone("RightBGLeg", aCrabToSave->GetRightBGLeg()); - } else if (const ACRocket *acRocketToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("RightLeg", acRocketToSave->GetRightLeg()); - WriteHardcodedAttachableOrNone("LeftLeg", acRocketToSave->GetLeftLeg()); - WriteHardcodedAttachableOrNone("MainThruster", acRocketToSave->GetMainThruster()); - WriteHardcodedAttachableOrNone("RightThruster", acRocketToSave->GetRightThruster()); - WriteHardcodedAttachableOrNone("LeftThruster", acRocketToSave->GetLeftThruster()); - WriteHardcodedAttachableOrNone("UpRightThruster", acRocketToSave->GetURightThruster()); - WriteHardcodedAttachableOrNone("UpRightThruster", acRocketToSave->GetULeftThruster()); - } else if (const ACDropShip *acDropShipToSave = dynamic_cast(sceneObjectToSave)) { - WriteHardcodedAttachableOrNone("RightThruster", acDropShipToSave->GetRightThruster()); - WriteHardcodedAttachableOrNone("LeftThruster", acDropShipToSave->GetLeftThruster()); - WriteHardcodedAttachableOrNone("UpRightThruster", acDropShipToSave->GetURightThruster()); - WriteHardcodedAttachableOrNone("UpLeftThruster", acDropShipToSave->GetULeftThruster()); - WriteHardcodedAttachableOrNone("RightHatchDoor", acDropShipToSave->GetRightHatch()); - WriteHardcodedAttachableOrNone("LeftHatchDoor", acDropShipToSave->GetLeftHatch()); + for (const Attachable* attachable: attachablesToSave) { + if (!mosRotatingToSave->AttachableIsHardcoded(attachable)) { + writer.NewProperty("AddAttachable"); + SaveSceneObject(writer, attachable, true, saveFullData); + } + } + for (const AEmitter* wound: mosRotatingToSave->GetWoundList()) { + writer.NewProperty("SpecialBehaviour_AddWound"); + SaveSceneObject(writer, wound, true, saveFullData); + } } - } else if (const AHuman *aHumanToSave = dynamic_cast(sceneObjectToSave)) { - if (const HeldDevice *equippedItem = aHumanToSave->GetEquippedItem()) { - writer.NewProperty("AddInventory"); - SaveSceneObject(writer, equippedItem, true, saveFullData); + + for (auto& [key, value]: mosRotatingToSave->GetStringValueMap()) { + writer.NewProperty("AddCustomValue"); + writer.ObjectStart("StringValue"); + writer.NewPropertyWithValue(key, value); + writer.ObjectEnd(); } - if (const HeldDevice *bgEquippedItem = aHumanToSave->GetEquippedBGItem()) { - writer.NewProperty("AddInventory"); - SaveSceneObject(writer, bgEquippedItem, true, saveFullData); + + for (auto& [key, value]: mosRotatingToSave->GetNumberValueMap()) { + writer.NewProperty("AddCustomValue"); + writer.ObjectStart("NumberValue"); + writer.NewPropertyWithValue(key, value); + writer.ObjectEnd(); } } - } - writer.ObjectEnd(); -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (const Attachable* attachableToSave = dynamic_cast(sceneObjectToSave); attachableToSave && saveFullData) { + writer.NewPropertyWithValue("ParentOffset", attachableToSave->GetParentOffset()); + writer.NewPropertyWithValue("DrawAfterParent", attachableToSave->IsDrawnAfterParent()); + writer.NewPropertyWithValue("DeleteWhenRemovedFromParent", attachableToSave->GetDeleteWhenRemovedFromParent()); + writer.NewPropertyWithValue("GibWhenRemovedFromParent", attachableToSave->GetGibWhenRemovedFromParent()); + writer.NewPropertyWithValue("JointStrength", attachableToSave->GetJointStrength()); + writer.NewPropertyWithValue("JointStiffness", attachableToSave->GetJointStiffness()); + writer.NewPropertyWithValue("JointOffset", attachableToSave->GetJointOffset()); + writer.NewPropertyWithValue("InheritsHFlipped", attachableToSave->InheritsHFlipped()); + writer.NewPropertyWithValue("InheritsRotAngle", attachableToSave->InheritsRotAngle()); + writer.NewPropertyWithValue("InheritedRotAngleOffset", attachableToSave->GetInheritedRotAngleOffset()); + writer.NewPropertyWithValue("InheritsFrame", attachableToSave->InheritsFrame()); + writer.NewPropertyWithValue("CollidesWithTerrainWhileAttached", attachableToSave->GetCollidesWithTerrainWhileAttached()); + + if (const AEmitter* aemitterToSave = dynamic_cast(sceneObjectToSave)) { + writer.NewPropertyWithValue("EmissionEnabled", aemitterToSave->IsEmitting()); + writer.NewPropertyWithValue("EmissionCount", aemitterToSave->GetEmitCount()); + writer.NewPropertyWithValue("EmissionCountLimit", aemitterToSave->GetEmitCountLimit()); + writer.NewPropertyWithValue("NegativeThrottleMultiplier", aemitterToSave->GetNegativeThrottleMultiplier()); + writer.NewPropertyWithValue("PositiveThrottleMultiplier", aemitterToSave->GetPositiveThrottleMultiplier()); + writer.NewPropertyWithValue("Throttle", aemitterToSave->GetThrottle()); + writer.NewPropertyWithValue("BurstScale", aemitterToSave->GetBurstScale()); + writer.NewPropertyWithValue("BurstDamage", aemitterToSave->GetBurstDamage()); + writer.NewPropertyWithValue("EmitterDamageMultiplier", aemitterToSave->GetEmitterDamageMultiplier()); + writer.NewPropertyWithValue("BurstSpacing", aemitterToSave->GetBurstSpacing()); + writer.NewPropertyWithValue("BurstTriggered", aemitterToSave->IsSetToBurst()); + writer.NewPropertyWithValue("EmissionAngle", aemitterToSave->GetEmitAngleMatrix()); + writer.NewPropertyWithValue("EmissionOffset", aemitterToSave->GetEmitOffset()); + writer.NewPropertyWithValue("EmissionDamage", aemitterToSave->GetEmitDamage()); + WriteHardcodedAttachableOrNone("Flash", aemitterToSave->GetFlash()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the Scene object. - -void Scene::Destroy(bool notInherited) -{ - delete m_pTerrain; - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - delete m_ResidentBrains[player]; - } - - for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) - { - for (std::list::iterator oItr = m_PlacedObjects[set].begin(); oItr != m_PlacedObjects[set].end(); ++oItr) - { - delete (*oItr); - *oItr = 0; - } - } - - for (std::list::iterator slItr = m_BackLayerList.begin(); slItr != m_BackLayerList.end(); ++slItr) - { - delete (*slItr); - *slItr = 0; - } - - for (std::list::iterator slItr = m_Deployments.begin(); slItr != m_Deployments.end(); ++slItr) - { - delete (*slItr); - *slItr = 0; + if (const AEJetpack* jetpackToSave = dynamic_cast(sceneObjectToSave)) { + writer.NewProperty("JetpackType"); + switch (jetpackToSave->GetJetpackType()) { + default: + case AEJetpack::JetpackType::Standard: + writer << "Standard"; + break; + case AEJetpack::JetpackType::JumpPack: + writer << "JumpPack"; + break; + } + + writer.NewPropertyWithValue("JumpTime", jetpackToSave->GetJetTimeTotal() / 1000.0f); // Convert to seconds + writer.NewPropertyWithValue("JumpReplenishRate", jetpackToSave->GetJetReplenishRate()); + writer.NewPropertyWithValue("MinimumFuelRatio", jetpackToSave->GetMinimumFuelRatio()); + writer.NewPropertyWithValue("JumpAngleRange", jetpackToSave->GetJetAngleRange()); + writer.NewPropertyWithValue("CanAdjustAngleWhileFiring", jetpackToSave->GetCanAdjustAngleWhileFiring()); + } + + if (const Arm* armToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("HeldDevice", armToSave->GetHeldDevice()); + } + + if (const Leg* legToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("Foot", legToSave->GetFoot()); + } + + if (const Turret* turretToSave = dynamic_cast(sceneObjectToSave)) { + for (const HeldDevice* heldDeviceToSave: turretToSave->GetMountedDevices()) { + WriteHardcodedAttachableOrNone("AddMountedDevice", heldDeviceToSave); + } + } + + if (const HeldDevice* heldDeviceToSave = dynamic_cast(sceneObjectToSave)) { + writer.NewPropertyWithValue("SpecialBehaviour_Activated", heldDeviceToSave->IsActivated()); + writer.NewPropertyWithValue("SpecialBehaviour_ActivationTimerElapsedSimTimeMS", heldDeviceToSave->GetActivationTimer().GetElapsedSimTimeMS()); + } + + if (const HDFirearm* hdFirearmToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("Magazine", hdFirearmToSave->GetMagazine()); + WriteHardcodedAttachableOrNone("Flash", hdFirearmToSave->GetFlash()); + } + + if (const Magazine* magazineToSave = dynamic_cast(sceneObjectToSave)) { + writer.NewPropertyWithValue("RoundCount", magazineToSave->GetRoundCount()); + } + } + + if (const Actor* actorToSave = dynamic_cast(sceneObjectToSave)) { + writer.NewPropertyWithValue("Health", actorToSave->GetHealth()); + writer.NewPropertyWithValue("MaxHealth", actorToSave->GetMaxHealth()); + if (saveFullData) { + writer.NewPropertyWithValue("Status", actorToSave->GetStatus()); + writer.NewPropertyWithValue("PlayerControllable", actorToSave->IsPlayerControllable()); + + int aiModeToSave = actorToSave->GetAIMode() == Actor::AIMode::AIMODE_SQUAD ? Actor::AIMode::AIMODE_GOTO : actorToSave->GetAIMode(); + if (aiModeToSave == Actor::AIMode::AIMODE_GOTO && (!actorToSave->GetMOMoveTarget() && g_SceneMan.ShortestDistance(actorToSave->GetMovePathEnd(), actorToSave->GetPos(), g_SceneMan.SceneWrapsX()).MagnitudeIsLessThan(1.0F))) { + aiModeToSave = Actor::AIMode::AIMODE_SENTRY; + } + writer.NewPropertyWithValue("AIMode", aiModeToSave); + if (aiModeToSave == Actor::AIMode::AIMODE_GOTO) { + const std::string addWaypointPropertyName = "SpecialBehaviour_AddAISceneWaypoint"; + if (const MovableObject* actorToSaveMOMoveTarget = actorToSave->GetMOMoveTarget()) { + writer.NewPropertyWithValue(addWaypointPropertyName, actorToSaveMOMoveTarget->GetPos()); + } else { + writer.NewPropertyWithValue(addWaypointPropertyName, actorToSave->GetMovePathEnd()); + for (auto& [waypointPosition, waypointObject]: actorToSave->GetWaypointList()) { + writer.NewPropertyWithValue(addWaypointPropertyName, waypointPosition); + } + } + } + } + + if (actorToSave->GetDeploymentID()) { + writer.NewPropertyWithValue("DeploymentID", actorToSave->GetDeploymentID()); + } + + for (const MovableObject* inventoryItem: *actorToSave->GetInventory()) { + writer.NewProperty("AddInventory"); + SaveSceneObject(writer, inventoryItem, true, saveFullData); + } + + if (saveFullData) { + if (const ADoor* aDoorToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("Door", aDoorToSave->GetDoor()); + } else if (const AHuman* aHumanToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("Head", aHumanToSave->GetHead()); + WriteHardcodedAttachableOrNone("Jetpack", aHumanToSave->GetJetpack()); + WriteHardcodedAttachableOrNone("FGArm", aHumanToSave->GetFGArm()); + WriteHardcodedAttachableOrNone("BGArm", aHumanToSave->GetBGArm()); + WriteHardcodedAttachableOrNone("FGLeg", aHumanToSave->GetFGLeg()); + WriteHardcodedAttachableOrNone("BGLeg", aHumanToSave->GetBGLeg()); + } else if (const ACrab* aCrabToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("Turret", aCrabToSave->GetTurret()); + WriteHardcodedAttachableOrNone("Jetpack", aCrabToSave->GetJetpack()); + WriteHardcodedAttachableOrNone("LeftFGLeg", aCrabToSave->GetLeftFGLeg()); + WriteHardcodedAttachableOrNone("LeftBGLeg", aCrabToSave->GetLeftBGLeg()); + WriteHardcodedAttachableOrNone("RightFGLeg", aCrabToSave->GetRightFGLeg()); + WriteHardcodedAttachableOrNone("RightBGLeg", aCrabToSave->GetRightBGLeg()); + } else if (const ACRocket* acRocketToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("RightLeg", acRocketToSave->GetRightLeg()); + WriteHardcodedAttachableOrNone("LeftLeg", acRocketToSave->GetLeftLeg()); + WriteHardcodedAttachableOrNone("MainThruster", acRocketToSave->GetMainThruster()); + WriteHardcodedAttachableOrNone("RightThruster", acRocketToSave->GetRightThruster()); + WriteHardcodedAttachableOrNone("LeftThruster", acRocketToSave->GetLeftThruster()); + WriteHardcodedAttachableOrNone("UpRightThruster", acRocketToSave->GetURightThruster()); + WriteHardcodedAttachableOrNone("UpRightThruster", acRocketToSave->GetULeftThruster()); + } else if (const ACDropShip* acDropShipToSave = dynamic_cast(sceneObjectToSave)) { + WriteHardcodedAttachableOrNone("RightThruster", acDropShipToSave->GetRightThruster()); + WriteHardcodedAttachableOrNone("LeftThruster", acDropShipToSave->GetLeftThruster()); + WriteHardcodedAttachableOrNone("UpRightThruster", acDropShipToSave->GetURightThruster()); + WriteHardcodedAttachableOrNone("UpLeftThruster", acDropShipToSave->GetULeftThruster()); + WriteHardcodedAttachableOrNone("RightHatchDoor", acDropShipToSave->GetRightHatch()); + WriteHardcodedAttachableOrNone("LeftHatchDoor", acDropShipToSave->GetLeftHatch()); + } + } else if (const AHuman* aHumanToSave = dynamic_cast(sceneObjectToSave)) { + if (const HeldDevice* equippedItem = aHumanToSave->GetEquippedItem()) { + writer.NewProperty("AddInventory"); + SaveSceneObject(writer, equippedItem, true, saveFullData); + } + if (const HeldDevice* bgEquippedItem = aHumanToSave->GetEquippedBGItem()) { + writer.NewProperty("AddInventory"); + SaveSceneObject(writer, bgEquippedItem, true, saveFullData); + } + } + } + writer.ObjectEnd(); } - delete m_apUnseenLayer[Activity::TeamOne]; - delete m_apUnseenLayer[Activity::TeamTwo]; - delete m_apUnseenLayer[Activity::TeamThree]; - delete m_apUnseenLayer[Activity::TeamFour]; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //if (m_PreviewBitmapOwned) - destroy_bitmap(m_pPreviewBitmap); - m_pPreviewBitmap = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the Scene object. - if (!notInherited) - Entity::Destroy(); - Clear(); -} + void Scene::Destroy(bool notInherited) { + delete m_pTerrain; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + delete m_ResidentBrains[player]; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: MigrateToModule -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this an original Preset in a different module than it was before. -// It severs ties deeply to the old module it was saved in. + for (int set = PLACEONLOAD; set < PLACEDSETSCOUNT; ++set) { + for (std::list::iterator oItr = m_PlacedObjects[set].begin(); oItr != m_PlacedObjects[set].end(); ++oItr) { + delete (*oItr); + *oItr = 0; + } + } -bool Scene::MigrateToModule(int whichModule) -{ - if (!Entity::MigrateToModule(whichModule)) - return false; + for (std::list::iterator slItr = m_BackLayerList.begin(); slItr != m_BackLayerList.end(); ++slItr) { + delete (*slItr); + *slItr = 0; + } - m_pTerrain->MigrateToModule(whichModule); + for (std::list::iterator slItr = m_Deployments.begin(); slItr != m_Deployments.end(); ++slItr) { + delete (*slItr); + *slItr = 0; + } - return true; -} + delete m_apUnseenLayer[Activity::TeamOne]; + delete m_apUnseenLayer[Activity::TeamTwo]; + delete m_apUnseenLayer[Activity::TeamThree]; + delete m_apUnseenLayer[Activity::TeamFour]; + // if (m_PreviewBitmapOwned) + destroy_bitmap(m_pPreviewBitmap); + m_pPreviewBitmap = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FillUnseenLayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a new SceneLayer for a specific team and fills it with black -// pixels that end up being a specific size on the screen. - -void Scene::FillUnseenLayer(Vector pixelSize, int team, bool createNow) -{ - if (team == Activity::NoTeam || !(pixelSize.m_X >= 1.0 && pixelSize.m_Y >= 1.0)) - return; - - m_UnseenPixelSize[team] = pixelSize; - - // Dynamically create the unseen layer - // Create the bitmap to make the unseen scene layer out of - if (createNow) - { - BITMAP *pUnseenBitmap = create_bitmap_ex(8, GetWidth() / m_UnseenPixelSize[team].m_X, GetHeight() / m_UnseenPixelSize[team].m_Y); - clear_to_color(pUnseenBitmap, g_BlackColor); - // Replace any old unseen layer with the new one that is generated - delete m_apUnseenLayer[team]; - m_apUnseenLayer[team] = new SceneLayer(); - m_apUnseenLayer[team]->Create(pUnseenBitmap, true, Vector(), WrapsX(), WrapsY(), Vector(1.0, 1.0)); - // Calculate how many times smaller the unseen map is compared to the entire terrain's dimensions, and set it as the scale factor on the Unseen layer - m_apUnseenLayer[team]->SetScaleFactor(Vector((float)GetTerrain()->GetBitmap()->w / (float)m_apUnseenLayer[team]->GetBitmap()->w, (float)GetTerrain()->GetBitmap()->h / (float)m_apUnseenLayer[team]->GetBitmap()->h)); - } -} + if (!notInherited) + Entity::Destroy(); + Clear(); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: MigrateToModule + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this an original Preset in a different module than it was before. + // It severs ties deeply to the old module it was saved in. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetUnseenLayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the unseen layer of a specific team. + bool Scene::MigrateToModule(int whichModule) { + if (!Entity::MigrateToModule(whichModule)) + return false; -void Scene::SetUnseenLayer(SceneLayer *pNewLayer, int team) -{ - if (team == Activity::NoTeam || !pNewLayer) - return; + m_pTerrain->MigrateToModule(whichModule); - // Replace any old unseen layer with the new one that is generated - delete m_apUnseenLayer[team]; - m_apUnseenLayer[team] = pNewLayer; - // Calculate how many times smaller the unseen map is compared to the entire terrain's dimensions, and set it as the scale factor on the Unseen layer - m_apUnseenLayer[team]->SetScaleFactor(Vector((float)GetTerrain()->GetBitmap()->w / (float)m_apUnseenLayer[team]->GetBitmap()->w, (float)GetTerrain()->GetBitmap()->h / (float)m_apUnseenLayer[team]->GetBitmap()->h)); -} + return true; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FillUnseenLayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a new SceneLayer for a specific team and fills it with black + // pixels that end up being a specific size on the screen. + + void Scene::FillUnseenLayer(Vector pixelSize, int team, bool createNow) { + if (team == Activity::NoTeam || !(pixelSize.m_X >= 1.0 && pixelSize.m_Y >= 1.0)) + return; + + m_UnseenPixelSize[team] = pixelSize; + + // Dynamically create the unseen layer + // Create the bitmap to make the unseen scene layer out of + if (createNow) { + BITMAP* pUnseenBitmap = create_bitmap_ex(8, GetWidth() / m_UnseenPixelSize[team].m_X, GetHeight() / m_UnseenPixelSize[team].m_Y); + clear_to_color(pUnseenBitmap, g_BlackColor); + // Replace any old unseen layer with the new one that is generated + delete m_apUnseenLayer[team]; + m_apUnseenLayer[team] = new SceneLayer(); + m_apUnseenLayer[team]->Create(pUnseenBitmap, true, Vector(), WrapsX(), WrapsY(), Vector(1.0, 1.0)); + // Calculate how many times smaller the unseen map is compared to the entire terrain's dimensions, and set it as the scale factor on the Unseen layer + m_apUnseenLayer[team]->SetScaleFactor(Vector((float)GetTerrain()->GetBitmap()->w / (float)m_apUnseenLayer[team]->GetBitmap()->w, (float)GetTerrain()->GetBitmap()->h / (float)m_apUnseenLayer[team]->GetBitmap()->h)); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearSeenPixels -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the pixels that have been seen on a team's unseen layer. - -void Scene::ClearSeenPixels(int team) -{ - if (team != Activity::NoTeam) - { - // Clear all the pixels off the map, set them to key color - if (m_apUnseenLayer[team]) - { - for (std::list::iterator itr = m_SeenPixels[team].begin(); itr != m_SeenPixels[team].end(); ++itr) - { - putpixel(m_apUnseenLayer[team]->GetBitmap(), (*itr).m_X, (*itr).m_Y, g_MaskColor); - - // Clean up around the removed pixels too - CleanOrphanPixel((*itr).m_X + 1, (*itr).m_Y, W, team); - CleanOrphanPixel((*itr).m_X - 1, (*itr).m_Y, E, team); - CleanOrphanPixel((*itr).m_X, (*itr).m_Y + 1, N, team); - CleanOrphanPixel((*itr).m_X, (*itr).m_Y - 1, S, team); - CleanOrphanPixel((*itr).m_X + 1, (*itr).m_Y + 1, NW, team); - CleanOrphanPixel((*itr).m_X - 1, (*itr).m_Y + 1, NE, team); - CleanOrphanPixel((*itr).m_X - 1, (*itr).m_Y - 1, SE, team); - CleanOrphanPixel((*itr).m_X + 1, (*itr).m_Y - 1, SW, team); - } - } - - // Now actually clear the list too - m_SeenPixels[team].clear(); - - // Transfer all cleaned pixels from orphans to the seen pixels for next frame - for (std::list::iterator itr = m_CleanedPixels[team].begin(); itr != m_CleanedPixels[team].end(); ++itr) - m_SeenPixels[team].push_back(*itr); - - // We have moved the cleaned pixels to the seen pixels list, now clean up the list for next frame - m_CleanedPixels[team].clear(); - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetUnseenLayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the unseen layer of a specific team. + void Scene::SetUnseenLayer(SceneLayer* pNewLayer, int team) { + if (team == Activity::NoTeam || !pNewLayer) + return; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CleanOrphanPixel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks a specific unseen pixel for only having two or less unseen -// neighbors, and if so, makes it seen. - -bool Scene::CleanOrphanPixel(int posX, int posY, NeighborDirection checkingFrom, int team) -{ - if (team == Activity::NoTeam || !m_apUnseenLayer[team]) - return false; - - // Do any necessary wrapping - m_apUnseenLayer[team]->WrapPosition(posX, posY); - - // First check the actual position of the checked pixel, it may already been seen. - if (getpixel(m_apUnseenLayer[team]->GetBitmap(), posX, posY) == g_MaskColor) - return false; - - // Ok, not seen, so check surrounding pixels for 'support', ie unseen ones that will keep this also unseen - float support = 0; - int testPosX, testPosY; - if (checkingFrom != E) - { - testPosX = posX + 1; - testPosY = posY; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; - } - if (checkingFrom != W) - { - testPosX = posX - 1; - testPosY = posY; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; - } - if (checkingFrom != S) - { - testPosX = posX; - testPosY = posY + 1; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; - } - if (checkingFrom != N) - { - testPosX = posX; - testPosY = posY - 1; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; - } - if (checkingFrom != SE) - { - testPosX = posX + 1; - testPosY = posY + 1; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; - } - if (checkingFrom != SW) - { - testPosX = posX - 1; - testPosY = posY + 1; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; - } - if (checkingFrom != NW) - { - testPosX = posX - 1; - testPosY = posY - 1; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; - } - if (checkingFrom != NE) - { - testPosX = posX + 1; - testPosY = posY - 1; - m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); - support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; - } - - // Orphaned enough to remove? - if (support <= 2.5) - { - putpixel(m_apUnseenLayer[team]->GetBitmap(), posX, posY, g_MaskColor); - m_CleanedPixels[team].push_back(Vector(posX, posY)); - return true; - } - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Vector Scene::GetDimensions() const { - if (m_pTerrain) { - if (const BITMAP *terrainBitmap = m_pTerrain->GetBitmap()) { - return Vector(static_cast(terrainBitmap->w), static_cast(terrainBitmap->h)); - } - return Vector(static_cast(m_pTerrain->GetWidth()), static_cast(m_pTerrain->GetHeight())); - } - return Vector(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int Scene::GetWidth() const { - if (m_pTerrain) { - if (const BITMAP *terrainBitmap = m_pTerrain->GetBitmap()) { - return terrainBitmap->w; - } - return m_pTerrain->GetWidth(); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int Scene::GetHeight() const { - if (m_pTerrain) { - if (const BITMAP *terrainBitmap = m_pTerrain->GetBitmap()) { - return terrainBitmap->h; - } - return m_pTerrain->GetHeight(); - } - return 0; -} + // Replace any old unseen layer with the new one that is generated + delete m_apUnseenLayer[team]; + m_apUnseenLayer[team] = pNewLayer; + // Calculate how many times smaller the unseen map is compared to the entire terrain's dimensions, and set it as the scale factor on the Unseen layer + m_apUnseenLayer[team]->SetScaleFactor(Vector((float)GetTerrain()->GetBitmap()->w / (float)m_apUnseenLayer[team]->GetBitmap()->w, (float)GetTerrain()->GetBitmap()->h / (float)m_apUnseenLayer[team]->GetBitmap()->h)); + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearSeenPixels + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the pixels that have been seen on a team's unseen layer. + + void Scene::ClearSeenPixels(int team) { + if (team != Activity::NoTeam) { + // Clear all the pixels off the map, set them to key color + if (m_apUnseenLayer[team]) { + for (std::list::iterator itr = m_SeenPixels[team].begin(); itr != m_SeenPixels[team].end(); ++itr) { + putpixel(m_apUnseenLayer[team]->GetBitmap(), (*itr).m_X, (*itr).m_Y, g_MaskColor); + + // Clean up around the removed pixels too + CleanOrphanPixel((*itr).m_X + 1, (*itr).m_Y, W, team); + CleanOrphanPixel((*itr).m_X - 1, (*itr).m_Y, E, team); + CleanOrphanPixel((*itr).m_X, (*itr).m_Y + 1, N, team); + CleanOrphanPixel((*itr).m_X, (*itr).m_Y - 1, S, team); + CleanOrphanPixel((*itr).m_X + 1, (*itr).m_Y + 1, NW, team); + CleanOrphanPixel((*itr).m_X - 1, (*itr).m_Y + 1, NE, team); + CleanOrphanPixel((*itr).m_X - 1, (*itr).m_Y - 1, SE, team); + CleanOrphanPixel((*itr).m_X + 1, (*itr).m_Y - 1, SW, team); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapsX -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the scene wraps its scrolling around the X axis. + // Now actually clear the list too + m_SeenPixels[team].clear(); -bool Scene::WrapsX() const { return m_pTerrain ? m_pTerrain->WrapsX() : false; } + // Transfer all cleaned pixels from orphans to the seen pixels for next frame + for (std::list::iterator itr = m_CleanedPixels[team].begin(); itr != m_CleanedPixels[team].end(); ++itr) + m_SeenPixels[team].push_back(*itr); + // We have moved the cleaned pixels to the seen pixels list, now clean up the list for next frame + m_CleanedPixels[team].clear(); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapsY -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the scene wraps its scrolling around the Y axis. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CleanOrphanPixel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks a specific unseen pixel for only having two or less unseen + // neighbors, and if so, makes it seen. + + bool Scene::CleanOrphanPixel(int posX, int posY, NeighborDirection checkingFrom, int team) { + if (team == Activity::NoTeam || !m_apUnseenLayer[team]) + return false; + + // Do any necessary wrapping + m_apUnseenLayer[team]->WrapPosition(posX, posY); + + // First check the actual position of the checked pixel, it may already been seen. + if (getpixel(m_apUnseenLayer[team]->GetBitmap(), posX, posY) == g_MaskColor) + return false; + + // Ok, not seen, so check surrounding pixels for 'support', ie unseen ones that will keep this also unseen + float support = 0; + int testPosX, testPosY; + if (checkingFrom != E) { + testPosX = posX + 1; + testPosY = posY; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; + } + if (checkingFrom != W) { + testPosX = posX - 1; + testPosY = posY; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; + } + if (checkingFrom != S) { + testPosX = posX; + testPosY = posY + 1; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; + } + if (checkingFrom != N) { + testPosX = posX; + testPosY = posY - 1; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 1 : 0; + } + if (checkingFrom != SE) { + testPosX = posX + 1; + testPosY = posY + 1; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; + } + if (checkingFrom != SW) { + testPosX = posX - 1; + testPosY = posY + 1; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; + } + if (checkingFrom != NW) { + testPosX = posX - 1; + testPosY = posY - 1; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; + } + if (checkingFrom != NE) { + testPosX = posX + 1; + testPosY = posY - 1; + m_apUnseenLayer[team]->WrapPosition(testPosX, testPosY); + support += getpixel(m_apUnseenLayer[team]->GetBitmap(), testPosX, testPosY) != g_MaskColor ? 0.5f : 0; + } -bool Scene::WrapsY() const { return m_pTerrain ? m_pTerrain->WrapsY() : false; } + // Orphaned enough to remove? + if (support <= 2.5) { + putpixel(m_apUnseenLayer[team]->GetBitmap(), posX, posY, g_MaskColor); + m_CleanedPixels[team].push_back(Vector(posX, posY)); + return true; + } + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PlaceResidentBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Places the individual brain of a single player which may be stationed -// on this Scene, and registers them as such in an Activity. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool Scene::PlaceResidentBrain(int player, Activity &newActivity) -{ - if (m_ResidentBrains[player]) - { -#ifdef DEBUG_BUILD - RTEAssert(m_ResidentBrains[player]->GetTeam() == newActivity.GetTeamOfPlayer(player), "Resident Brain is of the wrong team!!"); -#endif + Vector Scene::GetDimensions() const { + if (m_pTerrain) { + if (const BITMAP* terrainBitmap = m_pTerrain->GetBitmap()) { + return Vector(static_cast(terrainBitmap->w), static_cast(terrainBitmap->h)); + } + return Vector(static_cast(m_pTerrain->GetWidth()), static_cast(m_pTerrain->GetHeight())); + } + return Vector(); + } - Actor *pBrainActor = dynamic_cast(m_ResidentBrains[player]); - if (pBrainActor)// && pBrainActor->IsActor()) - { - // Set the team before adding it to the MovableMan - pBrainActor->SetTeam(newActivity.GetTeamOfPlayer(player)); - // Passing in ownership of the brain here - g_MovableMan.AddActor(pBrainActor); - // Register it with the Activity too - newActivity.SetPlayerBrain(pBrainActor, player); - // Clear the resident brain slot.. it may be set again at the end of the game, if this fella survives - m_ResidentBrains[player] = 0; - return true; - } -// TODO: Handle brains being inside other things as residents?? - } - - return false; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int Scene::GetWidth() const { + if (m_pTerrain) { + if (const BITMAP* terrainBitmap = m_pTerrain->GetBitmap()) { + return terrainBitmap->w; + } + return m_pTerrain->GetWidth(); + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PlaceResidentBrains -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Places the individual brains of the various players which may be -// stationed on this Scene, and registers them as such in an Activity. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int Scene::PlaceResidentBrains(Activity &newActivity) -{ - int found = 0; + int Scene::GetHeight() const { + if (m_pTerrain) { + if (const BITMAP* terrainBitmap = m_pTerrain->GetBitmap()) { + return terrainBitmap->h; + } + return m_pTerrain->GetHeight(); + } + return 0; + } - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (PlaceResidentBrain(player, newActivity)) - ++found; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapsX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the scene wraps its scrolling around the X axis. - return found; -} + bool Scene::WrapsX() const { return m_pTerrain ? m_pTerrain->WrapsX() : false; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapsY + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the scene wraps its scrolling around the Y axis. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RetrieveResidentBrains -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Looks at the Activity and its players' registered brain Actors, and -// saves them as resident brains for this Scene. Done when a fight is over -// and the survivors remain! + bool Scene::WrapsY() const { return m_pTerrain ? m_pTerrain->WrapsY() : false; } -int Scene::RetrieveResidentBrains(Activity &oldActivity) -{ - int found = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PlaceResidentBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Places the individual brain of a single player which may be stationed + // on this Scene, and registers them as such in an Activity. - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { -// RTEAssert(oldActivity.GetPlayerBrain(player) && oldActivity.GetPlayerBrain(player)->GetTeam() == oldActivity.GetTeamOfPlayer(player), "Resident Brain is of the wrong team BEFORE being retrieved!!"); + bool Scene::PlaceResidentBrain(int player, Activity& newActivity) { + if (m_ResidentBrains[player]) { +#ifdef DEBUG_BUILD + RTEAssert(m_ResidentBrains[player]->GetTeam() == newActivity.GetTeamOfPlayer(player), "Resident Brain is of the wrong team!!"); +#endif - // Replace existing brain residencies - delete m_ResidentBrains[player]; - // Slurp up any brains and save em, transferring ownership when we release below - m_ResidentBrains[player] = oldActivity.GetPlayerBrain(player); - // Nullify the Activity brain - oldActivity.SetPlayerBrain(0, player); - // Try to find and remove the activity's brain actors in the MO pools, releasing ownership - if (g_MovableMan.RemoveActor(dynamic_cast(m_ResidentBrains[player]))) - ++found; - // If failed to find, then we didn't retrieve it - else - m_ResidentBrains[player] = 0; + Actor* pBrainActor = dynamic_cast(m_ResidentBrains[player]); + if (pBrainActor) // && pBrainActor->IsActor()) + { + // Set the team before adding it to the MovableMan + pBrainActor->SetTeam(newActivity.GetTeamOfPlayer(player)); + // Passing in ownership of the brain here + g_MovableMan.AddActor(pBrainActor); + // Register it with the Activity too + newActivity.SetPlayerBrain(pBrainActor, player); + // Clear the resident brain slot.. it may be set again at the end of the game, if this fella survives + m_ResidentBrains[player] = 0; + return true; + } + // TODO: Handle brains being inside other things as residents?? + } -// RTEAssert(m_ResidentBrains[player] && m_ResidentBrains[player]->GetTeam() == oldActivity.GetTeamOfPlayer(player), "Resident Brain is of the wrong team AFTER being retrieved!!"); - } + return false; + } - return found; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PlaceResidentBrains + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Places the individual brains of the various players which may be + // stationed on this Scene, and registers them as such in an Activity. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int Scene::PlaceResidentBrains(Activity& newActivity) { + int found = 0; -int Scene::RetrieveSceneObjects(bool transferOwnership, int onlyTeam, bool noBrains) { - int found = 0; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (PlaceResidentBrain(player, newActivity)) + ++found; + } - found += g_MovableMan.GetAllActors(transferOwnership, m_PlacedObjects[PlacedObjectSets::PLACEONLOAD], onlyTeam, noBrains); - found += g_MovableMan.GetAllItems(transferOwnership, m_PlacedObjects[PlacedObjectSets::PLACEONLOAD]); - found += g_MovableMan.GetAllParticles(transferOwnership, m_PlacedObjects[PlacedObjectSets::PLACEONLOAD]); + return found; + } - return found; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RetrieveResidentBrains + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Looks at the Activity and its players' registered brain Actors, and + // saves them as resident brains for this Scene. Done when a fight is over + // and the survivors remain! + + int Scene::RetrieveResidentBrains(Activity& oldActivity) { + int found = 0; + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + // RTEAssert(oldActivity.GetPlayerBrain(player) && oldActivity.GetPlayerBrain(player)->GetTeam() == oldActivity.GetTeamOfPlayer(player), "Resident Brain is of the wrong team BEFORE being retrieved!!"); + + // Replace existing brain residencies + delete m_ResidentBrains[player]; + // Slurp up any brains and save em, transferring ownership when we release below + m_ResidentBrains[player] = oldActivity.GetPlayerBrain(player); + // Nullify the Activity brain + oldActivity.SetPlayerBrain(0, player); + // Try to find and remove the activity's brain actors in the MO pools, releasing ownership + if (g_MovableMan.RemoveActor(dynamic_cast(m_ResidentBrains[player]))) + ++found; + // If failed to find, then we didn't retrieve it + else + m_ResidentBrains[player] = 0; + + // RTEAssert(m_ResidentBrains[player] && m_ResidentBrains[player]->GetTeam() == oldActivity.GetTeamOfPlayer(player), "Resident Brain is of the wrong team AFTER being retrieved!!"); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return found; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a SceneObject to be placed in this scene. Ownership IS transferred! + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void Scene::AddPlacedObject(int whichSet, SceneObject *pObjectToAdd, int listOrder) -{ - if (!pObjectToAdd) - return; + int Scene::RetrieveSceneObjects(bool transferOwnership, int onlyTeam, bool noBrains) { + int found = 0; - // Create unique ID for this deployment - Deployment * pDeployment = dynamic_cast(pObjectToAdd); - if (pDeployment) - pDeployment->NewID(); + found += g_MovableMan.GetAllActors(transferOwnership, m_PlacedObjects[PlacedObjectSets::PLACEONLOAD], onlyTeam, noBrains); + found += g_MovableMan.GetAllItems(transferOwnership, m_PlacedObjects[PlacedObjectSets::PLACEONLOAD]); + found += g_MovableMan.GetAllParticles(transferOwnership, m_PlacedObjects[PlacedObjectSets::PLACEONLOAD]); - if (listOrder < 0 || listOrder >= m_PlacedObjects[whichSet].size()) - m_PlacedObjects[whichSet].push_back(pObjectToAdd); - else - { - // Find the spot - std::list::iterator itr = m_PlacedObjects[whichSet].begin(); - for (int i = 0; i != listOrder && itr != m_PlacedObjects[whichSet].end(); ++i, ++itr) - ; + return found; + } - // Put 'er in - m_PlacedObjects[whichSet].insert(itr, pObjectToAdd); - } -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a SceneObject to be placed in this scene. Ownership IS transferred! -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemovePlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a SceneObject placed in this scene. - -void Scene::RemovePlacedObject(int whichSet, int whichToRemove) -{ - if (m_PlacedObjects[whichSet].empty()) - return; - - if (whichToRemove < 0 || whichToRemove >= m_PlacedObjects[whichSet].size()) - { - delete (m_PlacedObjects[whichSet].back()); - m_PlacedObjects[whichSet].pop_back(); - } - else - { - // Find the spot - std::list::iterator itr = m_PlacedObjects[whichSet].begin(); - for (int i = 0; i != whichToRemove && itr != m_PlacedObjects[whichSet].end(); ++i, ++itr) - ; - - delete (*itr); - m_PlacedObjects[whichSet].erase(itr); - } -} + void Scene::AddPlacedObject(int whichSet, SceneObject* pObjectToAdd, int listOrder) { + if (!pObjectToAdd) + return; + // Create unique ID for this deployment + Deployment* pDeployment = dynamic_cast(pObjectToAdd); + if (pDeployment) + pDeployment->NewID(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PickPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the last placed object that graphically overlaps an absolute -// point in the scene. - -const SceneObject * Scene::PickPlacedObject(int whichSet, Vector &scenePoint, int *pListOrderPlace) const -{ - // REVERSE! - int i = m_PlacedObjects[whichSet].size() - 1; - for (std::list::const_reverse_iterator itr = m_PlacedObjects[whichSet].rbegin(); itr != m_PlacedObjects[whichSet].rend(); ++itr, --i) - { - if ((*itr)->IsOnScenePoint(scenePoint)) - { - if (pListOrderPlace) - *pListOrderPlace = i; - return *itr; - } - } - - if (pListOrderPlace) - *pListOrderPlace = -1; - return 0; -} + if (listOrder < 0 || listOrder >= m_PlacedObjects[whichSet].size()) + m_PlacedObjects[whichSet].push_back(pObjectToAdd); + else { + // Find the spot + std::list::iterator itr = m_PlacedObjects[whichSet].begin(); + for (int i = 0; i != listOrder && itr != m_PlacedObjects[whichSet].end(); ++i, ++itr) + ; + // Put 'er in + m_PlacedObjects[whichSet].insert(itr, pObjectToAdd); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PickPlacedActorInRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the last placed actor object that is closer than range to scenePoint -// -// Arguments: Which set of placed objects to pick from. See the PlacedObjectSets enum. -// The point in absolute scene coordinates that will be used to pick the -// closest placed SceneObject near it. -// The range to check for nearby objects. -// An int which will be filled out with the order place of any found object -// in the list. if nothing is found, it will get a value of -1. -// -// Return value: The closest actor SceneObject, if any. Ownership is NOT transferred! - -const SceneObject * Scene::PickPlacedActorInRange(int whichSet, Vector &scenePoint, int range, int *pListOrderPlace) const -{ - SceneObject * pFoundObject = 0; - float sqrDistance = static_cast(range * range); - - // REVERSE! - int i = m_PlacedObjects[whichSet].size() - 1; - for (std::list::const_reverse_iterator itr = m_PlacedObjects[whichSet].rbegin(); itr != m_PlacedObjects[whichSet].rend(); ++itr, --i) - { - if (dynamic_cast(*itr)) - { - float sqrCheckDistance = g_SceneMan.ShortestDistance((*itr)->GetPos(), scenePoint, true).GetSqrMagnitude(); - if (sqrCheckDistance < sqrDistance) - { + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemovePlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a SceneObject placed in this scene. + + void Scene::RemovePlacedObject(int whichSet, int whichToRemove) { + if (m_PlacedObjects[whichSet].empty()) + return; + + if (whichToRemove < 0 || whichToRemove >= m_PlacedObjects[whichSet].size()) { + delete (m_PlacedObjects[whichSet].back()); + m_PlacedObjects[whichSet].pop_back(); + } else { + // Find the spot + std::list::iterator itr = m_PlacedObjects[whichSet].begin(); + for (int i = 0; i != whichToRemove && itr != m_PlacedObjects[whichSet].end(); ++i, ++itr) + ; + + delete (*itr); + m_PlacedObjects[whichSet].erase(itr); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PickPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the last placed object that graphically overlaps an absolute + // point in the scene. + + const SceneObject* Scene::PickPlacedObject(int whichSet, Vector& scenePoint, int* pListOrderPlace) const { + // REVERSE! + int i = m_PlacedObjects[whichSet].size() - 1; + for (std::list::const_reverse_iterator itr = m_PlacedObjects[whichSet].rbegin(); itr != m_PlacedObjects[whichSet].rend(); ++itr, --i) { + if ((*itr)->IsOnScenePoint(scenePoint)) { if (pListOrderPlace) *pListOrderPlace = i; - sqrDistance = sqrCheckDistance; - pFoundObject = *itr; + return *itr; } } - } - if (pFoundObject) - return pFoundObject; + if (pListOrderPlace) + *pListOrderPlace = -1; + return 0; + } - if (pListOrderPlace) - *pListOrderPlace = -1; - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PickPlacedActorInRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the last placed actor object that is closer than range to scenePoint + // + // Arguments: Which set of placed objects to pick from. See the PlacedObjectSets enum. + // The point in absolute scene coordinates that will be used to pick the + // closest placed SceneObject near it. + // The range to check for nearby objects. + // An int which will be filled out with the order place of any found object + // in the list. if nothing is found, it will get a value of -1. + // + // Return value: The closest actor SceneObject, if any. Ownership is NOT transferred! + + const SceneObject* Scene::PickPlacedActorInRange(int whichSet, Vector& scenePoint, int range, int* pListOrderPlace) const { + SceneObject* pFoundObject = 0; + float sqrDistance = static_cast(range * range); + + // REVERSE! + int i = m_PlacedObjects[whichSet].size() - 1; + for (std::list::const_reverse_iterator itr = m_PlacedObjects[whichSet].rbegin(); itr != m_PlacedObjects[whichSet].rend(); ++itr, --i) { + if (dynamic_cast(*itr)) { + float sqrCheckDistance = g_SceneMan.ShortestDistance((*itr)->GetPos(), scenePoint, true).GetSqrMagnitude(); + if (sqrCheckDistance < sqrDistance) { + if (pListOrderPlace) + *pListOrderPlace = i; + sqrDistance = sqrCheckDistance; + pFoundObject = *itr; + } + } + } + if (pFoundObject) + return pFoundObject; + if (pListOrderPlace) + *pListOrderPlace = -1; + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePlacedObjects -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updated the objects in the placed scene objects list of this. This is -// mostly for the editor to represent the items correctly. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePlacedObjects + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updated the objects in the placed scene objects list of this. This is + // mostly for the editor to represent the items correctly. + + void Scene::UpdatePlacedObjects(int whichSet) { + if (whichSet == PLACEONLOAD) { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) + if (m_ResidentBrains[player]) + m_ResidentBrains[player]->FullUpdate(); + } -void Scene::UpdatePlacedObjects(int whichSet) -{ - if (whichSet == PLACEONLOAD) - { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - if (m_ResidentBrains[player]) - m_ResidentBrains[player]->FullUpdate(); - } + for (std::list::iterator itr = m_PlacedObjects[whichSet].begin(); itr != m_PlacedObjects[whichSet].end(); ++itr) { + (*itr)->FullUpdate(); + } + } - for (std::list::iterator itr = m_PlacedObjects[whichSet].begin(); itr != m_PlacedObjects[whichSet].end(); ++itr) - { - (*itr)->FullUpdate(); - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearPlacedObjectSet + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes all entries in a specific set of placed Objects. + int Scene::ClearPlacedObjectSet(int whichSet, bool weHaveOwnership) { + if (weHaveOwnership) { + for (std::list::iterator itr = m_PlacedObjects[whichSet].begin(); itr != m_PlacedObjects[whichSet].end(); ++itr) { + delete *itr; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearPlacedObjectSet -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes all entries in a specific set of placed Objects. + int count = m_PlacedObjects[whichSet].size(); + m_PlacedObjects[whichSet].clear(); + return count; + } -int Scene::ClearPlacedObjectSet(int whichSet, bool weHaveOwnership) -{ - if (weHaveOwnership) { - for (std::list::iterator itr = m_PlacedObjects[whichSet].begin(); itr != m_PlacedObjects[whichSet].end(); ++itr) { - delete *itr; - } - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetResidentBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the resident brain Actor of a specific player from this scene, + // if there is any. OWNERSHIP IS NOT TRANSFERRED! - int count = m_PlacedObjects[whichSet].size(); - m_PlacedObjects[whichSet].clear(); - return count; -} + SceneObject* Scene::GetResidentBrain(int player) const { + // if (m_ResidentBrains[player]) + return m_ResidentBrains[player]; + // for (std::list::iterator itr = m_PlacedObjects[PLACEONLOAD].begin(); itr != m_PlacedObjects[PLACEONLOAD].end(); ++itr) + // { + // (*itr)->teamUpdate(); + // } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetResidentBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the resident brain Actor of a specific player from this scene, -// if there is any. OWNERSHIP IS NOT TRANSFERRED! + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetResidentBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the resident brain Actor of a specific player from this scene, + // if there is any. Ownership IS transferred! -SceneObject * Scene::GetResidentBrain(int player) const -{ -// if (m_ResidentBrains[player]) - return m_ResidentBrains[player]; + void Scene::SetResidentBrain(int player, SceneObject* pNewBrain) { + if (MovableObject* asMo = dynamic_cast(m_ResidentBrains[player])) { + asMo->DestroyScriptState(); + } + delete m_ResidentBrains[player]; + m_ResidentBrains[player] = pNewBrain; + } -// for (std::list::iterator itr = m_PlacedObjects[PLACEONLOAD].begin(); itr != m_PlacedObjects[PLACEONLOAD].end(); ++itr) -// { -// (*itr)->teamUpdate(); -// } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetResidentBrainCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of brains currently residing in this scene. + int Scene::GetResidentBrainCount() const { + int count = 0; + for (int p = Players::PlayerOne; p < Players::MaxPlayerCount; ++p) { + if (m_ResidentBrains[p]) + count++; + } + return count; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetResidentBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the resident brain Actor of a specific player from this scene, -// if there is any. Ownership IS transferred! + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds or modifies an existing area of this Scene. + + bool Scene::SetArea(Area& newArea) { + for (std::list::iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) { + // Try to find an existing area of the same name + if ((*aItr).GetName() == newArea.GetName()) { + // Deep copy into the existing area + (*aItr).Reset(); + (*aItr).Create(newArea); + return true; + } + } + // Couldn't find one, so just add the new Area + m_AreaList.push_back(newArea); -void Scene::SetResidentBrain(int player, SceneObject *pNewBrain) -{ - if (MovableObject* asMo = dynamic_cast(m_ResidentBrains[player])) { - asMo->DestroyScriptState(); - } - delete m_ResidentBrains[player]; - m_ResidentBrains[player] = pNewBrain; -} + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks for the existence of a specific Area identified by a name. + // This won't throw any errors to the console if the Area isn't found. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetResidentBrainCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of brains currently residing in this scene. + bool Scene::HasArea(std::string areaName) { + for (std::list::iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) { + if ((*aItr).GetName() == areaName) + return true; + } + return false; + } -int Scene::GetResidentBrainCount() const -{ - int count = 0; - for (int p = Players::PlayerOne; p < Players::MaxPlayerCount; ++p) - { - if (m_ResidentBrains[p]) - count++; - } - return count; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a specific area box identified by a name. Ownership is NOT transferred! + Scene::Area* Scene::GetArea(const std::string_view& areaName, bool required) { + for (Scene::Area& area: m_AreaList) { + if (area.GetName() == areaName) { + return &area; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds or modifies an existing area of this Scene. - -bool Scene::SetArea(Area &newArea) -{ - for (std::list::iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) - { - // Try to find an existing area of the same name - if ((*aItr).GetName() == newArea.GetName()) - { - // Deep copy into the existing area - (*aItr).Reset(); - (*aItr).Create(newArea); - return true; - } - } - // Couldn't find one, so just add the new Area - m_AreaList.push_back(newArea); - - return false; -} + if (required) { + g_ConsoleMan.PrintString("WARNING: Could not find the requested Scene Area named : " + std::string(areaName)); + } + return nullptr; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks for the existence of a specific Area identified by a name. -// This won't throw any errors to the console if the Area isn't found. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a specific Area identified by a name. -bool Scene::HasArea(std::string areaName) -{ - for (std::list::iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) - { - if ((*aItr).GetName() == areaName) - return true; - } - return false; -} + bool Scene::RemoveArea(std::string areaName) { + for (std::list::iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) { + if ((*aItr).GetName() == areaName) { + m_AreaList.erase(aItr); + return true; + } + } + return false; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WithinArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if a point is within a specific named Area of this Scene. If + // no Area of the name is found, this just returns false without error. + // Arguments: The name of the Area to try to check against. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a specific area box identified by a name. Ownership is NOT transferred! + bool Scene::WithinArea(std::string areaName, const Vector& point) const { + if (areaName.empty()) + return false; -Scene::Area * Scene::GetArea(const std::string_view &areaName, bool required) { - for (Scene::Area &area : m_AreaList) { - if (area.GetName() == areaName) { - return &area; + for (std::list::const_iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) { + if ((*aItr).GetName() == areaName && (*aItr).IsInside(point)) + return true; } - } - if (required) { - g_ConsoleMan.PrintString("WARNING: Could not find the requested Scene Area named : " + std::string(areaName)); - } + return false; + } - return nullptr; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTeamOwnership + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the team who owns this Scene in a Metagame + void Scene::SetTeamOwnership(int newTeam) { + m_OwnedByTeam = newTeam; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a specific Area identified by a name. - -bool Scene::RemoveArea(std::string areaName) -{ - for (std::list::iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) - { - if ((*aItr).GetName() == areaName) - { - m_AreaList.erase(aItr); - return true; - } - } - return false; -} + // Go through all the things placed and make sure they are all set to the new owner team + for (int set = PLACEONLOAD; set <= AIPLAN; ++set) { + for (std::list::const_iterator bpItr = m_PlacedObjects[set].begin(); bpItr != m_PlacedObjects[set].end(); ++bpItr) { + if (*bpItr) + (*bpItr)->SetTeam(m_OwnedByTeam); + } + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalcBuildBudgetUse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Figure out exactly how much of the build budget would be used if + // as many blueprint objects as can be afforded and exists would be built. + + float Scene::CalcBuildBudgetUse(int player, int* pAffordCount, int* pAffordAIPlanCount) const { + if (pAffordCount) + *pAffordCount = 0; + + if (player < Players::PlayerOne || player >= Players::MaxPlayerCount) + return 0; + + // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WithinArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if a point is within a specific named Area of this Scene. If -// no Area of the name is found, this just returns false without error. -// Arguments: The name of the Area to try to check against. + // Go through the list of blueprint objects and move as many as can be afforded by the budget to the list that is placed on next scene load + int objCount = 0; + float fundsAfforded = 0; + float budget = m_BuildBudget[player]; + float objectCost = 0; + Deployment* pDeployment = 0; + SceneObject* pObjectToPlace = 0; + // The last resident brain that is encountered in the building list, starting with the preexisting resident brain. Not owned here + SceneObject* pLastBrain = m_ResidentBrains[player]; + // The total list of objects that WILL be placed as the building phase goes on for real - nothing is owned by this! + std::list virtualPlacedList; + // Add all the already placed objects int he scene to it; then we'll add the objects that would be placed this round - ownership is NOT passed + for (std::list::const_iterator placedItr = m_PlacedObjects[PLACEONLOAD].begin(); placedItr != m_PlacedObjects[PLACEONLOAD].end(); ++placedItr) + virtualPlacedList.push_back(*placedItr); + + // First go through the blueprints that are already placed, THEN go through the AI plan objects if we are specified to + for (int set = BLUEPRINT; set <= AIPLAN; ++set) { + // Skip the AI plan set if we're not asked to consider it + if (set == AIPLAN && !pAffordAIPlanCount) + continue; -bool Scene::WithinArea(std::string areaName, const Vector &point) const -{ - if (areaName.empty()) - return false; + // Two passes, one for only things placed by this player, second to see if we can still afford any placed by teammates + for (int pass = 0; pass < 2; ++pass) { + for (std::list::const_iterator bpItr = m_PlacedObjects[set].begin(); bpItr != m_PlacedObjects[set].end(); ++bpItr) { + // Skip objects on the first pass that aren't placed by this player + // Skip objects on the second pass that WERE placed by this player.. because we already counted them + if ((pass == 0 && (*bpItr)->GetPlacedByPlayer() != player) || + (pass == 1 && (*bpItr)->GetPlacedByPlayer() == player)) + continue; + + // If Deployment, we need to check if we're going to be spawning something this building round or not + pDeployment = dynamic_cast(*bpItr); + if (pDeployment) { + // Reset the object cost because the creating of the Deployment spawn only adds to the passed-in tally + objectCost = 0; + // See if we can spawn an Actor from this Deployment + pObjectToPlace = pDeployment->CreateDeployedActor(player, objectCost); + // If not an Actor, at least an item? + if (!pObjectToPlace) + pObjectToPlace = pDeployment->CreateDeployedObject(player, objectCost); + + // Only place things if there isn't somehting similar of the same team within a radius + if (pObjectToPlace) { + // If there's already similar placed in the scene that is close enough to this Deployment to block it, then abort placing the new spawn! + // We're passing in the virtual list of things that already were placed before, and that have been placed up til now in this build phase + if (pDeployment->DeploymentBlocked(player, virtualPlacedList)) { + delete pObjectToPlace; + pObjectToPlace = 0; + } + } - for (std::list::const_iterator aItr = m_AreaList.begin(); aItr != m_AreaList.end(); ++aItr) - { - if ((*aItr).GetName() == areaName && (*aItr).IsInside(point)) - return true; - } + // If we didn't end up spawning anything, just continue to the next thing in the blueprint queue + if (!pObjectToPlace) + continue; + } + // Regular object, will always be bought + else { + pObjectToPlace = *bpItr; + if (pObjectToPlace) + objectCost = pObjectToPlace->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + } - return false; -} + // If this is a brain, then we will replace any previous/existing resident brain with this one, and adjust the difference in cost + if (pObjectToPlace && pObjectToPlace->IsInGroup("Brains") && pLastBrain) { + objectCost = pObjectToPlace->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult) - pLastBrain->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); + pLastBrain = pObjectToPlace; + } + // Check if the remaining budget allows for this item + if (budget >= objectCost) { + // Add it to the virtual list of things we're comparing against for spawn blockages - ownership is NOT passed + virtualPlacedList.push_back(pObjectToPlace); + fundsAfforded += objectCost; + budget -= objectCost; + objCount++; + // Count the number of AI Plan objects we can afford, if we're asked to do so + if (set == AIPLAN && pAffordAIPlanCount) + (*pAffordAIPlanCount)++; + } + // That's it, we can't afford the next item in the queue + else + break; + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTeamOwnership -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the team who owns this Scene in a Metagame + // Report the number of objects actually built + if (pAffordCount) + *pAffordCount = objCount; -void Scene::SetTeamOwnership(int newTeam) -{ - m_OwnedByTeam = newTeam; + return fundsAfforded; + } - // Go through all the things placed and make sure they are all set to the new owner team - for (int set = PLACEONLOAD; set <= AIPLAN; ++set) - { - for (std::list::const_iterator bpItr = m_PlacedObjects[set].begin(); bpItr != m_PlacedObjects[set].end(); ++bpItr) - { - if (*bpItr) - (*bpItr)->SetTeam(m_OwnedByTeam); - } - } -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyAIPlan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Puts the pre-built AI base plan into effect by transferring as many + // pieces as the current base budget allows from the AI plan to the actual + // blueprints to be built at this Scene. + + float Scene::ApplyAIPlan(int player, int* pObjectsApplied) { + if (pObjectsApplied) + *pObjectsApplied = 0; + + if (player < Players::PlayerOne || player >= Players::MaxPlayerCount) + return 0; + + // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); + } + float valueOfApplied = 0; + int totalToBuildCount = 0; + int affordAIPlanObjectsCount = 0; + // Figure out how many objects in the bluprints we can afford to build already, without adding AI plans + float bpTotalValue = CalcBuildBudgetUse(player, &totalToBuildCount, &affordAIPlanObjectsCount); + + // If we have budget enough to build everything we have in blueprints already, AND dip into AI plans, + // then we should move over as many Objects from the AI plan queue to the blueprint as we have been told we can afford + float objValue = 0; + for (int i = 0; i < affordAIPlanObjectsCount && !m_PlacedObjects[AIPLAN].empty(); ++i) { + // Get the object off the AI plan + SceneObject* pObject = m_PlacedObjects[AIPLAN].front(); + if (pObject) { + m_PlacedObjects[AIPLAN].pop_front(); + + // How much does it cost? Add it to the total blueprint tally + objValue = pObject->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); + bpTotalValue += objValue; + valueOfApplied += objValue; + + // Mark this as having been placed by this player + pObject->SetPlacedByPlayer(player); + + // Create unique ID for this deployment + Deployment* pDeployment = dynamic_cast(pObject); + if (pDeployment) + pDeployment->NewID(); + + // Now add it to the blueprint queue + m_PlacedObjects[BLUEPRINT].push_back(pObject); + + // Count it + if (pObjectsApplied) + ++(*pObjectsApplied); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalcBuildBudgetUse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Figure out exactly how much of the build budget would be used if -// as many blueprint objects as can be afforded and exists would be built. - -float Scene::CalcBuildBudgetUse(int player, int *pAffordCount, int *pAffordAIPlanCount) const -{ - if (pAffordCount) - *pAffordCount = 0; - - if (player < Players::PlayerOne || player >= Players::MaxPlayerCount) - return 0; - - // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - } - - // Go through the list of blueprint objects and move as many as can be afforded by the budget to the list that is placed on next scene load - int objCount = 0; - float fundsAfforded = 0; - float budget = m_BuildBudget[player]; - float objectCost = 0; - Deployment *pDeployment = 0; - SceneObject *pObjectToPlace = 0; - // The last resident brain that is encountered in the building list, starting with the preexisting resident brain. Not owned here - SceneObject *pLastBrain = m_ResidentBrains[player]; - // The total list of objects that WILL be placed as the building phase goes on for real - nothing is owned by this! - std::list virtualPlacedList; - // Add all the already placed objects int he scene to it; then we'll add the objects that would be placed this round - ownership is NOT passed - for (std::list::const_iterator placedItr = m_PlacedObjects[PLACEONLOAD].begin(); placedItr != m_PlacedObjects[PLACEONLOAD].end(); ++placedItr) - virtualPlacedList.push_back(*placedItr); - - // First go through the blueprints that are already placed, THEN go through the AI plan objects if we are specified to - for (int set = BLUEPRINT; set <= AIPLAN; ++set) - { - // Skip the AI plan set if we're not asked to consider it - if (set == AIPLAN && !pAffordAIPlanCount) - continue; - - // Two passes, one for only things placed by this player, second to see if we can still afford any placed by teammates - for (int pass = 0; pass < 2; ++pass) - { - for (std::list::const_iterator bpItr = m_PlacedObjects[set].begin(); bpItr != m_PlacedObjects[set].end(); ++bpItr) - { - // Skip objects on the first pass that aren't placed by this player - // Skip objects on the second pass that WERE placed by this player.. because we already counted them - if ((pass == 0 && (*bpItr)->GetPlacedByPlayer() != player) || - (pass == 1 && (*bpItr)->GetPlacedByPlayer() == player)) - continue; - - // If Deployment, we need to check if we're going to be spawning something this building round or not - pDeployment = dynamic_cast(*bpItr); - if (pDeployment) - { - // Reset the object cost because the creating of the Deployment spawn only adds to the passed-in tally - objectCost = 0; - // See if we can spawn an Actor from this Deployment - pObjectToPlace = pDeployment->CreateDeployedActor(player, objectCost); - // If not an Actor, at least an item? - if (!pObjectToPlace) - pObjectToPlace = pDeployment->CreateDeployedObject(player, objectCost); - - // Only place things if there isn't somehting similar of the same team within a radius - if (pObjectToPlace) - { - // If there's already similar placed in the scene that is close enough to this Deployment to block it, then abort placing the new spawn! - // We're passing in the virtual list of things that already were placed before, and that have been placed up til now in this build phase - if (pDeployment->DeploymentBlocked(player, virtualPlacedList)) - { - delete pObjectToPlace; - pObjectToPlace = 0; - } - } - - // If we didn't end up spawning anything, just continue to the next thing in the blueprint queue - if (!pObjectToPlace) - continue; - } - // Regular object, will always be bought - else - { - pObjectToPlace = *bpItr; - if (pObjectToPlace) - objectCost = pObjectToPlace->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); - } - - // If this is a brain, then we will replace any previous/existing resident brain with this one, and adjust the difference in cost - if (pObjectToPlace && pObjectToPlace->IsInGroup("Brains") && pLastBrain) - { - objectCost = pObjectToPlace->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult) - pLastBrain->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); - pLastBrain = pObjectToPlace; - } - - // Check if the remaining budget allows for this item - if (budget >= objectCost) - { - // Add it to the virtual list of things we're comparing against for spawn blockages - ownership is NOT passed - virtualPlacedList.push_back(pObjectToPlace); - fundsAfforded += objectCost; - budget -= objectCost; - objCount++; - // Count the number of AI Plan objects we can afford, if we're asked to do so - if (set == AIPLAN && pAffordAIPlanCount) - (*pAffordAIPlanCount)++; - } - // That's it, we can't afford the next item in the queue - else - break; - } - } - } - - // Report the number of objects actually built - if (pAffordCount) - *pAffordCount = objCount; - - return fundsAfforded; -} + return valueOfApplied; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyBuildBudget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Actually builds as many objects in the specific player's Blueprint + // list as can be afforded by his build budget. The budget is deducted + // accordingly. + + float Scene::ApplyBuildBudget(int player, int* pObjectsBuilt) { + if (pObjectsBuilt) + *pObjectsBuilt = 0; + + if (player < Players::PlayerOne || player >= Players::MaxPlayerCount) + return 0; + + // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn + int nativeModule = 0; + float foreignCostMult = 1.0; + float nativeCostMult = 1.0; + int team = Activity::NoTeam; + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + if (g_MetaMan.GameInProgress() && pMetaPlayer) { + nativeModule = pMetaPlayer->GetNativeTechModule(); + foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); + nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); + + // Also find out the team so we can apply it to the things we are building + team = pMetaPlayer->GetTeam(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyAIPlan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Puts the pre-built AI base plan into effect by transferring as many -// pieces as the current base budget allows from the AI plan to the actual -// blueprints to be built at this Scene. - -float Scene::ApplyAIPlan(int player, int *pObjectsApplied) -{ - if (pObjectsApplied) - *pObjectsApplied = 0; - - if (player < Players::PlayerOne || player >= Players::MaxPlayerCount) - return 0; - - // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - } - - float valueOfApplied = 0; - int totalToBuildCount = 0; - int affordAIPlanObjectsCount = 0; - // Figure out how many objects in the bluprints we can afford to build already, without adding AI plans - float bpTotalValue = CalcBuildBudgetUse(player, &totalToBuildCount, &affordAIPlanObjectsCount); - - // If we have budget enough to build everything we have in blueprints already, AND dip into AI plans, - // then we should move over as many Objects from the AI plan queue to the blueprint as we have been told we can afford - float objValue = 0; - for (int i = 0; i < affordAIPlanObjectsCount && !m_PlacedObjects[AIPLAN].empty(); ++i) - { - // Get the object off the AI plan - SceneObject *pObject = m_PlacedObjects[AIPLAN].front(); - if (pObject) - { - m_PlacedObjects[AIPLAN].pop_front(); - - // How much does it cost? Add it to the total blueprint tally - objValue = pObject->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); - bpTotalValue += objValue; - valueOfApplied += objValue; - - // Mark this as having been placed by this player - pObject->SetPlacedByPlayer(player); - - // Create unique ID for this deployment - Deployment * pDeployment = dynamic_cast(pObject); - if (pDeployment) - pDeployment->NewID(); - - // Now add it to the blueprint queue - m_PlacedObjects[BLUEPRINT].push_back(pObject); - - // Count it - if (pObjectsApplied) - ++(*pObjectsApplied); - } - } - - return valueOfApplied; -} + // Go through the list of blueprint objects and move as many as can be afforded by the budget to the list that is placed on next scene load + bool remove = false; + int placedCount = 0; + float fundsSpent = 0; + float objectCost = 0; + std::list::iterator bpItr; + std::list::iterator delItr; + SceneObject* pObjectToPlace = 0; + Deployment* pDeployment = 0; + // The last resident brain that is encountered in the building list, starting with the preexisting resident brain. Not owned here + SceneObject* pLastBrain = m_ResidentBrains[player]; + // Two passes, one for only things placed by this player, second to see if we can still afford any placed by teammates + for (int pass = 0; pass < 2; ++pass) { + for (bpItr = m_PlacedObjects[BLUEPRINT].begin(); bpItr != m_PlacedObjects[BLUEPRINT].end();) { + // Skip objects on the first pass that aren't placed by this player + // Skip objects on the second pass that WERE placed by this player.. because we already went through them on first pass + if ((pass == 0 && (*bpItr)->GetPlacedByPlayer() != player) || + (pass == 1 && (*bpItr)->GetPlacedByPlayer() == player)) { + // Increment since the for loop header doesn't do it + ++bpItr; + continue; + } + // If Deployment, just add the new instances of whatever we're spawning + // and LEAVE the blueprint Deployment where it is in the queue, so it can keep spitting out new stuff each buying round + pDeployment = dynamic_cast(*bpItr); + if (pDeployment) { + // Set the team + pDeployment->SetTeam(team); + // If there's already similar placed in the scene that is close enough to this Deployment to block it, then don't count it! + if (pDeployment->DeploymentBlocked(player, m_PlacedObjects[PLACEONLOAD])) { + ++bpItr; + continue; + } + // Okay there's a valid deployment happening here, so count how much it costs + else { + // Reset the object cost because the creating of the Deployment spawn only adds to the passed-in tally + objectCost = 0; + // See if we can spawn an Actor from this Deployment + pObjectToPlace = pDeployment->CreateDeployedActor(player, objectCost); + + // Assign deployment ID to placed actor + if (pObjectToPlace) { + if (!pDeployment->GetID()) + pDeployment->NewID(); + + Actor* pActor = dynamic_cast(pObjectToPlace); + if (pActor) + pActor->SetDeploymentID(pDeployment->GetID()); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyBuildBudget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Actually builds as many objects in the specific player's Blueprint -// list as can be afforded by his build budget. The budget is deducted -// accordingly. - -float Scene::ApplyBuildBudget(int player, int *pObjectsBuilt) -{ - if (pObjectsBuilt) - *pObjectsBuilt = 0; - - if (player < Players::PlayerOne || player >= Players::MaxPlayerCount) - return 0; - - // Take metaplayer tech modifiers into account when calculating costs of this Deployment spawn - int nativeModule = 0; - float foreignCostMult = 1.0; - float nativeCostMult = 1.0; - int team = Activity::NoTeam; - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - if (g_MetaMan.GameInProgress() && pMetaPlayer) - { - nativeModule = pMetaPlayer->GetNativeTechModule(); - foreignCostMult = pMetaPlayer->GetForeignCostMultiplier(); - nativeCostMult = pMetaPlayer->GetNativeCostMultiplier(); - - // Also find out the team so we can apply it to the things we are building - team = pMetaPlayer->GetTeam(); - } - - // Go through the list of blueprint objects and move as many as can be afforded by the budget to the list that is placed on next scene load - bool remove = false; - int placedCount = 0; - float fundsSpent = 0; - float objectCost = 0; - std::list::iterator bpItr; - std::list::iterator delItr; - SceneObject *pObjectToPlace = 0; - Deployment *pDeployment = 0; - // The last resident brain that is encountered in the building list, starting with the preexisting resident brain. Not owned here - SceneObject *pLastBrain = m_ResidentBrains[player]; - // Two passes, one for only things placed by this player, second to see if we can still afford any placed by teammates - for (int pass = 0; pass < 2; ++pass) - { - for (bpItr = m_PlacedObjects[BLUEPRINT].begin(); bpItr != m_PlacedObjects[BLUEPRINT].end();) - { - // Skip objects on the first pass that aren't placed by this player - // Skip objects on the second pass that WERE placed by this player.. because we already went through them on first pass - if ((pass == 0 && (*bpItr)->GetPlacedByPlayer() != player) || - (pass == 1 && (*bpItr)->GetPlacedByPlayer() == player)) - { - // Increment since the for loop header doesn't do it - ++bpItr; - continue; - } - - // If Deployment, just add the new instances of whatever we're spawning - // and LEAVE the blueprint Deployment where it is in the queue, so it can keep spitting out new stuff each buying round - pDeployment = dynamic_cast(*bpItr); - if (pDeployment) - { - // Set the team - pDeployment->SetTeam(team); - // If there's already similar placed in the scene that is close enough to this Deployment to block it, then don't count it! - if (pDeployment->DeploymentBlocked(player, m_PlacedObjects[PLACEONLOAD])) - { - ++bpItr; - continue; - } - // Okay there's a valid deployment happening here, so count how much it costs - else - { - // Reset the object cost because the creating of the Deployment spawn only adds to the passed-in tally - objectCost = 0; - // See if we can spawn an Actor from this Deployment - pObjectToPlace = pDeployment->CreateDeployedActor(player, objectCost); - - // Assign deployment ID to placed actor + // If this is a BRAIN, replace the old resident brain with this new one + if (pObjectToPlace->IsInGroup("Brains")) { + // Get a refund for the previous brain we are replacing + if (m_ResidentBrains[player]) { + float refund = m_ResidentBrains[player]->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); + m_BuildBudget[player] += refund; + fundsSpent -= refund; + delete m_ResidentBrains[player]; + } + // Deduct the cost of the new brain from the budget and tally the total + m_BuildBudget[player] -= objectCost; + fundsSpent += objectCost; + // Transfer ownership of the brain to the scene.. we are done with this object now + m_ResidentBrains[player] = pObjectToPlace; + // We are done with this since it's a special brain placement; continue to next item + pObjectToPlace = 0; + } else { + // If not an Actor, at least an item? + if (!pObjectToPlace) + pObjectToPlace = pDeployment->CreateDeployedObject(player, objectCost); + } + } + } + // A regular blueprint object which only gets placed once and then removed from blueprints + else { + pObjectToPlace = *bpItr; if (pObjectToPlace) - { - if (!pDeployment->GetID()) - pDeployment->NewID(); + // Get the cost here since a deployment spawn above already gets it + objectCost = pObjectToPlace->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); + } - Actor *pActor = dynamic_cast(pObjectToPlace); - if (pActor) - pActor->SetDeploymentID(pDeployment->GetID()); - } + // If we didn't end up spawning anything, just continue to the next thing in the blueprint queue + if (!pObjectToPlace) { + ++bpItr; + continue; + } - // If this is a BRAIN, replace the old resident brain with this new one - if (pObjectToPlace->IsInGroup("Brains")) - { - // Get a refund for the previous brain we are replacing - if (m_ResidentBrains[player]) - { - float refund = m_ResidentBrains[player]->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); - m_BuildBudget[player] += refund; - fundsSpent -= refund; - delete m_ResidentBrains[player]; - } - // Deduct the cost of the new brain from the budget and tally the total - m_BuildBudget[player] -= objectCost; - fundsSpent += objectCost; - // Transfer ownership of the brain to the scene.. we are done with this object now - m_ResidentBrains[player] = pObjectToPlace; - // We are done with this since it's a special brain placement; continue to next item - pObjectToPlace = 0; - } - else - { - // If not an Actor, at least an item? - if (!pObjectToPlace) - pObjectToPlace = pDeployment->CreateDeployedObject(player, objectCost); - } - } - } - // A regular blueprint object which only gets placed once and then removed from blueprints - else - { - pObjectToPlace = *bpItr; - if (pObjectToPlace) - // Get the cost here since a deployment spawn above already gets it - objectCost = pObjectToPlace->GetGoldValue(nativeModule, foreignCostMult, nativeCostMult); - } - - // If we didn't end up spawning anything, just continue to the next thing in the blueprint queue - if (!pObjectToPlace) - { - ++bpItr; - continue; - } - - // If this is a brain, then we will replace any previous/existing resident brain with this one, and adjust the difference in cost - if (pObjectToPlace && pObjectToPlace->IsInGroup("Brains") && pLastBrain) - { - objectCost = pObjectToPlace->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult) - pLastBrain->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); - pLastBrain = pObjectToPlace; - } - - // Check if the remaining budget allows for this thing to be placed - if (m_BuildBudget[player] >= objectCost) - { - // Deduct the cost from the budget and tally the total - m_BuildBudget[player] -= objectCost; - fundsSpent += objectCost; - // Set the team of the thing we're building - pObjectToPlace->SetTeam(team); - // Mark this as having been placed by this player - pObjectToPlace->SetPlacedByPlayer(player); - // If applicable, replace the old resident brain with this new one - if (pObjectToPlace->IsInGroup("Brains")) - { - // Get a refund for the previous brain we are replacing - if (m_ResidentBrains[player]) - { - float refund = m_ResidentBrains[player]->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); - m_BuildBudget[player] += refund; - fundsSpent -= refund; - delete m_ResidentBrains[player]; - // Don't count the 'replacing' of a brain as an item - } - // If there wasn't a brain before, then count this as a new placement - else - placedCount++; - m_ResidentBrains[player] = pObjectToPlace; - } - // Regular non-brain object; simply move it to the list of objects to place on next load, TRANSFERRING OWNERSHIP - else - { - m_PlacedObjects[PLACEONLOAD].push_back(pObjectToPlace); - // Always count regular objects placed - placedCount++; - - // Add placed object's locations as boxes to the specified 'MetaBase' area - TerrainObject * pTO = dynamic_cast(pObjectToPlace); - if (pTO) - { - if (HasArea(METABASE_AREA_NAME)) - { - Scene::Area * metaBase = GetArea(METABASE_AREA_NAME); - if (metaBase) - { - float x1 = pTO->GetPos().m_X + pTO->GetBitmapOffset().m_X; - float y1 = pTO->GetPos().m_Y + pTO->GetBitmapOffset().m_Y; - float x2 = x1 + pTO->GetBitmapWidth(); - float y2 = y1 + pTO->GetBitmapHeight(); - - metaBase->AddBox(Box(x1, y1, x2, y2)); - } + // If this is a brain, then we will replace any previous/existing resident brain with this one, and adjust the difference in cost + if (pObjectToPlace && pObjectToPlace->IsInGroup("Brains") && pLastBrain) { + objectCost = pObjectToPlace->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult) - pLastBrain->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); + pLastBrain = pObjectToPlace; + } + + // Check if the remaining budget allows for this thing to be placed + if (m_BuildBudget[player] >= objectCost) { + // Deduct the cost from the budget and tally the total + m_BuildBudget[player] -= objectCost; + fundsSpent += objectCost; + // Set the team of the thing we're building + pObjectToPlace->SetTeam(team); + // Mark this as having been placed by this player + pObjectToPlace->SetPlacedByPlayer(player); + // If applicable, replace the old resident brain with this new one + if (pObjectToPlace->IsInGroup("Brains")) { + // Get a refund for the previous brain we are replacing + if (m_ResidentBrains[player]) { + float refund = m_ResidentBrains[player]->GetTotalValue(nativeModule, foreignCostMult, nativeCostMult); + m_BuildBudget[player] += refund; + fundsSpent -= refund; + delete m_ResidentBrains[player]; + // Don't count the 'replacing' of a brain as an item } + // If there wasn't a brain before, then count this as a new placement + else + placedCount++; + m_ResidentBrains[player] = pObjectToPlace; } - } - - // Save the iterator so we can remove its entry after we increment - delItr = bpItr; - // Don't remove Deployment blueprints; they remain in the blueprints and re-spawn their Loadouts each building round - remove = pDeployment ? false : true; - } - // Ok we can't afford any more stuff in the queue - else - break; - - // Increment to next placed object - ++bpItr; - // Remove the previous entry from the blueprint list if it was built and added to the PLACEONLOAD list - // DON'T remove any Deployment objects; they will re-spawn their Loadout things anew each building round! - if (remove) - m_PlacedObjects[BLUEPRINT].erase(delItr); - remove = false; - } - } - - // Traverse through all brain hideouts to always move the brain to the last available brain hideout no matter what - if (m_ResidentBrains[player] && dynamic_cast(m_ResidentBrains[player])) - for (bpItr = m_PlacedObjects[BLUEPRINT].begin(); bpItr != m_PlacedObjects[BLUEPRINT].end(); bpItr++) - { - pDeployment = dynamic_cast(*bpItr); - if (pDeployment) - { - // If this is a brain hideout, then move curent brain to new hideout or infantry brain deployment - if (pDeployment->GetPresetName() == "Brain Hideout" || pDeployment->GetPresetName() == "Infantry Brain") - { - // Get a refund for the previous brain we are replacing - if (m_ResidentBrains[player]) - { - m_ResidentBrains[player]->SetPos(pDeployment->GetPos()); + // Regular non-brain object; simply move it to the list of objects to place on next load, TRANSFERRING OWNERSHIP + else { + m_PlacedObjects[PLACEONLOAD].push_back(pObjectToPlace); + // Always count regular objects placed + placedCount++; + + // Add placed object's locations as boxes to the specified 'MetaBase' area + TerrainObject* pTO = dynamic_cast(pObjectToPlace); + if (pTO) { + if (HasArea(METABASE_AREA_NAME)) { + Scene::Area* metaBase = GetArea(METABASE_AREA_NAME); + if (metaBase) { + float x1 = pTO->GetPos().m_X + pTO->GetBitmapOffset().m_X; + float y1 = pTO->GetPos().m_Y + pTO->GetBitmapOffset().m_Y; + float x2 = x1 + pTO->GetBitmapWidth(); + float y2 = y1 + pTO->GetBitmapHeight(); + + metaBase->AddBox(Box(x1, y1, x2, y2)); + } + } + } } + + // Save the iterator so we can remove its entry after we increment + delItr = bpItr; + // Don't remove Deployment blueprints; they remain in the blueprints and re-spawn their Loadouts each building round + remove = pDeployment ? false : true; } + // Ok we can't afford any more stuff in the queue + else + break; + + // Increment to next placed object + ++bpItr; + // Remove the previous entry from the blueprint list if it was built and added to the PLACEONLOAD list + // DON'T remove any Deployment objects; they will re-spawn their Loadout things anew each building round! + if (remove) + m_PlacedObjects[BLUEPRINT].erase(delItr); + remove = false; } } - // Report the number of objects actually built - if (pObjectsBuilt) - *pObjectsBuilt = placedCount; + // Traverse through all brain hideouts to always move the brain to the last available brain hideout no matter what + if (m_ResidentBrains[player] && dynamic_cast(m_ResidentBrains[player])) + for (bpItr = m_PlacedObjects[BLUEPRINT].begin(); bpItr != m_PlacedObjects[BLUEPRINT].end(); bpItr++) { + pDeployment = dynamic_cast(*bpItr); + if (pDeployment) { + // If this is a brain hideout, then move curent brain to new hideout or infantry brain deployment + if (pDeployment->GetPresetName() == "Brain Hideout" || pDeployment->GetPresetName() == "Infantry Brain") { + // Get a refund for the previous brain we are replacing + if (m_ResidentBrains[player]) { + m_ResidentBrains[player]->SetPos(pDeployment->GetPos()); + } + } + } + } - // Add the spent amount to the tally of total investments in this scene - m_TotalInvestment += fundsSpent; + // Report the number of objects actually built + if (pObjectsBuilt) + *pObjectsBuilt = placedCount; - return fundsSpent; -} + // Add the spent amount to the tally of total investments in this scene + m_TotalInvestment += fundsSpent; + return fundsSpent; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveAllPlacedActors -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Remove all actors that are in the placed set of objects to load for -// this scene. All except for an optionally specified team, that is. - -int Scene::RemoveAllPlacedActors(int exceptTeam) -{ - int removedCount = 0; - - bool remove = false; - Actor *pActor = 0; - std::list::iterator soItr; - std::list::iterator delItr; - - // Scrub both blueprints and the stuff that is already bought and about to be placed on loading the scene - for (int set = PLACEONLOAD; set <= BLUEPRINT; ++set) - { - for (soItr = m_PlacedObjects[set].begin(); soItr != m_PlacedObjects[set].end();) - { - remove = false; - // Only look for actors of any team except the specified exception team - pActor = dynamic_cast(*soItr); - if (pActor && pActor->GetTeam() != exceptTeam) - { - // Mark for removal - remove = true; - delItr = soItr; - } - - // Increment to next placed object - ++soItr; - - // Remove the previous entry from the set list now after we incremented so our soItr can remain valid - if (remove) - { - // Properly destroy and remove the entry from the set list - delete (*delItr); - m_PlacedObjects[set].erase(delItr); - removedCount++; - } - } - } - - return removedCount; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveAllPlacedActors + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Remove all actors that are in the placed set of objects to load for + // this scene. All except for an optionally specified team, that is. + + int Scene::RemoveAllPlacedActors(int exceptTeam) { + int removedCount = 0; + + bool remove = false; + Actor* pActor = 0; + std::list::iterator soItr; + std::list::iterator delItr; + + // Scrub both blueprints and the stuff that is already bought and about to be placed on loading the scene + for (int set = PLACEONLOAD; set <= BLUEPRINT; ++set) { + for (soItr = m_PlacedObjects[set].begin(); soItr != m_PlacedObjects[set].end();) { + remove = false; + // Only look for actors of any team except the specified exception team + pActor = dynamic_cast(*soItr); + if (pActor && pActor->GetTeam() != exceptTeam) { + // Mark for removal + remove = true; + delItr = soItr; + } + // Increment to next placed object + ++soItr; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOwnerOfAllDoors -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the ownership of all doors placed in this scene to a specific team -// Arguments: The team to change the ownership to - -int Scene::SetOwnerOfAllDoors(int team, int player) -{ - int changedCount = 0; - - ADoor *pDoor = 0; - std::list::iterator soItr; - - // Affect both blueprints and the stuff that is already bought and about to be placed on loading the scene - for (int set = PLACEONLOAD; set <= BLUEPRINT; ++set) - { - for (soItr = m_PlacedObjects[set].begin(); soItr != m_PlacedObjects[set].end(); ++soItr) - { - // Only mess with doors - if (pDoor = dynamic_cast(*soItr)) - { - // Update team - pDoor->SetTeam(team); - // Update which player placed this - pDoor->SetPlacedByPlayer(player); - ++changedCount; - } - } - } - - return changedCount; -} + // Remove the previous entry from the set list now after we incremented so our soItr can remain valid + if (remove) { + // Properly destroy and remove the entry from the set list + delete (*delItr); + m_PlacedObjects[set].erase(delItr); + removedCount++; + } + } + } + return removedCount; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ResetPathFinding -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Recalculates all of the pathfinding data. This is very expensive, so -// do very rarely! + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOwnerOfAllDoors + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the ownership of all doors placed in this scene to a specific team + // Arguments: The team to change the ownership to + + int Scene::SetOwnerOfAllDoors(int team, int player) { + int changedCount = 0; + + ADoor* pDoor = 0; + std::list::iterator soItr; + + // Affect both blueprints and the stuff that is already bought and about to be placed on loading the scene + for (int set = PLACEONLOAD; set <= BLUEPRINT; ++set) { + for (soItr = m_PlacedObjects[set].begin(); soItr != m_PlacedObjects[set].end(); ++soItr) { + // Only mess with doors + if (pDoor = dynamic_cast(*soItr)) { + // Update team + pDoor->SetTeam(team); + // Update which player placed this + pDoor->SetPlacedByPlayer(player); + ++changedCount; + } + } + } -void Scene::ResetPathFinding() { - GetPathFinder(Activity::Teams::NoTeam)->RecalculateAllCosts(); - for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { - g_MovableMan.OverrideMaterialDoors(true, team); - GetPathFinder(static_cast(team))->RecalculateAllCosts(); - g_MovableMan.OverrideMaterialDoors(false, team); + return changedCount; } -} -////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResetPathFinding + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Recalculates all of the pathfinding data. This is very expensive, so + // do very rarely! + + void Scene::ResetPathFinding() { + GetPathFinder(Activity::Teams::NoTeam)->RecalculateAllCosts(); + for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { + g_MovableMan.OverrideMaterialDoors(true, team); + GetPathFinder(static_cast(team))->RecalculateAllCosts(); + g_MovableMan.OverrideMaterialDoors(false, team); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// -void Scene::BlockUntilAllPathingRequestsComplete() { - for (int team = Activity::Teams::NoTeam; team < Activity::Teams::MaxTeamCount; ++team) { - while (GetPathFinder(static_cast(team))->GetCurrentPathingRequests() != 0) {}; + void Scene::BlockUntilAllPathingRequestsComplete() { + for (int team = Activity::Teams::NoTeam; team < Activity::Teams::MaxTeamCount; ++team) { + while (GetPathFinder(static_cast(team))->GetCurrentPathingRequests() != 0) {}; + } } -} -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePathFinding -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Recalculates only the areas of the pathfinding data that have been -// marked as outdated. - -void Scene::UpdatePathFinding() -{ - ZoneScoped; - - constexpr int nodeUpdatesPerCall = 100; - constexpr int maxUnupdatedMaterialAreas = 1000; - - // If any pathing requests are active, don't update things yet, wait till they're finished - // TODO: this can indefinitely block updates if pathing requests are made every frame. Figure out a solution for this - // Either force-complete pathing requests occasionally, or delay starting new pathing requests if we've not updated in a while - for (int team = Activity::Teams::NoTeam; team < Activity::Teams::MaxTeamCount; ++team) { - if (GetPathFinder(static_cast(team))->GetCurrentPathingRequests() != 0) { - return; - }; - } - - int nodesToUpdate = nodeUpdatesPerCall / g_ActivityMan.GetActivity()->GetTeamCount(); - if (m_pTerrain->GetUpdatedMaterialAreas().size() > maxUnupdatedMaterialAreas) { - // Our list of boxes is getting too big and a bit out of hand, so clear everything. - nodesToUpdate = std::numeric_limits::max(); - } - - // Update our shared pathFinder - std::vector updatedNodes = GetPathFinder(Activity::Teams::NoTeam)->RecalculateAreaCosts(m_pTerrain->GetUpdatedMaterialAreas(), nodesToUpdate); - if (!updatedNodes.empty()) { - // Update each team's pathFinder - for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { - if (!g_ActivityMan.ActivityRunning() || !g_ActivityMan.GetActivity()->TeamActive(team)) { - continue; - } - - // Remove the material representation of all doors of this team so we can navigate through them (they'll open for us). - g_MovableMan.OverrideMaterialDoors(true, team); - - GetPathFinder(static_cast(team))->UpdateNodeList(updatedNodes); - - // Place back the material representation of all doors of this team so they are as we found them. - g_MovableMan.OverrideMaterialDoors(false, team); - } - } - - m_PartialPathUpdateTimer.Reset(); - m_PathfindingUpdated = true; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePathFinding + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Recalculates only the areas of the pathfinding data that have been + // marked as outdated. + + void Scene::UpdatePathFinding() { + ZoneScoped; + + constexpr int nodeUpdatesPerCall = 100; + constexpr int maxUnupdatedMaterialAreas = 1000; + + // If any pathing requests are active, don't update things yet, wait till they're finished + // TODO: this can indefinitely block updates if pathing requests are made every frame. Figure out a solution for this + // Either force-complete pathing requests occasionally, or delay starting new pathing requests if we've not updated in a while + for (int team = Activity::Teams::NoTeam; team < Activity::Teams::MaxTeamCount; ++team) { + if (GetPathFinder(static_cast(team))->GetCurrentPathingRequests() != 0) { + return; + }; + } + int nodesToUpdate = nodeUpdatesPerCall / g_ActivityMan.GetActivity()->GetTeamCount(); + if (m_pTerrain->GetUpdatedMaterialAreas().size() > maxUnupdatedMaterialAreas) { + // Our list of boxes is getting too big and a bit out of hand, so clear everything. + nodesToUpdate = std::numeric_limits::max(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculatePath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates and returns the least difficult path between two points on -// the current scene. Takes both distance and materials into account. + // Update our shared pathFinder + std::vector updatedNodes = GetPathFinder(Activity::Teams::NoTeam)->RecalculateAreaCosts(m_pTerrain->GetUpdatedMaterialAreas(), nodesToUpdate); + if (!updatedNodes.empty()) { + // Update each team's pathFinder + for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { + if (!g_ActivityMan.ActivityRunning() || !g_ActivityMan.GetActivity()->TeamActive(team)) { + continue; + } -float Scene::CalculatePath(const Vector &start, const Vector &end, std::list &pathResult, float digStrength, Activity::Teams team) { - float totalCostResult = -1; + // Remove the material representation of all doors of this team so we can navigate through them (they'll open for us). + g_MovableMan.OverrideMaterialDoors(true, team); - if (const std::unique_ptr &pathFinder = GetPathFinder(team)) { - int result = pathFinder->CalculatePath(start, end, pathResult, totalCostResult, digStrength); + GetPathFinder(static_cast(team))->UpdateNodeList(updatedNodes); - // It's ok if start and end nodes happen to be the same, the exact pixel locations are added at the front and end of the result regardless - return (result == micropather::MicroPather::SOLVED || result == micropather::MicroPather::START_END_SAME) ? totalCostResult : -1; - } + // Place back the material representation of all doors of this team so they are as we found them. + g_MovableMan.OverrideMaterialDoors(false, team); + } + } - return false; -} + m_PartialPathUpdateTimer.Reset(); + m_PathfindingUpdated = true; + } -std::shared_ptr Scene::CalculatePathAsync(const Vector &start, const Vector &end, float digStrength, Activity::Teams team, PathCompleteCallback callback) { - if (const std::unique_ptr &pathFinder = GetPathFinder(team)) { - return pathFinder->CalculatePathAsync(start, end, digStrength, callback); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculatePath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates and returns the least difficult path between two points on + // the current scene. Takes both distance and materials into account. - return nullptr; -} + float Scene::CalculatePath(const Vector& start, const Vector& end, std::list& pathResult, float digStrength, Activity::Teams team) { + float totalCostResult = -1; -int Scene::GetScenePathSize() const { - return s_ScenePath.size(); -} + if (const std::unique_ptr& pathFinder = GetPathFinder(team)) { + int result = pathFinder->CalculatePath(start, end, pathResult, totalCostResult, digStrength); -std::list& Scene::GetScenePath() { - return s_ScenePath; -} + // It's ok if start and end nodes happen to be the same, the exact pixel locations are added at the front and end of the result regardless + return (result == micropather::MicroPather::SOLVED || result == micropather::MicroPather::START_END_SAME) ? totalCostResult : -1; + } -bool Scene::PositionsAreTheSamePathNode(const Vector &pos1, const Vector &pos2) const { - if (const std::unique_ptr &pathFinder = const_cast(this)->GetPathFinder(Activity::Teams::NoTeam)) { - return pathFinder->PositionsAreTheSamePathNode(pos1, pos2); - } - - return false; -} + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Lock -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Locks all dynamic internal scene bitmaps so that manipulaitons of the -// scene's color and matter representations can take place. -// Doing it in a separate method like this is more efficient because -// many bitmap manipulaitons can be performed between a lock and unlock. -// UnlockScene() should always be called after accesses are completed. - -void Scene::Lock() -{ -// RTEAssert(!m_Locked, "Hey, locking already locked scene!"); - if (!m_Locked) - { - m_pTerrain->LockBitmaps(); - m_Locked = true; - } -} + std::shared_ptr Scene::CalculatePathAsync(const Vector& start, const Vector& end, float digStrength, Activity::Teams team, PathCompleteCallback callback) { + if (const std::unique_ptr& pathFinder = GetPathFinder(team)) { + return pathFinder->CalculatePathAsync(start, end, digStrength, callback); + } + return nullptr; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Unlock -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Unlocks the scene's bitmaps and prevents access to display memory. -// Doing it in a separate method like this is more efficient because -// many bitmap accesses can be performed between a lock and an unlock. -// UnlockScene() should only be called after LockScene(). - -void Scene::Unlock() -{ -// RTEAssert(m_Locked, "Hey, unlocking already unlocked scene!"); - if (m_Locked) - { - m_pTerrain->UnlockBitmaps(); - m_Locked = false; - } -} + int Scene::GetScenePathSize() const { + return s_ScenePath.size(); + } + std::list& Scene::GetScenePath() { + return s_ScenePath; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Scene. Supposed to be done every frame -// before drawing. + bool Scene::PositionsAreTheSamePathNode(const Vector& pos1, const Vector& pos2) const { + if (const std::unique_ptr& pathFinder = const_cast(this)->GetPathFinder(Activity::Teams::NoTeam)) { + return pathFinder->PositionsAreTheSamePathNode(pos1, pos2); + } + + return false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Lock + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Locks all dynamic internal scene bitmaps so that manipulaitons of the + // scene's color and matter representations can take place. + // Doing it in a separate method like this is more efficient because + // many bitmap manipulaitons can be performed between a lock and unlock. + // UnlockScene() should always be called after accesses are completed. + + void Scene::Lock() { + // RTEAssert(!m_Locked, "Hey, locking already locked scene!"); + if (!m_Locked) { + m_pTerrain->LockBitmaps(); + m_Locked = true; + } + } -void Scene::Update() -{ - ZoneScoped; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Unlock + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Unlocks the scene's bitmaps and prevents access to display memory. + // Doing it in a separate method like this is more efficient because + // many bitmap accesses can be performed between a lock and an unlock. + // UnlockScene() should only be called after LockScene(). + + void Scene::Unlock() { + // RTEAssert(m_Locked, "Hey, unlocking already unlocked scene!"); + if (m_Locked) { + m_pTerrain->UnlockBitmaps(); + m_Locked = false; + } + } - m_PathfindingUpdated = false; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Scene. Supposed to be done every frame + // before drawing. - if (g_SettingsMan.BlipOnRevealUnseen()) - { - // Highlight the pixels that have been revealed on the unseen maps - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - if (m_apUnseenLayer[team]) - { - for (std::list::iterator itr = m_SeenPixels[team].begin(); itr != m_SeenPixels[team].end(); ++itr) - { - putpixel(m_apUnseenLayer[team]->GetBitmap(), (*itr).m_X, (*itr).m_Y, g_WhiteColor); + void Scene::Update() { + ZoneScoped; + + m_PathfindingUpdated = false; + + if (g_SettingsMan.BlipOnRevealUnseen()) { + // Highlight the pixels that have been revealed on the unseen maps + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + if (m_apUnseenLayer[team]) { + for (std::list::iterator itr = m_SeenPixels[team].begin(); itr != m_SeenPixels[team].end(); ++itr) { + putpixel(m_apUnseenLayer[team]->GetBitmap(), (*itr).m_X, (*itr).m_Y, g_WhiteColor); + } } } } - } - if (m_NavigatableAreasUpToDate == false) { - // Need to block until all current pathfinding requests are finished. Ugh, if only we had a better way (interrupt/cancel a path request to start a new one?) - // TODO: Make the PathRequest struct more capable and maybe we can delay starting or cancel mid-request? - BlockUntilAllPathingRequestsComplete(); + if (m_NavigatableAreasUpToDate == false) { + // Need to block until all current pathfinding requests are finished. Ugh, if only we had a better way (interrupt/cancel a path request to start a new one?) + // TODO: Make the PathRequest struct more capable and maybe we can delay starting or cancel mid-request? + BlockUntilAllPathingRequestsComplete(); - m_NavigatableAreasUpToDate = true; - for (int team = Activity::Teams::NoTeam; team < Activity::Teams::MaxTeamCount; ++team) { - PathFinder& pathFinder = *GetPathFinder(static_cast(team)); + m_NavigatableAreasUpToDate = true; + for (int team = Activity::Teams::NoTeam; team < Activity::Teams::MaxTeamCount; ++team) { + PathFinder& pathFinder = *GetPathFinder(static_cast(team)); - pathFinder.MarkAllNodesNavigatable(m_NavigatableAreas.empty()); + pathFinder.MarkAllNodesNavigatable(m_NavigatableAreas.empty()); - for (const std::string &navigatableArea : m_NavigatableAreas) { - if (HasArea(navigatableArea)) { - for (const Box &navigatableBox : GetArea(navigatableArea)->GetBoxes()) { - pathFinder.MarkBoxNavigatable(navigatableBox, true); - } - } - } - } - } + for (const std::string& navigatableArea: m_NavigatableAreas) { + if (HasArea(navigatableArea)) { + for (const Box& navigatableBox: GetArea(navigatableArea)->GetBoxes()) { + pathFinder.MarkBoxNavigatable(navigatableBox, true); + } + } + } + } + } - // Occasionally update pathfinding. There's a tradeoff between how often updates occur vs how big the multithreaded batched node lists to update are. - if (m_PartialPathUpdateTimer.IsPastRealMS(100)) { - UpdatePathFinding(); - } -} + // Occasionally update pathfinding. There's a tradeoff between how often updates occur vs how big the multithreaded batched node lists to update are. + if (m_PartialPathUpdateTimer.IsPastRealMS(100)) { + UpdatePathFinding(); + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -std::unique_ptr& Scene::GetPathFinder(Activity::Teams team) { - // Note - we use + 1 when getting pathfinders by index, because our shared NoTeam pathfinder occupies index 0, and the rest come after that. - return m_pPathFinders[static_cast(team) + 1]; -} + std::unique_ptr& Scene::GetPathFinder(Activity::Teams team) { + // Note - we use + 1 when getting pathfinders by index, because our shared NoTeam pathfinder occupies index 0, and the rest come after that. + return m_pPathFinders[static_cast(team) + 1]; + } } // namespace RTE diff --git a/Source/Entities/Scene.h b/Source/Entities/Scene.h index fbdb2d729..b0df3366c 100644 --- a/Source/Entities/Scene.h +++ b/Source/Entities/Scene.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,1453 +18,1352 @@ #include "Activity.h" #include "PathFinder.h" -namespace RTE -{ - -class ContentFile; -class MovableObject; -class PathFinder; -class SLBackground; -class SLTerrain; -class SceneLayer; -class BunkerAssembly; -class SceneObject; -class Deployment; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: Scene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Contains everything that defines a complete scene. -// Parent(s): Entity. -// Class history: 08/02/2006 Scene created. - -class Scene : public Entity { - - friend struct EntityLuaBindings; +namespace RTE { -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableOverrideMethods; - ClassInfoGetters; - - //Available placed objects sets - enum PlacedObjectSets - { - PLACEONLOAD = 0, - BLUEPRINT, - AIPLAN, - PLACEDSETSCOUNT - }; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Nested class: Area - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Something to bundle the properties of scene areas together - // Parent(s): Serializable. - // Class history: 07/18/2008 Area created. + class ContentFile; + class MovableObject; + class PathFinder; + class SLBackground; + class SLTerrain; + class SceneLayer; + class BunkerAssembly; + class SceneObject; + class Deployment; - class Area: - public Serializable - { + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: Scene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Contains everything that defines a complete scene. + // Parent(s): Entity. + // Class history: 08/02/2006 Scene created. - friend class Scene; - friend class AreaEditorGUI; - friend class AreaPickerGUI; + class Scene : public Entity { - friend struct EntityLuaBindings; + friend struct EntityLuaBindings; - ////////////////////////////////////////////////////////////////////////////////////////// - // Public member variable, method and friend function declarations + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations - public: - - SerializableClassNameGetter; + public: SerializableOverrideMethods; + ClassInfoGetters; + + // Available placed objects sets + enum PlacedObjectSets { + PLACEONLOAD = 0, + BLUEPRINT, + AIPLAN, + PLACEDSETSCOUNT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Nested class: Area + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Something to bundle the properties of scene areas together + // Parent(s): Serializable. + // Class history: 07/18/2008 Area created. + + class Area : + public Serializable { + + friend class Scene; + friend class AreaEditorGUI; + friend class AreaPickerGUI; + + friend struct EntityLuaBindings; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableClassNameGetter; + SerializableOverrideMethods; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Area + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Area object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Area() { + Clear(); + Create(); + } + Area(std::string name) { + Clear(); + m_Name = name; + Create(); + } + Area(const Area& reference) { + Clear(); + Create(reference); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Area object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Area to be identical to another, by deep copy. + // Arguments: A reference to the Area to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Area& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Serializable, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: AddBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a Box to this' area coverage. + // Arguments: The Box to add. A copy will be made and added. + // Return value: Whether the Box was successfully added or not. + + bool AddBox(const Box& newBox); + + /// + /// Removes the first Box in the Area that has the same Corner, Width and Height of the passed-in Box. + /// + /// A Box whose values are used to determine what Box to remove. + /// Whether or not a Box was removed. + bool RemoveBox(const Box& boxToRemove); + + /// + /// Gets the first Box in this Area. + /// + /// The first Box in this Area. + const Box* GetFirstBox() const { return m_BoxList.empty() ? nullptr : &m_BoxList[0]; } + + /// + /// Gets the boxes for this area. + /// + /// The boxes in this Area. + const std::vector& GetBoxes() const { return m_BoxList; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: HasNoArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this really has no Area at all, ie it doesn't have any + // Box:es with both width and height. + // Arguments: None. + // Return value: Whether this Area actually covers any area. + + bool HasNoArea() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsInside + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether a point is anywhere inside this Area's coverage. + // Arguments: The point to check if it's inside the Area, in absolute scene coordinates. + // Return value: Whether the point is inside any of this Area's Box:es. + + bool IsInside(const Vector& point) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsInsideX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the + // X-axis only. + // Arguments: The x coord to check if it's inside the Area, in absolute scene units. + // Return value: Whether the point is inside any of this Area's Box:es in the X axis. + + bool IsInsideX(float pointX) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsInsideY + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the + // Y-axis only. + // Arguments: The x coord to check if it's inside the Area, in absolute scene units. + // Return value: Whether the point is inside any of this Area's Box:es in the Y axis. + + bool IsInsideY(float pointY) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: MovePointInsideX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Moves a coordinate to the closest value which is within any of this + // Area's Box:es, in the X axis only. + // Arguments: The x coord to transform to the closest inside poistion in the x-axis. + // Which direction to limit the search to. < 0 means can only look in the + // negative dir, 0 means can look in both directions. + // Return value: Whether the point was moved at all to get inside this' x-space. + + bool MovePointInsideX(float& pointX, int direction = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetBoxInside + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the first Box encountered in this that contains a specific point. + // Arguments: The point to check for Box collision, in absolute scene coordinates. + // Return value: Pointer to the first Box which was found to contain the point. 0 if + // none was found. OWNERSHIP IS NOT TRANSFERRED! + + Box* GetBoxInside(const Vector& point); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: RemoveBoxInside + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes the first Box encountered in this that contains a specific point. + // Arguments: The point to check for Box collision, in absolute scene coordinates. + // Return value: Copy of the Box that was removed. Will be NoArea Box if none was found. + + Box RemoveBoxInside(const Vector& point); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetCenterPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a center point for this of all the boxes waeighted by their sizes. + // Arguments: None. + // Return value: A center point of this area, can be outside the actual area though, if + // pulled apart by two separate boxes, for example. 0,0 if this has no Area + + Vector GetCenterPoint() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRandomPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a random coordinate contained within any of this' Box:es. + // Arguments: None. + // Return value: A random point that is within this Area. 0,0 if this has no Area + + Vector GetRandomPoint() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of the Area + // Arguments: None. + // Return value: The name used to ID this Area. + + std::string GetName() const { return m_Name; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // The list of Box:es defining the Area in the owner Scene + std::vector m_BoxList; + // The name tag of this Area + std::string m_Name; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Exit, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; + + friend class AreaEditor; + friend class AreaEditorGUI; + friend class AreaPickerGUI; - ////////////////////////////////////////////////////////////////////////////////////////// - // Constructor: Area - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Constructor method used to instantiate a Area object in system - // memory. Create() should be called before using the object. - // Arguments: None. - - Area() { Clear(); Create(); } - Area(std::string name) { Clear(); m_Name = name; Create(); } - Area(const Area &reference) { Clear(); Create(reference); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Makes the Area object ready for use. - // Arguments: None. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create() override; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Creates a Area to be identical to another, by deep copy. - // Arguments: A reference to the Area to deep copy. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create(const Area &reference); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Reset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Resets the entire Serializable, including its inherited members, to their - // default settings or values. - // Arguments: None. - // Return value: None. - - void Reset() override { Clear(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: AddBox - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Adds a Box to this' area coverage. - // Arguments: The Box to add. A copy will be made and added. - // Return value: Whether the Box was successfully added or not. - - bool AddBox(const Box &newBox); +#define METABASE_AREA_NAME "MetabaseServiceArea" - /// - /// Removes the first Box in the Area that has the same Corner, Width and Height of the passed-in Box. - /// - /// A Box whose values are used to determine what Box to remove. - /// Whether or not a Box was removed. - bool RemoveBox(const Box &boxToRemove); + enum NeighborDirection { + NODIR = -1, + E = 0, + SE, + S, + SW, + W, + NW, + N, + NE + }; + + // Concrete allocation and cloning definitions + EntityAllocation(Scene) + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: Scene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a Scene object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + Scene() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~Scene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a Scene object before deletion + // from system memory. + // Arguments: None. + + ~Scene() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the Scene object ready for use. + // Arguments: The Terrain to use. Ownership IS transferred! + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(SLTerrain* pNewTerrain); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a Scene to be identical to another, by deep copy. + // Arguments: A reference to the Scene to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const Scene& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: LoadData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Actually loads previously specified/created data into memory. Has + // to be done before using this Scene. + // Arguments: Whetehr to actually place out all the sceneobjects associated with the + // Scene's definition. If not, they still remain in the internal placed + // objects list. This avoids messing with the MovableMan at all. + // Whether to do pathfinding init, which should be avoided if we are only + // loading and saving purposes of MetaMan, for example. + // Whether to place actors and deployments (doors not affected). + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int LoadData(bool placeObjects = true, bool initPathfinding = true, bool placeUnits = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ExpandAIPlanAssemblySchemes + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Replace all assembly shemes by corresponding bunker assemblies in + // AI plan objects set. + // Arguments: None. + // Return value: None. + + int ExpandAIPlanAssemblySchemes(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SaveData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves data currently in memory to disk. + // Arguments: The filepath base to the where to save the Bitmap data. This means + // everything up to the extension. "FG" and "Mat" etc will be added. + // Whether or not to save asynchronously. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int SaveData(std::string pathBase, bool doAsyncSaves = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SavePreview + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves preview bitmap for this scene. + // + // Arguments: The full filepath the where to save the Bitmap data. + // Return value: None. + + int SavePreview(const std::string& bitmapPath); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ClearData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out any previously loaded bitmap data from memory. + // Arguments: None. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int ClearData(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Scene, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Entity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the Scene object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: MigrateToModule + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes this an original Preset in a different module than it was before. + // It severs ties deeply to the old module it was saved in. + // Arguments: The ID of the new module. + // Return value: Whether the migration was successful. If you tried to migrate to the + // same module it already was in, this would return false. + + bool MigrateToModule(int whichModule) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLocation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the specified location of this scene on the planet view + // Arguments: None. + // Return value: A Vector showing the location of this scene on the planet view. + + Vector GetLocation() const { return m_Location; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLocationOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the specified temporary location offset of this scene on the planet view. + // Arguments: None. + // Return value: A Vector showing the temporary location offset of this scene on the planet view. + + Vector GetLocationOffset() const { return m_LocationOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLocationOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the specified temporary location offset of this scene on the planet view. + // Arguments: A Vector showing the temporary location offset of this scene on the planet view. + // Return value: None. + + void SetLocationOffset(Vector newOffset) { m_LocationOffset = newOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsMetagamePlayable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is compatible with metagame play at all. + // Arguments: None. + // Return value: Whether this can be used on the metagame map. + + bool IsMetagamePlayable() const { return m_MetagamePlayable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsRevealed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this is revealed on the metagame map. + // Arguments: None. + // Return value: Whether this can be seen on the metagame map yet. + + bool IsRevealed() const { return m_Revealed; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTeamOwnership + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows which team owns this Scene in a Metagame, if any + // Arguments: None. + // Return value: The team that owns this site in a Metagame, if any + + int GetTeamOwnership() const { return m_OwnedByTeam; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRoundIncome + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows how much income this Scene pulls in for its owning team each + // round of a metagame. + // Arguments: None. + // Return value: The income in oz that this generates each metagame round. + + float GetRoundIncome() const { return m_RoundIncome; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBuildBudget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows how much gold this Scene is budgeted to be built for this round. + // Arguments: Which player's set budget to show. + // Return value: The budget in oz that this is allocated to have built for this round. + + float GetBuildBudget(int player) const { return m_BuildBudget[player]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBuildBudgetRatio + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows how much of a player's budget this Scene is allocated to be + // built for this round. + // Arguments: Which player's set budget ratio to show. + // Return value: The budget in normalized ratio that this is allocated last round. + + float GetBuildBudgetRatio(int player) const { return m_BuildBudgetRatio[player]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAutoDesigned + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this should be automatically designed by the AI plan + // even if owned by human players. + // Arguments: What to set the setting to. + // Return value: None. + + void SetAutoDesigned(bool autoDesigned = true) { m_AutoDesigned = autoDesigned; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAutoDesigned + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this should be automatically designed by the AI plan + // even if owned by human players. + // Arguments: None. + // Return value: Whether this should be autodesigned or not. + + bool GetAutoDesigned() const { return m_AutoDesigned; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTotalInvestment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the total defense investment this scene has experienced by all + // teams since the metagame started. + // Arguments: What to set the total investment in gold oz) to. + // Return value: None. + + void SetTotalInvestment(float totalInvestment) { m_TotalInvestment = totalInvestment; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalInvestment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total defense investment this scene has experienced by all + // teams since the metagame started. + // Arguments: None. + // Return value: The total investment in this scene. + + float GetTotalInvestment() const { return m_TotalInvestment; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the SLTerrain. + // Arguments: None. + // Return value: A pointer to the SLTerrain. Ownership is NOT transferred! + + SLTerrain* GetTerrain() { return m_pTerrain; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBackLayers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets access to the background layer list. + // Arguments: None. + // Return value: A reference to the std::list containing all the background layers. + // Ownership is NOT transferred! + + std::list& GetBackLayers() { return m_BackLayerList; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds area to the list if this scene's areas. + // Arguments: Area to add. + // Return value: None. + + void AddArea(Scene::Area& newArea) { m_AreaList.push_back(newArea); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FillUnseenLayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a new SceneLayer for a specific team and fills it with black + // pixels that end up being a specific size on the screen. + // Arguments: A Vector with the desired dimensions of the unseen layer's chunky pixels. + // Which team to get the unseen layer for. + // Whether to create the unseen layers now, or wait until next time + // LoadData is called on this. + // Return value: None. + + void FillUnseenLayer(Vector pixelSize, int team = Activity::TeamOne, bool createNow = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetUnseenLayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the unseen layer of a specific team. + // Arguments: The new SceneLayer to use as the new unseen layer, Ownership IS XFERRED! + // Which team to get the unseen layer for. + // Return value: None. + + void SetUnseenLayer(SceneLayer* pNewLayer, int team = Activity::TeamOne); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetUnseenLayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the unseen layer of a specific team. + // Arguments: Which team to get the unseen layer for. + // Return value: A pointer to the SceneLayer representing what hasn't been seen by a + // specific team yet. Ownership is NOT transferred! + + SceneLayer* GetUnseenLayer(int team = Activity::TeamOne) const { return team != Activity::NoTeam ? m_apUnseenLayer[team] : 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSeenPixels + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of pixels that have been seen on a team's unseen layer. + // Arguments: Which team to get the unseen layer for. + // Return value: The list of pixel coordinates in the unseen layer's scale. + + std::list& GetSeenPixels(int team = Activity::TeamOne) { return m_SeenPixels[team]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearSeenPixels + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the pixels that have been seen on a team's unseen layer. + // Arguments: Which team to get the unseen layer for. + // Return value: None. + + void ClearSeenPixels(int team = Activity::TeamOne); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CleanOrphanPixel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks a specific unseen pixel for only having two or less unseen + // neighbors, and if so, makes it seen. + // Arguments: Coordinates to the pixel to check for orphaness. + // The direction we might be checking 'from', ie the neighbor we can + // already assume is seen without poking at the unseen map. + // Which team's unseen layer to check the pixel on. + // Return value: Whether the pixel was deemed to be orphan and thus cleaned up. + + bool CleanOrphanPixel(int posX, int posY, NeighborDirection checkingFrom = NODIR, int team = Activity::TeamOne); /// - /// Gets the first Box in this Area. + /// Gets the total dimensions (width and height) of the scene, in pixels. /// - /// The first Box in this Area. - const Box * GetFirstBox() const { return m_BoxList.empty() ? nullptr : &m_BoxList[0]; } - - /// - /// Gets the boxes for this area. - /// - /// The boxes in this Area. - const std::vector & GetBoxes() const { return m_BoxList; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: HasNoArea - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Shows whether this really has no Area at all, ie it doesn't have any - // Box:es with both width and height. - // Arguments: None. - // Return value: Whether this Area actually covers any area. - - bool HasNoArea() const; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: IsInside - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Shows whether a point is anywhere inside this Area's coverage. - // Arguments: The point to check if it's inside the Area, in absolute scene coordinates. - // Return value: Whether the point is inside any of this Area's Box:es. - - bool IsInside(const Vector &point) const; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: IsInsideX - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the - // X-axis only. - // Arguments: The x coord to check if it's inside the Area, in absolute scene units. - // Return value: Whether the point is inside any of this Area's Box:es in the X axis. - - bool IsInsideX(float pointX) const; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: IsInsideY - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Shows whether a coordinate is anywhere inside this Area's coverage, in the - // Y-axis only. - // Arguments: The x coord to check if it's inside the Area, in absolute scene units. - // Return value: Whether the point is inside any of this Area's Box:es in the Y axis. - - bool IsInsideY(float pointY) const; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: MovePointInsideX - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Moves a coordinate to the closest value which is within any of this - // Area's Box:es, in the X axis only. - // Arguments: The x coord to transform to the closest inside poistion in the x-axis. - // Which direction to limit the search to. < 0 means can only look in the - // negative dir, 0 means can look in both directions. - // Return value: Whether the point was moved at all to get inside this' x-space. - - bool MovePointInsideX(float &pointX, int direction = 0) const; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: GetBoxInside - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the first Box encountered in this that contains a specific point. - // Arguments: The point to check for Box collision, in absolute scene coordinates. - // Return value: Pointer to the first Box which was found to contain the point. 0 if - // none was found. OWNERSHIP IS NOT TRANSFERRED! - - Box * GetBoxInside(const Vector &point); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: RemoveBoxInside - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Removes the first Box encountered in this that contains a specific point. - // Arguments: The point to check for Box collision, in absolute scene coordinates. - // Return value: Copy of the Box that was removed. Will be NoArea Box if none was found. - - Box RemoveBoxInside(const Vector &point); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: GetCenterPoint - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets a center point for this of all the boxes waeighted by their sizes. - // Arguments: None. - // Return value: A center point of this area, can be outside the actual area though, if - // pulled apart by two separate boxes, for example. 0,0 if this has no Area - - Vector GetCenterPoint() const; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: GetRandomPoint - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets a random coordinate contained within any of this' Box:es. - // Arguments: None. - // Return value: A random point that is within this Area. 0,0 if this has no Area - - Vector GetRandomPoint() const; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: GetName - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the name of the Area - // Arguments: None. - // Return value: The name used to ID this Area. - - std::string GetName() const { return m_Name; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Protected member variable and method declarations - - protected: - - // The list of Box:es defining the Area in the owner Scene - std::vector m_BoxList; - // The name tag of this Area - std::string m_Name; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Private member variable and method declarations - - private: - - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Clear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Clears all the member variables of this Exit, effectively - // resetting the members of this abstraction level only. - // Arguments: None. - // Return value: None. - - void Clear(); - - }; - -friend class AreaEditor; -friend class AreaEditorGUI; -friend class AreaPickerGUI; - -#define METABASE_AREA_NAME "MetabaseServiceArea" - -enum NeighborDirection -{ - NODIR = -1, - E = 0, - SE, - S, - SW, - W, - NW, - N, - NE -}; - -// Concrete allocation and cloning definitions -EntityAllocation(Scene) - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: Scene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a Scene object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - Scene() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~Scene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a Scene object before deletion -// from system memory. -// Arguments: None. - - ~Scene() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the Scene object ready for use. -// Arguments: The Terrain to use. Ownership IS transferred! -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(SLTerrain *pNewTerrain); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a Scene to be identical to another, by deep copy. -// Arguments: A reference to the Scene to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const Scene &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: LoadData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Actually loads previously specified/created data into memory. Has -// to be done before using this Scene. -// Arguments: Whetehr to actually place out all the sceneobjects associated with the -// Scene's definition. If not, they still remain in the internal placed -// objects list. This avoids messing with the MovableMan at all. -// Whether to do pathfinding init, which should be avoided if we are only -// loading and saving purposes of MetaMan, for example. -// Whether to place actors and deployments (doors not affected). -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int LoadData(bool placeObjects = true, bool initPathfinding = true, bool placeUnits = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ExpandAIPlanAssemblySchemes -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Replace all assembly shemes by corresponding bunker assemblies in -// AI plan objects set. -// Arguments: None. -// Return value: None. - - int ExpandAIPlanAssemblySchemes(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SaveData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves data currently in memory to disk. -// Arguments: The filepath base to the where to save the Bitmap data. This means -// everything up to the extension. "FG" and "Mat" etc will be added. -// Whether or not to save asynchronously. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int SaveData(std::string pathBase, bool doAsyncSaves = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SavePreview -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves preview bitmap for this scene. -// -// Arguments: The full filepath the where to save the Bitmap data. -// Return value: None. - - int SavePreview(const std::string &bitmapPath); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ClearData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out any previously loaded bitmap data from memory. -// Arguments: None. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int ClearData(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire Scene, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Entity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the Scene object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: MigrateToModule -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes this an original Preset in a different module than it was before. -// It severs ties deeply to the old module it was saved in. -// Arguments: The ID of the new module. -// Return value: Whether the migration was successful. If you tried to migrate to the -// same module it already was in, this would return false. - - bool MigrateToModule(int whichModule) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLocation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the specified location of this scene on the planet view -// Arguments: None. -// Return value: A Vector showing the location of this scene on the planet view. - - Vector GetLocation() const { return m_Location; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLocationOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the specified temporary location offset of this scene on the planet view. -// Arguments: None. -// Return value: A Vector showing the temporary location offset of this scene on the planet view. - - Vector GetLocationOffset() const { return m_LocationOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLocationOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the specified temporary location offset of this scene on the planet view. -// Arguments: A Vector showing the temporary location offset of this scene on the planet view. -// Return value: None. - - void SetLocationOffset(Vector newOffset) { m_LocationOffset = newOffset; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsMetagamePlayable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is compatible with metagame play at all. -// Arguments: None. -// Return value: Whether this can be used on the metagame map. - - bool IsMetagamePlayable() const { return m_MetagamePlayable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsRevealed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this is revealed on the metagame map. -// Arguments: None. -// Return value: Whether this can be seen on the metagame map yet. - - bool IsRevealed() const { return m_Revealed; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTeamOwnership -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows which team owns this Scene in a Metagame, if any -// Arguments: None. -// Return value: The team that owns this site in a Metagame, if any - - int GetTeamOwnership() const { return m_OwnedByTeam; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRoundIncome -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows how much income this Scene pulls in for its owning team each -// round of a metagame. -// Arguments: None. -// Return value: The income in oz that this generates each metagame round. - - float GetRoundIncome() const { return m_RoundIncome; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBuildBudget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows how much gold this Scene is budgeted to be built for this round. -// Arguments: Which player's set budget to show. -// Return value: The budget in oz that this is allocated to have built for this round. - - float GetBuildBudget(int player) const { return m_BuildBudget[player]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBuildBudgetRatio -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows how much of a player's budget this Scene is allocated to be -// built for this round. -// Arguments: Which player's set budget ratio to show. -// Return value: The budget in normalized ratio that this is allocated last round. - - float GetBuildBudgetRatio(int player) const { return m_BuildBudgetRatio[player]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAutoDesigned -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this should be automatically designed by the AI plan -// even if owned by human players. -// Arguments: What to set the setting to. -// Return value: None. - - void SetAutoDesigned(bool autoDesigned = true) { m_AutoDesigned = autoDesigned; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAutoDesigned -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this should be automatically designed by the AI plan -// even if owned by human players. -// Arguments: None. -// Return value: Whether this should be autodesigned or not. - - bool GetAutoDesigned() const { return m_AutoDesigned; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTotalInvestment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the total defense investment this scene has experienced by all -// teams since the metagame started. -// Arguments: What to set the total investment in gold oz) to. -// Return value: None. - - void SetTotalInvestment(float totalInvestment) { m_TotalInvestment = totalInvestment; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalInvestment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total defense investment this scene has experienced by all -// teams since the metagame started. -// Arguments: None. -// Return value: The total investment in this scene. - - float GetTotalInvestment() const { return m_TotalInvestment; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the SLTerrain. -// Arguments: None. -// Return value: A pointer to the SLTerrain. Ownership is NOT transferred! - - SLTerrain * GetTerrain() { return m_pTerrain; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBackLayers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets access to the background layer list. -// Arguments: None. -// Return value: A reference to the std::list containing all the background layers. -// Ownership is NOT transferred! - - std::list & GetBackLayers() { return m_BackLayerList; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds area to the list if this scene's areas. -// Arguments: Area to add. -// Return value: None. - - void AddArea(Scene::Area & newArea) { m_AreaList.push_back(newArea); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FillUnseenLayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a new SceneLayer for a specific team and fills it with black -// pixels that end up being a specific size on the screen. -// Arguments: A Vector with the desired dimensions of the unseen layer's chunky pixels. -// Which team to get the unseen layer for. -// Whether to create the unseen layers now, or wait until next time -// LoadData is called on this. -// Return value: None. - - void FillUnseenLayer(Vector pixelSize, int team = Activity::TeamOne, bool createNow = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetUnseenLayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the unseen layer of a specific team. -// Arguments: The new SceneLayer to use as the new unseen layer, Ownership IS XFERRED! -// Which team to get the unseen layer for. -// Return value: None. - - void SetUnseenLayer(SceneLayer *pNewLayer, int team = Activity::TeamOne); + /// A Vector describing the scene dimensions. + Vector GetDimensions() const; + /// + /// Gets the total width of the scene, in pixels. + /// + /// An int describing the scene width. + int GetWidth() const; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetUnseenLayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the unseen layer of a specific team. -// Arguments: Which team to get the unseen layer for. -// Return value: A pointer to the SceneLayer representing what hasn't been seen by a -// specific team yet. Ownership is NOT transferred! + /// + /// Gets the total height of the scene, in pixels. + /// + /// An int describing the scene height. + int GetHeight() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapsX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the scene wraps its scrolling around the X axis. + // Arguments: None. + // Return value: Whether the scene wraps around the X axis or not. + + bool WrapsX() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapsY + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the scene wraps its scrolling around the Y axis. + // Arguments: None. + // Return value: Whether the scene wraps around the Y axis or not. + + bool WrapsY() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PlaceResidentBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Places the individual brain of a single player which may be stationed + // on this Scene, and registers them as such in an Activity. + // Arguments: The player's brain to place. + // The Activity to register the placed brains with. OWNERSHIP IS NOT TRANSFERRED! + // Return value: If the brain was successfully found as resident and placed. + + bool PlaceResidentBrain(int player, Activity& newActivity); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PlaceResidentBrains + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Places the individual brains of the various players which may be + // stationed on this Scene, and registers them as such in an Activity. + // Arguments: The Activity to register the placed brains with. OWNERSHIP IS NOT TRANSFERRED! + // Return value: How many brains were finally placed. + + int PlaceResidentBrains(Activity& newActivity); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RetrieveResidentBrains + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Looks at the Activity and its players' registered brain Actors, and + // saves them as resident brains for this Scene. Done when a fight is over + // and the survivors remain! + // Arguments: The Activity to check for registered brains. OWNERSHIP IS NOT TRANSFERRED! + // Return value: How many brains were found registered with the passed in Activity. + + int RetrieveResidentBrains(Activity& oldActivity); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RetrieveSceneObjects + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sucks up all the Actors, Items and Particles currently active in MovableMan and + // puts them into this' list of objects to place on next load. + // Arguments: The team to only retrieve Actors of. If NoTeam, then all will be grabbed. + // Whether to not get any brains at all. + // Return value: How many objects were found knocking about in the world, and stored. + + int RetrieveSceneObjects(bool transferOwnership, int onlyTeam = -1, bool noBrains = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlacedObjects + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of SceneObject:s which are placed in this scene on loading. + // Arguments: Which set of placed objects to get. See the PlacedObjectSets enum. + // Return value: The list of of placed objects. Ownership is NOT transferred! + + const std::list* GetPlacedObjects(int whichSet) const { return &m_PlacedObjects[whichSet]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a SceneObject to be placed in this scene. Ownership IS transferred! + // Arguments: Which set of placed objects to add to. See the PlacedObjectSets enum. + // The SceneObject instance to add, OIT! + // Where in the list the object should be inserted. -1 means at the end + // of the list. + // Return value: None. + + void AddPlacedObject(int whichSet, SceneObject* pObjectToAdd, int listOrder = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemovePlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a SceneObject placed in this scene. + // Arguments: Which set of placed objects to rem from. See the PlacedObjectSets enum. + // The list order number of the object to remove. If -1, the last one is removed. + // Return value: None. + + void RemovePlacedObject(int whichSet, int whichToRemove = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PickPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the last placed object that graphically overlaps an absolute + // point in the scene. + // Arguments: Which set of placed objects to pick from. See the PlacedObjectSets enum. + // The point in absolute scene coordinates that will be used to pick the + // last placed SceneObject which overlaps it. + // An int which will be filled out with the order place of any found object + // in the list. if nothing is found, it will get a value of -1. + // Return value: The last hit SceneObject, if any. Ownership is NOT transferred! + + const SceneObject* PickPlacedObject(int whichSet, Vector& scenePoint, int* pListOrderPlace = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PickPlacedActorInRange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the last placed actor object that is closer than range to scenePoint + // + // Arguments: Which set of placed objects to pick from. See the PlacedObjectSets enum. + // The point in absolute scene coordinates that will be used to pick the + // closest placed SceneObject near it. + // The range to check for nearby objects. + // An int which will be filled out with the order place of any found object + // in the list. if nothing is found, it will get a value of -1. + // + // Return value: The closest actor SceneObject, if any. Ownership is NOT transferred! + + const SceneObject* PickPlacedActorInRange(int whichSet, Vector& scenePoint, int range, int* pListOrderPlace) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePlacedObjects + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updated the objects in the placed scene objects list of this. This is + // mostly for the editor to represent the items correctly. + // Arguments: Which set of placed objects to update. See the PlacedObjectSets enum. + // Return value: None. + + void UpdatePlacedObjects(int whichSet); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearPlacedObjectSet + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes all entries in a specific set of placed Objects. + // Arguments: Which set of placed objects to clear. See the PlacedObjectSets enum. + // Whether or not we have ownership of these items, and should delete them. + // Return value: How many things were removed in teh process of clearing that set. + + int ClearPlacedObjectSet(int whichSet, bool weHaveOwnership = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetResidentBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the resident brain Actor of a specific player from this scene, + // if there is any. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: Which player to get the resident brain of. + // Return value: The SO containing the brain, or 0 if there aren't any of that player. + + SceneObject* GetResidentBrain(int player) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetResidentBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the resident brain Actor of a specific player from this scene, + // if there is any. Ownership IS transferred! + // Arguments: Which player to set the resident brain of. + // The Actor to set as the resident brain of the specified player. + // Return value: None. + + void SetResidentBrain(int player, SceneObject* pNewBrain); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetResidentBrainCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of brains currently residing in this scene. + // Arguments: None. + // Return value: The number of resident brains who are installed here. + + int GetResidentBrainCount() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds one or modifies an existing area of this Scene. + // Arguments: The area to add or modify of the same name in this Scene. Ownership is + // NOT transferred! + // Return value: Whether the specified area was previously defined in this scene. + + bool SetArea(Area& newArea); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks for the existence of a specific Area identified by a name. + // This won't throw any errors to the console if the Area isn't found. + // Arguments: The name of the Area to try to find in this Scene. + // Return value: Whether the specified area is defined in this Scene. + + bool HasArea(std::string areaName); - SceneLayer * GetUnseenLayer(int team = Activity::TeamOne) const { return team != Activity::NoTeam ? m_apUnseenLayer[team] : 0; } + /// + /// Gets a specified Area identified by name. Ownership is NOT transferred! + /// + /// The name of the Area to try to get. + /// Whether the area is required, and should throw an error if not found. + /// A pointer to the Area asked for, or nullptr if no Area of that name was found. + Area* GetArea(const std::string_view& areaName, bool required); + /// + /// Gets a specified Area identified by name. Ownership is NOT transferred! + /// + /// The name of the Area to try to get. + /// A pointer to the Area asked for, or nullptr if no Area of that name was found. + Area* GetArea(const std::string& areaName) { return GetArea(areaName, true); } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSeenPixels -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of pixels that have been seen on a team's unseen layer. -// Arguments: Which team to get the unseen layer for. -// Return value: The list of pixel coordinates in the unseen layer's scale. + /// + /// Gets a specified Area identified by name, showing a Lua warning if it's not found. Ownership is NOT transferred! + /// Using this function will not add the area to the list of required areas which Scenario GUI uses to show compatible areas. + /// + /// The name of the Area to try to get. + /// A pointer to the Area asked for, or nullptr if no Area of that name was found. + Area* GetOptionalArea(const std::string& areaName) { return GetArea(areaName, false); } + + void AddNavigatableArea(const std::string& areaName) { + m_NavigatableAreas.push_back(areaName); + m_NavigatableAreasUpToDate = false; + } + void ClearNavigatableAreas(const std::string& areaName) { + m_NavigatableAreas.clear(); + m_NavigatableAreasUpToDate = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a specific Area identified by a name. + // Arguments: The name of the Area to try to remove. + // Return value: Whether an Area of that name was found, and subsequently removed. + + bool RemoveArea(std::string areaName); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WithinArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if a point is within a specific named Area of this Scene. If + // no Area of the name is found, this just returns false without error. + // Arguments: The name of the Area to try to check against. + // The point to see if it's within the specified Area. + // Return value: Whether any Area of that name was found, AND the point falls within it. + + bool WithinArea(std::string areaName, const Vector& point) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGlobalAcc + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the global acceleration (in m/s^2) that is applied to all movable + // objects' velocities during every frame. Typically models gravity. + // Arguments: None. + // Return value: A Vector describing the global acceleration. + + Vector GetGlobalAcc() const { return m_GlobalAcc; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetGlobalAcc + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the global acceleration (in m/s^2) that is applied to all movable + // objects' velocities during every frame. Typically models gravity. + // Arguments: A Vector describing the global acceleration. + // Return value: None. + + void SetGlobalAcc(Vector newValue) { m_GlobalAcc = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMetasceneParent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns parent scene name of this metascene. + // Arguments: None. + // Return value: Name of a parent scene. + + std::string GetMetasceneParent() const { return m_MetasceneParent; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLocation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the specified location of this Scene in the scene + // Arguments: A Vector with the desired location of this Scene in the scene. + // Return value: None. + + void SetLocation(const Vector& newLocation) { m_Location = newLocation; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMetagamePlayable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this can be played in the Metagame map at all. + // Arguments: Whether this is compatible with metagame play at all. + // Return value: None. + + void SetMetagamePlayable(bool isPlayable) { m_MetagamePlayable = isPlayable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRevealed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this should show up on the Metagame map yet. + // Arguments: Whether to reveal this on the metagame map or not. + // Return value: None. + + void SetRevealed(bool isRevealed) { m_Revealed = isRevealed; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTeamOwnership + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the team who owns this Scene in a Metagame + // Arguments: The team who should now own this Scene + // Return value: None. + + void SetTeamOwnership(int newTeam); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBuildBudget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets how much gold this Scene is budgeted to be built for this round. + // Arguments: The player whom is setting the budget. + // The budget in oz that this is allocated to have built for this round. + // Return value: None. + + void SetBuildBudget(int player, float budget) { m_BuildBudget[player] = budget; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetBuildBudgetRatio + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets how much of a player's budget this Scene is budgeted to be build + // for each turn. + // Arguments: The player whom is setting the budget ratio. + // The budget in normalized ratio that this is allocated of the total. + // Return value: None. + + void SetBuildBudgetRatio(int player, float budgetRatio) { m_BuildBudgetRatio[player] = budgetRatio; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalcBuildBudgetUse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Figure out exactly how much of the build budget would be used if + // as many blueprint objects as can be afforded and exists would be built. + // Arguments: The player for whom we are calculating this budget use. + // An optional int that will be filled with number of objects that can + // acutally be built. + // An optional int that will be filled with number of objects that can + // built out of the AI plan set, AFTER the blueprints are built. + // Return value: The amount of funds that would be applied to the building of objects. + + float CalcBuildBudgetUse(int player, int* pAffordCount = 0, int* pAffordAIPlanCount = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyAIPlan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Puts the pre-built AI base plan into effect by transferring as many + // pieces as the current base budget allows from the AI plan to the actual + // blueprints to be built at this Scene. + // Arguments: The AI player whom is putting his plans into motion. + // An optional int that will be filled with number of objects that were + // acutally moved from the AI plan to the blueprints. + // Return value: The value of the AI plan objects that were put onto the blueprints. + + float ApplyAIPlan(int player, int* pObjectsApplied = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyBuildBudget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Actually builds as many objects in the specific player's Blueprint + // list as can be afforded by his build budget. The budget is deducted + // accordingly. + // Arguments: The player whom is using his budget. + // An optional int that will be filled with number of objects that were + // acutally built. + // Return value: The amount of funds that were applied to the building of objects. + + float ApplyBuildBudget(int player, int* pObjectsBuilt = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveAllPlacedActors + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Remove all actors that are in the placed set of objects to load for + // this scene. All except for an optionally specified team, that is. + // Arguments: Remove all actors but of this team. + // Return value: How many actors were actually removed. + + int RemoveAllPlacedActors(int exceptTeam = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOwnerOfAllDoors + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the ownership of all doors placed in this scene to a specific team + // Arguments: The team to change the ownership to + // The player which placed these doors. + // Return value: How many doors were actually affected. + + int SetOwnerOfAllDoors(int team, int player); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsScanScheduled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a specific team has scheduled an orbital Scan of this. + // Arguments: The team to check for. + // Return value: Whether the scan has been scheduled and paid for. + + bool IsScanScheduled(int team) const { return m_ScanScheduled[team]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetScheduledScan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this to be orbitally scanned by a specific team on next load. + // Arguments: The team to schedule the scan for. + // Whether to actually schedule the scan or clear it. + // Return value: None. + + void SetScheduledScan(int team, bool scan = true) { m_ScanScheduled[team] = scan; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResetPathFinding + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Recalculates all of the pathfinding data. This is very expensive, so + // do very rarely! + // Arguments: None. + // Return value: None. + + void ResetPathFinding(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BlockUntilAllPathingRequestsComplete + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Blocks this thread until all pathing requests are completed. + // Arguments: None. + // Return value: None. + + void BlockUntilAllPathingRequestsComplete(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePathFinding + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Recalculates only the areas of the pathfinding data that have been + // marked as outdated. + // Arguments: None. + // Return value: None. + + void UpdatePathFinding(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PathFindingUpdated + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether the pathfinding data has been updated in the last frame. + // Arguments: None. + // Return value: Whether the pathfinding data was recalculated fully or partially. + + bool PathFindingUpdated() { return m_PathfindingUpdated; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculatePath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates and returns the least difficult path between two points on + // the current scene. Takes both distance and materials into account. + // When pathing using the NoTeam pathFinder, no doors are considered passable. + // Arguments: Start and end positions on the scene to find the path between. + // A list which will be filled out with waypoints between the start and end. + // The maximum material strength any actor traveling along the path can dig through. + // The team we're pathing for (doors for this team will be considered passable) + // Return value: The total minimum difficulty cost calculated between the two points on + // the scene. + + float CalculatePath(const Vector& start, const Vector& end, std::list& pathResult, float digStrength = c_PathFindingDefaultDigStrength, Activity::Teams team = Activity::Teams::NoTeam); - std::list & GetSeenPixels(int team = Activity::TeamOne) { return m_SeenPixels[team]; } + /// + /// Asynchronously calculates the least difficult path between two points on the current Scene. Takes both distance and materials into account. + /// When pathing using the NoTeam pathFinder, no doors are considered passable. + /// + /// Start position of the pathfinding request. + /// End position of the pathfinding request. + /// The maximum material strength any actor traveling along the path can dig through. + /// The team we're pathing for (doors for this team will be considered passable) + /// A shared pointer to the volatile PathRequest to be used to track whehter the asynchrnous path calculation has been completed, and check its results. + std::shared_ptr CalculatePathAsync(const Vector& start, const Vector& end, float digStrength = c_PathFindingDefaultDigStrength, Activity::Teams team = Activity::Teams::NoTeam, PathCompleteCallback callback = nullptr); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetScenePathSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how many waypoints there are in the ScenePath currently + // Arguments: None. + // Return value: The number of waypoints in the ScenePath. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearSeenPixels -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the pixels that have been seen on a team's unseen layer. -// Arguments: Which team to get the unseen layer for. -// Return value: None. + int GetScenePathSize() const; - void ClearSeenPixels(int team = Activity::TeamOne); + std::list& GetScenePath(); + /// + /// Returns whether two position represent the same path nodes. + /// + /// First coordinates to compare. + /// Second coordinates to compare. + /// Whether both coordinates represent the same path node. + bool PositionsAreTheSamePathNode(const Vector& pos1, const Vector& pos2) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Lock + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Locks all dynamic internal scene bitmaps so that manipulaitons of the + // scene's color and matter representations can take place. + // Doing it in a separate method like this is more efficient because + // many bitmap manipulaitons can be performed between a lock and unlock. + // UnlockScene() should always be called after accesses are completed. + // Arguments: None. + // Return value: None. + + void Lock(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Unlock + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Unlocks the scene's bitmaps and prevents access to display memory. + // Doing it in a separate method like this is more efficient because + // many bitmap accesses can be performed between a lock and an unlock. + // UnlockScene() should only be called after LockScene(). + // Arguments: None. + // Return value: None. + + void Unlock(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsLocked + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the entire scene is currently locked or not. + // Arguments: None. + // Return value: Whether the entire scene is currently locked or not. + + bool IsLocked() const { return m_Locked; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Scene. Supposed to be done every frame + // before drawing. + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsMetagameInternal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Whether this scene is a temprorary metagame scene and should + // not be used anywhere except in metagame. + // Arguments: None. + // Return value: Whether scene belongs to metagame or not. + + bool IsMetagameInternal() const { return m_IsMetagameInternal; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMetagameInternal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this scene is a temprorary metagame scene and should + // not be used anywhere except in metagame. + // Arguments: New value. + // Return value: None. + + void SetMetagameInternal(bool newValue) { m_IsMetagameInternal = newValue; } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CleanOrphanPixel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks a specific unseen pixel for only having two or less unseen -// neighbors, and if so, makes it seen. -// Arguments: Coordinates to the pixel to check for orphaness. -// The direction we might be checking 'from', ie the neighbor we can -// already assume is seen without poking at the unseen map. -// Which team's unseen layer to check the pixel on. -// Return value: Whether the pixel was deemed to be orphan and thus cleaned up. + /// + /// Gets whether this Scene is a saved game Scene copy and should not be used anywhere except for game saving and loading. + /// + /// Whether this Scene is a saved game Scene copy. + bool IsSavedGameInternal() const { return m_IsSavedGameInternal; } - bool CleanOrphanPixel(int posX, int posY, NeighborDirection checkingFrom = NODIR, int team = Activity::TeamOne); + /// + /// Sets whether this Scene is a saved game Scene copy and should not be used anywhere except for game saving and loading. + /// + /// Whether this Scene is a saved game Scene copy. + void SetSavedGameInternal(bool newValue) { m_IsSavedGameInternal = newValue; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPreviewBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns preview bitmap pointer for this scene. + // Arguments: None. + // Return value: Pointer to preview bitmap. + + BITMAP* GetPreviewBitmap() const { return m_pPreviewBitmap; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Member variables + static Entity::ClassInfo m_sClass; + + // Position of the site/scene on the planet in the site selection menu view, relative to the center of the planet + Vector m_Location; + // Temporary location offset used to correct scene position when scene dots overlap. + Vector m_LocationOffset; + // Whether at all eligible for the Metagame + bool m_MetagamePlayable; + // Whether this is revealed on the metagame planet map yet or not + bool m_Revealed; + // Owned by which Team, if any (<0 if none) + int m_OwnedByTeam; + // Total income this place generates per Metagame round for its owner team + float m_RoundIncome; + // The special placed brain actors of each player that inhabit this Scene, OWNED here + SceneObject* m_ResidentBrains[Players::MaxPlayerCount]; + // Budget in oz this place is allocated per player for a metagame round for building (applying) blueprint objects. + float m_BuildBudget[Players::MaxPlayerCount]; + // Budget in ratio of the player for a metagame round. This is used to re-set the BuildBudget to match the ratio + // that a player budgeted to this site in the previous turn. + float m_BuildBudgetRatio[Players::MaxPlayerCount]; + // Whether this should be automatically designed by the AI Plan even if it's owned by a human player + bool m_AutoDesigned; + // The total amount of gold (in oz) that has been invested in the defenses of this site, by all teams + float m_TotalInvestment; + // Terrain definition + SLTerrain* m_pTerrain; + + // Pathfinding graph and logic. Owned by this + // The array of PathFinders for each team. Because we also have a shared pathfinder using index 0, we need to use MaxTeamCount + 1 to handle all the Teams' PathFinders. + std::array, Activity::Teams::MaxTeamCount + 1> m_pPathFinders; + // Is set to true on any frame the pathfinding data has been updated + bool m_PathfindingUpdated; + // Timer for when to do an update of the pathfinding data + Timer m_PartialPathUpdateTimer; + + // SceneObject:s to be placed in the scene, divided up by different sets - OWNED HERE + std::list m_PlacedObjects[PLACEDSETSCOUNT]; + // List of background layers, first is the closest to the terrain, last is closest to the back + std::list m_BackLayerList; + // Dimensions of the pixels of the unseen layers, when they are dynamically generated. If 0, the layer was not generated + Vector m_UnseenPixelSize[Activity::MaxTeamCount]; + // Layers representing the unknown areas for each team + SceneLayer* m_apUnseenLayer[Activity::MaxTeamCount]; + // Which pixels of the unseen map have just been revealed this frame, in the coordinates of the unseen map + std::list m_SeenPixels[Activity::MaxTeamCount]; + // Pixels on the unseen map deemed to be orphans and cleaned up, will be moved to seen pixels next update + std::list m_CleanedPixels[Activity::MaxTeamCount]; + // Whether this Scene is scheduled to be orbitally scanned by any team + bool m_ScanScheduled[Activity::MaxTeamCount]; + + // List of all the specified Area's of the scene + std::list m_AreaList; + + // List of navigatable areas in the scene. If this list is empty, the entire scene is assumed to be navigatable + std::vector m_NavigatableAreas; + bool m_NavigatableAreasUpToDate; + + // Whether the scene's bitmaps are locked or not. + bool m_Locked; + // The global acceleration vector in m/s^2. (think gravity/wind) + Vector m_GlobalAcc; + // Names of all Schemes and selected assemblies for them + std::map m_SelectedAssemblies; + // Amounts of limited assemblies + std::map m_AssembliesCounts; + // Scene preview bitmap + BITMAP* m_pPreviewBitmap; + // Scene preview source file + ContentFile m_PreviewBitmapFile; + // Name of a scene which can be replaced by this scene in MetaGame + // Scenes with m_MetaSceneParent field set will be invisible for editors and activities unless + // ShowMetaScenes flag in settings.ini is set + std::string m_MetasceneParent; + + // Whether this scene must be shown anywhere in UIs + bool m_IsMetagameInternal; + bool m_IsSavedGameInternal; + + std::list m_Deployments; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + /// + /// Gets the pathfinder for a given team. + /// + /// The team to get the pathfinder for. NoTeam is valid, and will give a shared pathfinder. + /// A pointer to the pathfinder for the given team. + std::unique_ptr& GetPathFinder(Activity::Teams team); - - /// - /// Gets the total dimensions (width and height) of the scene, in pixels. - /// - /// A Vector describing the scene dimensions. - Vector GetDimensions() const; - - /// - /// Gets the total width of the scene, in pixels. - /// - /// An int describing the scene width. - int GetWidth() const; - - /// - /// Gets the total height of the scene, in pixels. - /// - /// An int describing the scene height. - int GetHeight() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapsX -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the scene wraps its scrolling around the X axis. -// Arguments: None. -// Return value: Whether the scene wraps around the X axis or not. - - bool WrapsX() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapsY -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the scene wraps its scrolling around the Y axis. -// Arguments: None. -// Return value: Whether the scene wraps around the Y axis or not. - - bool WrapsY() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PlaceResidentBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Places the individual brain of a single player which may be stationed -// on this Scene, and registers them as such in an Activity. -// Arguments: The player's brain to place. -// The Activity to register the placed brains with. OWNERSHIP IS NOT TRANSFERRED! -// Return value: If the brain was successfully found as resident and placed. - - bool PlaceResidentBrain(int player, Activity &newActivity); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PlaceResidentBrains -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Places the individual brains of the various players which may be -// stationed on this Scene, and registers them as such in an Activity. -// Arguments: The Activity to register the placed brains with. OWNERSHIP IS NOT TRANSFERRED! -// Return value: How many brains were finally placed. - - int PlaceResidentBrains(Activity &newActivity); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RetrieveResidentBrains -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Looks at the Activity and its players' registered brain Actors, and -// saves them as resident brains for this Scene. Done when a fight is over -// and the survivors remain! -// Arguments: The Activity to check for registered brains. OWNERSHIP IS NOT TRANSFERRED! -// Return value: How many brains were found registered with the passed in Activity. - - int RetrieveResidentBrains(Activity &oldActivity); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RetrieveSceneObjects -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sucks up all the Actors, Items and Particles currently active in MovableMan and -// puts them into this' list of objects to place on next load. -// Arguments: The team to only retrieve Actors of. If NoTeam, then all will be grabbed. -// Whether to not get any brains at all. -// Return value: How many objects were found knocking about in the world, and stored. - - int RetrieveSceneObjects(bool transferOwnership, int onlyTeam = -1, bool noBrains = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlacedObjects -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of SceneObject:s which are placed in this scene on loading. -// Arguments: Which set of placed objects to get. See the PlacedObjectSets enum. -// Return value: The list of of placed objects. Ownership is NOT transferred! - - const std::list * GetPlacedObjects(int whichSet) const { return &m_PlacedObjects[whichSet]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a SceneObject to be placed in this scene. Ownership IS transferred! -// Arguments: Which set of placed objects to add to. See the PlacedObjectSets enum. -// The SceneObject instance to add, OIT! -// Where in the list the object should be inserted. -1 means at the end -// of the list. -// Return value: None. - - void AddPlacedObject(int whichSet, SceneObject *pObjectToAdd, int listOrder = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemovePlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a SceneObject placed in this scene. -// Arguments: Which set of placed objects to rem from. See the PlacedObjectSets enum. -// The list order number of the object to remove. If -1, the last one is removed. -// Return value: None. - - void RemovePlacedObject(int whichSet, int whichToRemove = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PickPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the last placed object that graphically overlaps an absolute -// point in the scene. -// Arguments: Which set of placed objects to pick from. See the PlacedObjectSets enum. -// The point in absolute scene coordinates that will be used to pick the -// last placed SceneObject which overlaps it. -// An int which will be filled out with the order place of any found object -// in the list. if nothing is found, it will get a value of -1. -// Return value: The last hit SceneObject, if any. Ownership is NOT transferred! - - const SceneObject * PickPlacedObject(int whichSet, Vector &scenePoint, int *pListOrderPlace = 0) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PickPlacedActorInRange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the last placed actor object that is closer than range to scenePoint -// -// Arguments: Which set of placed objects to pick from. See the PlacedObjectSets enum. -// The point in absolute scene coordinates that will be used to pick the -// closest placed SceneObject near it. -// The range to check for nearby objects. -// An int which will be filled out with the order place of any found object -// in the list. if nothing is found, it will get a value of -1. -// -// Return value: The closest actor SceneObject, if any. Ownership is NOT transferred! - -const SceneObject * PickPlacedActorInRange(int whichSet, Vector &scenePoint, int range, int *pListOrderPlace) const; - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePlacedObjects -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updated the objects in the placed scene objects list of this. This is -// mostly for the editor to represent the items correctly. -// Arguments: Which set of placed objects to update. See the PlacedObjectSets enum. -// Return value: None. - - void UpdatePlacedObjects(int whichSet); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearPlacedObjectSet -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes all entries in a specific set of placed Objects. -// Arguments: Which set of placed objects to clear. See the PlacedObjectSets enum. -// Whether or not we have ownership of these items, and should delete them. -// Return value: How many things were removed in teh process of clearing that set. - - int ClearPlacedObjectSet(int whichSet, bool weHaveOwnership = true); - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetResidentBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the resident brain Actor of a specific player from this scene, -// if there is any. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: Which player to get the resident brain of. -// Return value: The SO containing the brain, or 0 if there aren't any of that player. - - SceneObject * GetResidentBrain(int player) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetResidentBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the resident brain Actor of a specific player from this scene, -// if there is any. Ownership IS transferred! -// Arguments: Which player to set the resident brain of. -// The Actor to set as the resident brain of the specified player. -// Return value: None. - - void SetResidentBrain(int player, SceneObject *pNewBrain); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetResidentBrainCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of brains currently residing in this scene. -// Arguments: None. -// Return value: The number of resident brains who are installed here. - - int GetResidentBrainCount() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds one or modifies an existing area of this Scene. -// Arguments: The area to add or modify of the same name in this Scene. Ownership is -// NOT transferred! -// Return value: Whether the specified area was previously defined in this scene. - - bool SetArea(Area &newArea); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks for the existence of a specific Area identified by a name. -// This won't throw any errors to the console if the Area isn't found. -// Arguments: The name of the Area to try to find in this Scene. -// Return value: Whether the specified area is defined in this Scene. - - bool HasArea(std::string areaName); - - /// - /// Gets a specified Area identified by name. Ownership is NOT transferred! - /// - /// The name of the Area to try to get. - /// Whether the area is required, and should throw an error if not found. - /// A pointer to the Area asked for, or nullptr if no Area of that name was found. - Area * GetArea(const std::string_view &areaName, bool required); - - /// - /// Gets a specified Area identified by name. Ownership is NOT transferred! - /// - /// The name of the Area to try to get. - /// A pointer to the Area asked for, or nullptr if no Area of that name was found. - Area* GetArea(const std::string &areaName) { return GetArea(areaName, true); } - - /// - /// Gets a specified Area identified by name, showing a Lua warning if it's not found. Ownership is NOT transferred! - /// Using this function will not add the area to the list of required areas which Scenario GUI uses to show compatible areas. - /// - /// The name of the Area to try to get. - /// A pointer to the Area asked for, or nullptr if no Area of that name was found. - Area * GetOptionalArea(const std::string &areaName) { return GetArea(areaName, false); } - - void AddNavigatableArea(const std::string &areaName) { m_NavigatableAreas.push_back(areaName); m_NavigatableAreasUpToDate = false; } - void ClearNavigatableAreas(const std::string &areaName) { m_NavigatableAreas.clear(); m_NavigatableAreasUpToDate = false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a specific Area identified by a name. -// Arguments: The name of the Area to try to remove. -// Return value: Whether an Area of that name was found, and subsequently removed. - - bool RemoveArea(std::string areaName); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WithinArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if a point is within a specific named Area of this Scene. If -// no Area of the name is found, this just returns false without error. -// Arguments: The name of the Area to try to check against. -// The point to see if it's within the specified Area. -// Return value: Whether any Area of that name was found, AND the point falls within it. - - bool WithinArea(std::string areaName, const Vector &point) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGlobalAcc -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the global acceleration (in m/s^2) that is applied to all movable -// objects' velocities during every frame. Typically models gravity. -// Arguments: None. -// Return value: A Vector describing the global acceleration. - - Vector GetGlobalAcc() const { return m_GlobalAcc; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetGlobalAcc -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the global acceleration (in m/s^2) that is applied to all movable -// objects' velocities during every frame. Typically models gravity. -// Arguments: A Vector describing the global acceleration. -// Return value: None. - - void SetGlobalAcc(Vector newValue) { m_GlobalAcc = newValue; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMetasceneParent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns parent scene name of this metascene. -// Arguments: None. -// Return value: Name of a parent scene. - - std::string GetMetasceneParent() const { return m_MetasceneParent; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLocation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the specified location of this Scene in the scene -// Arguments: A Vector with the desired location of this Scene in the scene. -// Return value: None. - - void SetLocation(const Vector& newLocation) { m_Location = newLocation; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMetagamePlayable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this can be played in the Metagame map at all. -// Arguments: Whether this is compatible with metagame play at all. -// Return value: None. - - void SetMetagamePlayable(bool isPlayable) { m_MetagamePlayable = isPlayable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetRevealed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this should show up on the Metagame map yet. -// Arguments: Whether to reveal this on the metagame map or not. -// Return value: None. - - void SetRevealed(bool isRevealed) { m_Revealed = isRevealed; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTeamOwnership -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the team who owns this Scene in a Metagame -// Arguments: The team who should now own this Scene -// Return value: None. - - void SetTeamOwnership(int newTeam); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBuildBudget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets how much gold this Scene is budgeted to be built for this round. -// Arguments: The player whom is setting the budget. -// The budget in oz that this is allocated to have built for this round. -// Return value: None. - - void SetBuildBudget(int player, float budget) { m_BuildBudget[player] = budget; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetBuildBudgetRatio -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets how much of a player's budget this Scene is budgeted to be build -// for each turn. -// Arguments: The player whom is setting the budget ratio. -// The budget in normalized ratio that this is allocated of the total. -// Return value: None. - - void SetBuildBudgetRatio(int player, float budgetRatio) { m_BuildBudgetRatio[player] = budgetRatio; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalcBuildBudgetUse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Figure out exactly how much of the build budget would be used if -// as many blueprint objects as can be afforded and exists would be built. -// Arguments: The player for whom we are calculating this budget use. -// An optional int that will be filled with number of objects that can -// acutally be built. -// An optional int that will be filled with number of objects that can -// built out of the AI plan set, AFTER the blueprints are built. -// Return value: The amount of funds that would be applied to the building of objects. - - float CalcBuildBudgetUse(int player, int *pAffordCount = 0, int *pAffordAIPlanCount = 0) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyAIPlan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Puts the pre-built AI base plan into effect by transferring as many -// pieces as the current base budget allows from the AI plan to the actual -// blueprints to be built at this Scene. -// Arguments: The AI player whom is putting his plans into motion. -// An optional int that will be filled with number of objects that were -// acutally moved from the AI plan to the blueprints. -// Return value: The value of the AI plan objects that were put onto the blueprints. - - float ApplyAIPlan(int player, int *pObjectsApplied = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyBuildBudget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Actually builds as many objects in the specific player's Blueprint -// list as can be afforded by his build budget. The budget is deducted -// accordingly. -// Arguments: The player whom is using his budget. -// An optional int that will be filled with number of objects that were -// acutally built. -// Return value: The amount of funds that were applied to the building of objects. - - float ApplyBuildBudget(int player, int *pObjectsBuilt = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveAllPlacedActors -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Remove all actors that are in the placed set of objects to load for -// this scene. All except for an optionally specified team, that is. -// Arguments: Remove all actors but of this team. -// Return value: How many actors were actually removed. - - int RemoveAllPlacedActors(int exceptTeam = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOwnerOfAllDoors -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the ownership of all doors placed in this scene to a specific team -// Arguments: The team to change the ownership to -// The player which placed these doors. -// Return value: How many doors were actually affected. - - int SetOwnerOfAllDoors(int team, int player); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsScanScheduled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a specific team has scheduled an orbital Scan of this. -// Arguments: The team to check for. -// Return value: Whether the scan has been scheduled and paid for. - - bool IsScanScheduled(int team) const { return m_ScanScheduled[team]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetScheduledScan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this to be orbitally scanned by a specific team on next load. -// Arguments: The team to schedule the scan for. -// Whether to actually schedule the scan or clear it. -// Return value: None. - - void SetScheduledScan(int team, bool scan = true) { m_ScanScheduled[team] = scan; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ResetPathFinding -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Recalculates all of the pathfinding data. This is very expensive, so -// do very rarely! -// Arguments: None. -// Return value: None. - - void ResetPathFinding(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BlockUntilAllPathingRequestsComplete -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Blocks this thread until all pathing requests are completed. -// Arguments: None. -// Return value: None. - - void BlockUntilAllPathingRequestsComplete(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePathFinding -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Recalculates only the areas of the pathfinding data that have been -// marked as outdated. -// Arguments: None. -// Return value: None. - - void UpdatePathFinding(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PathFindingUpdated -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether the pathfinding data has been updated in the last frame. -// Arguments: None. -// Return value: Whether the pathfinding data was recalculated fully or partially. - - bool PathFindingUpdated() { return m_PathfindingUpdated; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculatePath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates and returns the least difficult path between two points on -// the current scene. Takes both distance and materials into account. -// When pathing using the NoTeam pathFinder, no doors are considered passable. -// Arguments: Start and end positions on the scene to find the path between. -// A list which will be filled out with waypoints between the start and end. -// The maximum material strength any actor traveling along the path can dig through. -// The team we're pathing for (doors for this team will be considered passable) -// Return value: The total minimum difficulty cost calculated between the two points on -// the scene. - - float CalculatePath(const Vector &start, const Vector &end, std::list &pathResult, float digStrength = c_PathFindingDefaultDigStrength, Activity::Teams team = Activity::Teams::NoTeam); - - /// - /// Asynchronously calculates the least difficult path between two points on the current Scene. Takes both distance and materials into account. - /// When pathing using the NoTeam pathFinder, no doors are considered passable. - /// - /// Start position of the pathfinding request. - /// End position of the pathfinding request. - /// The maximum material strength any actor traveling along the path can dig through. - /// The team we're pathing for (doors for this team will be considered passable) - /// A shared pointer to the volatile PathRequest to be used to track whehter the asynchrnous path calculation has been completed, and check its results. - std::shared_ptr CalculatePathAsync(const Vector &start, const Vector &end, float digStrength = c_PathFindingDefaultDigStrength, Activity::Teams team = Activity::Teams::NoTeam, PathCompleteCallback callback = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetScenePathSize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how many waypoints there are in the ScenePath currently -// Arguments: None. -// Return value: The number of waypoints in the ScenePath. - - int GetScenePathSize() const; - - std::list& GetScenePath(); - - /// - /// Returns whether two position represent the same path nodes. - /// - /// First coordinates to compare. - /// Second coordinates to compare. - /// Whether both coordinates represent the same path node. - bool PositionsAreTheSamePathNode(const Vector &pos1, const Vector &pos2) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Lock -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Locks all dynamic internal scene bitmaps so that manipulaitons of the -// scene's color and matter representations can take place. -// Doing it in a separate method like this is more efficient because -// many bitmap manipulaitons can be performed between a lock and unlock. -// UnlockScene() should always be called after accesses are completed. -// Arguments: None. -// Return value: None. - - void Lock(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Unlock -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Unlocks the scene's bitmaps and prevents access to display memory. -// Doing it in a separate method like this is more efficient because -// many bitmap accesses can be performed between a lock and an unlock. -// UnlockScene() should only be called after LockScene(). -// Arguments: None. -// Return value: None. - - void Unlock(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsLocked -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the entire scene is currently locked or not. -// Arguments: None. -// Return value: Whether the entire scene is currently locked or not. - - bool IsLocked() const { return m_Locked; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Scene. Supposed to be done every frame -// before drawing. -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsMetagameInternal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Whether this scene is a temprorary metagame scene and should -// not be used anywhere except in metagame. -// Arguments: None. -// Return value: Whether scene belongs to metagame or not. - - bool IsMetagameInternal() const { return m_IsMetagameInternal; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMetagameInternal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this scene is a temprorary metagame scene and should -// not be used anywhere except in metagame. -// Arguments: New value. -// Return value: None. - - void SetMetagameInternal(bool newValue) { m_IsMetagameInternal = newValue; } - - - /// - /// Gets whether this Scene is a saved game Scene copy and should not be used anywhere except for game saving and loading. - /// - /// Whether this Scene is a saved game Scene copy. - bool IsSavedGameInternal() const { return m_IsSavedGameInternal; } - - /// - /// Sets whether this Scene is a saved game Scene copy and should not be used anywhere except for game saving and loading. - /// - /// Whether this Scene is a saved game Scene copy. - void SetSavedGameInternal(bool newValue) { m_IsSavedGameInternal = newValue; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPreviewBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns preview bitmap pointer for this scene. -// Arguments: None. -// Return value: Pointer to preview bitmap. - - BITMAP * GetPreviewBitmap() const { return m_pPreviewBitmap; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Member variables - static Entity::ClassInfo m_sClass; - - // Position of the site/scene on the planet in the site selection menu view, relative to the center of the planet - Vector m_Location; - // Temporary location offset used to correct scene position when scene dots overlap. - Vector m_LocationOffset; - // Whether at all eligible for the Metagame - bool m_MetagamePlayable; - // Whether this is revealed on the metagame planet map yet or not - bool m_Revealed; - // Owned by which Team, if any (<0 if none) - int m_OwnedByTeam; - // Total income this place generates per Metagame round for its owner team - float m_RoundIncome; - // The special placed brain actors of each player that inhabit this Scene, OWNED here - SceneObject *m_ResidentBrains[Players::MaxPlayerCount]; - // Budget in oz this place is allocated per player for a metagame round for building (applying) blueprint objects. - float m_BuildBudget[Players::MaxPlayerCount]; - // Budget in ratio of the player for a metagame round. This is used to re-set the BuildBudget to match the ratio - // that a player budgeted to this site in the previous turn. - float m_BuildBudgetRatio[Players::MaxPlayerCount]; - // Whether this should be automatically designed by the AI Plan even if it's owned by a human player - bool m_AutoDesigned; - // The total amount of gold (in oz) that has been invested in the defenses of this site, by all teams - float m_TotalInvestment; - // Terrain definition - SLTerrain *m_pTerrain; - - // Pathfinding graph and logic. Owned by this - // The array of PathFinders for each team. Because we also have a shared pathfinder using index 0, we need to use MaxTeamCount + 1 to handle all the Teams' PathFinders. - std::array, Activity::Teams::MaxTeamCount + 1> m_pPathFinders; - // Is set to true on any frame the pathfinding data has been updated - bool m_PathfindingUpdated; - // Timer for when to do an update of the pathfinding data - Timer m_PartialPathUpdateTimer; - - // SceneObject:s to be placed in the scene, divided up by different sets - OWNED HERE - std::list m_PlacedObjects[PLACEDSETSCOUNT]; - // List of background layers, first is the closest to the terrain, last is closest to the back - std::list m_BackLayerList; - // Dimensions of the pixels of the unseen layers, when they are dynamically generated. If 0, the layer was not generated - Vector m_UnseenPixelSize[Activity::MaxTeamCount]; - // Layers representing the unknown areas for each team - SceneLayer *m_apUnseenLayer[Activity::MaxTeamCount]; - // Which pixels of the unseen map have just been revealed this frame, in the coordinates of the unseen map - std::list m_SeenPixels[Activity::MaxTeamCount]; - // Pixels on the unseen map deemed to be orphans and cleaned up, will be moved to seen pixels next update - std::list m_CleanedPixels[Activity::MaxTeamCount]; - // Whether this Scene is scheduled to be orbitally scanned by any team - bool m_ScanScheduled[Activity::MaxTeamCount]; - - // List of all the specified Area's of the scene - std::list m_AreaList; - - // List of navigatable areas in the scene. If this list is empty, the entire scene is assumed to be navigatable - std::vector m_NavigatableAreas; - bool m_NavigatableAreasUpToDate; - - // Whether the scene's bitmaps are locked or not. - bool m_Locked; - // The global acceleration vector in m/s^2. (think gravity/wind) - Vector m_GlobalAcc; - // Names of all Schemes and selected assemblies for them - std::map m_SelectedAssemblies; - // Amounts of limited assemblies - std::map m_AssembliesCounts; - // Scene preview bitmap - BITMAP * m_pPreviewBitmap; - // Scene preview source file - ContentFile m_PreviewBitmapFile; - // Name of a scene which can be replaced by this scene in MetaGame - // Scenes with m_MetaSceneParent field set will be invisible for editors and activities unless - // ShowMetaScenes flag in settings.ini is set - std::string m_MetasceneParent; - - // Whether this scene must be shown anywhere in UIs - bool m_IsMetagameInternal; - bool m_IsSavedGameInternal; - - std::listm_Deployments; - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - /// - /// Gets the pathfinder for a given team. - /// - /// The team to get the pathfinder for. NoTeam is valid, and will give a shared pathfinder. - /// A pointer to the pathfinder for the given team. - std::unique_ptr & GetPathFinder(Activity::Teams team); - - /// - /// Serializes the SceneObject via the Writer. Necessary because full serialization doesn't know how to deal with duplicate properties. - /// - /// The Writer being used for serialization. - /// The SceneObject to save. - /// Convenience flag for whether or not this SceneObject is a child Attachable, and certain properties shouldn't be saved. - /// Whether or not to save most data. Turned off for stuff like SceneEditor saves. - void SaveSceneObject(Writer &writer, const SceneObject *sceneObjectToSave, bool isChildAttachable, bool saveFullData) const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this Scene, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - // Disallow the use of some implicit methods. - Scene(const Scene &reference) = delete; - void operator=(const Scene &rhs) = delete; - -}; + /// + /// Serializes the SceneObject via the Writer. Necessary because full serialization doesn't know how to deal with duplicate properties. + /// + /// The Writer being used for serialization. + /// The SceneObject to save. + /// Convenience flag for whether or not this SceneObject is a child Attachable, and certain properties shouldn't be saved. + /// Whether or not to save most data. Turned off for stuff like SceneEditor saves. + void SaveSceneObject(Writer& writer, const SceneObject* sceneObjectToSave, bool isChildAttachable, bool saveFullData) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this Scene, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + Scene(const Scene& reference) = delete; + void operator=(const Scene& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Entities/SceneLayer.cpp b/Source/Entities/SceneLayer.cpp index b86189f10..ac2b6804c 100644 --- a/Source/Entities/SceneLayer.cpp +++ b/Source/Entities/SceneLayer.cpp @@ -13,7 +13,7 @@ namespace RTE { ConcreteClassInfo(SceneLayerTracked, Entity, 0); ConcreteClassInfo(SceneLayer, Entity, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template void SceneLayerImpl::Clear() { @@ -34,10 +34,10 @@ namespace RTE { m_ScaledDimensions.SetXY(1.0F, 1.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - int SceneLayerImpl::Create(const ContentFile &bitmapFile, bool drawMasked, const Vector &offset, bool wrapX, bool wrapY, const Vector &scrollInfo) { + int SceneLayerImpl::Create(const ContentFile& bitmapFile, bool drawMasked, const Vector& offset, bool wrapX, bool wrapY, const Vector& scrollInfo) { m_BitmapFile = bitmapFile; m_MainBitmap = m_BitmapFile.GetAsBitmap(); Create(m_MainBitmap, drawMasked, offset, wrapX, wrapY, scrollInfo); @@ -47,10 +47,10 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - int SceneLayerImpl::Create(BITMAP *bitmap, bool drawMasked, const Vector &offset, bool wrapX, bool wrapY, const Vector &scrollInfo) { + int SceneLayerImpl::Create(BITMAP* bitmap, bool drawMasked, const Vector& offset, bool wrapX, bool wrapY, const Vector& scrollInfo) { m_MainBitmap = bitmap; RTEAssert(m_MainBitmap, "Null bitmap passed in when creating SceneLayerImpl!"); @@ -70,10 +70,10 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - int SceneLayerImpl::Create(const SceneLayerImpl &reference) { + int SceneLayerImpl::Create(const SceneLayerImpl& reference) { Entity::Create(reference); m_BitmapFile = reference.m_BitmapFile; @@ -88,7 +88,7 @@ namespace RTE { if (reference.m_MainBitmap) { // Make a copy of the bitmap because it can be modified in some use cases. - BITMAP *bitmapToCopy = reference.m_MainBitmap; + BITMAP* bitmapToCopy = reference.m_MainBitmap; RTEAssert(bitmapToCopy, "Couldn't load the bitmap file specified for SceneLayerImpl!"); m_MainBitmap = create_bitmap_ex(bitmap_color_depth(bitmapToCopy), bitmapToCopy->w, bitmapToCopy->h); @@ -108,24 +108,23 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - int SceneLayerImpl::ReadProperty(const std::string_view &propName, Reader &reader) { + int SceneLayerImpl::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("WrapX", { reader >> m_WrapX; }); MatchProperty("WrapY", { reader >> m_WrapY; }); MatchProperty("BitmapFile", { reader >> m_BitmapFile; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - int SceneLayerImpl::Save(Writer &writer) const { + int SceneLayerImpl::Save(Writer& writer) const { Entity::Save(writer); writer.NewPropertyWithValue("WrapX", m_WrapX); @@ -135,17 +134,23 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template void SceneLayerImpl::Destroy(bool notInherited) { - if (m_MainBitmapOwned) { destroy_bitmap(m_MainBitmap); } - if (m_BackBitmap) { destroy_bitmap(m_BackBitmap); } - if (!notInherited) { Entity::Destroy(); } + if (m_MainBitmapOwned) { + destroy_bitmap(m_MainBitmap); + } + if (m_BackBitmap) { + destroy_bitmap(m_BackBitmap); + } + if (!notInherited) { + Entity::Destroy(); + } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template void SceneLayerImpl::InitScrollRatios(bool initForNetworkPlayer, int player) { @@ -183,7 +188,7 @@ namespace RTE { m_ScaledDimensions.SetXY(mainBitmapWidth * m_ScaleFactor.GetX(), mainBitmapHeight * m_ScaleFactor.GetY()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template int SceneLayerImpl::LoadData() { @@ -198,20 +203,20 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - int SceneLayerImpl::SaveData(const std::string &bitmapPath, bool doAsyncSaves) { + int SceneLayerImpl::SaveData(const std::string& bitmapPath, bool doAsyncSaves) { if (bitmapPath.empty()) { return -1; } if (m_MainBitmap) { // Make a copy of the bitmap to pass to the thread because the bitmap may be offloaded mid thread and everything will be on fire. - BITMAP *outputBitmap = create_bitmap_ex(bitmap_color_depth(m_MainBitmap), m_MainBitmap->w, m_MainBitmap->h); + BITMAP* outputBitmap = create_bitmap_ex(bitmap_color_depth(m_MainBitmap), m_MainBitmap->w, m_MainBitmap->h); blit(m_MainBitmap, outputBitmap, 0, 0, 0, 0, m_MainBitmap->w, m_MainBitmap->h); - auto saveLayerBitmap = [bitmapPath, doAsyncSaves](BITMAP *bitmapToSave) { + auto saveLayerBitmap = [bitmapPath, doAsyncSaves](BITMAP* bitmapToSave) { PALETTE palette; get_palette(palette); if (save_png(bitmapPath.c_str(), bitmapToSave, palette) != 0) { @@ -222,7 +227,7 @@ namespace RTE { m_BitmapFile.SetDataPath(bitmapPath); if (doAsyncSaves) { - g_ActivityMan.GetSaveGameTask().push_back( g_ThreadMan.GetBackgroundThreadPool().submit(saveLayerBitmap, outputBitmap) ); + g_ActivityMan.GetSaveGameTask().push_back(g_ThreadMan.GetBackgroundThreadPool().submit(saveLayerBitmap, outputBitmap)); } else { saveLayerBitmap(outputBitmap); } @@ -230,30 +235,36 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template int SceneLayerImpl::ClearData() { - if (m_MainBitmap && m_MainBitmapOwned) { destroy_bitmap(m_MainBitmap); } + if (m_MainBitmap && m_MainBitmapOwned) { + destroy_bitmap(m_MainBitmap); + } m_MainBitmap = nullptr; m_MainBitmapOwned = false; - if (m_BackBitmap) { destroy_bitmap(m_BackBitmap); } + if (m_BackBitmap) { + destroy_bitmap(m_BackBitmap); + } m_BackBitmap = nullptr; m_LastClearColor = ColorKeys::g_InvalidColor; return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - void SceneLayerImpl::SetScaleFactor(const Vector &newScale) { + void SceneLayerImpl::SetScaleFactor(const Vector& newScale) { m_ScaleFactor = newScale; - if (m_MainBitmap) { m_ScaledDimensions.SetXY(static_cast(m_MainBitmap->w) * newScale.GetX(), static_cast(m_MainBitmap->h) * newScale.GetY()); } + if (m_MainBitmap) { + m_ScaledDimensions.SetXY(static_cast(m_MainBitmap->w) * newScale.GetX(), static_cast(m_MainBitmap->h) * newScale.GetY()); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template int SceneLayerImpl::GetPixel(int pixelX, int pixelY) const { @@ -261,7 +272,7 @@ namespace RTE { return (pixelX < 0 || pixelX >= m_MainBitmap->w || pixelY < 0 || pixelY >= m_MainBitmap->h) ? MaterialColorKeys::g_MaterialAir : _getpixel(m_MainBitmap, pixelX, pixelY); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template void SceneLayerImpl::SetPixel(int pixelX, int pixelY, int materialID) { @@ -277,14 +288,14 @@ namespace RTE { RegisterDrawing(pixelX, pixelY, pixelX, pixelY); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template bool SceneLayerImpl::IsWithinBounds(const int pixelX, const int pixelY, const int margin) const { return (m_WrapX || (pixelX >= -margin && pixelX < m_MainBitmap->w + margin)) && (m_WrapY || (pixelY >= -margin && pixelY < m_MainBitmap->h + margin)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template void SceneLayerImpl::ClearBitmap(ColorKeys clearTo) { @@ -303,18 +314,19 @@ namespace RTE { std::swap(m_MainBitmap, m_BackBitmap); // Start a new thread to clear the backbuffer bitmap asynchronously. - m_BitmapClearTask = g_ThreadMan.GetPriorityThreadPool().submit([this, clearTo](BITMAP *bitmap, std::vector drawings) { + m_BitmapClearTask = g_ThreadMan.GetPriorityThreadPool().submit([this, clearTo](BITMAP* bitmap, std::vector drawings) { ZoneScopedN("Clear Tracked Backbuffer"); ClearDrawings(bitmap, drawings, clearTo); - }, m_BackBitmap, m_Drawings); + }, + m_BackBitmap, m_Drawings); m_Drawings.clear(); // This was copied into the new thread, so can be safely deleted. } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - bool SceneLayerImpl::WrapPosition(int &posX, int &posY) const { + bool SceneLayerImpl::WrapPosition(int& posX, int& posY) const { int oldX = posX; int oldY = posY; @@ -337,10 +349,10 @@ namespace RTE { return oldX != posX || oldY != posY; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - bool SceneLayerImpl::ForceBounds(int &posX, int &posY) const { + bool SceneLayerImpl::ForceBounds(int& posX, int& posY) const { bool wrapped = false; int width = m_ScaledDimensions.GetFloorIntX(); int height = m_ScaledDimensions.GetFloorIntY(); @@ -384,10 +396,10 @@ namespace RTE { return wrapped; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - bool SceneLayerImpl::ForceBoundsOrWrapPosition(Vector &pos, bool forceBounds) const { + bool SceneLayerImpl::ForceBoundsOrWrapPosition(Vector& pos, bool forceBounds) const { int posX = pos.GetFloorIntX(); int posY = pos.GetFloorIntY(); bool wrapped = forceBounds ? ForceBounds(posX, posY) : WrapPosition(posX, posY); @@ -396,7 +408,7 @@ namespace RTE { return wrapped; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template void SceneLayerImpl::RegisterDrawing(int left, int top, int right, int bottom) { @@ -405,25 +417,33 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - void SceneLayerImpl::RegisterDrawing(const Vector ¢er, float radius) { + void SceneLayerImpl::RegisterDrawing(const Vector& center, float radius) { if (radius != 0.0F) { RegisterDrawing(static_cast(center.GetX() - radius), static_cast(center.GetY() - radius), static_cast(center.GetX() + radius), static_cast(center.GetY() + radius)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - void SceneLayerImpl::Draw(BITMAP *targetBitmap, Box &targetBox, bool offsetNeedsScrollRatioAdjustment) { + void SceneLayerImpl::Draw(BITMAP* targetBitmap, Box& targetBox, bool offsetNeedsScrollRatioAdjustment) { RTEAssert(m_MainBitmap, "Data of this SceneLayerImpl has not been loaded before trying to draw!"); - if (offsetNeedsScrollRatioAdjustment) { m_Offset.SetXY(std::floor(m_Offset.GetX() * m_ScrollRatio.GetX()), std::floor(m_Offset.GetY() * m_ScrollRatio.GetY())); } - if (targetBox.IsEmpty()) { targetBox = Box(Vector(), static_cast(targetBitmap->w), static_cast(targetBitmap->h)); } - if (!m_WrapX && static_cast(targetBitmap->w) > targetBox.GetWidth()) { m_Offset.SetX(0); } - if (!m_WrapY && static_cast(targetBitmap->h) > targetBox.GetHeight()) { m_Offset.SetY(0); } + if (offsetNeedsScrollRatioAdjustment) { + m_Offset.SetXY(std::floor(m_Offset.GetX() * m_ScrollRatio.GetX()), std::floor(m_Offset.GetY() * m_ScrollRatio.GetY())); + } + if (targetBox.IsEmpty()) { + targetBox = Box(Vector(), static_cast(targetBitmap->w), static_cast(targetBitmap->h)); + } + if (!m_WrapX && static_cast(targetBitmap->w) > targetBox.GetWidth()) { + m_Offset.SetX(0); + } + if (!m_WrapY && static_cast(targetBitmap->h) > targetBox.GetHeight()) { + m_Offset.SetY(0); + } m_Offset -= m_OriginOffset; WrapPosition(m_Offset); @@ -439,17 +459,17 @@ namespace RTE { set_clip_rect(targetBitmap, 0, 0, targetBitmap->w - 1, targetBitmap->h - 1); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - void SceneLayerImpl::DrawWrapped(BITMAP *targetBitmap, const Box &targetBox, bool drawScaled) const { + void SceneLayerImpl::DrawWrapped(BITMAP* targetBitmap, const Box& targetBox, bool drawScaled) const { if (!drawScaled) { - std::array sourcePosX = { m_Offset.GetFloorIntX(), 0 }; - std::array sourcePosY = { m_Offset.GetFloorIntY(), 0 }; - std::array sourceWidth = { m_MainBitmap->w - m_Offset.GetFloorIntX(), m_Offset.GetFloorIntX() }; - std::array sourceHeight = { m_MainBitmap->h - m_Offset.GetFloorIntY(), m_Offset.GetFloorIntY() }; - std::array destPosX = { targetBox.GetCorner().GetFloorIntX(), targetBox.GetCorner().GetFloorIntX() + m_MainBitmap->w - m_Offset.GetFloorIntX() }; - std::array destPosY = { targetBox.GetCorner().GetFloorIntY(), targetBox.GetCorner().GetFloorIntY() + m_MainBitmap->h - m_Offset.GetFloorIntY() }; + std::array sourcePosX = {m_Offset.GetFloorIntX(), 0}; + std::array sourcePosY = {m_Offset.GetFloorIntY(), 0}; + std::array sourceWidth = {m_MainBitmap->w - m_Offset.GetFloorIntX(), m_Offset.GetFloorIntX()}; + std::array sourceHeight = {m_MainBitmap->h - m_Offset.GetFloorIntY(), m_Offset.GetFloorIntY()}; + std::array destPosX = {targetBox.GetCorner().GetFloorIntX(), targetBox.GetCorner().GetFloorIntX() + m_MainBitmap->w - m_Offset.GetFloorIntX()}; + std::array destPosY = {targetBox.GetCorner().GetFloorIntY(), targetBox.GetCorner().GetFloorIntY() + m_MainBitmap->h - m_Offset.GetFloorIntY()}; for (int i = 0; i < 2; ++i) { for (int j = 0; j < 2; ++j) { @@ -461,10 +481,10 @@ namespace RTE { } } } else { - std::array sourceWidth = { m_MainBitmap->w, m_Offset.GetFloorIntX() / m_ScaleFactor.GetFloorIntX() }; - std::array sourceHeight = { m_MainBitmap->h, m_Offset.GetFloorIntY() / m_ScaleFactor.GetFloorIntY() }; - std::array destPosX = { targetBox.GetCorner().GetFloorIntX() - m_Offset.GetFloorIntX(), targetBox.GetCorner().GetFloorIntX() + m_ScaledDimensions.GetFloorIntX() - m_Offset.GetFloorIntX() }; - std::array destPosY = { targetBox.GetCorner().GetFloorIntY() - m_Offset.GetFloorIntY(), targetBox.GetCorner().GetFloorIntY() + m_ScaledDimensions.GetFloorIntY() - m_Offset.GetFloorIntY() }; + std::array sourceWidth = {m_MainBitmap->w, m_Offset.GetFloorIntX() / m_ScaleFactor.GetFloorIntX()}; + std::array sourceHeight = {m_MainBitmap->h, m_Offset.GetFloorIntY() / m_ScaleFactor.GetFloorIntY()}; + std::array destPosX = {targetBox.GetCorner().GetFloorIntX() - m_Offset.GetFloorIntX(), targetBox.GetCorner().GetFloorIntX() + m_ScaledDimensions.GetFloorIntX() - m_Offset.GetFloorIntX()}; + std::array destPosY = {targetBox.GetCorner().GetFloorIntY() - m_Offset.GetFloorIntY(), targetBox.GetCorner().GetFloorIntY() + m_ScaledDimensions.GetFloorIntY() - m_Offset.GetFloorIntY()}; for (int i = 0; i < 2; ++i) { for (int j = 0; j < 2; ++j) { @@ -478,10 +498,10 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - void SceneLayerImpl::DrawTiled(BITMAP *targetBitmap, const Box &targetBox, bool drawScaled) const { + void SceneLayerImpl::DrawTiled(BITMAP* targetBitmap, const Box& targetBox, bool drawScaled) const { int bitmapWidth = m_ScaledDimensions.GetFloorIntX(); int bitmapHeight = m_ScaledDimensions.GetFloorIntY(); int areaToCoverX = m_Offset.GetFloorIntX() + targetBox.GetCorner().GetFloorIntX() + std::min(targetBitmap->w, static_cast(targetBox.GetWidth())); @@ -518,12 +538,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - void SceneLayerImpl::ClearDrawings(BITMAP* bitmap, const std::vector &drawings, ColorKeys clearTo) const { + void SceneLayerImpl::ClearDrawings(BITMAP* bitmap, const std::vector& drawings, ColorKeys clearTo) const { if constexpr (TRACK_DRAWINGS) { - for (const IntRect &rect : drawings) { + for (const IntRect& rect: drawings) { int left = rect.m_Left; int top = rect.m_Top; int bottom = rect.m_Bottom; @@ -564,9 +584,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Force instantiation template class SceneLayerImpl; template class SceneLayerImpl; -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/SceneLayer.h b/Source/Entities/SceneLayer.h index 9b91cabe9..dfa8d3f4d 100644 --- a/Source/Entities/SceneLayer.h +++ b/Source/Entities/SceneLayer.h @@ -15,7 +15,6 @@ namespace RTE { friend class NetworkServer; public: - EntityAllocation(SceneLayerImpl); SerializableOverrideMethods; @@ -46,7 +45,7 @@ namespace RTE { /// A special command is if wrap is false and the corresponding component is -1.0, that signals that the own width or height should be used as scrollInfo input. /// /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const ContentFile &bitmapFile, bool drawMasked, const Vector &offset, bool wrapX, bool wrapY, const Vector &scrollInfo); + int Create(const ContentFile& bitmapFile, bool drawMasked, const Vector& offset, bool wrapX, bool wrapY, const Vector& scrollInfo); /// /// Makes the SceneLayer object ready for use. @@ -63,14 +62,14 @@ namespace RTE { /// A special command is if wrap is false and the corresponding component is -1.0, that signals that the own width or height should be used as scrollInfo input. /// /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(BITMAP *bitmap, bool drawMasked, const Vector &offset, bool wrapX, bool wrapY, const Vector &scrollInfo); + int Create(BITMAP* bitmap, bool drawMasked, const Vector& offset, bool wrapX, bool wrapY, const Vector& scrollInfo); /// /// Creates a SceneLayer to be identical to another, by deep copy. /// /// A reference to the SceneLayer to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const SceneLayerImpl &reference); + int Create(const SceneLayerImpl& reference); #pragma endregion #pragma region Destruction @@ -105,7 +104,7 @@ namespace RTE { /// The filepath to the where to save the bitmap data. /// Whether or not to save asynchronously. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - virtual int SaveData(const std::string &bitmapPath, bool doAsyncSaves = true); + virtual int SaveData(const std::string& bitmapPath, bool doAsyncSaves = true); /// /// Clears out any previously loaded bitmap data from memory. @@ -125,7 +124,7 @@ namespace RTE { /// Sets the scroll offset of this SceneLayer. Observe that this offset will be modified by the scroll ratio before applied. /// /// The new offset Vector. - void SetOffset(const Vector &newOffset) { m_Offset = newOffset; } + void SetOffset(const Vector& newOffset) { m_Offset = newOffset; } /// /// Gets the scroll ratio that modifies the offset. @@ -137,7 +136,7 @@ namespace RTE { /// Sets the scroll ratio of this SceneLayer. This modifies the offset before any actual scrolling occurs. /// /// The new scroll ratio vector. - void SetScrollRatio(const Vector &newRatio) { m_ScrollRatio = newRatio; } + void SetScrollRatio(const Vector& newRatio) { m_ScrollRatio = newRatio; } /// /// Gets the scale factor that this is drawn in. @@ -149,7 +148,7 @@ namespace RTE { /// Sets the scale that this should be drawn at when using DrawScaled. /// /// The new scale factor vector. - void SetScaleFactor(const Vector &newScale); + void SetScaleFactor(const Vector& newScale); /// /// Indicates whether the layer is set to wrap around the X axis when scrolled out of bounds. @@ -194,13 +193,15 @@ namespace RTE { /// Lock the internal bitmap so it can be accessed by GetPixel() etc. UnlockBitmaps() should always be called after accesses are completed. /// Doing it in a separate method like this is more efficient because many bitmap accesses can be performed between a lock and unlock. /// - void LockBitmaps() { /*acquire_bitmap(m_MainBitmap);*/ } + void LockBitmaps() { /*acquire_bitmap(m_MainBitmap);*/ + } /// /// Unlocks the internal bitmaps and prevents access to display memory. UnlockBitmaps() should only be called after LockBitmaps(). /// Doing it in a separate method like this is more efficient because many bitmap accesses can be performed between a lock and an unlock. /// - void UnlockBitmaps() { /*release_bitmap(m_MainBitmap);*/ } + void UnlockBitmaps() { /*release_bitmap(m_MainBitmap);*/ + } /// /// Clears our BITMAP. @@ -215,7 +216,7 @@ namespace RTE { /// The X coordinates of the position to wrap. /// The Y coordinates of the position to wrap. /// Whether wrapping was performed or not. - bool WrapPosition(int &posX, int &posY) const; + bool WrapPosition(int& posX, int& posY) const; /// /// Wraps the given position Vector if it is out of bounds of this SceneLayer and wrapping is enabled on the appropriate axes. @@ -223,7 +224,7 @@ namespace RTE { /// /// The vector coordinates of the position to wrap. /// Whether wrapping was performed or not. - bool WrapPosition(Vector &pos) const { return ForceBoundsOrWrapPosition(pos, false); } + bool WrapPosition(Vector& pos) const { return ForceBoundsOrWrapPosition(pos, false); } /// /// Wraps or bounds a position coordinate if it is out of bounds of the SceneLayer, depending on the wrap settings of this SceneLayer. @@ -231,14 +232,14 @@ namespace RTE { /// The X coordinates of the position to wrap. /// The Y coordinates of the position to wrap. /// Whether wrapping was performed or not. Does not report on bounding. - bool ForceBounds(int &posX, int &posY) const; + bool ForceBounds(int& posX, int& posY) const; /// /// Wraps or bounds a position coordinate if it is out of bounds of the SceneLayer, depending on the wrap settings of this SceneLayer. /// /// The Vector coordinates of the position to wrap. /// Whether wrapping was performed or not. Does not report on bounding. - bool ForceBounds(Vector &pos) const { return ForceBoundsOrWrapPosition(pos, true); } + bool ForceBounds(Vector& pos) const { return ForceBoundsOrWrapPosition(pos, true); } #pragma endregion #pragma region Drawing Tracking @@ -256,7 +257,7 @@ namespace RTE { /// /// The position of the center of the area to be drawn upon. /// The radius of the area to be drawn upon. - void RegisterDrawing(const Vector ¢er, float radius); + void RegisterDrawing(const Vector& center, float radius); #pragma endregion #pragma region Virtual Methods @@ -271,15 +272,14 @@ namespace RTE { /// The bitmap to draw to. /// The box on the target bitmap to limit drawing to, with the corner of box being where the scroll position lines up. /// Whether the offset of this SceneLayer or the passed in offset override need to be adjusted to scroll ratio. - virtual void Draw(BITMAP *targetBitmap, Box &targetBox, bool offsetNeedsScrollRatioAdjustment = false); + virtual void Draw(BITMAP* targetBitmap, Box& targetBox, bool offsetNeedsScrollRatioAdjustment = false); #pragma endregion protected: - ContentFile m_BitmapFile; //!< ContentFile containing the path to this SceneLayer's sprite file. - BITMAP *m_MainBitmap; //!< The main BITMAP of this SceneLayer. - BITMAP *m_BackBitmap; //!< The backbuffer BITMAP of this SceneLayer. + BITMAP* m_MainBitmap; //!< The main BITMAP of this SceneLayer. + BITMAP* m_BackBitmap; //!< The backbuffer BITMAP of this SceneLayer. // We use two bitmaps, as a backbuffer. While the main bitmap is being used, the secondary bitmap will be cleared on a separate thread. This is because we tend to want to clear some scene layers every frame and that is costly. std::future m_BitmapClearTask; //!< Task for clearing BITMAP async in background. @@ -313,7 +313,7 @@ namespace RTE { /// The Vector coordinates of the position to wrap. /// Whether to attempt bounding or wrapping, or just wrapping. /// Whether wrapping was performed or not. Does not report on bounding. - bool ForceBoundsOrWrapPosition(Vector &pos, bool forceBounds) const; + bool ForceBoundsOrWrapPosition(Vector& pos, bool forceBounds) const; #pragma region Draw Breakdown /// @@ -322,7 +322,7 @@ namespace RTE { /// The bitmap to draw to. /// The box on the target bitmap to limit drawing to, with the corner of box being where the scroll position lines up. /// Whether to use scaled drawing routines or not. - void DrawWrapped(BITMAP *targetBitmap, const Box &targetBox, bool drawScaled) const; + void DrawWrapped(BITMAP* targetBitmap, const Box& targetBox, bool drawScaled) const; /// /// Performs tiled drawing of this SceneLayer's bitmap to the screen in cases where the target bitmap is larger in some dimension. @@ -330,16 +330,15 @@ namespace RTE { /// The bitmap to draw to. /// The box on the target bitmap to limit drawing to, with the corner of box being where the scroll position lines up. /// Whether to use scaled drawing routines or not. - void DrawTiled(BITMAP *targetBitmap, const Box &targetBox, bool drawScaled) const; + void DrawTiled(BITMAP* targetBitmap, const Box& targetBox, bool drawScaled) const; #pragma endregion private: - /// /// Clears any tracked and drawn-to areas. /// /// Color to clear to. - void ClearDrawings(BITMAP *bitmap, const std::vector &drawings, ColorKeys clearTo) const; + void ClearDrawings(BITMAP* bitmap, const std::vector& drawings, ColorKeys clearTo) const; /// /// Clears all the member variables of this SceneLayer, effectively resetting the members of this abstraction level only. @@ -347,8 +346,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - SceneLayerImpl(const SceneLayerImpl &reference) = delete; - void operator=(const SceneLayerImpl &rhs) = delete; + SceneLayerImpl(const SceneLayerImpl& reference) = delete; + void operator=(const SceneLayerImpl& rhs) = delete; }; /// @@ -357,14 +356,14 @@ namespace RTE { class SceneLayerTracked : public SceneLayerImpl { public: - EntityAllocation(SceneLayerTracked); ClassInfoGetters; /// /// Constructor method used to instantiate a SceneLayerTracked object in system memory. Create() should be called before using the object. /// - SceneLayerTracked() : SceneLayerImpl() {} + SceneLayerTracked() : + SceneLayerImpl() {} // TODO: We shouldn't let external users access a non-const version of our bitmap. We should do all drawing to it internally, and track registering our MOID drawings internally too. // However, in the interest of time (and my own sanity), given that the old code already does this, we're not doing that yet. @@ -372,34 +371,32 @@ namespace RTE { /// Gets the BITMAP that this SceneLayer uses. /// /// A pointer to the BITMAP of this SceneLayer. Ownership is NOT transferred! - BITMAP * GetBitmap() const { return m_MainBitmap; } + BITMAP* GetBitmap() const { return m_MainBitmap; } protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. }; class SceneLayer : public SceneLayerImpl { public: - EntityAllocation(SceneLayer); ClassInfoGetters; /// /// Constructor method used to instantiate a SceneLayer object in system memory. Create() should be called before using the object. /// - SceneLayer() : SceneLayerImpl() {} + SceneLayer() : + SceneLayerImpl() {} /// /// Gets the BITMAP that this SceneLayer uses. /// /// A pointer to the BITMAP of this SceneLayer. Ownership is NOT transferred! - BITMAP * GetBitmap() const { return m_MainBitmap; } + BITMAP* GetBitmap() const { return m_MainBitmap; } protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/SceneObject.cpp b/Source/Entities/SceneObject.cpp index 1fd3df4dd..dbcb50ed8 100644 --- a/Source/Entities/SceneObject.cpp +++ b/Source/Entities/SceneObject.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,388 +18,351 @@ namespace RTE { -AbstractClassInfo(SceneObject, Entity); -const std::string SceneObject::SOPlacer::c_ClassName = "SOPlacer"; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this SOPlacer, effectively -// resetting the members of this abstraction level only. - -void SceneObject::SOPlacer::Clear() -{ - m_pObjectReference = 0; - m_Offset.Reset(); - m_RotAngle = 0; - m_HFlipped = false; - m_Team = Activity::NoTeam; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SOPlacer object ready for use. - -int SceneObject::SOPlacer::Create() -{ - if (Serializable::Create() < 0) - return -1; - - return 0; -} -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a SOPlacer to be identical to another, by deep copy. - -int SceneObject::SOPlacer::Create(const SOPlacer &reference) -{ - m_pObjectReference = reference.m_pObjectReference; - m_Offset = reference.m_Offset; - m_RotAngle = reference.m_RotAngle; - m_HFlipped = reference.m_HFlipped; - m_Team = reference.m_Team; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. - -int SceneObject::SOPlacer::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Serializable::ReadProperty(propName, reader)); - - MatchProperty("PlacedObject", - { - m_pObjectReference = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); - RTEAssert(m_pObjectReference, "Stream suggests allocating an unallocatable type in SOPlacer::Create!"); - }); - MatchProperty("Offset", { reader >> m_Offset; }); - MatchProperty("Rotation", - { - Matrix rot; - reader >> rot; - m_RotAngle = rot.GetRadAngle(); - }); - MatchProperty("HFlipped", { reader >> m_HFlipped; }); - MatchProperty("Team", { reader >> m_Team; }); - - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this SOPlacer with a Writer for -// later recreation with Create(Reader &reader); - -int SceneObject::SOPlacer::Save(Writer &writer) const -{ - Serializable::Save(writer); - - writer.NewProperty("PlacedObject"); - writer << m_pObjectReference; - writer.NewProperty("Offset"); - writer << m_Offset; -// TODO: make generalized way of detecting defaults - if (m_RotAngle != 0) - { - writer.NewProperty("Rotation"); - Matrix rot; - rot.SetRadAngle(m_RotAngle); - writer << rot; - } - if (m_HFlipped) - { - writer.NewProperty("HFlipped"); - writer << m_HFlipped; - } - if (m_Team >= Activity::TeamOne) - { - writer.NewProperty("Team"); - writer << m_Team; - } - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlacedCopy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes a copy of the preset instance, and applies the placement -// properties of this to it, finally returning it WITH OWNERSHIP. - -SceneObject * SceneObject::SOPlacer::GetPlacedCopy(const SceneObject *pParent) const -{ - RTEAssert(m_pObjectReference, "No Object reference to make copy from!"); - - SceneObject *pCopy = dynamic_cast(m_pObjectReference->Clone()); - if (pCopy) - { - // Make relative to the parent - if (pParent) - { - // Relative flipping (XOR) - bool placedFlip = (pParent->IsHFlipped() && m_HFlipped) ? false : (pParent->IsHFlipped() || m_HFlipped); - pCopy->SetHFlipped(placedFlip); - - // Relative rotation - Matrix placedRot(pParent->GetRotAngle() + m_RotAngle); - pCopy->SetRotAngle(placedRot.GetRadAngle()); - - // Relative position - pCopy->SetPos(pParent->GetPos() + m_Offset.GetXFlipped(pParent->IsHFlipped()) * pParent->GetRotMatrix()); - - // Relative team (parent overrides, if it has a set team) - if (pParent->GetTeam() >= 0) - pCopy->SetTeam(pParent->GetTeam()); - else - pCopy->SetTeam(m_Team); - } - // No parent to make relative from, so apply everything as aboslutes. - else - { - pCopy->SetHFlipped(m_HFlipped); - pCopy->SetRotAngle(m_RotAngle);//m_HFlipped ? -m_RotAngle : m_RotAngle); - pCopy->SetPos(m_Offset); - pCopy->SetTeam(m_Team); - } - } - - // Transfer ownership here - return pCopy; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this SceneObject, effectively -// resetting the members of this abstraction level only. - -void SceneObject::Clear() -{ - m_Pos.Reset(); - m_OzValue = 0; - m_Buyable = true; - m_BuyableMode = BuyableMode::NoRestrictions; - m_Team = Activity::NoTeam; - m_PlacedByPlayer = Players::NoPlayer; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SceneObject object ready for use. - -int SceneObject::Create() -{ - if (Entity::Create() < 0) - return -1; - - return 0; -} -*/ -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SceneObject object ready for use. - -int SceneObject::Create() -{ - - return 0; -} -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates an SceneObject object to be identical to another, by deep copy. - -int SceneObject::Create(const SceneObject &reference) -{ - Entity::Create(reference); - - m_Pos = reference.m_Pos; - m_OzValue = reference.m_OzValue; - m_Buyable = reference.m_Buyable; - m_BuyableMode = reference.m_BuyableMode; - m_Team = reference.m_Team; - m_PlacedByPlayer = reference.m_PlacedByPlayer; - - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a Reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the Reader's position is untouched. - -int SceneObject::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Entity::ReadProperty(propName, reader)); - - MatchProperty("Position", { reader >> m_Pos; }); - MatchForwards("GoldValue") MatchProperty("GoldCost", { reader >> m_OzValue; }); - MatchProperty("Buyable", { reader >> m_Buyable; }); - MatchProperty("BuyableMode", { m_BuyableMode = static_cast(std::stoi(reader.ReadPropValue())); }); - - MatchProperty("Team", - { - reader >> m_Team; - // Necessary to properly init (flag icons) some derived classes - // (actually, this rarely matters since tehre won't be an activity going when this is read!) - SetTeam(m_Team); - }); - MatchProperty("PlacedByPlayer", { reader >> m_PlacedByPlayer; }); - - EndPropertyList; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this SceneObject to an output stream for -// later recreation with Create(istream &stream); - -int SceneObject::Save(Writer &writer) const -{ - Entity::Save(writer); -// TODO: Make proper save system that knows not to save redundant data! -/* - writer.NewProperty("Position"); - writer << m_Pos; - writer.NewProperty("GoldValue"); - writer << m_OzValue; - writer.NewProperty("Buyable"); - writer << m_Buyable; - writer.NewProperty("BuyableMode"); - writer << static_cast(m_BuyableMode); - writer.NewProperty("Team"); - writer << m_Team; - writer.NewProperty("PlacedByPlayer"); - writer << m_PlacedByPlayer; -*/ - return 0; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneObject object. - -void SceneObject::Destroy(bool notInherited) -{ - - if (!notInherited) - Entity::Destroy(); - Clear(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the cost to purchase this item, in oz's of gold. - -float SceneObject::GetGoldValue(int nativeModule, float foreignMult, float nativeMult) const -{ - // Multiply the value of this according to whether its Tech is native or not to the specified DataModule - return m_OzValue * ((m_DefinedInModule > 0 && nativeModule > 0 && m_DefinedInModule != nativeModule) ? foreignMult : nativeMult); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldValueString -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a descriptive string describing the cost to purchase this item, -// in oz's of gold. - -std::string SceneObject::GetGoldValueString(int nativeModule, float foreignMult, float nativeMult) const -{ - float subjValue = GetGoldValue(nativeModule, foreignMult, nativeMult); - - char returnString[64]; - if (subjValue != 0) - { - // Just show number since adding oz at the end takes up too much space - std::snprintf(returnString, sizeof(returnString), "%.0f", subjValue); - } - else - return "FREE"; - - return returnString; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawTeamMark -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws team sign this terrain object belongs to. -void SceneObject::DrawTeamMark(BITMAP *pTargetBitmap, const Vector &targetPos) const -{ - // Only do HUD if on a team - if (m_Team < 0) - return; - - Vector drawPos = m_Pos - targetPos; - - // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam - if (!targetPos.IsZero()) - { - // Spans vertical scene seam - int sceneWidth = g_SceneMan.GetSceneWidth(); - if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) - { - if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) - drawPos.m_X -= sceneWidth; - else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) - drawPos.m_X += sceneWidth; - } - // Spans horizontal scene seam - int sceneHeight = g_SceneMan.GetSceneHeight(); - if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) - { - if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) - drawPos.m_Y -= sceneHeight; - else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) - drawPos.m_Y += sceneHeight; - } - } - - // Get the Icon bitmaps of this Actor's team, if any - BITMAP * teamIcon = g_ActivityMan.GetActivity()->GetTeamIcon(m_Team)->GetBitmaps8()[0]; - - // Now draw the Icon if we can - if (teamIcon) - { - // Make team icon blink faster as the health goes down - masked_blit(teamIcon, pTargetBitmap, 0, 0, drawPos.m_X - teamIcon->h / 2, drawPos.m_Y - teamIcon->h * 2, teamIcon->w, teamIcon->h); - } -} - + AbstractClassInfo(SceneObject, Entity); + const std::string SceneObject::SOPlacer::c_ClassName = "SOPlacer"; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this SOPlacer, effectively + // resetting the members of this abstraction level only. + + void SceneObject::SOPlacer::Clear() { + m_pObjectReference = 0; + m_Offset.Reset(); + m_RotAngle = 0; + m_HFlipped = false; + m_Team = Activity::NoTeam; + } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SOPlacer object ready for use. + + int SceneObject::SOPlacer::Create() + { + if (Serializable::Create() < 0) + return -1; + + return 0; + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a SOPlacer to be identical to another, by deep copy. + + int SceneObject::SOPlacer::Create(const SOPlacer& reference) { + m_pObjectReference = reference.m_pObjectReference; + m_Offset = reference.m_Offset; + m_RotAngle = reference.m_RotAngle; + m_HFlipped = reference.m_HFlipped; + m_Team = reference.m_Team; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. + + int SceneObject::SOPlacer::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Serializable::ReadProperty(propName, reader)); + + MatchProperty("PlacedObject", + { + m_pObjectReference = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); + RTEAssert(m_pObjectReference, "Stream suggests allocating an unallocatable type in SOPlacer::Create!"); + }); + MatchProperty("Offset", { reader >> m_Offset; }); + MatchProperty("Rotation", + { + Matrix rot; + reader >> rot; + m_RotAngle = rot.GetRadAngle(); + }); + MatchProperty("HFlipped", { reader >> m_HFlipped; }); + MatchProperty("Team", { reader >> m_Team; }); + + EndPropertyList; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this SOPlacer with a Writer for + // later recreation with Create(Reader &reader); + + int SceneObject::SOPlacer::Save(Writer& writer) const { + Serializable::Save(writer); + + writer.NewProperty("PlacedObject"); + writer << m_pObjectReference; + writer.NewProperty("Offset"); + writer << m_Offset; + // TODO: make generalized way of detecting defaults + if (m_RotAngle != 0) { + writer.NewProperty("Rotation"); + Matrix rot; + rot.SetRadAngle(m_RotAngle); + writer << rot; + } + if (m_HFlipped) { + writer.NewProperty("HFlipped"); + writer << m_HFlipped; + } + if (m_Team >= Activity::TeamOne) { + writer.NewProperty("Team"); + writer << m_Team; + } + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlacedCopy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes a copy of the preset instance, and applies the placement + // properties of this to it, finally returning it WITH OWNERSHIP. + + SceneObject* SceneObject::SOPlacer::GetPlacedCopy(const SceneObject* pParent) const { + RTEAssert(m_pObjectReference, "No Object reference to make copy from!"); + + SceneObject* pCopy = dynamic_cast(m_pObjectReference->Clone()); + if (pCopy) { + // Make relative to the parent + if (pParent) { + // Relative flipping (XOR) + bool placedFlip = (pParent->IsHFlipped() && m_HFlipped) ? false : (pParent->IsHFlipped() || m_HFlipped); + pCopy->SetHFlipped(placedFlip); + + // Relative rotation + Matrix placedRot(pParent->GetRotAngle() + m_RotAngle); + pCopy->SetRotAngle(placedRot.GetRadAngle()); + + // Relative position + pCopy->SetPos(pParent->GetPos() + m_Offset.GetXFlipped(pParent->IsHFlipped()) * pParent->GetRotMatrix()); + + // Relative team (parent overrides, if it has a set team) + if (pParent->GetTeam() >= 0) + pCopy->SetTeam(pParent->GetTeam()); + else + pCopy->SetTeam(m_Team); + } + // No parent to make relative from, so apply everything as aboslutes. + else { + pCopy->SetHFlipped(m_HFlipped); + pCopy->SetRotAngle(m_RotAngle); // m_HFlipped ? -m_RotAngle : m_RotAngle); + pCopy->SetPos(m_Offset); + pCopy->SetTeam(m_Team); + } + } + + // Transfer ownership here + return pCopy; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this SceneObject, effectively + // resetting the members of this abstraction level only. + + void SceneObject::Clear() { + m_Pos.Reset(); + m_OzValue = 0; + m_Buyable = true; + m_BuyableMode = BuyableMode::NoRestrictions; + m_Team = Activity::NoTeam; + m_PlacedByPlayer = Players::NoPlayer; + } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SceneObject object ready for use. + + int SceneObject::Create() + { + if (Entity::Create() < 0) + return -1; + + return 0; + } + */ + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SceneObject object ready for use. + + int SceneObject::Create() + { + + return 0; + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates an SceneObject object to be identical to another, by deep copy. + + int SceneObject::Create(const SceneObject& reference) { + Entity::Create(reference); + + m_Pos = reference.m_Pos; + m_OzValue = reference.m_OzValue; + m_Buyable = reference.m_Buyable; + m_BuyableMode = reference.m_BuyableMode; + m_Team = reference.m_Team; + m_PlacedByPlayer = reference.m_PlacedByPlayer; + + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a Reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the Reader's position is untouched. + + int SceneObject::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Entity::ReadProperty(propName, reader)); + + MatchProperty("Position", { reader >> m_Pos; }); + MatchForwards("GoldValue") MatchProperty("GoldCost", { reader >> m_OzValue; }); + MatchProperty("Buyable", { reader >> m_Buyable; }); + MatchProperty("BuyableMode", { m_BuyableMode = static_cast(std::stoi(reader.ReadPropValue())); }); + + MatchProperty("Team", + { + reader >> m_Team; + // Necessary to properly init (flag icons) some derived classes + // (actually, this rarely matters since tehre won't be an activity going when this is read!) + SetTeam(m_Team); + }); + MatchProperty("PlacedByPlayer", { reader >> m_PlacedByPlayer; }); + + EndPropertyList; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this SceneObject to an output stream for + // later recreation with Create(istream &stream); + + int SceneObject::Save(Writer& writer) const { + Entity::Save(writer); + // TODO: Make proper save system that knows not to save redundant data! + /* + writer.NewProperty("Position"); + writer << m_Pos; + writer.NewProperty("GoldValue"); + writer << m_OzValue; + writer.NewProperty("Buyable"); + writer << m_Buyable; + writer.NewProperty("BuyableMode"); + writer << static_cast(m_BuyableMode); + writer.NewProperty("Team"); + writer << m_Team; + writer.NewProperty("PlacedByPlayer"); + writer << m_PlacedByPlayer; + */ + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneObject object. + + void SceneObject::Destroy(bool notInherited) { + + if (!notInherited) + Entity::Destroy(); + Clear(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the cost to purchase this item, in oz's of gold. + + float SceneObject::GetGoldValue(int nativeModule, float foreignMult, float nativeMult) const { + // Multiply the value of this according to whether its Tech is native or not to the specified DataModule + return m_OzValue * ((m_DefinedInModule > 0 && nativeModule > 0 && m_DefinedInModule != nativeModule) ? foreignMult : nativeMult); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldValueString + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a descriptive string describing the cost to purchase this item, + // in oz's of gold. + + std::string SceneObject::GetGoldValueString(int nativeModule, float foreignMult, float nativeMult) const { + float subjValue = GetGoldValue(nativeModule, foreignMult, nativeMult); + + char returnString[64]; + if (subjValue != 0) { + // Just show number since adding oz at the end takes up too much space + std::snprintf(returnString, sizeof(returnString), "%.0f", subjValue); + } else + return "FREE"; + + return returnString; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawTeamMark + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws team sign this terrain object belongs to. + void SceneObject::DrawTeamMark(BITMAP* pTargetBitmap, const Vector& targetPos) const { + // Only do HUD if on a team + if (m_Team < 0) + return; + + Vector drawPos = m_Pos - targetPos; + + // Adjust the draw position to work if drawn to a target screen bitmap that is straddling a scene seam + if (!targetPos.IsZero()) { + // Spans vertical scene seam + int sceneWidth = g_SceneMan.GetSceneWidth(); + if (g_SceneMan.SceneWrapsX() && pTargetBitmap->w < sceneWidth) { + if ((targetPos.m_X < 0) && (m_Pos.m_X > (sceneWidth - pTargetBitmap->w))) + drawPos.m_X -= sceneWidth; + else if (((targetPos.m_X + pTargetBitmap->w) > sceneWidth) && (m_Pos.m_X < pTargetBitmap->w)) + drawPos.m_X += sceneWidth; + } + // Spans horizontal scene seam + int sceneHeight = g_SceneMan.GetSceneHeight(); + if (g_SceneMan.SceneWrapsY() && pTargetBitmap->h < sceneHeight) { + if ((targetPos.m_Y < 0) && (m_Pos.m_Y > (sceneHeight - pTargetBitmap->h))) + drawPos.m_Y -= sceneHeight; + else if (((targetPos.m_Y + pTargetBitmap->h) > sceneHeight) && (m_Pos.m_Y < pTargetBitmap->h)) + drawPos.m_Y += sceneHeight; + } + } + + // Get the Icon bitmaps of this Actor's team, if any + BITMAP* teamIcon = g_ActivityMan.GetActivity()->GetTeamIcon(m_Team)->GetBitmaps8()[0]; + + // Now draw the Icon if we can + if (teamIcon) { + // Make team icon blink faster as the health goes down + masked_blit(teamIcon, pTargetBitmap, 0, 0, drawPos.m_X - teamIcon->h / 2, drawPos.m_Y - teamIcon->h * 2, teamIcon->w, teamIcon->h); + } + } } // namespace RTE diff --git a/Source/Entities/SceneObject.h b/Source/Entities/SceneObject.h index 5667c4719..1ee5a2ae8 100644 --- a/Source/Entities/SceneObject.h +++ b/Source/Entities/SceneObject.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files, forward declarations, namespace stuff @@ -19,594 +18,547 @@ struct BITMAP; -namespace RTE -{ - -////////////////////////////////////////////////////////////////////////////////////////// -// Abstract class: SceneObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The base class shared by Both TerrainObject:s and MovableObject:s, ie -// anything that can be places in a scene. -// Parent(s): Entity. -// Class history: 8/6/2007 SceneObject created. - -class SceneObject : public Entity { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableOverrideMethods; - ClassInfoGetters; - - /// - /// Enumeration for the different buyable modes of this SceneObject. - /// - enum class BuyableMode { NoRestrictions, BuyMenuOnly, ObjectPickerOnly, ScriptOnly }; +namespace RTE { + ////////////////////////////////////////////////////////////////////////////////////////// + // Abstract class: SceneObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The base class shared by Both TerrainObject:s and MovableObject:s, ie + // anything that can be places in a scene. + // Parent(s): Entity. + // Class history: 8/6/2007 SceneObject created. - ////////////////////////////////////////////////////////////////////////////////////////// - // Nested class: SOPlacer - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Acts as a small memory object that only holds a pointer to a reference - // instance and the most essential properties to eventually place a copy - // of that reference when needed. - // Parent(s): Serializable. - // Class history: 11/25/2007 SOPlacer created. + class SceneObject : public Entity { - class SOPlacer: - public Serializable - { + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations - ////////////////////////////////////////////////////////////////////////////////////////// - // Public member variable, method and friend function declarations - - public: - - SerializableClassNameGetter; + public: SerializableOverrideMethods; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Constructor: SOPlacer - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Constructor method used to instantiate a SOPlacer object in system - // memory. Create() should be called before using the object. - // Arguments: None. - - SOPlacer() { Clear(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Create - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Creates a SOPlacer to be identical to another, by deep copy. - // Arguments: A reference to the SOPlacer to deep copy. - // Return value: An error return value signaling sucess or any particular failure. - // Anything below 0 is an error signal. - - int Create(const SOPlacer &reference); - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: Reset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Resets the entire Serializable, including its inherited members, to their - // default settings or values. - // Arguments: None. - // Return value: None. - - void Reset() override { Clear(); } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Virtual method: GetObjectReference - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the object reference to be placed. Owenership is NOT transferred! - // Arguments: None. - // Return value: A pointer to the reference object to be copied and placed. Not transferred! - - const SceneObject * GetObjectReference() { return m_pObjectReference; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetOffset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the place offset from the parent's position/origin. If in a scene - // this will yield the absolute scene coordinates. - // Arguments: None. - // Return value: The offset in pixels from the parent's position where this gets spawned. - - Vector GetOffset() const { return m_Offset; } - - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetOffset - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets the place offset from the parent's position/origin. - // Arguments: New offset. - // Return value: None. - - void SetOffset(Vector newOffset) { m_Offset = newOffset; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetRotation - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets the rotation angle of the object to be placed, in radians. - // Arguments: None. - // Return value: The placement rotational angle, in radians. - - float GetRotation() const { return m_RotAngle; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetHFlipped - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets whether the placement is horizontally flipped or not. - // Arguments: None. - // Return value: The horizontal flipping of the placement. - - bool GetHFlipped() const { return m_HFlipped; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetTeam - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Gets which team this is to be assigned to when placed. - // Arguments: None. - // Return value: The team number this is to be assigned to when placed. - - int GetTeam() const { return m_Team; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: SetTeam - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Sets which team this is to be assigned to when placed. - // Arguments: The team number this is to be assigned to when placed. - // Return value: None. - - void SetTeam(int team) { m_Team = team; } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: GetPlacedCopy - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Makes a copy of the preset instance, and applies the placement - // properties of this to it, finally returning it WITH OWNERSHIP. - // Arguments: The parent to place as offset from. If 0 is passed, the placement - // properties will be applied as absolutes instead of relative. - // Return value: The new copy with correct placement applied. OWNERSHIP IS TRANSFERRED! - - SceneObject * GetPlacedCopy(const SceneObject *pParent = 0) const; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Protected member variable and method declarations - - protected: - - // The pointer to the preset instance, that copies of which will be placed. Not Owned! - const SceneObject *m_pObjectReference; - // Offset placement position from owner/parent's position/origin. - Vector m_Offset; - // The placement's rotational angle in radians. - float m_RotAngle; - // Whether horizontal flipping is part of the placement. - bool m_HFlipped; - // The team of the placed object - int m_Team; - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Private member variable and method declarations - - private: - - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Clear - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Clears all the member variables of this SOPlacer, effectively - // resetting the members of this abstraction level only. - // Arguments: None. - // Return value: None. - - void Clear(); - - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: SceneObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a SceneObject object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - SceneObject() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~SceneObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a SceneObject object before deletion -// from system memory. -// Arguments: None. - - ~SceneObject() override { Destroy(true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SceneObject object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override { return 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates an SceneObject to be identical to another, by deep copy. -// Arguments: A reference to the SceneObject to deep copy. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(const SceneObject &reference); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire SceneObject, including its inherited members, to their -// default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); Entity::Reset(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Pure V. method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneObject object. -// Arguments: Whether to only destroy the members defined in this derived class, or -// to destroy all inherited members also. -// Return value: None. - - void Destroy(bool notInherited = false) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the absolute position of this SceneObject. -// Arguments: None. -// Return value: A Vector describing the current absolute position in pixels. - - const Vector & GetPos() const { return m_Pos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the absolute position of this SceneObject in the scene. -// Arguments: A Vector describing the current absolute position in pixels. -// Return value: None. - - void SetPos(const Vector &newPos) { m_Pos = newPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsHFlipped -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether this is being drawn flipped horizontally (around the -// vertical axis), or not. -// Arguments: None. -// Return value: Whether flipped or not. - - virtual bool IsHFlipped() const { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRotMatrix -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current rotational Matrix of of this MovableObject. -// Arguments: None. -// Return value: The rotational Matrix of this MovableObject. - - virtual Matrix GetRotMatrix() const { return Matrix(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetRotAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current rotational angle of of this, in radians. -// Arguments: None. -// Return value: The rotational angle of this, in radians. - - virtual float GetRotAngle() const { return 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virutal method: SetHFlipped -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether this should be drawn flipped horizontally (around the -// vertical axis). -// Arguments: A bool with the new value. -// Return value: None. - - virtual void SetHFlipped(const bool flipped) {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetRotAngle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current absolute angle of rotation of this. -// Arguments: The new absolute angle in radians. -// Return value: None. - - virtual void SetRotAngle(float newAngle) {} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which team this belongs to. -// Arguments: The assigned team number. -// Return value: None. - - virtual void SetTeam(int team) { m_Team = team; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets which team this belongs to. -// Arguments: None. -// Return value: The currently assigned team number. - - int GetTeam() const { return m_Team; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: SetPlacedByPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which player placed this object in the scene, if any. -// Arguments: The player responsible for placing this is in the scene, if any. -// Return value: None. - - void SetPlacedByPlayer(int player) { m_PlacedByPlayer = player; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: GetPlacedByPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets which player placed this object in the scene, if any. -// Arguments: None. -// Return value: The player responsible for placing this is in the scene, if any. - - int GetPlacedByPlayer() const { return m_PlacedByPlayer; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the cost to purchase this item, in oz's of gold. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// How much to multiply the value if this happens to be a native Tech. -// Return value: The cost, in oz of gold. - - virtual float GetGoldValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetGoldValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the cost to purchase this item, in oz's of gold. -// Arguments: The cost, in oz of gold. -// Return value: None. - - void SetGoldValue(float value) { m_OzValue = value; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldValueOld -////////////////////////////////////////////////////////////////////////////////////////// -// Description: DOES THE SAME THING AS GetGoldValue, USED ONLY TO PRESERVE LUA COMPATIBILITY - - virtual float GetGoldValueOld(int nativeModule, float foreignMult) const { return GetGoldValue(nativeModule, foreignMult, 1.0); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldValueString -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a descriptive string describing the cost to purchase this item, -// in oz's of gold. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// Return value: The cost, described in a friendly to read string: "100oz", or "Free" - - std::string GetGoldValueString(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total liquidation value of this, including everything inside. -// Arguments: If this is supposed to be adjusted for a specific Tech's subjective -// value, then pass in the native DataModule ID of that tech. 0 means -// no Tech is specified and the base value is returned. -// How much to multiply the value if this happens to be a foreign Tech. -// Return value: The current value of this and all contained assets. - - virtual float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const { return GetGoldValue(nativeModule, foreignMult, nativeMult); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsBuyable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether this should appear in teh buy menus at all. -// Arguments: None. -// Return value: Buyable or not. - - bool IsBuyable() const { return m_Buyable; } - - /// - /// Gets the BuyableMode of this SceneObject. - /// - /// The BuyableMode of this SceneObject - BuyableMode GetBuyableMode() const { return m_BuyableMode; } - - /// - /// Gets whether this SceneObject is available only in the BuyMenu list when buyable. - /// - /// Whether this SceneObject is available only in the BuyMenu list when buyable. - bool IsBuyableInBuyMenuOnly() const { return m_BuyableMode == BuyableMode::BuyMenuOnly; } - - /// - /// Gets whether this SceneObject is available only in the ObjectPicker list when buyable. - /// - /// Whether this SceneObject is available only in the ObjectPicker list when buyable. - bool IsBuyableInObjectPickerOnly() const { return m_BuyableMode == BuyableMode::ObjectPickerOnly; } - - /// - /// Gets whether this SceneObject is available only by lua functions like CreateRandom - /// - /// Whether this SceneObject is available only in the AI list when buyable. - bool IsBuyableInScriptOnly() const { return m_BuyableMode == BuyableMode::ScriptOnly; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGraphicalIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a bitmap showing a good identifyable icon of this, for use in -// GUI lists etc. -// Arguments: None. -// Return value: A good identifyable graphical representation of this in a BITMAP, if -// available. If not, 0 is returned. Ownership is NOT TRANSFERRED! - - virtual BITMAP * GetGraphicalIcon() const { return nullptr; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: IsOnScenePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether this' current graphical representation overlaps -// a point in absolute scene coordinates. -// Arguments: The point in absolute scene coordinates. -// Return value: Whether this' graphical rep overlaps the scene point. - - virtual bool IsOnScenePoint(Vector &scenePoint) const { return false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates this SceneObject. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - virtual void Update() { } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: FullUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the full state of this object in one call. -// Arguments: None. -// Return value: None. - virtual void FullUpdate() { Update(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: PostUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Function called after everything has finished updating. -// Arguments: None. -// Return value: None. - virtual void PostUpdate() { }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this SceneObject's current graphical representation to a BITMAP of -// choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// In which mode to draw in. See the DrawMode enumeration for the modes. -// Whether to not draw any extra 'ghost' items of this MovableObject, -// like indicator arrows or hovering HUD text and so on. -// Return value: None. - - virtual void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const = 0; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: DrawTeamMark -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws team sign this terrain object belongs to. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the Scene. -// Return value: None. - - void DrawTeamMark(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Forbidding copying - SceneObject(const SceneObject &reference) = delete; - SceneObject & operator=(const SceneObject &rhs) { return *this; } - - - // Member variables - static Entity::ClassInfo m_sClass; - // Absolute position of the center of this in the scene, in pixels - Vector m_Pos; - // How much this SceneObject costs to purchase, in oz's of gold. - float m_OzValue; - // Whether this shows up in the buy menu at all - bool m_Buyable; - - BuyableMode m_BuyableMode; //!< In which buy lists this SceneObject is available when buyable. - - // The team this object belongs to. -1 if none. - int m_Team; - // The player this was placed by in edit mode - int m_PlacedByPlayer; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this SceneObject, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - -}; + ClassInfoGetters; + + /// + /// Enumeration for the different buyable modes of this SceneObject. + /// + enum class BuyableMode { + NoRestrictions, + BuyMenuOnly, + ObjectPickerOnly, + ScriptOnly + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Nested class: SOPlacer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Acts as a small memory object that only holds a pointer to a reference + // instance and the most essential properties to eventually place a copy + // of that reference when needed. + // Parent(s): Serializable. + // Class history: 11/25/2007 SOPlacer created. + + class SOPlacer : + public Serializable { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableClassNameGetter; + SerializableOverrideMethods; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: SOPlacer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a SOPlacer object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + SOPlacer() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a SOPlacer to be identical to another, by deep copy. + // Arguments: A reference to the SOPlacer to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const SOPlacer& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire Serializable, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetObjectReference + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the object reference to be placed. Owenership is NOT transferred! + // Arguments: None. + // Return value: A pointer to the reference object to be copied and placed. Not transferred! + + const SceneObject* GetObjectReference() { return m_pObjectReference; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the place offset from the parent's position/origin. If in a scene + // this will yield the absolute scene coordinates. + // Arguments: None. + // Return value: The offset in pixels from the parent's position where this gets spawned. + + Vector GetOffset() const { return m_Offset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the place offset from the parent's position/origin. + // Arguments: New offset. + // Return value: None. + + void SetOffset(Vector newOffset) { m_Offset = newOffset; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRotation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rotation angle of the object to be placed, in radians. + // Arguments: None. + // Return value: The placement rotational angle, in radians. + + float GetRotation() const { return m_RotAngle; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetHFlipped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets whether the placement is horizontally flipped or not. + // Arguments: None. + // Return value: The horizontal flipping of the placement. + + bool GetHFlipped() const { return m_HFlipped; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets which team this is to be assigned to when placed. + // Arguments: None. + // Return value: The team number this is to be assigned to when placed. + + int GetTeam() const { return m_Team; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this is to be assigned to when placed. + // Arguments: The team number this is to be assigned to when placed. + // Return value: None. + + void SetTeam(int team) { m_Team = team; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlacedCopy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes a copy of the preset instance, and applies the placement + // properties of this to it, finally returning it WITH OWNERSHIP. + // Arguments: The parent to place as offset from. If 0 is passed, the placement + // properties will be applied as absolutes instead of relative. + // Return value: The new copy with correct placement applied. OWNERSHIP IS TRANSFERRED! + + SceneObject* GetPlacedCopy(const SceneObject* pParent = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // The pointer to the preset instance, that copies of which will be placed. Not Owned! + const SceneObject* m_pObjectReference; + // Offset placement position from owner/parent's position/origin. + Vector m_Offset; + // The placement's rotational angle in radians. + float m_RotAngle; + // Whether horizontal flipping is part of the placement. + bool m_HFlipped; + // The team of the placed object + int m_Team; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this SOPlacer, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: SceneObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a SceneObject object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + SceneObject() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~SceneObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a SceneObject object before deletion + // from system memory. + // Arguments: None. + + ~SceneObject() override { Destroy(true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SceneObject object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override { return 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates an SceneObject to be identical to another, by deep copy. + // Arguments: A reference to the SceneObject to deep copy. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(const SceneObject& reference); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire SceneObject, including its inherited members, to their + // default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { + Clear(); + Entity::Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Pure V. method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneObject object. + // Arguments: Whether to only destroy the members defined in this derived class, or + // to destroy all inherited members also. + // Return value: None. + + void Destroy(bool notInherited = false) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the absolute position of this SceneObject. + // Arguments: None. + // Return value: A Vector describing the current absolute position in pixels. + + const Vector& GetPos() const { return m_Pos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the absolute position of this SceneObject in the scene. + // Arguments: A Vector describing the current absolute position in pixels. + // Return value: None. + + void SetPos(const Vector& newPos) { m_Pos = newPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsHFlipped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether this is being drawn flipped horizontally (around the + // vertical axis), or not. + // Arguments: None. + // Return value: Whether flipped or not. + + virtual bool IsHFlipped() const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRotMatrix + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current rotational Matrix of of this MovableObject. + // Arguments: None. + // Return value: The rotational Matrix of this MovableObject. + + virtual Matrix GetRotMatrix() const { return Matrix(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetRotAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current rotational angle of of this, in radians. + // Arguments: None. + // Return value: The rotational angle of this, in radians. + + virtual float GetRotAngle() const { return 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virutal method: SetHFlipped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether this should be drawn flipped horizontally (around the + // vertical axis). + // Arguments: A bool with the new value. + // Return value: None. + + virtual void SetHFlipped(const bool flipped) {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetRotAngle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current absolute angle of rotation of this. + // Arguments: The new absolute angle in radians. + // Return value: None. + + virtual void SetRotAngle(float newAngle) {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which team this belongs to. + // Arguments: The assigned team number. + // Return value: None. + + virtual void SetTeam(int team) { m_Team = team; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets which team this belongs to. + // Arguments: None. + // Return value: The currently assigned team number. + + int GetTeam() const { return m_Team; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: SetPlacedByPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which player placed this object in the scene, if any. + // Arguments: The player responsible for placing this is in the scene, if any. + // Return value: None. + + void SetPlacedByPlayer(int player) { m_PlacedByPlayer = player; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: GetPlacedByPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets which player placed this object in the scene, if any. + // Arguments: None. + // Return value: The player responsible for placing this is in the scene, if any. + + int GetPlacedByPlayer() const { return m_PlacedByPlayer; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the cost to purchase this item, in oz's of gold. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // How much to multiply the value if this happens to be a native Tech. + // Return value: The cost, in oz of gold. + + virtual float GetGoldValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetGoldValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the cost to purchase this item, in oz's of gold. + // Arguments: The cost, in oz of gold. + // Return value: None. + + void SetGoldValue(float value) { m_OzValue = value; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldValueOld + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: DOES THE SAME THING AS GetGoldValue, USED ONLY TO PRESERVE LUA COMPATIBILITY + + virtual float GetGoldValueOld(int nativeModule, float foreignMult) const { return GetGoldValue(nativeModule, foreignMult, 1.0); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldValueString + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a descriptive string describing the cost to purchase this item, + // in oz's of gold. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // Return value: The cost, described in a friendly to read string: "100oz", or "Free" + + std::string GetGoldValueString(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total liquidation value of this, including everything inside. + // Arguments: If this is supposed to be adjusted for a specific Tech's subjective + // value, then pass in the native DataModule ID of that tech. 0 means + // no Tech is specified and the base value is returned. + // How much to multiply the value if this happens to be a foreign Tech. + // Return value: The current value of this and all contained assets. + + virtual float GetTotalValue(int nativeModule = 0, float foreignMult = 1.0, float nativeMult = 1.0) const { return GetGoldValue(nativeModule, foreignMult, nativeMult); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsBuyable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether this should appear in teh buy menus at all. + // Arguments: None. + // Return value: Buyable or not. + + bool IsBuyable() const { return m_Buyable; } + + /// + /// Gets the BuyableMode of this SceneObject. + /// + /// The BuyableMode of this SceneObject + BuyableMode GetBuyableMode() const { return m_BuyableMode; } + + /// + /// Gets whether this SceneObject is available only in the BuyMenu list when buyable. + /// + /// Whether this SceneObject is available only in the BuyMenu list when buyable. + bool IsBuyableInBuyMenuOnly() const { return m_BuyableMode == BuyableMode::BuyMenuOnly; } + + /// + /// Gets whether this SceneObject is available only in the ObjectPicker list when buyable. + /// + /// Whether this SceneObject is available only in the ObjectPicker list when buyable. + bool IsBuyableInObjectPickerOnly() const { return m_BuyableMode == BuyableMode::ObjectPickerOnly; } + + /// + /// Gets whether this SceneObject is available only by lua functions like CreateRandom + /// + /// Whether this SceneObject is available only in the AI list when buyable. + bool IsBuyableInScriptOnly() const { return m_BuyableMode == BuyableMode::ScriptOnly; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGraphicalIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a bitmap showing a good identifyable icon of this, for use in + // GUI lists etc. + // Arguments: None. + // Return value: A good identifyable graphical representation of this in a BITMAP, if + // available. If not, 0 is returned. Ownership is NOT TRANSFERRED! + + virtual BITMAP* GetGraphicalIcon() const { return nullptr; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: IsOnScenePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether this' current graphical representation overlaps + // a point in absolute scene coordinates. + // Arguments: The point in absolute scene coordinates. + // Return value: Whether this' graphical rep overlaps the scene point. + + virtual bool IsOnScenePoint(Vector& scenePoint) const { return false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates this SceneObject. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + virtual void Update() {} + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: FullUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the full state of this object in one call. + // Arguments: None. + // Return value: None. + virtual void FullUpdate() { Update(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: PostUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Function called after everything has finished updating. + // Arguments: None. + // Return value: None. + virtual void PostUpdate(){}; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this SceneObject's current graphical representation to a BITMAP of + // choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // In which mode to draw in. See the DrawMode enumeration for the modes. + // Whether to not draw any extra 'ghost' items of this MovableObject, + // like indicator arrows or hovering HUD text and so on. + // Return value: None. + + virtual void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const = 0; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: DrawTeamMark + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws team sign this terrain object belongs to. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the Scene. + // Return value: None. + + void DrawTeamMark(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Forbidding copying + SceneObject(const SceneObject& reference) = delete; + SceneObject& operator=(const SceneObject& rhs) { return *this; } + + // Member variables + static Entity::ClassInfo m_sClass; + // Absolute position of the center of this in the scene, in pixels + Vector m_Pos; + // How much this SceneObject costs to purchase, in oz's of gold. + float m_OzValue; + // Whether this shows up in the buy menu at all + bool m_Buyable; + + BuyableMode m_BuyableMode; //!< In which buy lists this SceneObject is available when buyable. + + // The team this object belongs to. -1 if none. + int m_Team; + // The player this was placed by in edit mode + int m_PlacedByPlayer; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this SceneObject, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + }; } // namespace RTE diff --git a/Source/Entities/SoundContainer.cpp b/Source/Entities/SoundContainer.cpp index 7aaae4402..f71b53dcb 100644 --- a/Source/Entities/SoundContainer.cpp +++ b/Source/Entities/SoundContainer.cpp @@ -6,18 +6,16 @@ namespace RTE { ConcreteClassInfo(SoundContainer, Entity, 50); const std::unordered_map SoundContainer::c_SoundOverlapModeMap = { - {"Overlap", SoundContainer::SoundOverlapMode::OVERLAP}, - {"Restart", SoundContainer::SoundOverlapMode::RESTART}, - {"Ignore Play", SoundContainer::SoundOverlapMode::IGNORE_PLAY} - }; + {"Overlap", SoundContainer::SoundOverlapMode::OVERLAP}, + {"Restart", SoundContainer::SoundOverlapMode::RESTART}, + {"Ignore Play", SoundContainer::SoundOverlapMode::IGNORE_PLAY}}; const std::unordered_map SoundContainer::c_BusRoutingMap = { - {"SFX", SoundContainer::BusRouting::SFX}, - {"UI", SoundContainer::BusRouting::UI}, - {"Music", SoundContainer::BusRouting::MUSIC} - }; + {"SFX", SoundContainer::BusRouting::SFX}, + {"UI", SoundContainer::BusRouting::UI}, + {"Music", SoundContainer::BusRouting::MUSIC}}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SoundContainer::Clear() { m_TopLevelSoundSet.Destroy(); @@ -42,9 +40,9 @@ namespace RTE { m_PitchVariation = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SoundContainer::Create(const SoundContainer &reference) { + int SoundContainer::Create(const SoundContainer& reference) { Entity::Create(reference); m_TopLevelSoundSet.Create(reference.m_TopLevelSoundSet); @@ -70,11 +68,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SoundContainer::ReadProperty(const std::string_view &propName, Reader &reader) { + int SoundContainer::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("SpecialBehaviour_TopLevelSoundSet", { reader >> m_TopLevelSoundSet; }); MatchProperty("AddSound", { m_TopLevelSoundSet.AddSoundData(SoundSet::ReadAndGetSoundData(reader)); }); MatchProperty("AddSoundSet", { @@ -90,7 +88,7 @@ namespace RTE { } else { try { m_SoundOverlapMode = static_cast(std::stoi(soundOverlapModeString)); - } catch (const std::exception &) { + } catch (const std::exception&) { reader.ReportError("Cycle mode " + soundOverlapModeString + " is invalid."); } } @@ -102,7 +100,7 @@ namespace RTE { } else { try { m_BusRouting = static_cast(std::stoi(busRoutingString)); - } catch (const std::exception &) { + } catch (const std::exception&) { reader.ReportError("Tried to route to non-existent sound bus " + busRoutingString); } } @@ -111,13 +109,17 @@ namespace RTE { MatchProperty("AttenuationStartDistance", { reader >> m_AttenuationStartDistance; }); MatchProperty("CustomPanValue", { reader >> m_CustomPanValue; - if (m_CustomPanValue < -1.0f || m_CustomPanValue > 1.0f) { reader.ReportError("SoundContainer CustomPanValue must be between -1 and 1."); } + if (m_CustomPanValue < -1.0f || m_CustomPanValue > 1.0f) { + reader.ReportError("SoundContainer CustomPanValue must be between -1 and 1."); + } }); MatchProperty("PanningStrengthMultiplier", { reader >> m_PanningStrengthMultiplier; }); MatchProperty("LoopSetting", { reader >> m_Loops; }); MatchProperty("Priority", { reader >> m_Priority; - if (m_Priority < 0 || m_Priority > 256) { reader.ReportError("SoundContainer priority must be between 256 (lowest priority) and 0 (highest priority)."); } + if (m_Priority < 0 || m_Priority > 256) { + reader.ReportError("SoundContainer priority must be between 256 (lowest priority) and 0 (highest priority)."); + } }); MatchProperty("AffectedByGlobalPitch", { reader >> m_AffectedByGlobalPitch; }); MatchProperty("Position", { reader >> m_Pos; }); @@ -128,9 +130,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - int SoundContainer::Save(Writer &writer) const { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SoundContainer::Save(Writer& writer) const { Entity::Save(writer); // Due to writer limitations, the top level SoundSet has to be explicitly written out, even though SoundContainer standard behaviour is to hide it in INI and just have properties be part of the SoundContainer. @@ -176,12 +178,12 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float SoundContainer::GetLength(LengthOfSoundType type) const { if (!m_SoundPropertiesUpToDate) { // Todo - use a post-load fixup stage instead of lazily initializing shit everywhere... Eugh. - const_cast(this)->UpdateSoundProperties(); + const_cast(this)->UpdateSoundProperties(); const_cast(this)->m_TopLevelSoundSet.SelectNextSounds(); } @@ -189,7 +191,7 @@ namespace RTE { m_TopLevelSoundSet.GetFlattenedSoundData(flattenedSoundData, type == LengthOfSoundType::NextPlayed); float lengthMilliseconds = 0.0f; - for (const SoundSet::SoundData *selectedSoundData : flattenedSoundData) { + for (const SoundSet::SoundData* selectedSoundData: flattenedSoundData) { unsigned int length; selectedSoundData->SoundObject->getLength(&length, FMOD_TIMEUNIT_MS); lengthMilliseconds = std::max(lengthMilliseconds, static_cast(length)); @@ -198,24 +200,24 @@ namespace RTE { return lengthMilliseconds; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::vector SoundContainer::GetSelectedSoundHashes() const { std::vector soundHashes; - std::vector flattenedSoundData; + std::vector flattenedSoundData; m_TopLevelSoundSet.GetFlattenedSoundData(flattenedSoundData, false); - for (const SoundSet::SoundData *selectedSoundData : flattenedSoundData) { + for (const SoundSet::SoundData* selectedSoundData: flattenedSoundData) { soundHashes.push_back(selectedSoundData->SoundFile.GetHash()); } return soundHashes; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - const SoundSet::SoundData * SoundContainer::GetSoundDataForSound(const FMOD::Sound *sound) const { - std::vector flattenedSoundData; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + const SoundSet::SoundData* SoundContainer::GetSoundDataForSound(const FMOD::Sound* sound) const { + std::vector flattenedSoundData; m_TopLevelSoundSet.GetFlattenedSoundData(flattenedSoundData, false); - for (const SoundSet::SoundData *soundData : flattenedSoundData) { + for (const SoundSet::SoundData* soundData: flattenedSoundData) { if (sound == soundData->SoundObject) { return soundData; } @@ -223,7 +225,7 @@ namespace RTE { return nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SoundContainer::Play(int player) { if (HasAnySounds()) { @@ -235,19 +237,18 @@ namespace RTE { } } return g_AudioMan.PlaySoundContainer(this, player); - } return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FMOD_RESULT SoundContainer::UpdateSoundProperties() { FMOD_RESULT result = FMOD_OK; - std::vector flattenedSoundData; + std::vector flattenedSoundData; m_TopLevelSoundSet.GetFlattenedSoundData(flattenedSoundData, false); - for (SoundSet::SoundData *soundData : flattenedSoundData) { + for (SoundSet::SoundData* soundData: flattenedSoundData) { FMOD_MODE soundMode = (m_Loops == 0) ? FMOD_LOOP_OFF : FMOD_LOOP_NORMAL; if (m_Immobile) { soundMode |= FMOD_2D; @@ -267,4 +268,4 @@ namespace RTE { return result; } -} +} // namespace RTE diff --git a/Source/Entities/SoundContainer.h b/Source/Entities/SoundContainer.h index ff6c38146..73322533e 100644 --- a/Source/Entities/SoundContainer.h +++ b/Source/Entities/SoundContainer.h @@ -12,9 +12,8 @@ namespace RTE { /// A container for sounds that represent a specific sound effect. /// class SoundContainer : public Entity { - - public: + public: EntityAllocation(SoundContainer); SerializableOverrideMethods; ClassInfoGetters; @@ -47,14 +46,17 @@ namespace RTE { /// Copy constructor method used to instantiate a SoundContainer object identical to an already existing one. /// /// A reference to the SoundContainer to deep copy. - SoundContainer(const SoundContainer &reference) { Clear(); Create(reference); } + SoundContainer(const SoundContainer& reference) { + Clear(); + Create(reference); + } /// /// Creates a SoundContainer to be identical to another, by deep copy. /// /// A reference to the SoundContainer to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const SoundContainer &reference); + int Create(const SoundContainer& reference); /// /// Creates a SoundContainer and adds a sound, optionally setting immobility, being affected by global pitch, and bus routing. @@ -64,7 +66,13 @@ namespace RTE { /// Whether this SoundContainer's sounds' frequency will be affected by the global pitch. /// Bus to route this sound to. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const std::string &soundFilePath, bool immobile = false, bool affectedByGlobalPitch = true, BusRouting busRouting = BusRouting::SFX) { m_TopLevelSoundSet.AddSound(soundFilePath, true); SetImmobile(immobile); SetAffectedByGlobalPitch(affectedByGlobalPitch); SetBusRouting(busRouting); return 0; } + int Create(const std::string& soundFilePath, bool immobile = false, bool affectedByGlobalPitch = true, BusRouting busRouting = BusRouting::SFX) { + m_TopLevelSoundSet.AddSound(soundFilePath, true); + SetImmobile(immobile); + SetAffectedByGlobalPitch(affectedByGlobalPitch); + SetBusRouting(busRouting); + return 0; + } #pragma endregion #pragma region Destruction @@ -77,12 +85,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the SoundContainer object. It doesn't delete the Sound files, since they're owned by ContentFile static maps. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Entity::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Entity::Destroy(); + } + Clear(); + } /// /// Resets the entire SoundContainer, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Entity::Reset(); } + void Reset() override { + Clear(); + Entity::Reset(); + } #pragma endregion #pragma region Sound Management Getters and Setters @@ -108,13 +124,16 @@ namespace RTE { /// Gets a reference to the top level SoundSet of this SoundContainer, to which all SoundData and sub SoundSets belong. /// /// A reference to the top level SoundSet of this SoundContainer. - SoundSet & GetTopLevelSoundSet() { return m_TopLevelSoundSet; } + SoundSet& GetTopLevelSoundSet() { return m_TopLevelSoundSet; } /// /// Copies the passed in SoundSet reference into the top level SoundSet of this SoundContainer, effectively making that the new top level SoundSet. /// /// A reference to the new top level SoundSet for this SoundContainer. - void SetTopLevelSoundSet(const SoundSet &newTopLevelSoundSet) { m_TopLevelSoundSet = newTopLevelSoundSet; m_SoundPropertiesUpToDate = false; } + void SetTopLevelSoundSet(const SoundSet& newTopLevelSoundSet) { + m_TopLevelSoundSet = newTopLevelSoundSet; + m_SoundPropertiesUpToDate = false; + } /// /// Gets a vector of hashes of the sounds selected to be played next in this SoundContainer. @@ -127,13 +146,13 @@ namespace RTE { /// /// The FMOD::Sound to search for. /// A pointer to the corresponding SoundData or a null pointer. - const SoundSet::SoundData * GetSoundDataForSound(const FMOD::Sound *sound) const; + const SoundSet::SoundData* GetSoundDataForSound(const FMOD::Sound* sound) const; /// /// Gets the channels playing sounds from this SoundContainer. /// /// The channels currently being used. - std::unordered_set const * GetPlayingChannels() const { return &m_PlayingChannels; } + std::unordered_set const* GetPlayingChannels() const { return &m_PlayingChannels; } /// /// Indicates whether any sound in this SoundContainer is currently being played. @@ -160,7 +179,7 @@ namespace RTE { SoundOverlapMode GetSoundOverlapMode() const { return m_SoundOverlapMode; } /// - /// Sets the SoundOverlapMode of this SoundContainer, which is used to determine how it should behave when it's told to play while already playing. + /// Sets the SoundOverlapMode of this SoundContainer, which is used to determine how it should behave when it's told to play while already playing. /// /// The new SoundOverlapMode this SoundContainer should use. void SetSoundOverlapMode(SoundOverlapMode newSoundOverlapMode) { m_SoundOverlapMode = newSoundOverlapMode; } @@ -179,7 +198,7 @@ namespace RTE { /// /// The new bus for this sound to route to. void SetBusRouting(BusRouting newBusRoute) { m_BusRouting = newBusRoute; } - + /// /// Gets whether the sounds in this SoundContainer should be considered immobile, i.e. always play at the listener's position. /// @@ -190,7 +209,10 @@ namespace RTE { /// Sets whether the sounds in this SoundContainer should be considered immobile, i.e. always play at the listener's position. Does not affect currently playing sounds. /// /// The new immobile setting. - void SetImmobile(bool immobile) { m_Immobile = immobile; m_SoundPropertiesUpToDate = false; } + void SetImmobile(bool immobile) { + m_Immobile = immobile; + m_SoundPropertiesUpToDate = false; + } /// /// Gets the attenuation start distance of this SoundContainer. @@ -202,7 +224,10 @@ namespace RTE { /// Sets the attenuation start distance of this SoundContainer. Values < 0 set it to default. Does not affect currently playing sounds. /// /// The new attenuation start distance. - void SetAttenuationStartDistance(float attenuationStartDistance) { m_AttenuationStartDistance = (attenuationStartDistance < 0) ? c_DefaultAttenuationStartDistance : attenuationStartDistance; m_SoundPropertiesUpToDate = false; } + void SetAttenuationStartDistance(float attenuationStartDistance) { + m_AttenuationStartDistance = (attenuationStartDistance < 0) ? c_DefaultAttenuationStartDistance : attenuationStartDistance; + m_SoundPropertiesUpToDate = false; + } /// /// Gets the custom pan value of this SoundContainer. @@ -214,8 +239,13 @@ namespace RTE { /// Sets the custom pan value of this SoundContainer. Clamped between -1 and 1. /// /// The new custom pan value. - void SetCustomPanValue(float customPanValue) { m_CustomPanValue = std::clamp(customPanValue, -1.0f, 1.0f); if (IsBeingPlayed()) { g_AudioMan.ChangeSoundContainerPlayingChannelsCustomPanValue(this); } } - + void SetCustomPanValue(float customPanValue) { + m_CustomPanValue = std::clamp(customPanValue, -1.0f, 1.0f); + if (IsBeingPlayed()) { + g_AudioMan.ChangeSoundContainerPlayingChannelsCustomPanValue(this); + } + } + /// /// Gets the panning strength multiplier of this SoundContainer. /// @@ -226,8 +256,11 @@ namespace RTE { /// Sets the panning strength multiplier of this SoundContainer. /// /// The new panning strength multiplier. - void SetPanningStrengthMultiplier(float panningStrengthMultiplier) { m_PanningStrengthMultiplier = panningStrengthMultiplier; m_SoundPropertiesUpToDate = false; } - + void SetPanningStrengthMultiplier(float panningStrengthMultiplier) { + m_PanningStrengthMultiplier = panningStrengthMultiplier; + m_SoundPropertiesUpToDate = false; + } + /// /// Gets the looping setting of this SoundContainer. /// @@ -239,7 +272,10 @@ namespace RTE { /// 0 means the sound is set to only play once. -1 means it loops indefinitely. /// /// The new loop count. - void SetLoopSetting(int loops) { m_Loops = loops; m_SoundPropertiesUpToDate = false; } + void SetLoopSetting(int loops) { + m_Loops = loops; + m_SoundPropertiesUpToDate = false; + } /// /// Gets whether the sounds in this SoundContainer have all had all their properties set appropriately. Used to account for issues with ordering in INI loading. @@ -275,14 +311,21 @@ namespace RTE { /// Gets the position at which this SoundContainer's sound will be played. Note that its individual sounds can be offset from this. /// /// The position of this SoundContainer. - const Vector & GetPosition() const { return m_Pos; } + const Vector& GetPosition() const { return m_Pos; } /// /// Sets the position of the SoundContainer's sounds while they're playing. /// /// The new position to play the SoundContainer's sounds. /// Whether this SoundContainer's attenuation setting was successful. - void SetPosition(const Vector &newPosition) { if (!m_Immobile && newPosition != m_Pos) { m_Pos = newPosition; if (IsBeingPlayed()) { g_AudioMan.ChangeSoundContainerPlayingChannelsPosition(this); } } } + void SetPosition(const Vector& newPosition) { + if (!m_Immobile && newPosition != m_Pos) { + m_Pos = newPosition; + if (IsBeingPlayed()) { + g_AudioMan.ChangeSoundContainerPlayingChannelsPosition(this); + } + } + } /// /// Gets the volume the sounds in this SoundContainer are played at. Note that this does not factor volume changes due to the SoundContainer's position. @@ -294,7 +337,13 @@ namespace RTE { /// Sets the volume sounds in this SoundContainer should be played at. Note that this does not factor volume changes due to the SoundContainer's position. Does not affect currently playing sounds. /// /// The new volume sounds in this SoundContainer should be played at. Limited between 0 and 10. - void SetVolume(float newVolume) { newVolume = std::clamp(newVolume, 0.0F, 10.0F); if (IsBeingPlayed()) { g_AudioMan.ChangeSoundContainerPlayingChannelsVolume(this, newVolume); } m_Volume = newVolume; } + void SetVolume(float newVolume) { + newVolume = std::clamp(newVolume, 0.0F, 10.0F); + if (IsBeingPlayed()) { + g_AudioMan.ChangeSoundContainerPlayingChannelsVolume(this, newVolume); + } + m_Volume = newVolume; + } /// /// Gets the pitch the sounds in this SoundContainer are played at. Note that this does not factor in global pitch. @@ -306,7 +355,12 @@ namespace RTE { /// Sets the pitch sounds in this SoundContainer should be played at and updates any playing instances accordingly. /// /// The new pitch sounds in this SoundContainer should be played at. Limited between 0.125 and 8 (8 octaves up or down). - void SetPitch(float newPitch) { m_Pitch = std::clamp(newPitch, 0.125F, 8.0F); if (IsBeingPlayed()) { g_AudioMan.ChangeSoundContainerPlayingChannelsPitch(this); } } + void SetPitch(float newPitch) { + m_Pitch = std::clamp(newPitch, 0.125F, 8.0F); + if (IsBeingPlayed()) { + g_AudioMan.ChangeSoundContainerPlayingChannelsPitch(this); + } + } /// /// Gets the pitch variation the sounds in this SoundContainer are played at. @@ -340,7 +394,7 @@ namespace RTE { /// /// The position at which to play the SoundContainer's sounds. /// Whether this SoundContainer successfully started playing on any channels. - bool Play(const Vector &position) { return Play(position, -1); } + bool Play(const Vector& position) { return Play(position, -1); } /// /// Plays the next sound of this SoundContainer with the given attenuation for a specific player. @@ -348,7 +402,10 @@ namespace RTE { /// The position at which to play the SoundContainer's sounds. /// The player to start playback of this SoundContainer's sounds for. /// Whether this SoundContainer successfully started playing on any channels. - bool Play(const Vector &position, int player) { SetPosition(position); return Play(player); } + bool Play(const Vector& position, int player) { + SetPosition(position); + return Play(player); + } /// /// Stops playback of this SoundContainer for all players. @@ -380,7 +437,11 @@ namespace RTE { /// Fades out playback of the SoundContainer to 0 volume. /// /// How long the fadeout should take. - void FadeOut(int fadeOutTime = 1000) { if (IsBeingPlayed()) { return g_AudioMan.FadeOutSoundContainerPlayingChannels(this, fadeOutTime); } } + void FadeOut(int fadeOutTime = 1000) { + if (IsBeingPlayed()) { + return g_AudioMan.FadeOutSoundContainerPlayingChannels(this, fadeOutTime); + } + } #pragma endregion #pragma region Miscellaneous @@ -393,28 +454,27 @@ namespace RTE { #pragma endregion private: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. static const std::unordered_map c_SoundOverlapModeMap; //!< A map of strings to SoundOverlapModes to support string parsing for the SoundOverlapMode enum. Populated in the implementing cpp file. static const std::unordered_map c_BusRoutingMap; //!< A map of strings to BusRoutings to support string parsing for the BusRouting enum. Populated in the implementing cpp file. - - SoundSet m_TopLevelSoundSet; //The top level SoundSet that handles all SoundData and sub SoundSets in this SoundContainer. + + SoundSet m_TopLevelSoundSet; // The top level SoundSet that handles all SoundData and sub SoundSets in this SoundContainer. std::unordered_set m_PlayingChannels; //!< The channels this SoundContainer is currently using. SoundOverlapMode m_SoundOverlapMode; //!< The SoundOverlapMode for this SoundContainer, used to determine how it should handle overlapping play calls. - + BusRouting m_BusRouting; //!< What bus this sound routes to. - + bool m_Immobile; //!< Whether this SoundContainer's sounds should be treated as immobile, i.e. not affected by 3D sound effects. float m_AttenuationStartDistance; //!< The distance away from the AudioSystem listener to start attenuating this sound. Attenuation follows FMOD 3D Inverse roll-off model. float m_CustomPanValue; //!< Custom stereo pan value using a Pan DSP on top of the basic spatialization. float m_PanningStrengthMultiplier; //!< Multiplier for panning strength. int m_Loops; //!< Number of loops (repeats) the SoundContainer's sounds should play when played. 0 means it plays once, -1 means it plays until stopped. bool m_SoundPropertiesUpToDate = false; //!< Whether this SoundContainer's sounds' modes and properties are up to date. Used primarily to handle discrepancies that can occur when loading from ini if the line ordering isn't ideal. - + int m_Priority; //!< The mixing priority of this SoundContainer's sounds. Higher values are more likely to be heard. bool m_AffectedByGlobalPitch; //!< Whether this SoundContainer's sounds should be able to be altered by global pitch changes. - + Vector m_Pos; //!< The current position of this SoundContainer's sounds. float m_Pitch; //!< The current natural pitch of this SoundContainer's sounds. float m_PitchVariation; //!< The randomized pitch variation of this SoundContainer's sounds. 1 means the sound will vary a full octave both ways. @@ -425,5 +485,5 @@ namespace RTE { /// void Clear(); }; -} +} // namespace RTE #endif diff --git a/Source/Entities/SoundSet.cpp b/Source/Entities/SoundSet.cpp index 0f1b306ec..1bdb6c999 100644 --- a/Source/Entities/SoundSet.cpp +++ b/Source/Entities/SoundSet.cpp @@ -8,12 +8,11 @@ namespace RTE { const std::string SoundSet::m_sClassName = "SoundSet"; const std::unordered_map SoundSet::c_SoundSelectionCycleModeMap = { - {"random", SoundSelectionCycleMode::RANDOM}, - {"forwards", SoundSelectionCycleMode::FORWARDS}, - {"all", SoundSelectionCycleMode::ALL} - }; + {"random", SoundSelectionCycleMode::RANDOM}, + {"forwards", SoundSelectionCycleMode::FORWARDS}, + {"all", SoundSelectionCycleMode::ALL}}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SoundSet::Clear() { m_SoundSelectionCycleMode = SoundSelectionCycleMode::RANDOM; @@ -23,15 +22,15 @@ namespace RTE { m_SubSoundSets.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SoundSet::Create(const SoundSet &reference) { + int SoundSet::Create(const SoundSet& reference) { m_SoundSelectionCycleMode = reference.m_SoundSelectionCycleMode; m_CurrentSelection = reference.m_CurrentSelection; - for (SoundData referenceSoundData : reference.m_SoundData) { + for (SoundData referenceSoundData: reference.m_SoundData) { m_SoundData.push_back(referenceSoundData); } - for (const SoundSet &referenceSoundSet : reference.m_SubSoundSets) { + for (const SoundSet& referenceSoundSet: reference.m_SubSoundSets) { SoundSet soundSet; soundSet.Create(referenceSoundSet); m_SubSoundSets.push_back(soundSet); @@ -40,11 +39,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SoundSet::ReadProperty(const std::string_view &propName, Reader &reader) { + int SoundSet::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("SoundSelectionCycleMode", { SetSoundSelectionCycleMode(ReadSoundSelectionCycleMode(reader)); }); MatchProperty("AddSound", { AddSoundData(ReadAndGetSoundData(reader)); }); MatchProperty("AddSoundSet", { @@ -52,27 +51,29 @@ namespace RTE { reader >> soundSetToAdd; AddSoundSet(soundSetToAdd); }); - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SoundSet::SoundData SoundSet::ReadAndGetSoundData(Reader &reader) { + SoundSet::SoundData SoundSet::ReadAndGetSoundData(Reader& reader) { SoundSet::SoundData soundData; /// /// Internal lambda function to load an audio file by path in as a ContentFile, which in turn loads it into FMOD, then returns SoundData for it in the outParam outSoundData. /// /// The path to the sound file. - auto readSoundFromPath = [&soundData, &reader](const std::string &soundPath) { + auto readSoundFromPath = [&soundData, &reader](const std::string& soundPath) { ContentFile soundFile(soundPath.c_str()); /// As Serializable::Create(&reader) isn't being used here, we need to set our formatted reader position manually. soundFile.SetFormattedReaderPosition("in file " + reader.GetCurrentFilePath() + " on line " + reader.GetCurrentFileLine()); - FMOD::Sound *soundObject = soundFile.GetAsSound(); - if (g_AudioMan.IsAudioEnabled() && !soundObject) { reader.ReportError(std::string("Failed to load the sound from the file")); } + FMOD::Sound* soundObject = soundFile.GetAsSound(); + if (g_AudioMan.IsAudioEnabled() && !soundObject) { + reader.ReportError(std::string("Failed to load the sound from the file")); + } soundData.SoundFile = soundFile; soundData.SoundObject = soundObject; @@ -100,13 +101,15 @@ namespace RTE { return soundData; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SoundSet::SoundSelectionCycleMode SoundSet::ReadSoundSelectionCycleMode(Reader &reader) { + SoundSet::SoundSelectionCycleMode SoundSet::ReadSoundSelectionCycleMode(Reader& reader) { SoundSelectionCycleMode soundSelectionCycleModeToReturn; std::string soundSelectionCycleModeString = reader.ReadPropValue(); std::locale locale; - for (char &character : soundSelectionCycleModeString) { character = std::tolower(character, locale); } + for (char& character: soundSelectionCycleModeString) { + character = std::tolower(character, locale); + } std::unordered_map::const_iterator soundSelectionCycleMode = c_SoundSelectionCycleModeMap.find(soundSelectionCycleModeString); if (soundSelectionCycleMode != c_SoundSelectionCycleModeMap.end()) { @@ -114,23 +117,23 @@ namespace RTE { } else { try { soundSelectionCycleModeToReturn = static_cast(std::stoi(soundSelectionCycleModeString)); - } catch (const std::exception &) { + } catch (const std::exception&) { reader.ReportError("Sound selection cycle mode " + soundSelectionCycleModeString + " is invalid."); } } - + return soundSelectionCycleModeToReturn; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SoundSet::Save(Writer &writer) const { + int SoundSet::Save(Writer& writer) const { Serializable::Save(writer); writer.NewProperty("SoundSelectionCycleMode"); SaveSoundSelectionCycleMode(writer, m_SoundSelectionCycleMode); - for (const SoundData &soundData : m_SoundData) { + for (const SoundData& soundData: m_SoundData) { writer.NewProperty("AddSound"); writer.ObjectStart("ContentFile"); @@ -146,7 +149,7 @@ namespace RTE { writer.ObjectEnd(); } - for (const SoundSet &subSoundSet : m_SubSoundSets) { + for (const SoundSet& subSoundSet: m_SubSoundSets) { writer.NewProperty("AddSoundSet"); writer.ObjectStart("SoundSet"); writer << subSoundSet; @@ -156,9 +159,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - void SoundSet::SaveSoundSelectionCycleMode(Writer &writer, SoundSelectionCycleMode soundSelectionCycleMode) { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SoundSet::SaveSoundSelectionCycleMode(Writer& writer, SoundSelectionCycleMode soundSelectionCycleMode) { auto cycleModeMapEntry = std::find_if(c_SoundSelectionCycleModeMap.begin(), c_SoundSelectionCycleModeMap.end(), [&soundSelectionCycleMode = soundSelectionCycleMode](auto element) { return element.second == soundSelectionCycleMode; }); if (cycleModeMapEntry != c_SoundSelectionCycleModeMap.end()) { writer << cycleModeMapEntry->first; @@ -167,11 +170,11 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SoundSet::AddSound(const std::string &soundFilePath, const Vector &offset, float minimumAudibleDistance, float attenuationStartDistance, bool abortGameForInvalidSound) { + void SoundSet::AddSound(const std::string& soundFilePath, const Vector& offset, float minimumAudibleDistance, float attenuationStartDistance, bool abortGameForInvalidSound) { ContentFile soundFile(soundFilePath.c_str()); - FMOD::Sound *soundObject = soundFile.GetAsSound(abortGameForInvalidSound, false); + FMOD::Sound* soundObject = soundFile.GetAsSound(abortGameForInvalidSound, false); if (!soundObject) { return; } @@ -179,24 +182,28 @@ namespace RTE { m_SoundData.push_back({soundFile, soundObject, offset, minimumAudibleDistance, attenuationStartDistance}); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool SoundSet::RemoveSound(const std::string &soundFilePath, bool removeFromSubSoundSets) { - auto soundsToRemove = std::remove_if(m_SoundData.begin(), m_SoundData.end(), [&soundFilePath](const SoundSet::SoundData &soundData) { return soundData.SoundFile.GetDataPath() == soundFilePath; }); + bool SoundSet::RemoveSound(const std::string& soundFilePath, bool removeFromSubSoundSets) { + auto soundsToRemove = std::remove_if(m_SoundData.begin(), m_SoundData.end(), [&soundFilePath](const SoundSet::SoundData& soundData) { return soundData.SoundFile.GetDataPath() == soundFilePath; }); bool anySoundsToRemove = soundsToRemove != m_SoundData.end(); - if (anySoundsToRemove) { m_SoundData.erase(soundsToRemove, m_SoundData.end()); } + if (anySoundsToRemove) { + m_SoundData.erase(soundsToRemove, m_SoundData.end()); + } if (removeFromSubSoundSets) { - for (SoundSet subSoundSet : m_SubSoundSets) { anySoundsToRemove |= RemoveSound(soundFilePath, removeFromSubSoundSets); } + for (SoundSet subSoundSet: m_SubSoundSets) { + anySoundsToRemove |= RemoveSound(soundFilePath, removeFromSubSoundSets); + } } return anySoundsToRemove; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SoundSet::HasAnySounds(bool includeSubSoundSets) const { bool hasAnySounds = !m_SoundData.empty(); if (!hasAnySounds && includeSubSoundSets) { - for (const SoundSet &subSoundSet : m_SubSoundSets) { + for (const SoundSet& subSoundSet: m_SubSoundSets) { hasAnySounds = subSoundSet.HasAnySounds(); if (hasAnySounds) { break; @@ -206,12 +213,16 @@ namespace RTE { return hasAnySounds; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SoundSet::GetFlattenedSoundData(std::vector &flattenedSoundData, bool onlyGetSelectedSoundData) { + void SoundSet::GetFlattenedSoundData(std::vector& flattenedSoundData, bool onlyGetSelectedSoundData) { if (!onlyGetSelectedSoundData || m_SoundSelectionCycleMode == SoundSelectionCycleMode::ALL) { - for (SoundData &soundData : m_SoundData) { flattenedSoundData.push_back(&soundData); } - for (SoundSet &subSoundSet : m_SubSoundSets) { subSoundSet.GetFlattenedSoundData(flattenedSoundData, onlyGetSelectedSoundData); } + for (SoundData& soundData: m_SoundData) { + flattenedSoundData.push_back(&soundData); + } + for (SoundSet& subSoundSet: m_SubSoundSets) { + subSoundSet.GetFlattenedSoundData(flattenedSoundData, onlyGetSelectedSoundData); + } } else { if (m_CurrentSelection.first == false) { flattenedSoundData.push_back(&m_SoundData[m_CurrentSelection.second]); @@ -221,12 +232,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SoundSet::GetFlattenedSoundData(std::vector &flattenedSoundData, bool onlyGetSelectedSoundData) const { + void SoundSet::GetFlattenedSoundData(std::vector& flattenedSoundData, bool onlyGetSelectedSoundData) const { if (!onlyGetSelectedSoundData || m_SoundSelectionCycleMode == SoundSelectionCycleMode::ALL) { - for (const SoundData &soundData : m_SoundData) { flattenedSoundData.push_back(&soundData); } - for (const SoundSet &subSoundSet : m_SubSoundSets) { subSoundSet.GetFlattenedSoundData(flattenedSoundData, onlyGetSelectedSoundData); } + for (const SoundData& soundData: m_SoundData) { + flattenedSoundData.push_back(&soundData); + } + for (const SoundSet& subSoundSet: m_SubSoundSets) { + subSoundSet.GetFlattenedSoundData(flattenedSoundData, onlyGetSelectedSoundData); + } } else { if (m_CurrentSelection.first == false) { flattenedSoundData.push_back(&m_SoundData[m_CurrentSelection.second]); @@ -236,11 +251,11 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SoundSet::SelectNextSounds() { if (m_SoundSelectionCycleMode == SoundSelectionCycleMode::ALL) { - for (SoundSet &subSoundSet : m_SubSoundSets) { + for (SoundSet& subSoundSet: m_SubSoundSets) { if (!subSoundSet.SelectNextSounds()) { return false; } @@ -311,4 +326,4 @@ namespace RTE { return true; } -} +} // namespace RTE diff --git a/Source/Entities/SoundSet.h b/Source/Entities/SoundSet.h index c4affe429..f39f1a7e7 100644 --- a/Source/Entities/SoundSet.h +++ b/Source/Entities/SoundSet.h @@ -14,7 +14,6 @@ namespace RTE { friend struct EntityLuaBindings; public: - SerializableOverrideMethods; /// @@ -31,7 +30,7 @@ namespace RTE { /// struct SoundData { ContentFile SoundFile; - FMOD::Sound *SoundObject; + FMOD::Sound* SoundObject; Vector Offset = Vector(); float MinimumAudibleDistance = 0.0F; float AttenuationStartDistance = -1.0F; @@ -48,7 +47,7 @@ namespace RTE { /// /// A reference to the SoundSet to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const SoundSet &reference); + int Create(const SoundSet& reference); #pragma endregion #pragma region Destruction @@ -70,21 +69,21 @@ namespace RTE { /// /// A Reader lined up to the value of the property to be read. /// SoundData for the newly read sound. - static SoundData ReadAndGetSoundData(Reader &reader); + static SoundData ReadAndGetSoundData(Reader& reader); /// /// Handles turning a SoundCelectionCycleMode from its user-friendly name in INI to its enum value, using the static SoundSelectionCycleMap. /// /// A Reader lined up to the value of the property to be read. /// The appropriate SoundSelectionCycleMode for the given INI value. - static SoundSelectionCycleMode ReadSoundSelectionCycleMode(Reader &reader); + static SoundSelectionCycleMode ReadSoundSelectionCycleMode(Reader& reader); /// /// Handles writing the given SoundSelectionCycleMode out to the given Writer, using the static SoundSelectionCycleMap. /// /// A Writer filled in with the property to write to. /// The SoundSelectionCycleMode to write. - static void SaveSoundSelectionCycleMode(Writer &writer, SoundSelectionCycleMode soundSelectionCycleMode); + static void SaveSoundSelectionCycleMode(Writer& writer, SoundSelectionCycleMode soundSelectionCycleMode); #pragma endregion #pragma region SoundData and SoundSet Addition @@ -92,14 +91,14 @@ namespace RTE { /// Adds a new sound to this SoundSet, spitting out a Lua error if it fails. The sound will have default configuration. /// /// A path to the new sound to add. This will be handled through PresetMan. - void AddSound(const std::string &soundFilePath) { AddSound(soundFilePath, false); } + void AddSound(const std::string& soundFilePath) { AddSound(soundFilePath, false); } /// /// Adds a new sound to this SoundSet, either spitting out a Lua error or aborting if it fails. The sound will have default configuration. /// /// A path to the new sound to add. This will be handled through PresetMan. /// Whether to abort the game if the sound couldn't be added, or just show a console error. - void AddSound(const std::string &soundFilePath, bool abortGameForInvalidSound) { AddSound(soundFilePath, Vector(), 0, -1, abortGameForInvalidSound); } + void AddSound(const std::string& soundFilePath, bool abortGameForInvalidSound) { AddSound(soundFilePath, Vector(), 0, -1, abortGameForInvalidSound); } /// /// Adds a new sound to this SoundSet, spitting out a Lua error if it fails. The sound will be configured based on parameters. @@ -108,7 +107,7 @@ namespace RTE { /// The offset position to play this sound at, where (0, 0) is no offset. /// The minimum distance at which this sound will be audible. 0 means there is none, which is normally the case. /// The attenuation start distance for this sound, -1 sets it to default. - void AddSound(const std::string &soundFilePath, const Vector &offset, float minimumAudibleDistance, float attenuationStartDistance) { AddSound(soundFilePath, offset, minimumAudibleDistance, attenuationStartDistance, false); } + void AddSound(const std::string& soundFilePath, const Vector& offset, float minimumAudibleDistance, float attenuationStartDistance) { AddSound(soundFilePath, offset, minimumAudibleDistance, attenuationStartDistance, false); } /// /// Adds a new sound to this SoundSet, either spitting out a Lua error or aborting if it fails. The sound will be configured based on parameters. @@ -118,14 +117,14 @@ namespace RTE { /// The minimum distance at which this sound will be audible. 0 means there is none, which is normally the case. /// The attenuation start distance for this sound, -1 sets it to default. /// Whether to abort the game if the sound couldn't be added, or just show a console error. - void AddSound(const std::string &soundFilePath, const Vector &offset, float minimumAudibleDistance, float attenuationStartDistance, bool abortGameForInvalidSound); + void AddSound(const std::string& soundFilePath, const Vector& offset, float minimumAudibleDistance, float attenuationStartDistance, bool abortGameForInvalidSound); /// /// Removes all instances of the sound with the given filepath from this SoundSet. Does not remove it from any sub-SoundSets. /// /// The path to the sound to be removed from this SoundSet. /// Whether or not a sound with the given filepath was found in this SoundSet. - bool RemoveSound(const std::string &soundFilePath) { return RemoveSound(soundFilePath, false); } + bool RemoveSound(const std::string& soundFilePath) { return RemoveSound(soundFilePath, false); } /// /// Removes all instances of the sound with the given filepath from this SoundSet, optionally removing it from all sub-SoundSets as well. @@ -133,19 +132,19 @@ namespace RTE { /// The path to the sound to be removed from this SoundSet. /// Whether or not to remove the sound from any sub-SoundSets as well as this SoundSet. /// Whether or not a sound with the given filepath was found in this SoundSet or, if set to remove from sub-SoundSets, any of its sub-SoundSets. - bool RemoveSound(const std::string &soundFilePath, bool removeFromSubSoundSets); + bool RemoveSound(const std::string& soundFilePath, bool removeFromSubSoundSets); /// /// Adds a copy of the given SoundData to this SoundSet. /// /// The SoundData to copy to this SoundSet. - void AddSoundData(const SoundData &soundDataToAdd) { m_SoundData.push_back(soundDataToAdd); } + void AddSoundData(const SoundData& soundDataToAdd) { m_SoundData.push_back(soundDataToAdd); } /// /// Adds a copy of the passed in SoundSet as a sub SoundSet of this SoundSet. Ownership IS transferred! /// /// A reference to the SoundSet to be copied in as a sub SoundSet of this SoundSet. Ownership IS transferred! - void AddSoundSet(const SoundSet &soundSetToAdd) { m_SubSoundSets.push_back(soundSetToAdd); } + void AddSoundSet(const SoundSet& soundSetToAdd) { m_SubSoundSets.push_back(soundSetToAdd); } #pragma endregion #pragma region Getters and Setters @@ -165,27 +164,32 @@ namespace RTE { /// Sets the SoundSelectionCycleMode for this SoundSet, which is used to determine what SoundSet to select next time SelectNextSounds is called. /// /// The new SoundSelectionCycleMode for this SoundSet. - void SetSoundSelectionCycleMode(SoundSelectionCycleMode newSoundSelectionCycleMode) { m_SoundSelectionCycleMode = newSoundSelectionCycleMode; if (m_SoundSelectionCycleMode == SoundSelectionCycleMode::FORWARDS) { m_CurrentSelection.second = -1; } } + void SetSoundSelectionCycleMode(SoundSelectionCycleMode newSoundSelectionCycleMode) { + m_SoundSelectionCycleMode = newSoundSelectionCycleMode; + if (m_SoundSelectionCycleMode == SoundSelectionCycleMode::FORWARDS) { + m_CurrentSelection.second = -1; + } + } /// /// Fills the passed in vector with the flattened SoundData in the SoundSet, optionally only getting currently selected SoundData. /// /// A reference vector of SoundData references to be filled with this SoundSet's flattened SoundData. /// Whether to only get SoundData that is currently selected, or to get all SoundData in this SoundSet. - void GetFlattenedSoundData(std::vector &flattenedSoundData, bool onlyGetSelectedSoundData); + void GetFlattenedSoundData(std::vector& flattenedSoundData, bool onlyGetSelectedSoundData); /// /// Fills the passed in vector with the flattened SoundData in the SoundSet, optionally only getting currently selected SoundData. /// /// A reference vector of SoundData references to be filled with this SoundSet's flattened SoundData. /// Whether to only get SoundData that is currently selected, or to get all SoundData in this SoundSet. - void GetFlattenedSoundData(std::vector &flattenedSoundData, bool onlyGetSelectedSoundData) const; + void GetFlattenedSoundData(std::vector& flattenedSoundData, bool onlyGetSelectedSoundData) const; /// /// Gets the vector of SubSoundSets for this SoundSet. /// /// The vector of SubSoundSets for this SoundSet. - std::vector & GetSubSoundSets() { return m_SubSoundSets; } + std::vector& GetSubSoundSets() { return m_SubSoundSets; } #pragma endregion #pragma region Miscellaneous @@ -201,11 +205,10 @@ namespace RTE { /// Gets the class name of this Serializable. /// /// A string with the friendly-formatted type name of this object. - const std::string &GetClassName() const override { return m_sClassName; } + const std::string& GetClassName() const override { return m_sClassName; } #pragma endregion private: - static const std::string m_sClassName; //!< A string with the friendly-formatted type name of this object. static const std::unordered_map c_SoundSelectionCycleModeMap; //!< A map of strings to SoundSelectionCycleModes to support string parsing for the SoundCycleMode enum. Populated in the implementing cpp file. @@ -220,5 +223,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/TDExplosive.cpp b/Source/Entities/TDExplosive.cpp index 90f21614d..99a59f98e 100644 --- a/Source/Entities/TDExplosive.cpp +++ b/Source/Entities/TDExplosive.cpp @@ -4,27 +4,29 @@ namespace RTE { ConcreteClassInfo(TDExplosive, ThrownDevice, 50); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TDExplosive::Clear() { m_IsAnimatedManually = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int TDExplosive::Create() { if (ThrownDevice::Create() < 0) { return -1; } - if (IsInGroup("Bombs - Payloads")) { m_HUDVisible = false; } + if (IsInGroup("Bombs - Payloads")) { + m_HUDVisible = false; + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TDExplosive::Create(const TDExplosive &reference) { + int TDExplosive::Create(const TDExplosive& reference) { if (ThrownDevice::Create(reference) < 0) { return -1; } @@ -33,14 +35,16 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TDExplosive::ReadProperty(const std::string_view &propName, Reader &reader) { + int TDExplosive::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return ThrownDevice::ReadProperty(propName, reader)); - + // TODO: Consider removing DetonationSound as GibSound already exists and could be used in its place MatchProperty("DetonationSound", { - if (!m_GibSound) { m_GibSound = new SoundContainer; } + if (!m_GibSound) { + m_GibSound = new SoundContainer; + } reader >> m_GibSound; }); MatchProperty("IsAnimatedManually", { reader >> m_IsAnimatedManually; }); @@ -48,32 +52,38 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TDExplosive::Save(Writer &writer) const { + int TDExplosive::Save(Writer& writer) const { ThrownDevice::Save(writer); writer.NewProperty("IsAnimatedManually"); writer << m_IsAnimatedManually; return 0; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TDExplosive::Update() { ThrownDevice::Update(); if (m_Activated) { // Display active frame if no animation mode has been defined - if (!m_IsAnimatedManually && m_SpriteAnimMode == NOANIM && m_FrameCount > 1) { m_Frame = 1; } + if (!m_IsAnimatedManually && m_SpriteAnimMode == NOANIM && m_FrameCount > 1) { + m_Frame = 1; + } m_RestTimer.Reset(); m_ToSettle = false; } - if (m_Activated && m_ActivationTimer.GetElapsedSimTimeMS() >= m_TriggerDelay) { GibThis(); } + if (m_Activated && m_ActivationTimer.GetElapsedSimTimeMS() >= m_TriggerDelay) { + GibThis(); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TDExplosive::DrawHUD(BITMAP *targetBitmap, const Vector &targetPos, int whichScreen, bool playerControlled) { - if (m_HUDVisible && !m_Activated) { ThrownDevice::DrawHUD(targetBitmap, targetPos, whichScreen); } + void TDExplosive::DrawHUD(BITMAP* targetBitmap, const Vector& targetPos, int whichScreen, bool playerControlled) { + if (m_HUDVisible && !m_Activated) { + ThrownDevice::DrawHUD(targetBitmap, targetPos, whichScreen); + } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/TDExplosive.h b/Source/Entities/TDExplosive.h index 9f6dcb7ac..bdc15d1e5 100644 --- a/Source/Entities/TDExplosive.h +++ b/Source/Entities/TDExplosive.h @@ -11,7 +11,6 @@ namespace RTE { class TDExplosive : public ThrownDevice { public: - EntityAllocation(TDExplosive); SerializableOverrideMethods; ClassInfoGetters; @@ -33,7 +32,7 @@ namespace RTE { /// /// A reference to the TDExplosive to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const TDExplosive &reference); + int Create(const TDExplosive& reference); #pragma endregion #pragma region Destruction @@ -46,12 +45,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the SceneLayer object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { ThrownDevice::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + ThrownDevice::Destroy(); + } + Clear(); + } /// /// Resets the entire TDExplosive, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); ThrownDevice::Reset(); } + void Reset() override { + Clear(); + ThrownDevice::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -81,26 +88,24 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// Which player's screen this is being drawn to. May affect what HUD elements get drawn etc. /// Whether or not this MovableObject is currently player controlled (not applicable for TDExplosive). - void DrawHUD(BITMAP *targetBitmap, const Vector &targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; + void DrawHUD(BITMAP* targetBitmap, const Vector& targetPos = Vector(), int whichScreen = 0, bool playerControlled = false) override; #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. bool m_IsAnimatedManually; //!< If true m_Frame is not changed during an update hence the animation is done by external Lua code. private: - /// /// Clears all the member variables of this TDExplosive, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - TDExplosive(const TDExplosive &reference) = delete; - TDExplosive & operator=(const TDExplosive &rhs) = delete; + TDExplosive(const TDExplosive& reference) = delete; + TDExplosive& operator=(const TDExplosive& rhs) = delete; }; -} +} // namespace RTE -#endif \ No newline at end of file +#endif diff --git a/Source/Entities/TerrainDebris.cpp b/Source/Entities/TerrainDebris.cpp index e470867b3..5624997d9 100644 --- a/Source/Entities/TerrainDebris.cpp +++ b/Source/Entities/TerrainDebris.cpp @@ -5,7 +5,7 @@ namespace RTE { ConcreteClassInfo(TerrainDebris, Entity, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TerrainDebris::Clear() { m_DebrisFile.Reset(); @@ -25,7 +25,7 @@ namespace RTE { m_Density = 0.01F; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int TerrainDebris::Create() { Entity::Create(); @@ -34,9 +34,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainDebris::Create(const TerrainDebris &reference) { + int TerrainDebris::Create(const TerrainDebris& reference) { Entity::Create(reference); m_DebrisFile = reference.m_DebrisFile; @@ -59,11 +59,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainDebris::ReadProperty(const std::string_view &propName, Reader &reader) { + int TerrainDebris::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Entity::ReadProperty(propName, reader)); - + MatchProperty("DebrisFile", { reader >> m_DebrisFile; }); MatchProperty("DebrisPieceCount", { reader >> m_BitmapCount; @@ -73,7 +73,9 @@ namespace RTE { MatchProperty("TargetMaterial", { reader >> m_TargetMaterial; }); MatchProperty("DebrisPlacementMode", { m_DebrisPlacementMode = static_cast(std::stoi(reader.ReadPropValue())); - if (m_DebrisPlacementMode < DebrisPlacementMode::NoPlacementRestrictions || m_DebrisPlacementMode > DebrisPlacementMode::OnOverhangAndCavityOverhang) { reader.ReportError("Invalid TerrainDebris placement mode!"); } + if (m_DebrisPlacementMode < DebrisPlacementMode::NoPlacementRestrictions || m_DebrisPlacementMode > DebrisPlacementMode::OnOverhangAndCavityOverhang) { + reader.ReportError("Invalid TerrainDebris placement mode!"); + } }); MatchProperty("OnlyBuried", { reader >> m_OnlyBuried; }); MatchProperty("MinDepth", { reader >> m_MinDepth; }); @@ -84,14 +86,13 @@ namespace RTE { MatchProperty("CanVFlip", { reader >> m_CanVFlip; }); MatchProperty("FlipChance", { reader >> m_FlipChance; }); MatchProperty("DensityPerMeter", { reader >> m_Density; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainDebris::Save(Writer &writer) const { + int TerrainDebris::Save(Writer& writer) const { Entity::Save(writer); writer.NewPropertyWithValue("DebrisFile", m_DebrisFile); @@ -112,10 +113,10 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool TerrainDebris::GetPiecePlacementPosition(SLTerrain *terrain, Box &possiblePiecePosition) const { - BITMAP *matBitmap = terrain->GetMaterialBitmap(); + bool TerrainDebris::GetPiecePlacementPosition(SLTerrain* terrain, Box& possiblePiecePosition) const { + BITMAP* matBitmap = terrain->GetMaterialBitmap(); int posX = RandomNum(0, matBitmap->w); int depth = RandomNum(m_MinDepth, m_MaxDepth); int buriedDepthOffset = m_OnlyBuried ? static_cast(possiblePiecePosition.GetHeight() * 0.6F) : 0; @@ -129,10 +130,10 @@ namespace RTE { int materialCheckPixel = _getpixel(matBitmap, posX, posY); if (materialCheckPixel != MaterialColorKeys::g_MaterialAir) { // TODO: Adding depth here will properly place debris only on target material, rather than any random pixel within depth range from the original target material pixel. - int depthAdjustedPosY = posY;// + (depth * (scanForOverhang ? -1 : 1)); + int depthAdjustedPosY = posY; // + (depth * (scanForOverhang ? -1 : 1)); if (scanForOverhang ? (depthAdjustedPosY > 0) : (depthAdjustedPosY < matBitmap->h)) { // TODO: Enable the depth check once multi TargetMaterial debris is supported. - //materialCheckPixel = _getpixel(matBitmap, posX, depthAdjustedPosY); + // materialCheckPixel = _getpixel(matBitmap, posX, depthAdjustedPosY); if (MaterialPixelIsValidTarget(materialCheckPixel, prevMaterialCheckPixel)) { surfacePosY += (depth + buriedDepthOffset); overhangPosY -= (depth + buriedDepthOffset); @@ -148,7 +149,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool TerrainDebris::MaterialPixelIsValidTarget(int materialCheckPixel, int prevMaterialCheckPixel) const { bool checkResult = true; @@ -160,15 +161,21 @@ namespace RTE { switch (m_DebrisPlacementMode) { case DebrisPlacementMode::OnSurfaceOnly: case DebrisPlacementMode::OnOverhangOnly: - if (prevMaterialCheckPixel != MaterialColorKeys::g_MaterialAir) { checkResult = false; } + if (prevMaterialCheckPixel != MaterialColorKeys::g_MaterialAir) { + checkResult = false; + } break; case DebrisPlacementMode::OnCavitySurfaceOnly: case DebrisPlacementMode::OnCavityOverhangOnly: - if (prevMaterialCheckPixel != MaterialColorKeys::g_MaterialCavity) { checkResult = false; } + if (prevMaterialCheckPixel != MaterialColorKeys::g_MaterialCavity) { + checkResult = false; + } break; case DebrisPlacementMode::OnSurfaceAndCavitySurface: case DebrisPlacementMode::OnOverhangAndCavityOverhang: - if (prevMaterialCheckPixel != MaterialColorKeys::g_MaterialAir && prevMaterialCheckPixel != MaterialColorKeys::g_MaterialCavity) { checkResult = false; } + if (prevMaterialCheckPixel != MaterialColorKeys::g_MaterialAir && prevMaterialCheckPixel != MaterialColorKeys::g_MaterialCavity) { + checkResult = false; + } break; default: // No placement restrictions, pixel just needs to be of target material. @@ -178,12 +185,12 @@ namespace RTE { return checkResult; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TerrainDebris::DrawToTerrain(SLTerrain *terrain, BITMAP *bitmapToDraw, const Vector &position) const { + void TerrainDebris::DrawToTerrain(SLTerrain* terrain, BITMAP* bitmapToDraw, const Vector& position) const { // Create a square temp bitmap that is larger than the original to avoid clipping if rotating. int dimensions = 10 + std::max(bitmapToDraw->w, bitmapToDraw->h); - BITMAP *tempDrawBitmap = create_bitmap_ex(8, dimensions, dimensions); + BITMAP* tempDrawBitmap = create_bitmap_ex(8, dimensions, dimensions); clear_bitmap(tempDrawBitmap); // Offset the original bitmap on the temp bitmap so it's centered, otherwise will be positioned incorrectly and can clip if rotated or flipped. @@ -191,7 +198,7 @@ namespace RTE { int offsetY = (dimensions - bitmapToDraw->h) / 2; blit(bitmapToDraw, tempDrawBitmap, 0, 0, offsetX, offsetY, bitmapToDraw->w, bitmapToDraw->h); - BITMAP *tempFlipAndRotBitmap = nullptr; + BITMAP* tempFlipAndRotBitmap = nullptr; if (m_CanHFlip || m_CanVFlip || m_MinRotation != 0 || m_MaxRotation != 0) { tempFlipAndRotBitmap = create_bitmap_ex(8, dimensions, dimensions); @@ -214,28 +221,32 @@ namespace RTE { draw_sprite(terrain->GetFGColorBitmap(), tempDrawBitmap, position.GetFloorIntX() - offsetX, position.GetFloorIntY() - offsetY); draw_character_ex(terrain->GetMaterialBitmap(), tempDrawBitmap, position.GetFloorIntX() - offsetX, position.GetFloorIntY() - offsetY, m_Material.GetIndex(), -1); - if (tempFlipAndRotBitmap) { destroy_bitmap(tempFlipAndRotBitmap); } + if (tempFlipAndRotBitmap) { + destroy_bitmap(tempFlipAndRotBitmap); + } destroy_bitmap(tempDrawBitmap); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TerrainDebris::ScatterOnTerrain(SLTerrain *terrain) { + void TerrainDebris::ScatterOnTerrain(SLTerrain* terrain) { RTEAssert(!m_Bitmaps.empty() && m_BitmapCount > 0, "No bitmaps loaded for terrain debris during TerrainDebris::ScatterOnTerrain!"); // Reference. Do not remove. - //acquire_bitmap(terrain->GetFGColorBitmap()); - //acquire_bitmap(terrain->GetMaterialBitmap()); + // acquire_bitmap(terrain->GetFGColorBitmap()); + // acquire_bitmap(terrain->GetMaterialBitmap()); int possiblePieceToPlaceCount = static_cast((static_cast(terrain->GetMaterialBitmap()->w) * c_MPP) * m_Density); for (int piece = 0; piece < possiblePieceToPlaceCount; ++piece) { int pieceBitmapIndex = RandomNum(0, m_BitmapCount - 1); RTEAssert(pieceBitmapIndex >= 0 && pieceBitmapIndex < m_BitmapCount, "Bitmap index was out of bounds during TerrainDebris::ScatterOnTerrain!"); Box possiblePiecePosition(Vector(), static_cast(m_Bitmaps[pieceBitmapIndex]->w), static_cast(m_Bitmaps.at(pieceBitmapIndex)->h)); - if (GetPiecePlacementPosition(terrain, possiblePiecePosition)) { DrawToTerrain(terrain, m_Bitmaps[pieceBitmapIndex], possiblePiecePosition.GetCorner()); } + if (GetPiecePlacementPosition(terrain, possiblePiecePosition)) { + DrawToTerrain(terrain, m_Bitmaps[pieceBitmapIndex], possiblePiecePosition.GetCorner()); + } } // Reference. Do not remove. - //release_bitmap(terrain->GetMaterialBitmap()); - //release_bitmap(terrain->GetFGColorBitmap()); + // release_bitmap(terrain->GetMaterialBitmap()); + // release_bitmap(terrain->GetFGColorBitmap()); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/TerrainDebris.h b/Source/Entities/TerrainDebris.h index ddcf01a29..6f3c837ac 100644 --- a/Source/Entities/TerrainDebris.h +++ b/Source/Entities/TerrainDebris.h @@ -16,7 +16,6 @@ namespace RTE { class TerrainDebris : public Entity { public: - EntityAllocation(TerrainDebris); SerializableOverrideMethods; ClassInfoGetters; @@ -38,7 +37,7 @@ namespace RTE { /// /// A reference to the TerrainDebris to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const TerrainDebris &reference); + int Create(const TerrainDebris& reference); #pragma endregion #pragma region Destruction @@ -51,7 +50,12 @@ namespace RTE { /// Destroys and resets (through Clear()) the TerrainDebris object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { Entity::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + Entity::Destroy(); + } + Clear(); + } #pragma endregion #pragma region Concrete Methods @@ -59,11 +63,10 @@ namespace RTE { /// Places random pieces of this TerrainDebris's at random positions on the specified SLTerrain. /// /// The SLTerrain to scatter this TerrainDebris on. Ownership is NOT transferred! - void ScatterOnTerrain(SLTerrain *terrain); + void ScatterOnTerrain(SLTerrain* terrain); #pragma endregion private: - /// /// Enumeration for the different debris placement modes. /// @@ -80,7 +83,7 @@ namespace RTE { static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. ContentFile m_DebrisFile; //!< ContentFile containing the path to the debris sprites. - std::vector m_Bitmaps; //!< All the different bitmaps of this debris. Not owned. + std::vector m_Bitmaps; //!< All the different bitmaps of this debris. Not owned. int m_BitmapCount; //!< How many individual pieces this debris has. Material m_Material; //!< The Material of the debris. @@ -108,7 +111,7 @@ namespace RTE { /// Pointer to the SLTerrain to check debris placement on. Ownership is NOT transferred! /// A Box that holds the debris piece's dimensions. The center position of the Box will be modified during checking. /// True if a valid placement position was found, which means the passed in Box's center or corner positions are good to be used as the piece's drawing position. - bool GetPiecePlacementPosition(SLTerrain *terrain, Box &possiblePiecePosition) const; + bool GetPiecePlacementPosition(SLTerrain* terrain, Box& possiblePiecePosition) const; /// /// Checks whether the passed in pixel color value is of target Material, and if extra conditions apply for it to be valid for placement, depending on DebrisPlacementMode. @@ -124,7 +127,7 @@ namespace RTE { /// Pointer to the SLTerrain to draw the debris piece on. Ownership is NOT transferred! /// The BITMAP to draw. Ownership is NOT transferred! /// The position to draw the debris piece on the terrain. - void DrawToTerrain(SLTerrain *terrain, BITMAP *bitmapToDraw, const Vector &position) const; + void DrawToTerrain(SLTerrain* terrain, BITMAP* bitmapToDraw, const Vector& position) const; #pragma endregion /// @@ -133,8 +136,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - TerrainDebris(const TerrainDebris &reference) = delete; - void operator=(const TerrainDebris &rhs) = delete; + TerrainDebris(const TerrainDebris& reference) = delete; + void operator=(const TerrainDebris& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/TerrainFrosting.cpp b/Source/Entities/TerrainFrosting.cpp index 260bf29cd..a2a2807f7 100644 --- a/Source/Entities/TerrainFrosting.cpp +++ b/Source/Entities/TerrainFrosting.cpp @@ -5,7 +5,7 @@ namespace RTE { const std::string TerrainFrosting::c_ClassName = "TerrainFrosting"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TerrainFrosting::Clear() { m_FrostingMaterial.Reset(); @@ -15,24 +15,23 @@ namespace RTE { m_InAirOnly = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainFrosting::ReadProperty(const std::string_view &propName, Reader &reader) { + int TerrainFrosting::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("FrostingMaterial", { reader >> m_FrostingMaterial; }); MatchProperty("TargetMaterial", { reader >> m_TargetMaterial; }); MatchProperty("MinThickness", { reader >> m_MinThickness; }); MatchProperty("MaxThickness", { reader >> m_MaxThickness; }); MatchProperty("InAirOnly", { reader >> m_InAirOnly; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainFrosting::Save(Writer &writer) const { + int TerrainFrosting::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("FrostingMaterial", m_FrostingMaterial); @@ -44,21 +43,21 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TerrainFrosting::FrostTerrain(SLTerrain *terrain) const { - BITMAP *frostingTexture = m_FrostingMaterial.GetFGTexture(); - BITMAP *fgColorBitmap = terrain->GetFGColorBitmap(); - BITMAP *matBitmap = terrain->GetBitmap(); + void TerrainFrosting::FrostTerrain(SLTerrain* terrain) const { + BITMAP* frostingTexture = m_FrostingMaterial.GetFGTexture(); + BITMAP* fgColorBitmap = terrain->GetFGColorBitmap(); + BITMAP* matBitmap = terrain->GetBitmap(); bool targetMatFound = false; bool applyingFrosting = false; int appliedThickness = 0; // Reference. Do not remove. - //acquire_bitmap(matBitmap); - //acquire_bitmap(fgColorBitmap); - //if (frostingTexture) { acquire_bitmap(frostingTexture); } + // acquire_bitmap(matBitmap); + // acquire_bitmap(fgColorBitmap); + // if (frostingTexture) { acquire_bitmap(frostingTexture); } for (int xPos = 0; xPos < matBitmap->w; ++xPos) { int thicknessGoal = RandomNum(m_MinThickness, m_MaxThickness); @@ -83,8 +82,8 @@ namespace RTE { } } // Reference. Do not remove. - //if (frostingTexture) { release_bitmap(frostingTexture); } - //release_bitmap(fgColorBitmap); - //release_bitmap(matBitmap); + // if (frostingTexture) { release_bitmap(frostingTexture); } + // release_bitmap(fgColorBitmap); + // release_bitmap(matBitmap); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/TerrainFrosting.h b/Source/Entities/TerrainFrosting.h index c2cb37a26..c83c2d20e 100644 --- a/Source/Entities/TerrainFrosting.h +++ b/Source/Entities/TerrainFrosting.h @@ -13,15 +13,16 @@ namespace RTE { class TerrainFrosting : public Serializable { public: - SerializableClassNameGetter - SerializableOverrideMethods + SerializableOverrideMethods #pragma region Creation - /// - /// Constructor method used to instantiate a TerrainFrosting object in system memory and make it ready for use. - /// - TerrainFrosting() { Clear(); } + /// + /// Constructor method used to instantiate a TerrainFrosting object in system memory and make it ready for use. + /// + TerrainFrosting() { + Clear(); + } #pragma endregion #pragma region Concrete Methods @@ -29,11 +30,10 @@ namespace RTE { /// Draws the frosting layer to the specified SLTerrain according to the read-in parameters. /// /// The SLTerrain to frost. Ownership is NOT transferred! - void FrostTerrain(SLTerrain *terrain) const; + void FrostTerrain(SLTerrain* terrain) const; #pragma endregion private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. Material m_FrostingMaterial; //!< The Material this frosting is made of. @@ -48,8 +48,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - TerrainFrosting(const TerrainFrosting &reference) = delete; - void operator=(const TerrainFrosting &rhs) = delete; + TerrainFrosting(const TerrainFrosting& reference) = delete; + void operator=(const TerrainFrosting& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/TerrainObject.cpp b/Source/Entities/TerrainObject.cpp index 515843a4a..e86cfa15a 100644 --- a/Source/Entities/TerrainObject.cpp +++ b/Source/Entities/TerrainObject.cpp @@ -6,7 +6,7 @@ namespace RTE { ConcreteClassInfo(TerrainObject, SceneObject, 0); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TerrainObject::Clear() { m_FGColorFile.Reset(); @@ -20,7 +20,7 @@ namespace RTE { m_ChildObjects.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int TerrainObject::Create() { SceneObject::Create(); @@ -29,15 +29,19 @@ namespace RTE { int bitmapWidth = GetBitmapWidth(); int bitmapHeight = GetBitmapHeight(); - if (bitmapWidth > 24) { m_BitmapOffset.SetX(-(static_cast(bitmapWidth / 2))); } - if (bitmapHeight > 24) { m_BitmapOffset.SetY(-(static_cast(bitmapHeight / 2))); } + if (bitmapWidth > 24) { + m_BitmapOffset.SetX(-(static_cast(bitmapWidth / 2))); + } + if (bitmapHeight > 24) { + m_BitmapOffset.SetY(-(static_cast(bitmapHeight / 2))); + } } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainObject::Create(const TerrainObject &reference) { + int TerrainObject::Create(const TerrainObject& reference) { SceneObject::Create(reference); m_FGColorFile = reference.m_FGColorFile; @@ -49,17 +53,17 @@ namespace RTE { m_BitmapOffset = reference.m_BitmapOffset; m_OffsetDefined = reference.m_OffsetDefined; - for (const SceneObject::SOPlacer &childObject : reference.m_ChildObjects) { + for (const SceneObject::SOPlacer& childObject: reference.m_ChildObjects) { m_ChildObjects.emplace_back(childObject); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainObject::ReadProperty(const std::string_view &propName, Reader &reader) { + int TerrainObject::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return SceneObject::ReadProperty(propName, reader)); - + MatchProperty("FGColorFile", { reader >> m_FGColorFile; m_FGColorBitmap = m_FGColorFile.GetAsBitmap(); @@ -93,26 +97,34 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int TerrainObject::Save(Writer &writer) const { + int TerrainObject::Save(Writer& writer) const { SceneObject::Save(writer); - if (!m_FGColorFile.GetDataPath().empty()) { writer.NewPropertyWithValue("FGColorFile", m_FGColorFile); } - if (!m_BGColorFile.GetDataPath().empty()) { writer.NewPropertyWithValue("BGColorFile", m_BGColorFile); } - if (!m_MaterialFile.GetDataPath().empty()) { writer.NewPropertyWithValue("MaterialFile", m_MaterialFile); } + if (!m_FGColorFile.GetDataPath().empty()) { + writer.NewPropertyWithValue("FGColorFile", m_FGColorFile); + } + if (!m_BGColorFile.GetDataPath().empty()) { + writer.NewPropertyWithValue("BGColorFile", m_BGColorFile); + } + if (!m_MaterialFile.GetDataPath().empty()) { + writer.NewPropertyWithValue("MaterialFile", m_MaterialFile); + } - if (m_OffsetDefined) { writer.NewPropertyWithValue("BitmapOffset", m_BitmapOffset); } + if (m_OffsetDefined) { + writer.NewPropertyWithValue("BitmapOffset", m_BitmapOffset); + } - for (const SceneObject::SOPlacer &childObject : m_ChildObjects) { + for (const SceneObject::SOPlacer& childObject: m_ChildObjects) { writer.NewPropertyWithValue("AddChildObject", childObject); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BITMAP * TerrainObject::GetGraphicalIcon() const { + BITMAP* TerrainObject::GetGraphicalIcon() const { if (m_FGColorBitmap) { // Check several spots on the FG bitmap, to be sure it has parts that aren't transparent. If not, show the background layer instead. int piece = m_FGColorBitmap->w / 10; @@ -123,18 +135,18 @@ namespace RTE { return m_BGColorBitmap; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TerrainObject::SetTeam(int team) { SceneObject::SetTeam(team); - for (SceneObject::SOPlacer &childObject : m_ChildObjects) { + for (SceneObject::SOPlacer& childObject: m_ChildObjects) { childObject.SetTeam(team); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool TerrainObject::IsOnScenePoint(Vector &scenePoint) const { + bool TerrainObject::IsOnScenePoint(Vector& scenePoint) const { // TODO: TAKE CARE OF WRAPPING Vector bitmapPos = m_Pos + m_BitmapOffset; if (WithinBox(scenePoint, bitmapPos, static_cast(GetBitmapWidth()), static_cast(GetBitmapHeight()))) { @@ -152,9 +164,9 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool TerrainObject::PlaceOnTerrain(SLTerrain *terrain) { + bool TerrainObject::PlaceOnTerrain(SLTerrain* terrain) { if (!terrain) { return false; } @@ -163,17 +175,17 @@ namespace RTE { // Reapply the team so all children are guaranteed to be on the same team. SetTeam(GetTeam()); - for (const SceneObject::SOPlacer &childObject : GetChildObjects()) { + for (const SceneObject::SOPlacer& childObject: GetChildObjects()) { // TODO: check if we're placing a brain, and have it replace the resident brain of the scene! g_SceneMan.AddSceneObject(childObject.GetPlacedCopy(this)); } return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TerrainObject::Draw(BITMAP *targetBitmap, const Vector &targetPos, DrawMode drawMode, bool onlyPhysical) const { - std::array drawPos = { m_Pos + m_BitmapOffset - targetPos }; + void TerrainObject::Draw(BITMAP* targetBitmap, const Vector& targetPos, DrawMode drawMode, bool onlyPhysical) const { + std::array drawPos = {m_Pos + m_BitmapOffset - targetPos}; int wrapPasses = 1; // See if need to double draw this across the scene seam if we're being drawn onto a scenewide bitmap. @@ -206,15 +218,25 @@ namespace RTE { for (int i = 0; i < wrapPasses; ++i) { switch (drawMode) { case DrawMode::g_DrawColor: - if (HasBGColorBitmap()) { masked_blit(m_BGColorBitmap, targetBitmap, 0, 0, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY(), m_BGColorBitmap->w, m_BGColorBitmap->h); } - if (HasFGColorBitmap()) { masked_blit(m_FGColorBitmap, targetBitmap, 0, 0, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY(), m_FGColorBitmap->w, m_FGColorBitmap->h); } + if (HasBGColorBitmap()) { + masked_blit(m_BGColorBitmap, targetBitmap, 0, 0, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY(), m_BGColorBitmap->w, m_BGColorBitmap->h); + } + if (HasFGColorBitmap()) { + masked_blit(m_FGColorBitmap, targetBitmap, 0, 0, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY(), m_FGColorBitmap->w, m_FGColorBitmap->h); + } break; case DrawMode::g_DrawMaterial: - if (HasMaterialBitmap()) { masked_blit(m_MaterialBitmap, targetBitmap, 0, 0, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY(), m_MaterialBitmap->w, m_MaterialBitmap->h); } + if (HasMaterialBitmap()) { + masked_blit(m_MaterialBitmap, targetBitmap, 0, 0, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY(), m_MaterialBitmap->w, m_MaterialBitmap->h); + } break; case DrawMode::g_DrawTrans: - if (HasFGColorBitmap()) { draw_trans_sprite(targetBitmap, m_FGColorBitmap, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY()); } - if (HasBGColorBitmap()) { draw_trans_sprite(targetBitmap, m_BGColorBitmap, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY()); } + if (HasFGColorBitmap()) { + draw_trans_sprite(targetBitmap, m_FGColorBitmap, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY()); + } + if (HasBGColorBitmap()) { + draw_trans_sprite(targetBitmap, m_BGColorBitmap, drawPos.at(i).GetFloorIntX(), drawPos.at(i).GetFloorIntY()); + } break; default: break; @@ -222,35 +244,59 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TerrainObject::DrawToTerrain(SLTerrain *terrain) { - BITMAP *terrainMatBitmap = terrain->GetMaterialBitmap(); - BITMAP *terrainBGBitmap = terrain->GetBGColorBitmap(); - BITMAP *terrainFGBitmap = terrain->GetFGColorBitmap(); + void TerrainObject::DrawToTerrain(SLTerrain* terrain) { + BITMAP* terrainMatBitmap = terrain->GetMaterialBitmap(); + BITMAP* terrainBGBitmap = terrain->GetBGColorBitmap(); + BITMAP* terrainFGBitmap = terrain->GetFGColorBitmap(); Vector posOnScene = m_Pos + m_BitmapOffset; if (terrain->WrapsX()) { if (posOnScene.GetFloorIntX() < 0) { - if (HasMaterialBitmap()) { draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX() + terrainMatBitmap->w, posOnScene.GetFloorIntY()); } - if (HasBGColorBitmap()) { draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX() + terrainBGBitmap->w, posOnScene.GetFloorIntY()); } - if (HasFGColorBitmap()) { draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX() + terrainFGBitmap->w, posOnScene.GetFloorIntY()); } + if (HasMaterialBitmap()) { + draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX() + terrainMatBitmap->w, posOnScene.GetFloorIntY()); + } + if (HasBGColorBitmap()) { + draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX() + terrainBGBitmap->w, posOnScene.GetFloorIntY()); + } + if (HasFGColorBitmap()) { + draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX() + terrainFGBitmap->w, posOnScene.GetFloorIntY()); + } } else if (posOnScene.GetFloorIntX() >= terrainMatBitmap->w - GetBitmapWidth()) { - if (HasMaterialBitmap()) { draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX() - terrainMatBitmap->w, posOnScene.GetFloorIntY()); } - if (HasBGColorBitmap()) { draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX() - terrainBGBitmap->w, posOnScene.GetFloorIntY()); } - if (HasFGColorBitmap()) { draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX() - terrainFGBitmap->w, posOnScene.GetFloorIntY()); } + if (HasMaterialBitmap()) { + draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX() - terrainMatBitmap->w, posOnScene.GetFloorIntY()); + } + if (HasBGColorBitmap()) { + draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX() - terrainBGBitmap->w, posOnScene.GetFloorIntY()); + } + if (HasFGColorBitmap()) { + draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX() - terrainFGBitmap->w, posOnScene.GetFloorIntY()); + } } } if (terrain->WrapsY()) { if (posOnScene.GetFloorIntY() < 0) { - if (HasMaterialBitmap()) { draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() + terrainMatBitmap->h); } - if (HasBGColorBitmap()) { draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() + terrainBGBitmap->h); } - if (HasFGColorBitmap()) { draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() + terrainFGBitmap->h); } + if (HasMaterialBitmap()) { + draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() + terrainMatBitmap->h); + } + if (HasBGColorBitmap()) { + draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() + terrainBGBitmap->h); + } + if (HasFGColorBitmap()) { + draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() + terrainFGBitmap->h); + } } else if (posOnScene.GetFloorIntY() >= terrainMatBitmap->h - GetBitmapHeight()) { - if (HasMaterialBitmap()) { draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() - terrainMatBitmap->h); } - if (HasBGColorBitmap()) { draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() - terrainBGBitmap->h); } - if (HasFGColorBitmap()) { draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() - terrainFGBitmap->h); } + if (HasMaterialBitmap()) { + draw_sprite(terrainMatBitmap, m_MaterialBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() - terrainMatBitmap->h); + } + if (HasBGColorBitmap()) { + draw_sprite(terrainBGBitmap, m_BGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() - terrainBGBitmap->h); + } + if (HasFGColorBitmap()) { + draw_sprite(terrainFGBitmap, m_FGColorBitmap, posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY() - terrainFGBitmap->h); + } } } if (HasMaterialBitmap()) { @@ -266,4 +312,4 @@ namespace RTE { g_SceneMan.RegisterTerrainChange(posOnScene.GetFloorIntX(), posOnScene.GetFloorIntY(), m_FGColorBitmap->w, m_FGColorBitmap->h, ColorKeys::g_MaskColor, false); } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/TerrainObject.h b/Source/Entities/TerrainObject.h index c043afcd3..9374419f3 100644 --- a/Source/Entities/TerrainObject.h +++ b/Source/Entities/TerrainObject.h @@ -14,7 +14,6 @@ namespace RTE { class TerrainObject : public SceneObject { public: - EntityAllocation(TerrainObject); SerializableOverrideMethods; ClassInfoGetters; @@ -36,7 +35,7 @@ namespace RTE { /// /// A reference to the TerrainObject to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const TerrainObject &reference); + int Create(const TerrainObject& reference); #pragma endregion #pragma region Destruction @@ -49,7 +48,12 @@ namespace RTE { /// Destroys and resets (through Clear()) the TerrainObject object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { SceneObject::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + SceneObject::Destroy(); + } + Clear(); + } #pragma endregion #pragma region Getters and Setters @@ -63,7 +67,7 @@ namespace RTE { /// Gets the BITMAP that this TerrainObject uses for its foreground color representation. /// /// A pointer to the foreground color BITMAP object. Ownership is NOT transferred! - BITMAP * GetFGColorBitmap() const { return m_FGColorBitmap; } + BITMAP* GetFGColorBitmap() const { return m_FGColorBitmap; } /// /// Returns whether this TerrainObject has any background color data. @@ -75,7 +79,7 @@ namespace RTE { /// Gets the BITMAP that this TerrainObject uses for its background color representation, if any. /// /// A pointer to the background color BITMAP object. This may be nullptr if there is no BG bitmap. Ownership is NOT transferred! - BITMAP * GetBGColorBitmap() const { return m_BGColorBitmap; } + BITMAP* GetBGColorBitmap() const { return m_BGColorBitmap; } /// /// Returns whether this TerrainObject has any material data. @@ -87,37 +91,37 @@ namespace RTE { /// Gets the BITMAP that this TerrainObject uses for its material representation, if any. /// /// A pointer to the material BITMAP object. Ownership is NOT transferred! - BITMAP * GetMaterialBitmap() const { return m_MaterialBitmap; } + BITMAP* GetMaterialBitmap() const { return m_MaterialBitmap; } /// /// Gets the offset from the position to the upper left corner of this TerrainObject's BITMAPs. /// /// A Vector describing the bitmap offset, in pixels. - const Vector & GetBitmapOffset() const { return m_BitmapOffset; } + const Vector& GetBitmapOffset() const { return m_BitmapOffset; } /// /// Gets the width of the widest BITMAP of this TerrainObject's layers. /// /// The width of this TerrainObject. - int GetBitmapWidth() const { return std::max({ m_MaterialBitmap ? m_MaterialBitmap->w : 0, m_BGColorBitmap ? m_BGColorBitmap->w : 0, m_FGColorBitmap ? m_FGColorBitmap->w : 0 }); } + int GetBitmapWidth() const { return std::max({m_MaterialBitmap ? m_MaterialBitmap->w : 0, m_BGColorBitmap ? m_BGColorBitmap->w : 0, m_FGColorBitmap ? m_FGColorBitmap->w : 0}); } /// /// Gets the height of the highest BITMAP of this TerrainObject's layers. /// /// The height of this TerrainObject. - int GetBitmapHeight() const { return std::max({ m_MaterialBitmap ? m_MaterialBitmap->h : 0, m_BGColorBitmap ? m_BGColorBitmap->h : 0, m_FGColorBitmap ? m_FGColorBitmap->h : 0 }); } + int GetBitmapHeight() const { return std::max({m_MaterialBitmap ? m_MaterialBitmap->h : 0, m_BGColorBitmap ? m_BGColorBitmap->h : 0, m_FGColorBitmap ? m_FGColorBitmap->h : 0}); } /// /// Gets the list of child objects that should be placed when this TerrainObject is placed. /// /// A reference to the list of child objects. Ownership of the list is NOT transferred! - const std::vector & GetChildObjects() const { return m_ChildObjects; } + const std::vector& GetChildObjects() const { return m_ChildObjects; } /// /// Gets a BITMAP showing a good identifiable icon of this, for use in GUI lists. /// /// A good identifiable graphical representation of this in a BITMAP, if available. If not, nullptr is returned. Ownership is NOT transferred! - BITMAP * GetGraphicalIcon() const override; + BITMAP* GetGraphicalIcon() const override; /// /// Sets which team this TerrainObject belongs to. @@ -132,7 +136,7 @@ namespace RTE { /// /// The SLTerrain to place this TerrainObject on. Ownership is NOT transferred! /// Whether the object was successfully placed on the terrain. - bool PlaceOnTerrain(SLTerrain *terrain); + bool PlaceOnTerrain(SLTerrain* terrain); #pragma endregion #pragma region Virtual Override Methods @@ -141,7 +145,7 @@ namespace RTE { /// /// The point in absolute scene coordinates. /// Whether this' graphical rep overlaps the scene point. - bool IsOnScenePoint(Vector &scenePoint) const override; + bool IsOnScenePoint(Vector& scenePoint) const override; /// /// Draws this TerrainObject's current graphical representation to a BITMAP of choice. @@ -150,21 +154,20 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// In which mode to draw in. See the DrawMode enumeration for the modes. /// Whether to not draw any extra 'ghost' items of this TerrainObject, like indicator arrows or hovering HUD text and so on. - void Draw(BITMAP *targetBitmap, const Vector &targetPos = Vector(), DrawMode drawMode = DrawMode::g_DrawColor, bool onlyPhysical = false) const override; + void Draw(BITMAP* targetBitmap, const Vector& targetPos = Vector(), DrawMode drawMode = DrawMode::g_DrawColor, bool onlyPhysical = false) const override; #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. ContentFile m_FGColorFile; //!< ContentFile containing the path to this TerrainObject's foreground color layer representation. - BITMAP *m_FGColorBitmap; //!< Foreground color BITMAP of this TerrainObject. + BITMAP* m_FGColorBitmap; //!< Foreground color BITMAP of this TerrainObject. ContentFile m_BGColorFile; //!< ContentFile containing the path to this TerrainObject's background color layer representation. - BITMAP *m_BGColorBitmap; //!< Background color BITMAP of this TerrainObject. + BITMAP* m_BGColorBitmap; //!< Background color BITMAP of this TerrainObject. ContentFile m_MaterialFile; //!< ContentFile containing the path to this TerrainObject's Material layer representation. - BITMAP *m_MaterialBitmap; //!< Material BITMAP of this TerrainObject. + BITMAP* m_MaterialBitmap; //!< Material BITMAP of this TerrainObject. Vector m_BitmapOffset; //!< Offset from the position of this to the top left corner of the bitmap. The inversion of this should point to a corner or pattern in the bitmaps which will snap well with a 24px grid. bool m_OffsetDefined; //!< Whether the offset has been defined and shouldn't be automatically set. @@ -172,12 +175,11 @@ namespace RTE { std::vector m_ChildObjects; //!< The objects that are placed along with this TerrainObject on the Scene. private: - /// /// Draws this TerrainObject's graphical and material representations to the specified SLTerrain's respective layers. /// /// The SLTerrain to draw this TerrainObject to. Ownership is NOT transferred! - void DrawToTerrain(SLTerrain *terrain); + void DrawToTerrain(SLTerrain* terrain); /// /// Clears all the member variables of this TerrainObject, effectively resetting the members of this abstraction level only. @@ -185,8 +187,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - TerrainObject(const TerrainObject &reference) = delete; - void operator=(const TerrainObject &rhs) = delete; + TerrainObject(const TerrainObject& reference) = delete; + void operator=(const TerrainObject& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/ThrownDevice.cpp b/Source/Entities/ThrownDevice.cpp index 007f4a8cb..e1b469230 100644 --- a/Source/Entities/ThrownDevice.cpp +++ b/Source/Entities/ThrownDevice.cpp @@ -7,7 +7,7 @@ namespace RTE { ConcreteClassInfo(ThrownDevice, HeldDevice, 50); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ThrownDevice::Clear() { m_ActivationSound.Reset(); @@ -20,7 +20,7 @@ namespace RTE { m_StrikerLever = nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int ThrownDevice::Create() { if (HeldDevice::Create() < 0) { @@ -31,9 +31,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ThrownDevice::Create(const ThrownDevice &reference) { + int ThrownDevice::Create(const ThrownDevice& reference) { HeldDevice::Create(reference); m_MOType = MovableObject::TypeThrownDevice; @@ -51,11 +51,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ThrownDevice::ReadProperty(const std::string_view &propName, Reader &reader) { + int ThrownDevice::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return HeldDevice::ReadProperty(propName, reader)); - + MatchProperty("ActivationSound", { reader >> m_ActivationSound; }); MatchProperty("StartThrowOffset", { reader >> m_StartThrowOffset; }); MatchProperty("EndThrowOffset", { reader >> m_EndThrowOffset; }); @@ -63,14 +63,14 @@ namespace RTE { MatchProperty("MaxThrowVel", { reader >> m_MaxThrowVel; }); MatchProperty("TriggerDelay", { reader >> m_TriggerDelay; }); MatchProperty("ActivatesWhenReleased", { reader >> m_ActivatesWhenReleased; }); - MatchProperty("StrikerLever", { m_StrikerLever = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); + MatchProperty("StrikerLever", { m_StrikerLever = dynamic_cast(g_PresetMan.GetEntityPreset(reader)); }); EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ThrownDevice::Save(Writer &writer) const { + int ThrownDevice::Save(Writer& writer) const { HeldDevice::Save(writer); writer.NewProperty("ActivationSound"); @@ -93,32 +93,34 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float ThrownDevice::GetCalculatedMaxThrowVelIncludingArmThrowStrength() { if (m_MaxThrowVel > 0) { return m_MaxThrowVel; - } else if (const Arm *parentAsArm = dynamic_cast(GetParent())) { + } else if (const Arm* parentAsArm = dynamic_cast(GetParent())) { return (parentAsArm->GetThrowStrength() + std::abs(GetRootParent()->GetAngularVel() * 0.5F)) / std::sqrt(std::abs(GetMass()) + 1.0F); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ThrownDevice::ResetAllTimers() { double elapsedTime = m_Activated ? m_ActivationTimer.GetElapsedSimTimeMS() : 0; HeldDevice::ResetAllTimers(); - if (m_Activated) { m_ActivationTimer.SetElapsedSimTimeMS(elapsedTime); } + if (m_Activated) { + m_ActivationTimer.SetElapsedSimTimeMS(elapsedTime); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ThrownDevice::Activate() { if (!m_Activated) { m_ActivationTimer.Reset(); m_ActivationSound.Play(m_Pos); - if (MovableObject *strikerLever = m_StrikerLever ? dynamic_cast(m_StrikerLever->Clone()) : nullptr) { + if (MovableObject* strikerLever = m_StrikerLever ? dynamic_cast(m_StrikerLever->Clone()) : nullptr) { Vector randomVel(m_Vel.GetMagnitude() * 0.25F + 1.0F, 0); strikerLever->SetVel(m_Vel * 0.5F + randomVel.RadRotate(c_PI * RandomNormalNum())); @@ -133,4 +135,4 @@ namespace RTE { m_Activated = true; } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/ThrownDevice.h b/Source/Entities/ThrownDevice.h index af6fa43b2..9738b68da 100644 --- a/Source/Entities/ThrownDevice.h +++ b/Source/Entities/ThrownDevice.h @@ -11,7 +11,6 @@ namespace RTE { class ThrownDevice : public HeldDevice { public: - EntityAllocation(ThrownDevice); SerializableOverrideMethods; ClassInfoGetters; @@ -33,7 +32,7 @@ namespace RTE { /// /// A reference to the ThrownDevice to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const ThrownDevice &reference); + int Create(const ThrownDevice& reference); #pragma endregion #pragma region Destruction @@ -46,12 +45,20 @@ namespace RTE { /// Destroys and resets (through Clear()) the SceneLayer object. /// /// Whether to only destroy the members defined in this derived class, or to destroy all inherited members also. - void Destroy(bool notInherited = false) override { if (!notInherited) { HeldDevice::Destroy(); } Clear(); } + void Destroy(bool notInherited = false) override { + if (!notInherited) { + HeldDevice::Destroy(); + } + Clear(); + } /// /// Resets the entire ThrownDevice, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Attachable::Reset(); } + void Reset() override { + Clear(); + Attachable::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -131,11 +138,15 @@ namespace RTE { /// /// Does the calculations necessary to detect whether this ThrownDevice is at rest or not. IsAtRest() retrieves the answer. /// - void RestDetection() override { HeldDevice::RestDetection(); if (m_Activated) { m_RestTimer.Reset(); } } + void RestDetection() override { + HeldDevice::RestDetection(); + if (m_Activated) { + m_RestTimer.Reset(); + } + } #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. SoundContainer m_ActivationSound; //!< Activation sound. @@ -146,18 +157,17 @@ namespace RTE { float m_MaxThrowVel; //!< The maximum throw velocity this gets when thrown. long m_TriggerDelay; //!< Time in millisecs from the time of being thrown to triggering whatever it is that this ThrownDevice does. bool m_ActivatesWhenReleased; //!< Whether this activates when its throw is started, or waits until it is released from the arm that is throwing it. - const MovableObject *m_StrikerLever; //!< Striker lever particle MovableObject preset instance. + const MovableObject* m_StrikerLever; //!< Striker lever particle MovableObject preset instance. private: - /// /// Clears all the member variables of this ThrownDevice, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - ThrownDevice(const ThrownDevice &reference) = delete; - ThrownDevice & operator=(const ThrownDevice &rhs) = delete; + ThrownDevice(const ThrownDevice& reference) = delete; + ThrownDevice& operator=(const ThrownDevice& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Entities/Turret.cpp b/Source/Entities/Turret.cpp index b020845ae..40c1a6391 100644 --- a/Source/Entities/Turret.cpp +++ b/Source/Entities/Turret.cpp @@ -7,20 +7,20 @@ namespace RTE { ConcreteClassInfo(Turret, Attachable, 20); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Turret::Clear() { m_MountedDevices.clear(); m_MountedDeviceRotationOffset = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Turret::Create(const Turret &reference) { + int Turret::Create(const Turret& reference) { if (!reference.m_MountedDevices.empty()) { - for (const HeldDevice *referenceMountedDevice : reference.m_MountedDevices) { + for (const HeldDevice* referenceMountedDevice: reference.m_MountedDevices) { m_ReferenceHardcodedAttachableUniqueIDs.insert(referenceMountedDevice->GetUniqueID()); - AddMountedDevice(dynamic_cast(referenceMountedDevice->Clone())); + AddMountedDevice(dynamic_cast(referenceMountedDevice->Clone())); } } Attachable::Create(reference); @@ -30,33 +30,36 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Turret::Destroy(bool notInherited) { - if (!notInherited) { Attachable::Destroy(); } - for (const HeldDevice *mountedDevice : m_MountedDevices) { m_HardcodedAttachableUniqueIDsAndRemovers.erase(mountedDevice->GetUniqueID()); } + if (!notInherited) { + Attachable::Destroy(); + } + for (const HeldDevice* mountedDevice: m_MountedDevices) { + m_HardcodedAttachableUniqueIDsAndRemovers.erase(mountedDevice->GetUniqueID()); + } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Turret::ReadProperty(const std::string_view &propName, Reader &reader) { + int Turret::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Attachable::ReadProperty(propName, reader)); - - MatchProperty("MountedDevice", { SetFirstMountedDevice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); - MatchProperty("AddMountedDevice", { AddMountedDevice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + + MatchProperty("MountedDevice", { SetFirstMountedDevice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); + MatchProperty("AddMountedDevice", { AddMountedDevice(dynamic_cast(g_PresetMan.ReadReflectedPreset(reader))); }); MatchProperty("MountedDeviceRotationOffset", { reader >> m_MountedDeviceRotationOffset; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Turret::Save(Writer &writer) const { + int Turret::Save(Writer& writer) const { Attachable::Save(writer); - for (const HeldDevice *mountedDevice : m_MountedDevices) { + for (const HeldDevice* mountedDevice: m_MountedDevices) { writer.NewProperty("AddMountedDevice"); writer << mountedDevice; } @@ -66,88 +69,92 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Turret::SetFirstMountedDevice(HeldDevice *newMountedDevice) { - if (HasMountedDevice()) { RemoveAndDeleteAttachable(m_MountedDevices[0]); } + void Turret::SetFirstMountedDevice(HeldDevice* newMountedDevice) { + if (HasMountedDevice()) { + RemoveAndDeleteAttachable(m_MountedDevices[0]); + } if (newMountedDevice != nullptr) { m_MountedDevices.emplace(m_MountedDevices.begin(), newMountedDevice); AddAttachable(newMountedDevice); - m_HardcodedAttachableUniqueIDsAndRemovers.insert({ newMountedDevice->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - HeldDevice *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to RemoveMountedDevice."); - dynamic_cast(parent)->RemoveMountedDevice(castedAttachable); - }}); + m_HardcodedAttachableUniqueIDsAndRemovers.insert({newMountedDevice->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + HeldDevice* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to RemoveMountedDevice."); + dynamic_cast(parent)->RemoveMountedDevice(castedAttachable); + }}); m_MountedDevices[0]->SetInheritsRotAngle(false); m_MountedDevices[0]->SetUnPickupable(true); m_MountedDevices[0]->SetGibWithParentChance(1.0F); - //Force weapons mounted on turrets to never be removed due to forces. This doesn't affect them gibbing from hitting their impulse limits though. + // Force weapons mounted on turrets to never be removed due to forces. This doesn't affect them gibbing from hitting their impulse limits though. m_MountedDevices[0]->SetJointStrength(0.0F); m_MountedDevices[0]->SetSupportable(true); m_MountedDevices[0]->SetSupportAvailable(true); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Turret::AddMountedDevice(HeldDevice *newMountedDevice) { + void Turret::AddMountedDevice(HeldDevice* newMountedDevice) { if (newMountedDevice == nullptr) { return; } m_MountedDevices.emplace_back(newMountedDevice); AddAttachable(newMountedDevice); - m_HardcodedAttachableUniqueIDsAndRemovers.insert({ newMountedDevice->GetUniqueID(), [](MOSRotating *parent, Attachable *attachable) { - HeldDevice *castedAttachable = dynamic_cast(attachable); - RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to RemoveMountedDevice."); - dynamic_cast(parent)->RemoveMountedDevice(castedAttachable); - }}); + m_HardcodedAttachableUniqueIDsAndRemovers.insert({newMountedDevice->GetUniqueID(), [](MOSRotating* parent, Attachable* attachable) { + HeldDevice* castedAttachable = dynamic_cast(attachable); + RTEAssert(!attachable || castedAttachable, "Tried to pass incorrect Attachable subtype " + (attachable ? attachable->GetClassName() : "") + " to RemoveMountedDevice."); + dynamic_cast(parent)->RemoveMountedDevice(castedAttachable); + }}); newMountedDevice->SetInheritsRotAngle(false); newMountedDevice->SetUnPickupable(true); newMountedDevice->SetGibWithParentChance(1.0F); - //Force weapons mounted on turrets to never be removed due to forces. This doesn't affect them gibbing from hitting their impulse limits though. + // Force weapons mounted on turrets to never be removed due to forces. This doesn't affect them gibbing from hitting their impulse limits though. newMountedDevice->SetJointStrength(0.0F); newMountedDevice->SetSupportable(true); newMountedDevice->SetSupportAvailable(true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Turret::Update() { - for (HeldDevice *mountedDevice : m_MountedDevices) { + for (HeldDevice* mountedDevice: m_MountedDevices) { mountedDevice->SetRotAngle(m_Rotation.GetRadAngle() + m_MountedDeviceRotationOffset); } Attachable::Update(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Turret::Draw(BITMAP *pTargetBitmap, const Vector &targetPos, DrawMode mode, bool onlyPhysical) const { + void Turret::Draw(BITMAP* pTargetBitmap, const Vector& targetPos, DrawMode mode, bool onlyPhysical) const { Attachable::Draw(pTargetBitmap, targetPos, mode, onlyPhysical); - //TODO replace this with a relative draw order property or something that lets you organize attachable drawing so it doesn't need special hardcoding crap. Use this for ahuman limbs and arm held mo if possible. - for (HeldDevice *mountedDevice : m_MountedDevices) { - if (mountedDevice->IsDrawnAfterParent()) { mountedDevice->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); } + // TODO replace this with a relative draw order property or something that lets you organize attachable drawing so it doesn't need special hardcoding crap. Use this for ahuman limbs and arm held mo if possible. + for (HeldDevice* mountedDevice: m_MountedDevices) { + if (mountedDevice->IsDrawnAfterParent()) { + mountedDevice->Draw(pTargetBitmap, targetPos, mode, onlyPhysical); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Turret::SetParent(MOSRotating *newParent) { + void Turret::SetParent(MOSRotating* newParent) { Attachable::SetParent(newParent); - for (HeldDevice *mountedDevice : m_MountedDevices) { + for (HeldDevice* mountedDevice: m_MountedDevices) { mountedDevice->Deactivate(); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Turret::RemoveMountedDevice(const HeldDevice *mountedDeviceToRemove) { - std::vector::iterator mountedDeviceIterator = std::find_if(m_MountedDevices.begin(), m_MountedDevices.end(), [&mountedDeviceToRemove](const HeldDevice *mountedDevice) { + void Turret::RemoveMountedDevice(const HeldDevice* mountedDeviceToRemove) { + std::vector::iterator mountedDeviceIterator = std::find_if(m_MountedDevices.begin(), m_MountedDevices.end(), [&mountedDeviceToRemove](const HeldDevice* mountedDevice) { return mountedDevice == mountedDeviceToRemove; }); m_MountedDevices.erase(mountedDeviceIterator); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Entities/Turret.h b/Source/Entities/Turret.h index 558a56717..f7205ea4b 100644 --- a/Source/Entities/Turret.h +++ b/Source/Entities/Turret.h @@ -13,7 +13,6 @@ namespace RTE { class Turret : public Attachable { public: - EntityAllocation(Turret); SerializableOverrideMethods; ClassInfoGetters; @@ -29,7 +28,7 @@ namespace RTE { /// /// A reference to the Turret to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Turret &reference); + int Create(const Turret& reference); #pragma endregion #pragma region Destruction @@ -47,7 +46,10 @@ namespace RTE { /// /// Resets the entire Turret, including its inherited members, to their default settings or values. /// - void Reset() override { Clear(); Attachable::Reset(); } + void Reset() override { + Clear(); + Attachable::Reset(); + } #pragma endregion #pragma region Getters and Setters @@ -61,27 +63,27 @@ namespace RTE { /// Gets the first mounted HeldDevice of this Turret, mostly here for Lua convenience. /// /// A pointer to mounted HeldDevice of this Turret. Ownership is NOT transferred! - HeldDevice * GetFirstMountedDevice() const { return m_MountedDevices[0]; } + HeldDevice* GetFirstMountedDevice() const { return m_MountedDevices[0]; } /// /// Sets the first mounted HeldDevice for this Turret, mostly here for Lua convenience. Ownership IS transferred! /// The current first mounted HeldDevice (if there is one) will be dropped and added to MovableMan. /// /// The new HeldDevice to use. - void SetFirstMountedDevice(HeldDevice *newMountedDevice); + void SetFirstMountedDevice(HeldDevice* newMountedDevice); /// /// Gets the vector of mounted HeldDevices for this Turret. /// /// The vector of mounted HeldDevices for this Turret. - const std::vector & GetMountedDevices() const { return m_MountedDevices; } + const std::vector& GetMountedDevices() const { return m_MountedDevices; } /// /// Adds a HeldDevice to be mounted on this Turret. Ownership IS transferred! /// Will not remove any other HeldDevices mounted on this Turret. /// /// The new HeldDevice to be mounted on this Turret. - void AddMountedDevice(HeldDevice *newMountedDevice); + void AddMountedDevice(HeldDevice* newMountedDevice); /// /// Gets the current rotational offset of the mounted HeldDevice from the rest of the Turret. @@ -109,31 +111,29 @@ namespace RTE { /// The absolute position of the target bitmap's upper left corner in the Scene. /// In which mode to draw in. See the DrawMode enumeration for the modes. /// Whether to not draw any extra 'ghost' items of this MovableObject, indicator arrows or hovering HUD text and so on. - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), DrawMode mode = g_DrawColor, bool onlyPhysical = false) const override; #pragma endregion protected: - /// /// Sets this Attachable's parent MOSRotating, and also sets its Team based on its parent and, if the Attachable is set to collide, adds/removes Atoms to its new/old parent. /// Additionally, deactivates all MountedDevices. /// /// A pointer to the MOSRotating to set as the new parent. Ownership is NOT transferred! - void SetParent(MOSRotating *newParent) override; + void SetParent(MOSRotating* newParent) override; static Entity::ClassInfo m_sClass; //!< ClassInfo for this class. private: - - //TODO I think things would be cleaner if this (and all hardcoded attachable pointers) used weak_ptrs. It would solve some weird ownership stuff, particularly with this. However, for that to be possible, m_Attachables has to be shared_ptrs though. - std::vector m_MountedDevices; //!< Vector of pointers to the mounted HeldDevices of this Turret, if any. Owned here. + // TODO I think things would be cleaner if this (and all hardcoded attachable pointers) used weak_ptrs. It would solve some weird ownership stuff, particularly with this. However, for that to be possible, m_Attachables has to be shared_ptrs though. + std::vector m_MountedDevices; //!< Vector of pointers to the mounted HeldDevices of this Turret, if any. Owned here. float m_MountedDeviceRotationOffset; //!< The relative offset angle (in radians) of the mounted HeldDevice from this Turret's rotation. /// /// Removes the HeldDevice from this turret's vector of mounted devices if it's in there. This releases the unique_ptr for it, leaving the caller to take care of it. /// /// A pointer to the mounted device to remove. - void RemoveMountedDevice(const HeldDevice *mountedDeviceToRemove); + void RemoveMountedDevice(const HeldDevice* mountedDeviceToRemove); /// /// Clears all the member variables of this Turret, effectively resetting the members of this abstraction level only. @@ -141,8 +141,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - Turret(const Turret &reference) = delete; - Turret & operator=(const Turret &rhs) = delete; + Turret(const Turret& reference) = delete; + Turret& operator=(const Turret& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/GUI/GUI.h b/Source/GUI/GUI.h index 6406e4107..29a658a81 100644 --- a/Source/GUI/GUI.h +++ b/Source/GUI/GUI.h @@ -13,7 +13,12 @@ /// /// The GUIRect structure defines a rectangle by the coordinates of its upper-left and lower-right corners. /// -struct GUIRect { long left; long top; long right; long bottom; }; +struct GUIRect { + long left; + long top; + long right; + long bottom; +}; /// /// Sets the bounds of a GUIRect. @@ -23,7 +28,12 @@ struct GUIRect { long left; long top; long right; long bottom; }; /// Position of top left corner on Y axis. /// Position of bottom right corner on X axis. /// Position of bottom right corner on Y axis. -inline void SetRect(GUIRect *rect, int left, int top, int right, int bottom) { rect->left = left; rect->top = top; rect->right = right; rect->bottom = bottom; } +inline void SetRect(GUIRect* rect, int left, int top, int right, int bottom) { + rect->left = left; + rect->top = top; + rect->right = right; + rect->bottom = bottom; +} #pragma endregion #ifndef GUI_STANDALONE @@ -47,4 +57,4 @@ inline void SetRect(GUIRect *rect, int left, int top, int right, int bottom) { r #include "GUISound.h" #endif -#endif \ No newline at end of file +#endif diff --git a/Source/GUI/GUIBanner.cpp b/Source/GUI/GUIBanner.cpp index 00b355d86..920dc5f90 100644 --- a/Source/GUI/GUIBanner.cpp +++ b/Source/GUI/GUIBanner.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -16,495 +15,440 @@ namespace RTE { -std::map GUIBanner::m_sFontCache; -std::map GUIBanner::m_sCharCapCache; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIBanner -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIBanner object in system -// memory. - -GUIBanner::GUIBanner() -{ - m_pFontImage[REGULAR] = 0; - m_pFontImage[BLURRED] = 0; - memset(m_aaFontChars[REGULAR], 0, sizeof(FontChar) * MAXBANNERFONTCHARS); - memset(m_aaFontChars[BLURRED], 0, sizeof(FontChar) * MAXBANNERFONTCHARS); - m_CharIndexCap = MAXBANNERFONTCHARS; - m_FontHeight = 0; - m_Kerning = 0; - m_BannerText.clear(); - m_BannerChars.clear(); - m_TargetSize.Reset(); - m_BannerPosY = 240; - m_FlySpeed = 1500; - m_FlySpacing = 100; - m_BannerChars.clear(); - m_AnimMode = BLINKING; - m_AnimState = NOTSTARTED; - m_TotalAnimTimer.Reset(); - m_DisplayTimer.Reset(); - m_SpacingTimer.Reset(); - m_FrameTimer.Reset(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the font from an image file. - -bool GUIBanner::Create(const std::string fontFilePath, const std::string fontBlurFilePath, int bitDepth) -{ - // Package the font bitmap paths o they are more easily processed below - std::string filePaths[2] = {fontFilePath, fontBlurFilePath}; - - // Now process them and extract the character data from each - ContentFile fontFile; - std::map::iterator fontItr; - std::map::iterator indexItr; - int y, dotColor; - for (int mode = REGULAR; mode < FONTMODECOUNT; ++mode) - { - // Load the font images - fontFile.SetDataPath(filePaths[mode].c_str()); - m_pFontImage[mode] = fontFile.GetAsBitmap(bitDepth == 8 ? COLORCONV_REDUCE_TO_256 : COLORCONV_8_TO_32); - RTEAssert(m_pFontImage[mode], "Couldn't load font bitmap for banner font from this file:\n" + fontFilePath); - - // Check the color key to be the same color as the Bottom-Right hand corner pixel - int keyColor = getpixel(m_pFontImage[mode], m_pFontImage[mode]->w - 1, m_pFontImage[mode]->h - 1); -// No need (or way!) to actually set it; it's assumed to be bright pink (255, 255, 0) -// m_pFontImage[mode]->SetColorKey(keyColor); - - // Check if these files have already been read and loaded from disk before. - fontItr = m_sFontCache.find(filePaths[mode]); - - if (fontItr != m_sFontCache.end()) - { - // Yes, has been loaded previously, then use that data from memory. - memcpy(m_aaFontChars[mode], (*fontItr).second, sizeof(FontChar) * MAXBANNERFONTCHARS); - // Also retrieve the font max number of characters if we can - indexItr = m_sCharCapCache.find(filePaths[mode]); - if (indexItr != m_sCharCapCache.end()) - m_CharIndexCap = (*indexItr).second; - else - m_CharIndexCap = MAXBANNERFONTCHARS; - - // Calc the font height - the horizontally blurred one should be the same - if (mode == REGULAR) - { - // The red separator MUST be on the Top-Left hand corner - dotColor = getpixel(m_pFontImage[mode], 0, 0); - m_FontHeight = 0; - for (y = 1; y < m_pFontImage[mode]->h; y++) - { - if (getpixel(m_pFontImage[mode], 0, y) == dotColor) - { - m_FontHeight = y; - break; - } - } - } - } - // Hasn't been loaded previously, so go ahead and do so now. - else - { - // The red separator MUST be on the Top-Left hand corner - dotColor = getpixel(m_pFontImage[mode], 0, 0); - // Find the separating gap of the font lines - // Calc the font height - the horizontally blurred one should be the same - if (mode == REGULAR) - { - m_FontHeight = 0; - for (y = 1; y < m_pFontImage[mode]->h; y++) - { - if (getpixel(m_pFontImage[mode], 0, y) == dotColor) - { - m_FontHeight = y; - break; - } - } - } - - // Pre-calculate all the font character details - memset(m_aaFontChars[mode], 0, sizeof(FontChar) * MAXBANNERFONTCHARS); - - int x = 1; - y = 0; - int charOnLine = 0; - for (int chr = 32; chr < MAXBANNERFONTCHARS; chr++) - { - m_aaFontChars[mode][chr].m_Offset = x; - - // Find the next red pixel - int w = 0; - int n; - for (n = x; n < m_pFontImage[mode]->w; n++, w++) - { - if (getpixel(m_pFontImage[mode], n, y) == dotColor) - { - break; - } - } - - // Calculate the maximum height of the character - int Height = 0; - for (int j = y; j < y + m_FontHeight; j++) - { - for (int i = x; i < x + w; i++) - { - int Pixel = getpixel(m_pFontImage[mode], i, j); - if (Pixel != dotColor && Pixel != keyColor) - Height = MAX(Height, j - y); - } - } - - m_aaFontChars[mode][chr].m_Height = Height; - m_aaFontChars[mode][chr].m_Width = w - 1; - x += w + 1; - - m_CharIndexCap = chr + 1; - - charOnLine++; - if (charOnLine >= 16) - { - charOnLine = 0; - x = 1; - y += m_FontHeight; - // Stop if we run out of bitmap - if ((y + m_FontHeight) > m_pFontImage[mode]->h) - break; - } - } - } - - // Add the calculated charIndexcap to the cache so we can use it in other banner instances - // that use the same font bitmap files. - m_sCharCapCache.insert(std::pair(filePaths[mode], m_CharIndexCap)); - // Also add the now calculated font char data to the cache - // Allocate a dynamic array to throw into the map.. probably until app close - FontChar *aNewCache = new FontChar[MAXBANNERFONTCHARS]; - // Copy the font data into the cache - memcpy(aNewCache, m_aaFontChars[mode], sizeof(FontChar) * MAXBANNERFONTCHARS); - // Now put it into the cache map - m_sFontCache.insert(std::pair(filePaths[mode], aNewCache)); - } - - return true; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys the font data - -void GUIBanner::Destroy() -{ - m_BannerText.clear(); - m_BannerChars.clear(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SpaceBetween -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells how much space, in pixels, currently exists between two flying -// characters. - -int GUIBanner::SpaceBetween(const FlyingChar &first, FontMode firstMode, const FlyingChar &second, FontMode secondMode) const -{ - if (first.m_PosX < second.m_PosX) - return second.m_PosX - first.m_PosX - CalculateWidth(first.m_Character, firstMode); - else - return first.m_PosX - second.m_PosX - CalculateWidth(second.m_Character, secondMode); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ShowText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Starts the display animation of a text string in this banner's font. - -void GUIBanner::ShowText(const std::string &text, AnimMode mode, long duration, Vector targetSize, float yOnTarget, int flySpeed, int flySpacing) -{ - m_BannerText = text; - m_AnimMode = mode; - m_AnimState = SHOWING; - m_TotalAnimTimer.Reset(); - m_SpacingTimer.Reset(); - m_DisplayTimer.SetRealTimeLimitMS(duration); - m_DisplayTimer.Reset(); - m_TargetSize = targetSize; - m_BannerPosY = (m_TargetSize.m_Y * yOnTarget) - (m_FontHeight / 2); - m_FlySpeed = flySpeed; - m_FlySpacing = flySpacing; - - // Clear out the old text string so we can reload it with the new text string - m_BannerChars.clear(); - // Starting position of the first character - int startPosX = m_AnimMode == FLYBYLEFTWARD ? m_TargetSize.m_X : -(CalculateWidth(text, BLURRED) + ((int)(text.length() - 1) * m_FlySpacing)); - // The showing position for the first character - int showPosX = (m_TargetSize.m_X / 2) - (CalculateWidth(text, REGULAR) / 2); - int whichChar = 0; - for (std::string::const_iterator tItr = text.begin(); tItr != text.end(); ++tItr) - { - whichChar++; - // Create the flying character entry - m_BannerChars.push_back(FlyingChar((*tItr), NOTSTARTED, showPosX, m_FlySpeed)); - - if (m_AnimMode == FLYBYLEFTWARD) - { - // Set up the starting and end positions - m_BannerChars.back().m_StartPosX = startPosX; - m_BannerChars.back().m_HidePosX = -CalculateWidth((*tItr), BLURRED); - } - // Now the characters are going reverse - else if (m_AnimMode == FLYBYRIGHTWARD) - { - // Set up the starting and end positions - again, opposite of above - m_BannerChars.back().m_StartPosX = startPosX; - m_BannerChars.back().m_HidePosX = m_TargetSize.m_X; - } - // Blinking, they stay put, so no different start/end positions - else - { - - } - - // Set the current position to match the starting pos - m_BannerChars.back().m_PosX = m_BannerChars.back().m_StartPosX; - // Set up the next character's starting position - startPosX += CalculateWidth((*tItr), BLURRED) + m_FlySpacing; - // Set up the next character's showing position - showPosX += CalculateWidth((*tItr), REGULAR) + GetKerning(); - } - - // If we're flying to the right we need to reverse the order of the characters - if (m_AnimMode == FLYBYRIGHTWARD) - m_BannerChars.reverse(); - - m_FrameTimer.Reset(); - m_SpacingTimer.Reset(); -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HideText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells the banner to animate away elegantly. Especially useful when -// a ShowText is waiting with a negative duration. - -void GUIBanner::HideText() -{ - -} -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the position of the flying characters of this banner. - -void GUIBanner::Update() -{ - double deltaS = m_FrameTimer.GetElapsedRealTimeS(); - - // Only bother updating if things are visible at all - if (m_AnimState < SHOWING || m_AnimState > HIDING) - return; - - // Time out the showing as set - if (m_AnimState == SHOW && m_DisplayTimer.IsPastRealTimeLimit()) - m_AnimState = HIDING; - - int flyDirection = m_AnimMode == FLYBYLEFTWARD ? -1 : 1; - int whichChar = 0; - // Go through every character, updating their positions and states - std::list::iterator prevItr = m_BannerChars.end(); - for (std::list::iterator cItr = m_BannerChars.begin(); cItr != m_BannerChars.end(); ++cItr) - { - whichChar++; - // Start off each character's motion at the appropriate order and timing - if ((*cItr).m_MoveState == NOTSTARTED) - { -// // Get the very first character going, or any consecutive one after the previous has cleared off enough -// if (cItr == m_BannerChars.begin() || ((*prevItr).m_MoveState >= SHOWING && SpaceBetween(*prevItr, BLURRED, *cItr, BLURRED) >= m_FlySpacing)) - // All the spacings are now set up in the starting positions, so just let them all fly at the same time - { -// TODO: Play a starting sound? - (*cItr).m_MoveState = SHOWING; - (*cItr).m_Speed = m_FlySpeed * flyDirection; - } - } - // Move each character along that is currently in flight - if ((*cItr).m_MoveState == SHOWING) - { - (*cItr).m_PosX += (*cItr).m_Speed * deltaS; - - // Stop each character that is at or past its showing destination OR - // before going too far into its stopped predecessor, taking blurring into account - if ((m_AnimMode == FLYBYLEFTWARD && (*cItr).m_PosX <= (*cItr).m_ShowPosX) || - (m_AnimMode == FLYBYRIGHTWARD && (*cItr).m_PosX >= (*cItr).m_ShowPosX) || - (cItr != m_BannerChars.begin() && (*prevItr).m_MoveState == SHOW && SpaceBetween(*prevItr, REGULAR, *cItr, BLURRED) < m_Kerning)) - { -// TODO: Play a stopping sound? - (*cItr).m_PosX = (*cItr).m_ShowPosX; - (*cItr).m_MoveState = SHOW; - (*cItr).m_Speed = 0; - // If all characters are now showing, update the overall animation state of the banner to reflect that - if (whichChar == m_BannerChars.size() && m_BannerChars.front().m_MoveState == SHOW) - { - m_AnimState = SHOW; - m_DisplayTimer.Reset(); - } - } - } - // If we're supposed to be hiding the shown chars, then do so in an orderly fashion - if ((*cItr).m_MoveState == SHOW && m_AnimState >= HIDING) - { - // Get the very first character going, or any consecutive one after the previous has cleared off enough - if (cItr == m_BannerChars.begin() || ((*prevItr).m_MoveState >= HIDING && SpaceBetween(*prevItr, BLURRED, *cItr, BLURRED) >= m_FlySpacing)) - { - (*cItr).m_MoveState = HIDING; - (*cItr).m_Speed = m_FlySpeed * flyDirection; - } - } - // If we're hiding chars, check if they have gone off the screen completely and can now be retired - if ((*cItr).m_MoveState == HIDING) - { - (*cItr).m_PosX += (*cItr).m_Speed * deltaS; - - // Stop each character that has now traveled off the screen - if ((m_AnimMode == FLYBYLEFTWARD && (*cItr).m_PosX <= (*cItr).m_HidePosX) || - (m_AnimMode == FLYBYRIGHTWARD && (*cItr).m_PosX >= (*cItr).m_HidePosX)) - { - (*cItr).m_PosX = (*cItr).m_HidePosX; - (*cItr).m_MoveState = OVER; -// Let them travel off screen -// (*cItr).m_Speed = 0; - // If this was the last character to fly off screen, the the banner showing is over - if (whichChar == m_BannerChars.size()) - m_AnimState = OVER; - } - } - // Keep traveling these suckers even off screen, because char spacings larger than half the screen will cause problems otherwise - if ((*cItr).m_MoveState == OVER) - { - (*cItr).m_PosX += (*cItr).m_Speed * deltaS; - } - - // Update the iterator we'll use on the next char to check distances to etc - prevItr = cItr; - } - - m_FrameTimer.Reset(); -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws text to a bitmap. - -void GUIBanner::Draw(BITMAP *pTargetBitmap) -{ - // Only bother drawing if things are visible at all - if (m_AnimState < SHOWING || m_AnimState > HIDING) - return; - - // Go through every character in the banner, drawing the ones that are showing - unsigned char c; - int mode, charWidth, offX, offY; - for (std::list::iterator cItr = m_BannerChars.begin(); cItr != m_BannerChars.end(); ++cItr) - { - // Only draw anything if the character is even visible - if ((*cItr).m_MoveState >= SHOWING && (*cItr).m_MoveState <= HIDING) - { - // Validate the character - c = (*cItr).m_Character; - if (c == '\n') - { - - } - if (c == '\t') - { - - } - if (c < 0) - c += m_CharIndexCap; - if (c < 32 || c >= m_CharIndexCap) - continue; - - // Figure out where on the font bitmap we're cutting out the character from - mode = (*cItr).m_MoveState == SHOW ? REGULAR : BLURRED; - charWidth = m_aaFontChars[mode][c].m_Width; - offX = m_aaFontChars[mode][c].m_Offset; - offY = ((c - 32) / 16) * m_FontHeight; - - // Draw the character onto the target - masked_blit(m_pFontImage[mode], pTargetBitmap, offX, offY, (*cItr).m_PosX, m_BannerPosY, charWidth, m_FontHeight); - } - } -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the width of a piece of text. - -int GUIBanner::CalculateWidth(const std::string text, FontMode mode) const -{ - unsigned char c; - int Width = 0; - - // Go through every character - for(int i = 0; i < text.length(); i++) - { - c = text.at(i); - - // Reset line counting if newline encountered - if (c == '\n') - { -/* No newlines allowed in banners - if (Width > WidestLine) - WidestLine = Width; - Width = 0; -*/ - continue; - } - if (c < 0) - c += m_CharIndexCap; - if (c < 32 || c >= m_CharIndexCap) - continue; - - Width += m_aaFontChars[mode][c].m_Width; - - // Add kerning, IF NOT BLURRED - //if (i < Text.length() - 1) - if (mode != BLURRED) - Width += m_Kerning; - } - - return Width; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the width of a piece of text. - -int GUIBanner::CalculateWidth(const char Character, FontMode mode) const -{ - unsigned char c = Character; - if (c >= 32 && c < m_CharIndexCap) - return m_aaFontChars[mode][c].m_Width + m_Kerning; - - return 0; -} + std::map GUIBanner::m_sFontCache; + std::map GUIBanner::m_sCharCapCache; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIBanner + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIBanner object in system + // memory. + + GUIBanner::GUIBanner() { + m_pFontImage[REGULAR] = 0; + m_pFontImage[BLURRED] = 0; + memset(m_aaFontChars[REGULAR], 0, sizeof(FontChar) * MAXBANNERFONTCHARS); + memset(m_aaFontChars[BLURRED], 0, sizeof(FontChar) * MAXBANNERFONTCHARS); + m_CharIndexCap = MAXBANNERFONTCHARS; + m_FontHeight = 0; + m_Kerning = 0; + m_BannerText.clear(); + m_BannerChars.clear(); + m_TargetSize.Reset(); + m_BannerPosY = 240; + m_FlySpeed = 1500; + m_FlySpacing = 100; + m_BannerChars.clear(); + m_AnimMode = BLINKING; + m_AnimState = NOTSTARTED; + m_TotalAnimTimer.Reset(); + m_DisplayTimer.Reset(); + m_SpacingTimer.Reset(); + m_FrameTimer.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the font from an image file. + + bool GUIBanner::Create(const std::string fontFilePath, const std::string fontBlurFilePath, int bitDepth) { + // Package the font bitmap paths o they are more easily processed below + std::string filePaths[2] = {fontFilePath, fontBlurFilePath}; + + // Now process them and extract the character data from each + ContentFile fontFile; + std::map::iterator fontItr; + std::map::iterator indexItr; + int y, dotColor; + for (int mode = REGULAR; mode < FONTMODECOUNT; ++mode) { + // Load the font images + fontFile.SetDataPath(filePaths[mode].c_str()); + m_pFontImage[mode] = fontFile.GetAsBitmap(bitDepth == 8 ? COLORCONV_REDUCE_TO_256 : COLORCONV_8_TO_32); + RTEAssert(m_pFontImage[mode], "Couldn't load font bitmap for banner font from this file:\n" + fontFilePath); + + // Check the color key to be the same color as the Bottom-Right hand corner pixel + int keyColor = getpixel(m_pFontImage[mode], m_pFontImage[mode]->w - 1, m_pFontImage[mode]->h - 1); + // No need (or way!) to actually set it; it's assumed to be bright pink (255, 255, 0) + // m_pFontImage[mode]->SetColorKey(keyColor); + + // Check if these files have already been read and loaded from disk before. + fontItr = m_sFontCache.find(filePaths[mode]); + + if (fontItr != m_sFontCache.end()) { + // Yes, has been loaded previously, then use that data from memory. + memcpy(m_aaFontChars[mode], (*fontItr).second, sizeof(FontChar) * MAXBANNERFONTCHARS); + // Also retrieve the font max number of characters if we can + indexItr = m_sCharCapCache.find(filePaths[mode]); + if (indexItr != m_sCharCapCache.end()) + m_CharIndexCap = (*indexItr).second; + else + m_CharIndexCap = MAXBANNERFONTCHARS; + + // Calc the font height - the horizontally blurred one should be the same + if (mode == REGULAR) { + // The red separator MUST be on the Top-Left hand corner + dotColor = getpixel(m_pFontImage[mode], 0, 0); + m_FontHeight = 0; + for (y = 1; y < m_pFontImage[mode]->h; y++) { + if (getpixel(m_pFontImage[mode], 0, y) == dotColor) { + m_FontHeight = y; + break; + } + } + } + } + // Hasn't been loaded previously, so go ahead and do so now. + else { + // The red separator MUST be on the Top-Left hand corner + dotColor = getpixel(m_pFontImage[mode], 0, 0); + // Find the separating gap of the font lines + // Calc the font height - the horizontally blurred one should be the same + if (mode == REGULAR) { + m_FontHeight = 0; + for (y = 1; y < m_pFontImage[mode]->h; y++) { + if (getpixel(m_pFontImage[mode], 0, y) == dotColor) { + m_FontHeight = y; + break; + } + } + } + + // Pre-calculate all the font character details + memset(m_aaFontChars[mode], 0, sizeof(FontChar) * MAXBANNERFONTCHARS); + + int x = 1; + y = 0; + int charOnLine = 0; + for (int chr = 32; chr < MAXBANNERFONTCHARS; chr++) { + m_aaFontChars[mode][chr].m_Offset = x; + + // Find the next red pixel + int w = 0; + int n; + for (n = x; n < m_pFontImage[mode]->w; n++, w++) { + if (getpixel(m_pFontImage[mode], n, y) == dotColor) { + break; + } + } + + // Calculate the maximum height of the character + int Height = 0; + for (int j = y; j < y + m_FontHeight; j++) { + for (int i = x; i < x + w; i++) { + int Pixel = getpixel(m_pFontImage[mode], i, j); + if (Pixel != dotColor && Pixel != keyColor) + Height = MAX(Height, j - y); + } + } + + m_aaFontChars[mode][chr].m_Height = Height; + m_aaFontChars[mode][chr].m_Width = w - 1; + x += w + 1; + + m_CharIndexCap = chr + 1; + + charOnLine++; + if (charOnLine >= 16) { + charOnLine = 0; + x = 1; + y += m_FontHeight; + // Stop if we run out of bitmap + if ((y + m_FontHeight) > m_pFontImage[mode]->h) + break; + } + } + } + + // Add the calculated charIndexcap to the cache so we can use it in other banner instances + // that use the same font bitmap files. + m_sCharCapCache.insert(std::pair(filePaths[mode], m_CharIndexCap)); + // Also add the now calculated font char data to the cache + // Allocate a dynamic array to throw into the map.. probably until app close + FontChar* aNewCache = new FontChar[MAXBANNERFONTCHARS]; + // Copy the font data into the cache + memcpy(aNewCache, m_aaFontChars[mode], sizeof(FontChar) * MAXBANNERFONTCHARS); + // Now put it into the cache map + m_sFontCache.insert(std::pair(filePaths[mode], aNewCache)); + } + + return true; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys the font data + + void GUIBanner::Destroy() { + m_BannerText.clear(); + m_BannerChars.clear(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SpaceBetween + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells how much space, in pixels, currently exists between two flying + // characters. + + int GUIBanner::SpaceBetween(const FlyingChar& first, FontMode firstMode, const FlyingChar& second, FontMode secondMode) const { + if (first.m_PosX < second.m_PosX) + return second.m_PosX - first.m_PosX - CalculateWidth(first.m_Character, firstMode); + else + return first.m_PosX - second.m_PosX - CalculateWidth(second.m_Character, secondMode); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ShowText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Starts the display animation of a text string in this banner's font. + + void GUIBanner::ShowText(const std::string& text, AnimMode mode, long duration, Vector targetSize, float yOnTarget, int flySpeed, int flySpacing) { + m_BannerText = text; + m_AnimMode = mode; + m_AnimState = SHOWING; + m_TotalAnimTimer.Reset(); + m_SpacingTimer.Reset(); + m_DisplayTimer.SetRealTimeLimitMS(duration); + m_DisplayTimer.Reset(); + m_TargetSize = targetSize; + m_BannerPosY = (m_TargetSize.m_Y * yOnTarget) - (m_FontHeight / 2); + m_FlySpeed = flySpeed; + m_FlySpacing = flySpacing; + + // Clear out the old text string so we can reload it with the new text string + m_BannerChars.clear(); + // Starting position of the first character + int startPosX = m_AnimMode == FLYBYLEFTWARD ? m_TargetSize.m_X : -(CalculateWidth(text, BLURRED) + ((int)(text.length() - 1) * m_FlySpacing)); + // The showing position for the first character + int showPosX = (m_TargetSize.m_X / 2) - (CalculateWidth(text, REGULAR) / 2); + int whichChar = 0; + for (std::string::const_iterator tItr = text.begin(); tItr != text.end(); ++tItr) { + whichChar++; + // Create the flying character entry + m_BannerChars.push_back(FlyingChar((*tItr), NOTSTARTED, showPosX, m_FlySpeed)); + + if (m_AnimMode == FLYBYLEFTWARD) { + // Set up the starting and end positions + m_BannerChars.back().m_StartPosX = startPosX; + m_BannerChars.back().m_HidePosX = -CalculateWidth((*tItr), BLURRED); + } + // Now the characters are going reverse + else if (m_AnimMode == FLYBYRIGHTWARD) { + // Set up the starting and end positions - again, opposite of above + m_BannerChars.back().m_StartPosX = startPosX; + m_BannerChars.back().m_HidePosX = m_TargetSize.m_X; + } + // Blinking, they stay put, so no different start/end positions + else { + } + + // Set the current position to match the starting pos + m_BannerChars.back().m_PosX = m_BannerChars.back().m_StartPosX; + // Set up the next character's starting position + startPosX += CalculateWidth((*tItr), BLURRED) + m_FlySpacing; + // Set up the next character's showing position + showPosX += CalculateWidth((*tItr), REGULAR) + GetKerning(); + } + + // If we're flying to the right we need to reverse the order of the characters + if (m_AnimMode == FLYBYRIGHTWARD) + m_BannerChars.reverse(); + + m_FrameTimer.Reset(); + m_SpacingTimer.Reset(); + } + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HideText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells the banner to animate away elegantly. Especially useful when + // a ShowText is waiting with a negative duration. + + void GUIBanner::HideText() + { + + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the position of the flying characters of this banner. + + void GUIBanner::Update() { + double deltaS = m_FrameTimer.GetElapsedRealTimeS(); + + // Only bother updating if things are visible at all + if (m_AnimState < SHOWING || m_AnimState > HIDING) + return; + + // Time out the showing as set + if (m_AnimState == SHOW && m_DisplayTimer.IsPastRealTimeLimit()) + m_AnimState = HIDING; + + int flyDirection = m_AnimMode == FLYBYLEFTWARD ? -1 : 1; + int whichChar = 0; + // Go through every character, updating their positions and states + std::list::iterator prevItr = m_BannerChars.end(); + for (std::list::iterator cItr = m_BannerChars.begin(); cItr != m_BannerChars.end(); ++cItr) { + whichChar++; + // Start off each character's motion at the appropriate order and timing + if ((*cItr).m_MoveState == NOTSTARTED) { + // // Get the very first character going, or any consecutive one after the previous has cleared off enough + // if (cItr == m_BannerChars.begin() || ((*prevItr).m_MoveState >= SHOWING && SpaceBetween(*prevItr, BLURRED, *cItr, BLURRED) >= m_FlySpacing)) + // All the spacings are now set up in the starting positions, so just let them all fly at the same time + { + // TODO: Play a starting sound? + (*cItr).m_MoveState = SHOWING; + (*cItr).m_Speed = m_FlySpeed * flyDirection; + } + } + // Move each character along that is currently in flight + if ((*cItr).m_MoveState == SHOWING) { + (*cItr).m_PosX += (*cItr).m_Speed * deltaS; + + // Stop each character that is at or past its showing destination OR + // before going too far into its stopped predecessor, taking blurring into account + if ((m_AnimMode == FLYBYLEFTWARD && (*cItr).m_PosX <= (*cItr).m_ShowPosX) || + (m_AnimMode == FLYBYRIGHTWARD && (*cItr).m_PosX >= (*cItr).m_ShowPosX) || + (cItr != m_BannerChars.begin() && (*prevItr).m_MoveState == SHOW && SpaceBetween(*prevItr, REGULAR, *cItr, BLURRED) < m_Kerning)) { + // TODO: Play a stopping sound? + (*cItr).m_PosX = (*cItr).m_ShowPosX; + (*cItr).m_MoveState = SHOW; + (*cItr).m_Speed = 0; + // If all characters are now showing, update the overall animation state of the banner to reflect that + if (whichChar == m_BannerChars.size() && m_BannerChars.front().m_MoveState == SHOW) { + m_AnimState = SHOW; + m_DisplayTimer.Reset(); + } + } + } + // If we're supposed to be hiding the shown chars, then do so in an orderly fashion + if ((*cItr).m_MoveState == SHOW && m_AnimState >= HIDING) { + // Get the very first character going, or any consecutive one after the previous has cleared off enough + if (cItr == m_BannerChars.begin() || ((*prevItr).m_MoveState >= HIDING && SpaceBetween(*prevItr, BLURRED, *cItr, BLURRED) >= m_FlySpacing)) { + (*cItr).m_MoveState = HIDING; + (*cItr).m_Speed = m_FlySpeed * flyDirection; + } + } + // If we're hiding chars, check if they have gone off the screen completely and can now be retired + if ((*cItr).m_MoveState == HIDING) { + (*cItr).m_PosX += (*cItr).m_Speed * deltaS; + + // Stop each character that has now traveled off the screen + if ((m_AnimMode == FLYBYLEFTWARD && (*cItr).m_PosX <= (*cItr).m_HidePosX) || + (m_AnimMode == FLYBYRIGHTWARD && (*cItr).m_PosX >= (*cItr).m_HidePosX)) { + (*cItr).m_PosX = (*cItr).m_HidePosX; + (*cItr).m_MoveState = OVER; + // Let them travel off screen + // (*cItr).m_Speed = 0; + // If this was the last character to fly off screen, the the banner showing is over + if (whichChar == m_BannerChars.size()) + m_AnimState = OVER; + } + } + // Keep traveling these suckers even off screen, because char spacings larger than half the screen will cause problems otherwise + if ((*cItr).m_MoveState == OVER) { + (*cItr).m_PosX += (*cItr).m_Speed * deltaS; + } + + // Update the iterator we'll use on the next char to check distances to etc + prevItr = cItr; + } + + m_FrameTimer.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws text to a bitmap. + + void GUIBanner::Draw(BITMAP* pTargetBitmap) { + // Only bother drawing if things are visible at all + if (m_AnimState < SHOWING || m_AnimState > HIDING) + return; + + // Go through every character in the banner, drawing the ones that are showing + unsigned char c; + int mode, charWidth, offX, offY; + for (std::list::iterator cItr = m_BannerChars.begin(); cItr != m_BannerChars.end(); ++cItr) { + // Only draw anything if the character is even visible + if ((*cItr).m_MoveState >= SHOWING && (*cItr).m_MoveState <= HIDING) { + // Validate the character + c = (*cItr).m_Character; + if (c == '\n') { + } + if (c == '\t') { + } + if (c < 0) + c += m_CharIndexCap; + if (c < 32 || c >= m_CharIndexCap) + continue; + + // Figure out where on the font bitmap we're cutting out the character from + mode = (*cItr).m_MoveState == SHOW ? REGULAR : BLURRED; + charWidth = m_aaFontChars[mode][c].m_Width; + offX = m_aaFontChars[mode][c].m_Offset; + offY = ((c - 32) / 16) * m_FontHeight; + + // Draw the character onto the target + masked_blit(m_pFontImage[mode], pTargetBitmap, offX, offY, (*cItr).m_PosX, m_BannerPosY, charWidth, m_FontHeight); + } + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the width of a piece of text. + + int GUIBanner::CalculateWidth(const std::string text, FontMode mode) const { + unsigned char c; + int Width = 0; + + // Go through every character + for (int i = 0; i < text.length(); i++) { + c = text.at(i); + + // Reset line counting if newline encountered + if (c == '\n') { + /* No newlines allowed in banners + if (Width > WidestLine) + WidestLine = Width; + Width = 0; + */ + continue; + } + if (c < 0) + c += m_CharIndexCap; + if (c < 32 || c >= m_CharIndexCap) + continue; + + Width += m_aaFontChars[mode][c].m_Width; + + // Add kerning, IF NOT BLURRED + // if (i < Text.length() - 1) + if (mode != BLURRED) + Width += m_Kerning; + } + + return Width; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the width of a piece of text. + + int GUIBanner::CalculateWidth(const char Character, FontMode mode) const { + unsigned char c = Character; + if (c >= 32 && c < m_CharIndexCap) + return m_aaFontChars[mode][c].m_Width + m_Kerning; + + return 0; + } } // namespace RTE diff --git a/Source/GUI/GUIBanner.h b/Source/GUI/GUIBanner.h index 98448bed7..b97477bcc 100644 --- a/Source/GUI/GUIBanner.h +++ b/Source/GUI/GUIBanner.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - #include "Vector.h" #include "Timer.h" #include "allegro.h" @@ -19,311 +18,300 @@ struct BITMAP; #define MAXBANNERFONTCHARS 256 -namespace RTE -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: GUIBanner -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A class to handle the drawing of LARGE text banners that fly across -// the screen, grabbing the player's attention. -// Parent(s): None. -// Class history: 5/7/2011 GUIBanner Created. - -class GUIBanner { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - enum FontMode - { - REGULAR = 0, - BLURRED, - FONTMODECOUNT - }; - - enum AnimMode - { - BLINKING = 0, - FLYBYLEFTWARD, - FLYBYRIGHTWARD, - ANIMMODECOUNT - }; - - enum AnimState - { - NOTSTARTED = 0, - SHOWING, - SHOW, - HIDING, - OVER, - ANIMSTATECOUNT - }; - - // Font character - struct FontChar { - int m_Width; - int m_Height; - int m_Offset; - }; - - // Flying characters - struct FlyingChar { - FlyingChar(char character, AnimState state, int showPosX, float speed) {m_Character = character; m_MoveState = state; m_PosX = m_StartPosX = m_ShowPosX = m_HidePosX = showPosX; m_Speed = speed; } - char m_Character; - AnimState m_MoveState; - int m_PosX; - int m_StartPosX; - int m_ShowPosX; - int m_HidePosX; - float m_Speed; - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIBanner -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIBanner object in system -// memory. -// Arguments: None. -// Return value: None. - - GUIBanner(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the font from an image file. -// Arguments: Path to the font bitmap file. -// Path to the blurred font bitmap file. -// At which color bit depth to load the font files as. -// Return value: None. - - bool Create(const std::string fontFilePath, const std::string fontBlurFilePath, int bitDepth); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys the font data -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBannerText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the currently displayed text string. -// Arguments: None. -// Return value: The currently displayed text string. - - std::string GetBannerText() const { return m_BannerText; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAnimState -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current state of the overall animation of this banner. -// Arguments: None. -// Return value: The current state of the animation. - - AnimState GetAnimState() const { return m_AnimState; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether this banner is currently showing anything on screen. -// Arguments: None. -// Return value: Whether this is showing anything presently. - - bool IsVisible() const { return m_AnimState >= SHOWING && m_AnimState <= HIDING; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the width of a piece of text. -// Arguments: Text. -// Return value: None. - - int CalculateWidth(const std::string Text, FontMode mode) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the width of a piece of text. -// Arguments: Character. -// Return value: None. - - int CalculateWidth(const char Character, FontMode mode) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFontHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the font height. -// Arguments: None. -// Return value: The font height in pixels. - - int GetFontHeight() const { return m_FontHeight; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetKerning -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get the character kerning (spacing) -// Arguments: None. -// Return value: Spacing between characters, in pixels. 1 = one empty pixel -// between chars, 0 = chars are touching. - - int GetKerning() const { return m_Kerning; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetKerning -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Set the character kerning (spacing), in pixels. 1 = one empty pixel -// between chars, 0 = chars are touching. -// Arguments: The new kerning value. -// Return value: None. - - void SetKerning(int newKerning = 1) { m_Kerning = newKerning; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SpaceBetween -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells how much space, in pixels, currently exists between two flying -// characters. -// Arguments: The first FlyingChar. -// The font mode of the first character. -// The second FlyingChar. -// The font mode of the second character. -// Return value: The space, in pixels. - - int SpaceBetween(const FlyingChar &first, FontMode firstMode, const FlyingChar &second, FontMode secondMode) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ShowText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Starts the display animation of a text string in this banner's font. -// This only needs to be called once per display animation. Any currently -// played animation will be interrupted and the banner restarted. -// Arguments: The text to display. -// The animation mode to display the text in. -// The duration of the animation the text is displayed in. Negative value -// means the text pauses at the display/center until HideText is called. -// The width and height of the bitmap target this will be displayed on. -// The Y position the banner should appear on the target, in normalized -// value. 0.5 = banner midline is centered on halfway down the target. -// The speed at which the characters will fly, in pixels per second. -// The spacing between the flying characters, in pixels. -// Return value: None. - - void ShowText(const std::string &text, AnimMode mode, long duration, Vector targetSize, float yOnTarget, int flySpeed = 1500, int flySpacing = 100); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HideText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells the banner to animate away elegantly. Especially useful when -// a ShowText is waiting with a negative duration. -// Arguments: The speed at which the characters will fly, in pixels per second. -// The spacing between the flying characters, in pixels. -// Return value: None. - - void HideText(int flySpeed = 1500, int flySpacing = 100) { if (m_AnimState <= SHOW) { m_AnimState = HIDING; } m_FlySpeed = flySpeed; m_FlySpacing = flySpacing; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Abruptly clears any text without animating it away. Resets this thing. -// Arguments: None. -// Return value: None. - - void ClearText() { m_BannerText.clear(); m_BannerChars.clear(); m_AnimState = NOTSTARTED; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the position of the flying characters of this banner. -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws text to a bitmap. -// Arguments: The target bitmap to draw to. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - // Font bitmap files - not owned - BITMAP *m_pFontImage[FONTMODECOUNT]; - - // The loaded font information for each filepath to a font bitmap - static std::map m_sFontCache; - // Cache of the highest indices of valid characters that was read in from the file - static std::map m_sCharCapCache; - - // The actual character info for this specific banner font - FontChar m_aaFontChars[FONTMODECOUNT][MAXBANNERFONTCHARS]; - // The highest index of valid characters that was read in from the file - int m_CharIndexCap; - - // Height of the font - int m_FontHeight; - // Spacing between characters, in pixels - int m_Kerning; - - // The text string currently being displayed - std::string m_BannerText; - // The actual characters of this banner and their positions etc - std::list m_BannerChars; - // The dimensions of the screen area that this banner is displayed on - Vector m_TargetSize; - // The pixel Y position that the banner has on the target - int m_BannerPosY; - // The speed at which the characters will fly, in pixels per second - int m_FlySpeed; - // The spacing between characters when they fly, in pixels - int m_FlySpacing; - // The mode of animation to show the above text in - AnimMode m_AnimMode; - // The current state of the animation - AnimState m_AnimState; - // The timer that keeps track of the total display animation. - Timer m_TotalAnimTimer; - // The timer that keeps track of how long to wait with the banner displaying before animating it away. - Timer m_DisplayTimer; - // Timer for keeping track of how long between individual characters are shown - Timer m_SpacingTimer; - // Timer for keeping track of how long passed since last call to Update - Timer m_FrameTimer; -}; +namespace RTE { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: GUIBanner + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A class to handle the drawing of LARGE text banners that fly across + // the screen, grabbing the player's attention. + // Parent(s): None. + // Class history: 5/7/2011 GUIBanner Created. + + class GUIBanner { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + enum FontMode { + REGULAR = 0, + BLURRED, + FONTMODECOUNT + }; + + enum AnimMode { + BLINKING = 0, + FLYBYLEFTWARD, + FLYBYRIGHTWARD, + ANIMMODECOUNT + }; + + enum AnimState { + NOTSTARTED = 0, + SHOWING, + SHOW, + HIDING, + OVER, + ANIMSTATECOUNT + }; + + // Font character + struct FontChar { + int m_Width; + int m_Height; + int m_Offset; + }; + + // Flying characters + struct FlyingChar { + FlyingChar(char character, AnimState state, int showPosX, float speed) { + m_Character = character; + m_MoveState = state; + m_PosX = m_StartPosX = m_ShowPosX = m_HidePosX = showPosX; + m_Speed = speed; + } + char m_Character; + AnimState m_MoveState; + int m_PosX; + int m_StartPosX; + int m_ShowPosX; + int m_HidePosX; + float m_Speed; + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIBanner + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIBanner object in system + // memory. + // Arguments: None. + // Return value: None. + + GUIBanner(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the font from an image file. + // Arguments: Path to the font bitmap file. + // Path to the blurred font bitmap file. + // At which color bit depth to load the font files as. + // Return value: None. + + bool Create(const std::string fontFilePath, const std::string fontBlurFilePath, int bitDepth); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys the font data + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBannerText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the currently displayed text string. + // Arguments: None. + // Return value: The currently displayed text string. + + std::string GetBannerText() const { return m_BannerText; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAnimState + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current state of the overall animation of this banner. + // Arguments: None. + // Return value: The current state of the animation. + + AnimState GetAnimState() const { return m_AnimState; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether this banner is currently showing anything on screen. + // Arguments: None. + // Return value: Whether this is showing anything presently. + + bool IsVisible() const { return m_AnimState >= SHOWING && m_AnimState <= HIDING; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the width of a piece of text. + // Arguments: Text. + // Return value: None. + + int CalculateWidth(const std::string Text, FontMode mode) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the width of a piece of text. + // Arguments: Character. + // Return value: None. + + int CalculateWidth(const char Character, FontMode mode) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFontHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the font height. + // Arguments: None. + // Return value: The font height in pixels. + + int GetFontHeight() const { return m_FontHeight; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetKerning + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get the character kerning (spacing) + // Arguments: None. + // Return value: Spacing between characters, in pixels. 1 = one empty pixel + // between chars, 0 = chars are touching. + + int GetKerning() const { return m_Kerning; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetKerning + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Set the character kerning (spacing), in pixels. 1 = one empty pixel + // between chars, 0 = chars are touching. + // Arguments: The new kerning value. + // Return value: None. + + void SetKerning(int newKerning = 1) { m_Kerning = newKerning; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SpaceBetween + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells how much space, in pixels, currently exists between two flying + // characters. + // Arguments: The first FlyingChar. + // The font mode of the first character. + // The second FlyingChar. + // The font mode of the second character. + // Return value: The space, in pixels. + + int SpaceBetween(const FlyingChar& first, FontMode firstMode, const FlyingChar& second, FontMode secondMode) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ShowText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Starts the display animation of a text string in this banner's font. + // This only needs to be called once per display animation. Any currently + // played animation will be interrupted and the banner restarted. + // Arguments: The text to display. + // The animation mode to display the text in. + // The duration of the animation the text is displayed in. Negative value + // means the text pauses at the display/center until HideText is called. + // The width and height of the bitmap target this will be displayed on. + // The Y position the banner should appear on the target, in normalized + // value. 0.5 = banner midline is centered on halfway down the target. + // The speed at which the characters will fly, in pixels per second. + // The spacing between the flying characters, in pixels. + // Return value: None. + + void ShowText(const std::string& text, AnimMode mode, long duration, Vector targetSize, float yOnTarget, int flySpeed = 1500, int flySpacing = 100); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HideText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells the banner to animate away elegantly. Especially useful when + // a ShowText is waiting with a negative duration. + // Arguments: The speed at which the characters will fly, in pixels per second. + // The spacing between the flying characters, in pixels. + // Return value: None. + + void HideText(int flySpeed = 1500, int flySpacing = 100) { + if (m_AnimState <= SHOW) { + m_AnimState = HIDING; + } + m_FlySpeed = flySpeed; + m_FlySpacing = flySpacing; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Abruptly clears any text without animating it away. Resets this thing. + // Arguments: None. + // Return value: None. + + void ClearText() { + m_BannerText.clear(); + m_BannerChars.clear(); + m_AnimState = NOTSTARTED; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the position of the flying characters of this banner. + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws text to a bitmap. + // Arguments: The target bitmap to draw to. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + // Font bitmap files - not owned + BITMAP* m_pFontImage[FONTMODECOUNT]; + + // The loaded font information for each filepath to a font bitmap + static std::map m_sFontCache; + // Cache of the highest indices of valid characters that was read in from the file + static std::map m_sCharCapCache; + + // The actual character info for this specific banner font + FontChar m_aaFontChars[FONTMODECOUNT][MAXBANNERFONTCHARS]; + // The highest index of valid characters that was read in from the file + int m_CharIndexCap; + + // Height of the font + int m_FontHeight; + // Spacing between characters, in pixels + int m_Kerning; + + // The text string currently being displayed + std::string m_BannerText; + // The actual characters of this banner and their positions etc + std::list m_BannerChars; + // The dimensions of the screen area that this banner is displayed on + Vector m_TargetSize; + // The pixel Y position that the banner has on the target + int m_BannerPosY; + // The speed at which the characters will fly, in pixels per second + int m_FlySpeed; + // The spacing between characters when they fly, in pixels + int m_FlySpacing; + // The mode of animation to show the above text in + AnimMode m_AnimMode; + // The current state of the animation + AnimState m_AnimState; + // The timer that keeps track of the total display animation. + Timer m_TotalAnimTimer; + // The timer that keeps track of how long to wait with the banner displaying before animating it away. + Timer m_DisplayTimer; + // Timer for keeping track of how long between individual characters are shown + Timer m_SpacingTimer; + // Timer for keeping track of how long passed since last call to Update + Timer m_FrameTimer; + }; }; // namespace RTE -#endif // _GUIBanner_ \ No newline at end of file +#endif // _GUIBanner_ diff --git a/Source/GUI/GUIButton.cpp b/Source/GUI/GUIButton.cpp index e6b0993b0..f6a53ac61 100644 --- a/Source/GUI/GUIButton.cpp +++ b/Source/GUI/GUIButton.cpp @@ -7,7 +7,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIButton::GUIButton(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUIButton::GUIButton(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "BUTTON"; m_DrawBitmap = nullptr; m_ControlManager = ControlManager; @@ -20,7 +21,7 @@ GUIButton::GUIButton(GUIManager *Manager, GUIControlManager *ControlManager) : G ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIButton::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -37,8 +38,12 @@ void GUIButton::Create(const std::string &Name, int X, int Y, int Width, int Hei m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the button isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -53,13 +58,17 @@ void GUIButton::Create(const std::string &Name, int X, int Y, int Width, int Hei m_Text->SetEnabled(false); GUIPanel::AddChild(m_Text.get()); } - if (!m_Icon) { m_Icon = std::make_unique(); } - if (!m_BorderSizes) { m_BorderSizes = std::make_unique(); } + if (!m_Icon) { + m_Icon = std::make_unique(); + } + if (!m_BorderSizes) { + m_BorderSizes = std::make_unique(); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::Create(GUIProperties *Props) { +void GUIButton::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -86,8 +95,12 @@ void GUIButton::Create(GUIProperties *Props) { m_Text->SetEnabled(false); GUIPanel::AddChild(m_Text.get()); } - if (!m_Icon) { m_Icon = std::make_unique(); } - if (!m_BorderSizes) { m_BorderSizes = std::make_unique(); } + if (!m_Icon) { + m_Icon = std::make_unique(); + } + if (!m_BorderSizes) { + m_BorderSizes = std::make_unique(); + } // Load the values std::string text; @@ -114,7 +127,7 @@ void GUIButton::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::ChangeSkin(GUISkin *Skin) { +void GUIButton::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Build the button bitmap @@ -144,10 +157,12 @@ void GUIButton::BuildBitmap() { m_FontColor = m_Skin->ConvertColor(m_FontColor, m_DrawBitmap->GetColorDepth()); - //TODO consider getting rid of this line. Because of it GuiButton::SetFont does nothing, which is weird, but maybe there's a good reason for it. Test and investigate. - // Also, with the change of m_Text from a std::string to a GUILabel this seems maybe even sillier. SetFont should probably set the label's font + // TODO consider getting rid of this line. Because of it GuiButton::SetFont does nothing, which is weird, but maybe there's a good reason for it. Test and investigate. + // Also, with the change of m_Text from a std::string to a GUILabel this seems maybe even sillier. SetFont should probably set the label's font m_Font = m_Skin->GetFont(Filename); - if (m_Font) { m_Font->CacheColor(m_FontColor); } + if (m_Font) { + m_Font->CacheColor(m_FontColor); + } // Create the button image GUIRect buttonBorders; @@ -156,7 +171,7 @@ void GUIButton::BuildBitmap() { m_Skin->BuildStandardRect(m_DrawBitmap, "Button_Over", 0, m_Height, m_Width, m_Height); m_Skin->BuildStandardRect(m_DrawBitmap, "Button_Down", 0, m_Height * 2, m_Width, m_Height); - //TODO this should be 1 pixel ideally, to give space between content and the border. However, the green skin, which this is primarly used for, has padding built-in and doesn't work properly without it. + // TODO this should be 1 pixel ideally, to give space between content and the border. However, the green skin, which this is primarly used for, has padding built-in and doesn't work properly without it. const int buttonContentPadding = 0; const int contentMaxWidth = m_Width - m_BorderSizes->left - m_BorderSizes->right - (buttonContentPadding * 2) - 1; const int contentMaxHeight = m_Height - m_BorderSizes->top - m_BorderSizes->bottom - (buttonContentPadding * 2) - 1; @@ -172,7 +187,7 @@ void GUIButton::BuildBitmap() { if (hasIcon && !hasText) { iconYPos = centerY - (m_Icon->GetHeight() / 2); } else if (!hasIcon && hasText) { - //int y = m_Height/2-m_Font->CalculateHeight(m_Text)+2; //Note this commented line was here from CCOSS, it was here so that the idea of using the full height of the text stays around. + // int y = m_Height/2-m_Font->CalculateHeight(m_Text)+2; //Note this commented line was here from CCOSS, it was here so that the idea of using the full height of the text stays around. textYPos = centerY - (m_Font->GetFontHeight() / 2) - 1; } else if (hasIcon && hasText) { int iconAndTextHeight = m_Text->GetHorizontalOverflowScroll() ? m_Font->GetFontHeight() : m_Font->CalculateHeight(m_Text->GetText(), contentMaxWidth); @@ -221,7 +236,7 @@ void GUIButton::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::Draw(GUIScreen *Screen) { +void GUIButton::Draw(GUIScreen* Screen) { GUIRect Rect; int y = 0; if (m_Pushed) { @@ -231,7 +246,9 @@ void GUIButton::Draw(GUIScreen *Screen) { } SetRect(&Rect, 0, y, m_Width, y + m_Height); - if (m_Text->OverflowScrollIsActivated() && m_Font->CalculateWidth(m_Text->GetText()) > m_Width - m_BorderSizes->left - m_BorderSizes->right) { BuildBitmap(); } + if (m_Text->OverflowScrollIsActivated() && m_Font->CalculateWidth(m_Text->GetText()) > m_Width - m_BorderSizes->left - m_BorderSizes->right) { + BuildBitmap(); + } m_DrawBitmap->DrawTrans(Screen->GetBitmap(), m_X, m_Y, &Rect); @@ -253,7 +270,9 @@ void GUIButton::OnMouseDown(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIButton::OnMouseUp(int X, int Y, int Buttons, int Modifier) { - if (PointInside(X, Y)) { AddEvent(GUIEvent::Notification, Clicked, Buttons); } + if (PointInside(X, Y)) { + AddEvent(GUIEvent::Notification, Clicked, Buttons); + } if (!IsCaptured()) { return; @@ -263,7 +282,9 @@ void GUIButton::OnMouseUp(int X, int Y, int Buttons, int Modifier) { ReleaseMouse(); // If the mouse is over the button, add the command to the event queue - if (PointInside(X, Y)) { AddEvent(GUIEvent::Command, 0, 0); } + if (PointInside(X, Y)) { + AddEvent(GUIEvent::Command, 0, 0); + } AddEvent(GUIEvent::Notification, UnPushed, 0); } @@ -328,18 +349,17 @@ void GUIButton::OnMouseMove(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIButton::OnKeyDown(int KeyCode, int Modifier) { - } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIButton::GetPanel() { +GUIPanel* GUIButton::GetPanel() { return this; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIButton::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -383,16 +403,18 @@ void GUIButton::SetPushed(bool pushed) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::SetText(const std::string_view &newText, bool noBitmapRebuild) { +void GUIButton::SetText(const std::string_view& newText, bool noBitmapRebuild) { if (GetText() != newText) { m_Text->SetText(newText); - if (!noBitmapRebuild) { BuildBitmap(); } + if (!noBitmapRebuild) { + BuildBitmap(); + } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const std::string & GUIButton::GetText() const { +const std::string& GUIButton::GetText() const { return m_Text->GetText(); } @@ -400,37 +422,45 @@ const std::string & GUIButton::GetText() const { void GUIButton::SetHorizontalOverflowScroll(bool newOverflowScroll) { m_Text->SetHorizontalOverflowScroll(newOverflowScroll); - if (m_Text->GetHorizontalOverflowScroll()) { BuildBitmap(); } + if (m_Text->GetHorizontalOverflowScroll()) { + BuildBitmap(); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIButton::SetVerticalOverflowScroll(bool newOverflowScroll) { m_Text->SetVerticalOverflowScroll(newOverflowScroll); - if (m_Text->GetVerticalOverflowScroll()) { BuildBitmap(); } + if (m_Text->GetVerticalOverflowScroll()) { + BuildBitmap(); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::SetIcon(BITMAP *newIcon, bool noBitmapRebuild) { +void GUIButton::SetIcon(BITMAP* newIcon, bool noBitmapRebuild) { if (m_Icon && m_Icon->GetBitmap() != newIcon) { m_Icon->SetBitmap(newIcon); - if (!noBitmapRebuild) { BuildBitmap(); } + if (!noBitmapRebuild) { + BuildBitmap(); + } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::SetIconAndText(BITMAP *newIcon, const std::string_view &newText) { +void GUIButton::SetIconAndText(BITMAP* newIcon, const std::string_view& newText) { bool bitmapNeedsRebuild = (m_Icon && m_Icon->GetBitmap() != newIcon) || (m_Text && m_Text->GetText() != newText); SetIcon(newIcon, true); SetText(newText, true); - if (bitmapNeedsRebuild) { BuildBitmap(); } + if (bitmapNeedsRebuild) { + BuildBitmap(); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIButton::ApplyProperties(GUIProperties *Props) { +void GUIButton::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); std::string text; @@ -444,4 +474,4 @@ void GUIButton::ApplyProperties(GUIProperties *Props) { m_Text->SetVerticalOverflowScroll(overflowScroll); BuildBitmap(); -} \ No newline at end of file +} diff --git a/Source/GUI/GUIButton.h b/Source/GUI/GUIButton.h index 658adcebb..2111c0a9e 100644 --- a/Source/GUI/GUIButton.h +++ b/Source/GUI/GUIButton.h @@ -3,293 +3,270 @@ namespace RTE { - class GUILabel; - -/// -/// A button control class. -/// -class GUIButton : public GUIControl, public GUIPanel { - -public: - - // Button Notifications - enum { - Pushed = 0, - UnPushed, - Clicked, - Focused - } Notification; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIButton -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIButton object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUIButton(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseEnter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse enters the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseLeave -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse leaves the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; - - ////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnGainFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel gains focus. -// Arguments: None. - - void OnGainFocus() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnLoseFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel looses focus. -// Arguments: None. - - void OnLoseFocus() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnKeyDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when a key goes down. -// Arguments: KeyCode, Modifier. - - void OnKeyDown(int KeyCode, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "BUTTON"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - /// - /// Gets whether or not this button is currently pushed. - /// - /// Whether or not this button is currently pushed. - bool IsPushed() const { return m_Pushed; } - - /// - /// Sets whether or not this button is currently pushed. - /// - /// Whether or not this button should be pushed. - void SetPushed(bool pushed = false); - - /// - /// Gets whether or not this button is currently being moused over. - /// - /// Whether or not this button is currently being moused over. - bool IsMousedOver() const { return m_Over; } - - /// - /// Gets the text of this GUIButton's GUILabel. - /// - /// The text of this GUIButton's GUILabel. - const std::string & GetText() const; - - /// - /// Sets the text of this GUIButton's GUILabel. - /// - /// The new text for this GUIButton's GUILabel. - /// Lets this method NOT rebuild the button bitmap, even if the icon has changed. Defaults to false and should almost always stay that way. - void SetText(const std::string_view &newText, bool noBitmapRebuild = false); - - /// - /// Sets whether or not this GUIButton's text should scroll horizontally (right) when it overflows the button. - /// - /// Whether or not this GUIButton's text should scroll horizontally when it overflows. - void SetHorizontalOverflowScroll(bool newOverflowScroll); - - /// - /// Sets whether or not this GUIButton's text should scroll vertically (down) when it overflows the button. - /// - /// Whether or not this GUIButton's text should scroll vertically when it overflows. - void SetVerticalOverflowScroll(bool newOverflowScroll); - - /// - /// Gets whether or not this GUIButton has an icon with a Bitmap. - /// - bool HasIcon() const { return m_Icon->GetBitmap(); } - - /// - /// Sets the icon for this GUIButton. Ownership is NOT transferred. - /// - /// A pointer to the new icon BITMAP for this GUIButton. - /// Lets this method NOT rebuild the button bitmap, even if the icon has changed. Defaults to false and should almost always stay that way. - void SetIcon(BITMAP *newIcon, bool noBitmapRebuild = false); - - /// - /// Helper method to set both text and icon for this GUIButton at the same time. - /// - /// A pointer to the new icon BITMAP for this GUIButton. - /// The new text for this GUIButton's GUILabel. - void SetIconAndText(BITMAP *newIcon, const std::string_view &newText); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - - GUIBitmap *m_DrawBitmap; - - bool m_Pushed; - bool m_Over; - std::unique_ptr m_Text; - std::unique_ptr m_Icon; - std::unique_ptr m_BorderSizes; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the button bitmap to draw. -// Arguments: None. - - void BuildBitmap(); -}; -}; -#endif \ No newline at end of file + class GUILabel; + + /// + /// A button control class. + /// + class GUIButton : public GUIControl, public GUIPanel { + + public: + // Button Notifications + enum { + Pushed = 0, + UnPushed, + Clicked, + Focused + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIButton + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIButton object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUIButton(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseEnter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse enters the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseLeave + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse leaves the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnGainFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel gains focus. + // Arguments: None. + + void OnGainFocus() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnLoseFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel looses focus. + // Arguments: None. + + void OnLoseFocus() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnKeyDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when a key goes down. + // Arguments: KeyCode, Modifier. + + void OnKeyDown(int KeyCode, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "BUTTON"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + /// + /// Gets whether or not this button is currently pushed. + /// + /// Whether or not this button is currently pushed. + bool IsPushed() const { return m_Pushed; } + + /// + /// Sets whether or not this button is currently pushed. + /// + /// Whether or not this button should be pushed. + void SetPushed(bool pushed = false); + + /// + /// Gets whether or not this button is currently being moused over. + /// + /// Whether or not this button is currently being moused over. + bool IsMousedOver() const { return m_Over; } + + /// + /// Gets the text of this GUIButton's GUILabel. + /// + /// The text of this GUIButton's GUILabel. + const std::string& GetText() const; + + /// + /// Sets the text of this GUIButton's GUILabel. + /// + /// The new text for this GUIButton's GUILabel. + /// Lets this method NOT rebuild the button bitmap, even if the icon has changed. Defaults to false and should almost always stay that way. + void SetText(const std::string_view& newText, bool noBitmapRebuild = false); + + /// + /// Sets whether or not this GUIButton's text should scroll horizontally (right) when it overflows the button. + /// + /// Whether or not this GUIButton's text should scroll horizontally when it overflows. + void SetHorizontalOverflowScroll(bool newOverflowScroll); + + /// + /// Sets whether or not this GUIButton's text should scroll vertically (down) when it overflows the button. + /// + /// Whether or not this GUIButton's text should scroll vertically when it overflows. + void SetVerticalOverflowScroll(bool newOverflowScroll); + + /// + /// Gets whether or not this GUIButton has an icon with a Bitmap. + /// + bool HasIcon() const { return m_Icon->GetBitmap(); } + + /// + /// Sets the icon for this GUIButton. Ownership is NOT transferred. + /// + /// A pointer to the new icon BITMAP for this GUIButton. + /// Lets this method NOT rebuild the button bitmap, even if the icon has changed. Defaults to false and should almost always stay that way. + void SetIcon(BITMAP* newIcon, bool noBitmapRebuild = false); + + /// + /// Helper method to set both text and icon for this GUIButton at the same time. + /// + /// A pointer to the new icon BITMAP for this GUIButton. + /// The new text for this GUIButton's GUILabel. + void SetIconAndText(BITMAP* newIcon, const std::string_view& newText); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; + + private: + GUIBitmap* m_DrawBitmap; + + bool m_Pushed; + bool m_Over; + std::unique_ptr m_Text; + std::unique_ptr m_Icon; + std::unique_ptr m_BorderSizes; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the button bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUICheckbox.cpp b/Source/GUI/GUICheckbox.cpp index a43ac0279..6c1d623e9 100644 --- a/Source/GUI/GUICheckbox.cpp +++ b/Source/GUI/GUICheckbox.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUICheckbox::GUICheckbox(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUICheckbox::GUICheckbox(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "CHECKBOX"; m_Image = nullptr; m_ControlManager = ControlManager; @@ -15,7 +16,7 @@ GUICheckbox::GUICheckbox(GUIManager *Manager, GUIControlManager *ControlManager) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICheckbox::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUICheckbox::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -32,8 +33,12 @@ void GUICheckbox::Create(const std::string &Name, int X, int Y, int Width, int H m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the button isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -42,7 +47,7 @@ void GUICheckbox::Create(const std::string &Name, int X, int Y, int Width, int H ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICheckbox::Create(GUIProperties *Props) { +void GUICheckbox::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -60,7 +65,6 @@ void GUICheckbox::Create(GUIProperties *Props) { m_Width = std::max(m_Width, m_MinWidth); m_Height = std::max(m_Height, m_MinHeight); - // Grab the check value m_Check = Unchecked; std::string value; @@ -79,7 +83,7 @@ void GUICheckbox::Destroy() {} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICheckbox::ChangeSkin(GUISkin *Skin) { +void GUICheckbox::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Build the checkbox bitmap @@ -134,7 +138,7 @@ void GUICheckbox::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICheckbox::Draw(GUIScreen *Screen) { +void GUICheckbox::Draw(GUIScreen* Screen) { if (!m_Image) { return; } @@ -224,7 +228,7 @@ void GUICheckbox::OnMouseLeave(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUICheckbox::GetPanel() { +GUIPanel* GUICheckbox::GetPanel() { return this; } @@ -248,7 +252,7 @@ void GUICheckbox::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICheckbox::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUICheckbox::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -267,7 +271,7 @@ void GUICheckbox::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICheckbox::SetText(const std::string &Text) { +void GUICheckbox::SetText(const std::string& Text) { m_Text = Text; } @@ -291,7 +295,7 @@ int GUICheckbox::GetCheck() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICheckbox::ApplyProperties(GUIProperties *Props) { +void GUICheckbox::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); m_Check = Unchecked; @@ -303,4 +307,4 @@ void GUICheckbox::ApplyProperties(GUIProperties *Props) { m_Check = Greycheck; } m_Properties.GetValue("Text", &m_Text); -} \ No newline at end of file +} diff --git a/Source/GUI/GUICheckbox.h b/Source/GUI/GUICheckbox.h index 44ec6a974..086f2d158 100644 --- a/Source/GUI/GUICheckbox.h +++ b/Source/GUI/GUICheckbox.h @@ -3,233 +3,211 @@ namespace RTE { -/// -/// A checkbox control class. -/// -class GUICheckbox : public GUIControl, public GUIPanel { + /// + /// A checkbox control class. + /// + class GUICheckbox : public GUIControl, public GUIPanel { + + public: + // Check types + enum { + Unchecked = 0, + Checked, + Greycheck + }; + + // Checkbox Notifications + enum { + Pushed = 0, + UnPushed, + Changed, + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUICheckbox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUICheckbox object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUICheckbox(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseEnter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse enters the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseLeave + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse leaves the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "CHECKBOX"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; -public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; - // Check types - enum { - Unchecked = 0, - Checked, - Greycheck - }; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; - // Checkbox Notifications - enum { - Pushed = 0, - UnPushed, - Changed, - } Notification; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUICheckbox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUICheckbox object in -// system memory. -// Arguments: GUIManager, GUIControlManager. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the text. + // Arguments: Text. + + void SetText(const std::string& Text); - GUICheckbox(GUIManager *Manager, GUIControlManager *ControlManager); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the text. + // Arguments: None. + + std::string GetText() const; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the check state. + // Arguments: Check state. + + void SetCheck(int Check); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the check state. + // Arguments: None. + + int GetCheck() const; - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; + private: + GUIBitmap* m_Image; + GUIRect m_ImageRects[4]; + + int m_Check; + std::string m_Text; + int m_Mouseover; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseEnter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse enters the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseLeave -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse leaves the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "CHECKBOX"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the text. -// Arguments: Text. - - void SetText(const std::string &Text); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the text. -// Arguments: None. - - std::string GetText() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the check state. -// Arguments: Check state. - - void SetCheck(int Check); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the check state. -// Arguments: None. - - int GetCheck() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - - GUIBitmap *m_Image; - GUIRect m_ImageRects[4]; - - int m_Check; - std::string m_Text; - int m_Mouseover; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the checkbox bitmap to draw. -// Arguments: None. - - void BuildBitmap(); -}; -}; -#endif \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the checkbox bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUICollectionBox.cpp b/Source/GUI/GUICollectionBox.cpp index 16803e439..d1631aac2 100644 --- a/Source/GUI/GUICollectionBox.cpp +++ b/Source/GUI/GUICollectionBox.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUICollectionBox::GUICollectionBox(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUICollectionBox::GUICollectionBox(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "COLLECTIONBOX"; m_Background = nullptr; m_ControlManager = ControlManager; @@ -19,7 +20,7 @@ GUICollectionBox::GUICollectionBox(GUIManager *Manager, GUIControlManager *Contr ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICollectionBox::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUICollectionBox::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -36,8 +37,12 @@ void GUICollectionBox::Create(const std::string &Name, int X, int Y, int Width, m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the box isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -46,7 +51,7 @@ void GUICollectionBox::Create(const std::string &Name, int X, int Y, int Width, ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICollectionBox::Create(GUIProperties *Props) { +void GUICollectionBox::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -87,7 +92,7 @@ void GUICollectionBox::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICollectionBox::ChangeSkin(GUISkin *Skin) { +void GUICollectionBox::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Build the panel bitmap @@ -109,7 +114,7 @@ void GUICollectionBox::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICollectionBox::Draw(GUIScreen *Screen) { +void GUICollectionBox::Draw(GUIScreen* Screen) { if (m_DrawBackground) { if (m_DrawType == Color) { Screen->GetBitmap()->DrawRectangle(m_X, m_Y, m_Width, m_Height, m_Skin->ConvertColor(m_DrawColor, Screen->GetBitmap()->GetColorDepth()), true); @@ -157,7 +162,7 @@ void GUICollectionBox::OnMouseMove(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUICollectionBox::GetPanel() { +GUIPanel* GUICollectionBox::GetPanel() { return this; } @@ -171,9 +176,9 @@ void GUICollectionBox::Move(int X, int Y) { m_Y = Y; // Go through all my children moving them - std::vector::iterator it; + std::vector::iterator it; for (it = m_ControlChildren.begin(); it != m_ControlChildren.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; int CX; int CY; int CW; @@ -194,9 +199,9 @@ void GUICollectionBox::Resize(int Width, int Height) { m_Height = Height; // Go through all my children moving them - std::vector::iterator it; + std::vector::iterator it; for (it = m_ControlChildren.begin(); it != m_ControlChildren.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; int CX, CY, CW, CH; int Anchor = C->GetAnchor(); @@ -208,32 +213,44 @@ void GUICollectionBox::Resize(int Width, int Height) { int H = CH; // Attached to Right and/or Bottom edges - if ((Anchor & GUIControl::Anchor_Right) && !(Anchor & GUIControl::Anchor_Left)) { DX = m_Width - (OldWidth - (CX - m_X)) + m_X; } - if ((Anchor & GUIControl::Anchor_Bottom) && !(Anchor & GUIControl::Anchor_Top)) { DY = m_Height - (OldHeight - (CY - m_Y)) + m_Y; } + if ((Anchor & GUIControl::Anchor_Right) && !(Anchor & GUIControl::Anchor_Left)) { + DX = m_Width - (OldWidth - (CX - m_X)) + m_X; + } + if ((Anchor & GUIControl::Anchor_Bottom) && !(Anchor & GUIControl::Anchor_Top)) { + DY = m_Height - (OldHeight - (CY - m_Y)) + m_Y; + } - if (DX != CX || DY != CY) { C->Move(DX, DY); } + if (DX != CX || DY != CY) { + C->Move(DX, DY); + } CX -= m_X; CY -= m_Y; // Attached to opposing edges - if (Anchor & GUIControl::Anchor_Left && Anchor & GUIControl::Anchor_Right) { W = (m_Width - (OldWidth - (CX + CW))) - CX; } - if (Anchor & GUIControl::Anchor_Top && Anchor & GUIControl::Anchor_Bottom) { H = (m_Height - (OldHeight - (CY + CH))) - CY; } + if (Anchor & GUIControl::Anchor_Left && Anchor & GUIControl::Anchor_Right) { + W = (m_Width - (OldWidth - (CX + CW))) - CX; + } + if (Anchor & GUIControl::Anchor_Top && Anchor & GUIControl::Anchor_Bottom) { + H = (m_Height - (OldHeight - (CY + CH))) - CY; + } - if (W != CW || H != CH) { C->Resize(W, H); } + if (W != CW || H != CH) { + C->Resize(W, H); + } } BuildBitmap(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICollectionBox::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUICollectionBox::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICollectionBox::SetDrawImage(GUIBitmap *Bitmap) { +void GUICollectionBox::SetDrawImage(GUIBitmap* Bitmap) { // Free any old bitmap delete m_DrawBitmap; @@ -268,7 +285,7 @@ void GUICollectionBox::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUICollectionBox::ApplyProperties(GUIProperties *Props) { +void GUICollectionBox::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); // Get the values @@ -281,4 +298,4 @@ void GUICollectionBox::ApplyProperties(GUIProperties *Props) { m_DrawType = Image; } m_Properties.GetValue("DrawColor", &m_DrawColor); -} \ No newline at end of file +} diff --git a/Source/GUI/GUICollectionBox.h b/Source/GUI/GUICollectionBox.h index 25a2c1bd5..184711f14 100644 --- a/Source/GUI/GUICollectionBox.h +++ b/Source/GUI/GUICollectionBox.h @@ -3,262 +3,235 @@ namespace RTE { -/// -/// A collection box control class that contains child controls. -/// -class GUICollectionBox : public GUIControl, public GUIPanel { + /// + /// A collection box control class that contains child controls. + /// + class GUICollectionBox : public GUIControl, public GUIPanel { + + public: + // CollectionBox Notifications + enum { + Clicked = 0, + MouseMove // Mouse moved over the panel + } Notification; + + // Drawing type + enum { + Color, + Image, + Panel + } DrawType; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUICollectionBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUICollectionBox object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUICollectionBox(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~GUICollectionBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up this before deletion from memory. + // Arguments: None. + + ~GUICollectionBox() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and frees this' allocated data + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. -public: + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; - // CollectionBox Notifications - enum { - Clicked = 0, - MouseMove // Mouse moved over the panel - } Notification; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "COLLECTIONBOX"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDrawImage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the drawing image bitmap to draw + // Arguments: Bitmap, ownership IS transferred! + + void SetDrawImage(GUIBitmap* Bitmap); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDrawImage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the drawing image bitmap that is being drawn + // Arguments: Bitmap, ownership IS NOT transferred! + + GUIBitmap* GetDrawImage() { return m_DrawBitmap; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDrawBackground + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether to draw the background. + // Arguments: Draw. + + void SetDrawBackground(bool DrawBack); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDrawType + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the drawing type. + // Arguments: Type. + + void SetDrawType(int Type); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDrawType + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current drawing type. + // Arguments: None. + // Returns: Type. + + int GetDrawType() const { return m_DrawType; } - // Drawing type - enum { - Color, - Image, - Panel - } DrawType; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDrawColor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the drawing color. + // Arguments: Color. + + void SetDrawColor(unsigned long Color); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDrawColor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the drawing color. + // Returns: Color. + + unsigned long GetDrawColor() const { return m_DrawColor; } -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUICollectionBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUICollectionBox object in -// system memory. -// Arguments: GUIManager, GUIControlManager. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; - GUICollectionBox(GUIManager *Manager, GUIControlManager *ControlManager); + private: + GUIBitmap* m_Background; + + bool m_DrawBackground; + int m_DrawType; + unsigned long m_DrawColor; + GUIBitmap* m_DrawBitmap; - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~GUICollectionBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up this before deletion from memory. -// Arguments: None. - - ~GUICollectionBox() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and frees this' allocated data -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "COLLECTIONBOX"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDrawImage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the drawing image bitmap to draw -// Arguments: Bitmap, ownership IS transferred! - - void SetDrawImage(GUIBitmap *Bitmap); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDrawImage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the drawing image bitmap that is being drawn -// Arguments: Bitmap, ownership IS NOT transferred! - - GUIBitmap * GetDrawImage() { return m_DrawBitmap; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDrawBackground -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether to draw the background. -// Arguments: Draw. - - void SetDrawBackground(bool DrawBack); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDrawType -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the drawing type. -// Arguments: Type. - - void SetDrawType(int Type); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDrawType -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current drawing type. -// Arguments: None. -// Returns: Type. - - int GetDrawType() const { return m_DrawType; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDrawColor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the drawing color. -// Arguments: Color. - - void SetDrawColor(unsigned long Color); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDrawColor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the drawing color. -// Returns: Color. - - unsigned long GetDrawColor() const { return m_DrawColor; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - - -private: - - GUIBitmap *m_Background; - - bool m_DrawBackground; - int m_DrawType; - unsigned long m_DrawColor; - GUIBitmap *m_DrawBitmap; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the button bitmap to draw. -// Arguments: None. - - void BuildBitmap(); -}; -}; -#endif \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the button bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIComboBox.cpp b/Source/GUI/GUIComboBox.cpp index 8f3e89813..02ed8f255 100644 --- a/Source/GUI/GUIComboBox.cpp +++ b/Source/GUI/GUIComboBox.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIComboBox::GUIComboBox(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUIComboBox::GUIComboBox(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "COMBOBOX"; m_ControlManager = ControlManager; m_DrawBitmap = nullptr; @@ -26,7 +27,7 @@ GUIComboBox::GUIComboBox(GUIManager *Manager, GUIControlManager *ControlManager) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIComboBox::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -43,8 +44,12 @@ void GUIComboBox::Create(const std::string &Name, int X, int Y, int Width, int H m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the textbox isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -71,7 +76,7 @@ void GUIComboBox::Create(const std::string &Name, int X, int Y, int Width, int H ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::Create(GUIProperties *Props) { +void GUIComboBox::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -101,7 +106,6 @@ void GUIComboBox::Create(GUIProperties *Props) { m_ListPanel->EnableScrollbars(false, true); m_ListPanel->SetMouseScrolling(true); - // Create the button m_Button->Create(m_Width - 17, 0, 17, m_Height); m_Button->SetSignalTarget(this); @@ -163,7 +167,7 @@ void GUIComboBox::Activate() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::ChangeSkin(GUISkin *Skin) { +void GUIComboBox::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Free any old bitmap @@ -182,26 +186,30 @@ void GUIComboBox::ChangeSkin(GUISkin *Skin) { // Setup the skin in the panels too m_TextPanel->ChangeSkin(Skin); - if (m_CreatedList) { m_ListPanel->ChangeSkin(Skin); } + if (m_CreatedList) { + m_ListPanel->ChangeSkin(Skin); + } m_Button->ChangeSkin(Skin); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::Draw(GUIScreen *Screen) { +void GUIComboBox::Draw(GUIScreen* Screen) { // Draw the background m_DrawBitmap->Draw(Screen->GetBitmap(), m_X, m_Y, nullptr); // If selected item has a bitmap AND no text to show, just show the bitmap as the selected thing - if (m_ListPanel->GetSelected() && m_ListPanel->GetSelected()->m_Name.empty() && m_ListPanel->GetSelected()->m_pBitmap) { m_ListPanel->GetSelected()->m_pBitmap->DrawTrans(Screen->GetBitmap(), m_X + 4, m_Y + 4, nullptr); } + if (m_ListPanel->GetSelected() && m_ListPanel->GetSelected()->m_Name.empty() && m_ListPanel->GetSelected()->m_pBitmap) { + m_ListPanel->GetSelected()->m_pBitmap->DrawTrans(Screen->GetBitmap(), m_X + 4, m_Y + 4, nullptr); + } GUIPanel::Draw(Screen); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIComboBox::GetPanel() { +GUIPanel* GUIComboBox::GetPanel() { return this; } @@ -227,7 +235,9 @@ void GUIComboBox::ReceiveSignal(GUIPanel* Source, int Code, int Data) { m_ListPanel->ChangeZPosition(TopMost); // Save the current selection - if (m_ListPanel->GetSelectedIndex() >= 0 && m_ListPanel->GetSelectedIndex() < m_ListPanel->GetItemList()->size()) { m_OldSelection = m_ListPanel->GetSelectedIndex(); } + if (m_ListPanel->GetSelectedIndex() >= 0 && m_ListPanel->GetSelectedIndex() < m_ListPanel->GetItemList()->size()) { + m_OldSelection = m_ListPanel->GetSelectedIndex(); + } AddEvent(GUIEvent::Notification, Dropped, 0); } @@ -247,7 +257,9 @@ void GUIComboBox::ReceiveSignal(GUIPanel* Source, int Code, int Data) { m_ListPanel->ChangeZPosition(TopMost); // Save the current selection - if (m_ListPanel->GetSelectedIndex() >= 0 && m_ListPanel->GetSelectedIndex() < m_ListPanel->GetItemList()->size()) { m_OldSelection = m_ListPanel->GetSelectedIndex(); } + if (m_ListPanel->GetSelectedIndex() >= 0 && m_ListPanel->GetSelectedIndex() < m_ListPanel->GetItemList()->size()) { + m_OldSelection = m_ListPanel->GetSelectedIndex(); + } AddEvent(GUIEvent::Notification, Dropped, 0); } @@ -297,7 +309,9 @@ void GUIComboBox::ReceiveSignal(GUIPanel* Source, int Code, int Data) { if (m_DropDownStyle == DropDownList) { // Set the text to the item in the list panel - if (const GUIListPanel::Item* Item = m_ListPanel->GetSelected()) { m_TextPanel->SetText(Item->m_Name); } + if (const GUIListPanel::Item* Item = m_ListPanel->GetSelected()) { + m_TextPanel->SetText(Item->m_Name); + } } } } @@ -316,7 +330,7 @@ void GUIComboBox::EndUpdate() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::AddItem(const std::string &Name, const std::string &ExtraText, GUIBitmap *pBitmap, const Entity *pEntity) { +void GUIComboBox::AddItem(const std::string& Name, const std::string& ExtraText, GUIBitmap* pBitmap, const Entity* pEntity) { m_ListPanel->AddItem(Name, ExtraText, pBitmap, pEntity); } @@ -359,7 +373,7 @@ void GUIComboBox::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIComboBox::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -369,7 +383,7 @@ void GUIComboBox::DeleteItem(int Index) { m_ListPanel->DeleteItem(Index); // Update the selection - const GUIListPanel::Item *Item = m_ListPanel->GetSelected(); + const GUIListPanel::Item* Item = m_ListPanel->GetSelected(); if (!Item) { m_ListPanel->SetSelectedIndex(0); Item = m_ListPanel->GetSelected(); @@ -401,7 +415,9 @@ void GUIComboBox::SetSelectedIndex(int Index) { m_OldSelection = Index; // Set the text to the item in the list panel - if (const GUIListPanel::Item *Item = m_ListPanel->GetSelected()) { m_TextPanel->SetText(Item->m_Name); } + if (const GUIListPanel::Item* Item = m_ListPanel->GetSelected()) { + m_TextPanel->SetText(Item->m_Name); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -411,7 +427,7 @@ bool GUIComboBox::RollbackSelection() { if (m_OldSelection >= 0 && m_OldSelection < m_ListPanel->GetItemList()->size() && m_OldSelection != m_ListPanel->GetSelectedIndex()) { m_ListPanel->SetSelectedIndex(m_OldSelection); // Set the text to the item in the list panel - if (const GUIListPanel::Item *Item = m_ListPanel->GetSelected()) { + if (const GUIListPanel::Item* Item = m_ListPanel->GetSelected()) { m_TextPanel->SetText(Item->m_Name); return true; } @@ -422,7 +438,7 @@ bool GUIComboBox::RollbackSelection() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIListPanel::Item * GUIComboBox::GetItem(int Index) { +GUIListPanel::Item* GUIComboBox::GetItem(int Index) { return m_ListPanel->GetItem(Index); } @@ -450,7 +466,9 @@ void GUIComboBox::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIComboBox::SetDropDownStyle(int Style) { - if (Style == DropDown || Style == DropDownList) { m_DropDownStyle = Style; } + if (Style == DropDown || Style == DropDownList) { + m_DropDownStyle = Style; + } m_TextPanel->SetLocked(m_DropDownStyle == DropDownList); } @@ -465,7 +483,9 @@ int GUIComboBox::GetDropDownStyle() const { void GUIComboBox::SetVisible(bool Visible) { _SetVisible(Visible); - if (!Visible && m_ListPanel) { m_ListPanel->_SetVisible(false); } + if (!Visible && m_ListPanel) { + m_ListPanel->_SetVisible(false); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -478,7 +498,9 @@ bool GUIComboBox::GetVisible() { void GUIComboBox::SetEnabled(bool Enabled) { _SetEnabled(Enabled); - if (m_ListPanel) { m_ListPanel->_SetEnabled(Enabled); } + if (m_ListPanel) { + m_ListPanel->_SetEnabled(Enabled); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -501,13 +523,15 @@ std::string GUIComboBox::GetText() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::SetText(const std::string &Text) { - if (m_DropDownStyle == DropDown && m_TextPanel) { m_TextPanel->SetText(Text); } +void GUIComboBox::SetText(const std::string& Text) { + if (m_DropDownStyle == DropDown && m_TextPanel) { + m_TextPanel->SetText(Text); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBox::ApplyProperties(GUIProperties *Props) { +void GUIComboBox::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); m_Properties.GetValue("Dropheight", &m_DropHeight); @@ -528,14 +552,15 @@ void GUIComboBox::ApplyProperties(GUIProperties *Props) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIComboBoxButton::GUIComboBoxButton(GUIManager *Manager) : GUIPanel(Manager) { +GUIComboBoxButton::GUIComboBoxButton(GUIManager* Manager) : + GUIPanel(Manager) { m_DrawBitmap = nullptr; m_Pushed = false; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBoxButton::ChangeSkin(GUISkin *Skin) { +void GUIComboBoxButton::ChangeSkin(GUISkin* Skin) { // Free any old bitmap if (m_DrawBitmap) { m_DrawBitmap->Destroy(); @@ -554,7 +579,7 @@ void GUIComboBoxButton::ChangeSkin(GUISkin *Skin) { // Draw the arrow std::string Filename; Skin->GetValue("ComboBox_Arrow", "Filename", &Filename); - GUIBitmap *Arrow = Skin->CreateBitmap(Filename); + GUIBitmap* Arrow = Skin->CreateBitmap(Filename); if (!Arrow) { return; } @@ -576,7 +601,7 @@ void GUIComboBoxButton::ChangeSkin(GUISkin *Skin) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIComboBoxButton::Draw(GUIScreen *Screen) { +void GUIComboBoxButton::Draw(GUIScreen* Screen) { GUIRect Rect; SetRect(&Rect, 0, m_Pushed ? m_Height : 0, m_Width, m_Pushed ? m_Height * 2 : m_Height); @@ -622,4 +647,4 @@ void GUIComboBoxButton::Destroy() { delete m_DrawBitmap; m_DrawBitmap = nullptr; } -} \ No newline at end of file +} diff --git a/Source/GUI/GUIComboBox.h b/Source/GUI/GUIComboBox.h index 71013ae87..9b8dba087 100644 --- a/Source/GUI/GUIComboBox.h +++ b/Source/GUI/GUIComboBox.h @@ -6,492 +6,441 @@ namespace RTE { -class GUIComboBoxButton; - -/// -/// A ComboBox control class. -/// -class GUIComboBox : public GUIControl, public GUIPanel { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - // Notifications - enum { - Dropped, // When listpanel has dropped - Closed, // When listpanel has closed - } Notifications; - - // Combo Style - enum { - DropDown, - DropDownList, - } DropDownStyles; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIComboBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIComboBox object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUIComboBox(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Activate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control is activated and ready for use. -// Arguments: None. - - void Activate() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetListPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the ListPanel component of the control. -// Arguments: None. -// Returns: The ListPanel component of this ComboBox. - - GUIListPanel * GetListPanel() { return m_ListPanel; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "COMBOBOX"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReceiveSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when receiving a signal. -// Arguments: Signal source, Signal code, Signal data. - - void ReceiveSignal(GUIPanel *Source, int Code, int Data) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BeginUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Locks the control from updating every time a new item is added. -// Arguments: None. - - void BeginUpdate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EndUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: UnLocks the control from updating every time a new item is added. -// Will automatically update the control. -// Arguments: None. - - void EndUpdate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Add an item to the list. -// Arguments: Name, Extra text, bitmap to show in the list, extra entity data - - void AddItem(const std::string &Name, const std::string &ExtraText = "", GUIBitmap *pBitmap = nullptr, const Entity *pEntity = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DeleteItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Delete an item from the list. -// Arguments: Item Index. - - void DeleteItem(int Index); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the list. -// Arguments: None. - - void ClearList(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get the item count. -// Arguments: None. - - int GetCount(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelectedIndex -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get the index of the selected item. -// Arguments: None. - - int GetSelectedIndex(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOldSelectionIndex -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get the index of the previously selected item before the selection is -// made. -// Arguments: None. - - int GetOldSelectionIndex() const { return m_OldSelection; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSelectedIndex -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the index of the selected item. -// Arguments: None. - - void SetSelectedIndex(int Index); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RollbackSelection -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Rolls back the selection to the previous selected item. -// Arguments: None. -// Returns: Whether the rollback worked and was performed. - - bool RollbackSelection(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the Item structure at the index. -// Arguments: Index. -// Returns: Pointer to the item structure. 0 if the index was invalid. - - GUIListPanel::Item * GetItem(int Index); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelectedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the Item structure at the currently selected index. -// Arguments: Index. -// Returns: Pointer to the item structure. 0 if nothing valid is selected. - - GUIListPanel::Item * GetSelectedItem() { return GetItem(GetSelectedIndex()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDropHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the drop height of the list. -// Arguments: Height. - - void SetDropHeight(int Drop); + class GUIComboBoxButton; /// - /// Gets the drop height of the list. + /// A ComboBox control class. /// - /// The drop height of the list. - int GetDropHeight() const { return m_DropHeight; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDropDownStyle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the drop down style of the combo box. -// Arguments: Style. - - void SetDropDownStyle(int Style); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDropDownStyle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the drop down style of the combo box. -// Arguments: None. - - int GetDropDownStyle() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the visibility of the control. -// Arguments: Visible. - - void SetVisible(bool Visible) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the visibility of the control. -// Arguments: None. - - bool GetVisible() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the enabled state of the control. -// Arguments: Enabled. - - void SetEnabled(bool Enabled) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the enabled state of the control. -// Arguments: None. - - bool GetEnabled() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets text (only if style is DropDown). -// Arguments: None. -// Returns: Text. Returns empty string is style is not DropDown. - - std::string GetText(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets text (only if style is DropDown). -// Arguments: Text. + class GUIComboBox : public GUIControl, public GUIPanel { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Notifications + enum { + Dropped, // When listpanel has dropped + Closed, // When listpanel has closed + } Notifications; + + // Combo Style + enum { + DropDown, + DropDownList, + } DropDownStyles; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIComboBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIComboBox object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUIComboBox(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Activate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control is activated and ready for use. + // Arguments: None. + + void Activate() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetListPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the ListPanel component of the control. + // Arguments: None. + // Returns: The ListPanel component of this ComboBox. + + GUIListPanel* GetListPanel() { return m_ListPanel; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "COMBOBOX"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReceiveSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when receiving a signal. + // Arguments: Signal source, Signal code, Signal data. + + void ReceiveSignal(GUIPanel* Source, int Code, int Data) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BeginUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Locks the control from updating every time a new item is added. + // Arguments: None. + + void BeginUpdate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EndUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: UnLocks the control from updating every time a new item is added. + // Will automatically update the control. + // Arguments: None. + + void EndUpdate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Add an item to the list. + // Arguments: Name, Extra text, bitmap to show in the list, extra entity data + + void AddItem(const std::string& Name, const std::string& ExtraText = "", GUIBitmap* pBitmap = nullptr, const Entity* pEntity = nullptr); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DeleteItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Delete an item from the list. + // Arguments: Item Index. + + void DeleteItem(int Index); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the list. + // Arguments: None. + + void ClearList(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get the item count. + // Arguments: None. + + int GetCount(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelectedIndex + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get the index of the selected item. + // Arguments: None. + + int GetSelectedIndex(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOldSelectionIndex + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get the index of the previously selected item before the selection is + // made. + // Arguments: None. + + int GetOldSelectionIndex() const { return m_OldSelection; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSelectedIndex + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the index of the selected item. + // Arguments: None. + + void SetSelectedIndex(int Index); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RollbackSelection + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Rolls back the selection to the previous selected item. + // Arguments: None. + // Returns: Whether the rollback worked and was performed. + + bool RollbackSelection(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the Item structure at the index. + // Arguments: Index. + // Returns: Pointer to the item structure. 0 if the index was invalid. + + GUIListPanel::Item* GetItem(int Index); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelectedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the Item structure at the currently selected index. + // Arguments: Index. + // Returns: Pointer to the item structure. 0 if nothing valid is selected. + + GUIListPanel::Item* GetSelectedItem() { return GetItem(GetSelectedIndex()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDropHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the drop height of the list. + // Arguments: Height. + + void SetDropHeight(int Drop); + + /// + /// Gets the drop height of the list. + /// + /// The drop height of the list. + int GetDropHeight() const { return m_DropHeight; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDropDownStyle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the drop down style of the combo box. + // Arguments: Style. + + void SetDropDownStyle(int Style); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDropDownStyle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the drop down style of the combo box. + // Arguments: None. + + int GetDropDownStyle() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the visibility of the control. + // Arguments: Visible. + + void SetVisible(bool Visible) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the visibility of the control. + // Arguments: None. + + bool GetVisible() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the enabled state of the control. + // Arguments: Enabled. + + void SetEnabled(bool Enabled) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the enabled state of the control. + // Arguments: None. + + bool GetEnabled() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets text (only if style is DropDown). + // Arguments: None. + // Returns: Text. Returns empty string is style is not DropDown. + + std::string GetText(); - void SetText(const std::string &Text); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets text (only if style is DropDown). + // Arguments: Text. + + void SetText(const std::string& Text); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDropped + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether the list is currently dropped down or not. + // Arguments: None. + // Returns: Whether this is currently dropped down and showing the list. + + bool IsDropped() { return m_ListPanel->_GetVisible(); } - void ApplyProperties(GUIProperties *Props) override; + private: + GUIBitmap* m_DrawBitmap; + int m_OldSelection; + bool m_CreatedList; + + int m_DropHeight; + int m_DropDownStyle; + GUITextPanel* m_TextPanel; + GUIListPanel* m_ListPanel; + GUIComboBoxButton* m_Button; + }; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDropped -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether the list is currently dropped down or not. -// Arguments: None. -// Returns: Whether this is currently dropped down and showing the list. - - bool IsDropped() { return m_ListPanel->_GetVisible(); } - -private: - - GUIBitmap *m_DrawBitmap; - int m_OldSelection; - bool m_CreatedList; - - int m_DropHeight; - int m_DropDownStyle; - - GUITextPanel *m_TextPanel; - GUIListPanel *m_ListPanel; - GUIComboBoxButton *m_Button; -}; - - -/// -/// A ComboBoxButton control class. -/// -class GUIComboBoxButton : public GUIPanel { - -public: - - // Signals - enum { - Clicked - } Signals; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIComboBoxButton -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIComboBoxButton object in -// system memory. -// Arguments: GUIManager. - - explicit GUIComboBoxButton(GUIManager *Manager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the panel. -// Arguments: Position, Size. - - void Create(int X, int Y, int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys the button. -// Arguments: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPushed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the pushed state of the button. -// Arguments: Pushed. - - void SetPushed(bool Pushed); - -private: - - GUIBitmap *m_DrawBitmap; - bool m_Pushed; -}; -}; -#endif \ No newline at end of file + /// + /// A ComboBoxButton control class. + /// + class GUIComboBoxButton : public GUIPanel { + + public: + // Signals + enum { + Clicked + } Signals; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIComboBoxButton + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIComboBoxButton object in + // system memory. + // Arguments: GUIManager. + + explicit GUIComboBoxButton(GUIManager* Manager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the panel. + // Arguments: Position, Size. + + void Create(int X, int Y, int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys the button. + // Arguments: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPushed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the pushed state of the button. + // Arguments: Pushed. + + void SetPushed(bool Pushed); + + private: + GUIBitmap* m_DrawBitmap; + bool m_Pushed; + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIControl.cpp b/Source/GUI/GUIControl.cpp index 1776cf692..59eec6899 100644 --- a/Source/GUI/GUIControl.cpp +++ b/Source/GUI/GUIControl.cpp @@ -15,7 +15,7 @@ GUIControl::GUIControl() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControl::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIControl::Create(const std::string& Name, int X, int Y, int Width, int Height) { m_Properties.Clear(); m_Properties.AddVariable("Name", Name); m_Properties.AddVariable("Anchor", "Left, Top"); @@ -24,7 +24,7 @@ void GUIControl::Create(const std::string &Name, int X, int Y, int Width, int He ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControl::Create(GUIProperties *Props) { +void GUIControl::Create(GUIProperties* Props) { assert(Props); // Add the default variables @@ -45,7 +45,7 @@ void GUIControl::Activate() {} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControl::ChangeSkin(GUISkin *Skin) { +void GUIControl::ChangeSkin(GUISkin* Skin) { m_Skin = Skin; } @@ -81,17 +81,19 @@ std::string GUIControl::GetID() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIControl::GetPanel() { +GUIPanel* GUIControl::GetPanel() { return nullptr; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControl::AddChild(GUIControl *Control) { +void GUIControl::AddChild(GUIControl* Control) { assert(Control); // Remove the control from any previous parent - if (Control->GetParent()) { Control->GetParent()->GUIControl::RemoveChild(Control->GetName()); } + if (Control->GetParent()) { + Control->GetParent()->GUIControl::RemoveChild(Control->GetName()); + } Control->m_ControlParent = this; m_ControlChildren.push_back(Control); @@ -99,13 +101,13 @@ void GUIControl::AddChild(GUIControl *Control) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -std::vector * GUIControl::GetChildren() { +std::vector* GUIControl::GetChildren() { return &m_ControlChildren; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIControl::Save(GUIWriter *W) { +bool GUIControl::Save(GUIWriter* W) { std::string OutString = ""; std::string Name; @@ -134,8 +136,10 @@ bool GUIControl::Save(GUIWriter *W) { OutString += "\n"; // Get the main panel and write its location - GUIPanel *Pan = GetPanel(); - if (Pan) { OutString.append(Pan->ToString()); } + GUIPanel* Pan = GetPanel(); + if (Pan) { + OutString.append(Pan->ToString()); + } // Write out the properties OutString.append(m_Properties.ToString()); @@ -156,12 +160,20 @@ void GUIControl::Resize(int Width, int Height) {} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControl::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIControl::GetControlRect(int* X, int* Y, int* Width, int* Height) { // Zero the values for controls that don't override this - if (X) { *X = 0; } - if (Y) { *Y = 0; } - if (Width) { *Width = 0; } - if (Height) { *Height = 0; } + if (X) { + *X = 0; + } + if (Y) { + *Y = 0; + } + if (Width) { + *Width = 0; + } + if (Height) { + *Height = 0; + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -173,15 +185,27 @@ int GUIControl::GetAnchor() { int Count = m_Properties.GetValue("Anchor", Value, 4); for (int i = 0; i < Count; i++) { - if (stricmp(Value[i].c_str(), "left") == 0) { Anchor |= Anchor_Left; } - if (stricmp(Value[i].c_str(), "top") == 0) { Anchor |= Anchor_Top; } - if (stricmp(Value[i].c_str(), "right") == 0) { Anchor |= Anchor_Right; } - if (stricmp(Value[i].c_str(), "bottom") == 0) { Anchor |= Anchor_Bottom; } + if (stricmp(Value[i].c_str(), "left") == 0) { + Anchor |= Anchor_Left; + } + if (stricmp(Value[i].c_str(), "top") == 0) { + Anchor |= Anchor_Top; + } + if (stricmp(Value[i].c_str(), "right") == 0) { + Anchor |= Anchor_Right; + } + if (stricmp(Value[i].c_str(), "bottom") == 0) { + Anchor |= Anchor_Bottom; + } } // The anchor cannot have both sides missing, so we default to Left, Top is that is the case - if (!(Anchor & Anchor_Left) && !(Anchor & Anchor_Right)) { Anchor |= Anchor_Left; } - if (!(Anchor & Anchor_Top) && !(Anchor & Anchor_Bottom)) { Anchor |= Anchor_Top; } + if (!(Anchor & Anchor_Left) && !(Anchor & Anchor_Right)) { + Anchor |= Anchor_Left; + } + if (!(Anchor & Anchor_Top) && !(Anchor & Anchor_Bottom)) { + Anchor |= Anchor_Top; + } return Anchor; } @@ -194,15 +218,17 @@ void GUIControl::StoreProperties() {} void GUIControl::SetVisible(bool Visible) { // Default method is the grab the main panel and directly set its state. Controls that use multiple panels on the same layer will need to override this function - GUIPanel *Panel = GetPanel(); - if (Panel) { Panel->_SetVisible(Visible); } + GUIPanel* Panel = GetPanel(); + if (Panel) { + Panel->_SetVisible(Visible); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIControl::GetVisible() { // See SetVisible() comment - GUIPanel *Panel = GetPanel(); + GUIPanel* Panel = GetPanel(); if (Panel) { return Panel->_GetVisible(); } @@ -213,35 +239,39 @@ bool GUIControl::GetVisible() { void GUIControl::SetEnabled(bool Enabled) { // See SetVisible() comment - GUIPanel *Panel = GetPanel(); - if (Panel) { Panel->_SetEnabled(Enabled); } + GUIPanel* Panel = GetPanel(); + if (Panel) { + Panel->_SetEnabled(Enabled); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIControl::GetEnabled() { // See SetVisible() comment - GUIPanel *Panel = GetPanel(); - if (Panel) { return Panel->_GetEnabled(); } + GUIPanel* Panel = GetPanel(); + if (Panel) { + return Panel->_GetEnabled(); + } return false; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIControl * GUIControl::GetParent() { +GUIControl* GUIControl::GetParent() { return m_ControlParent; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIProperties * GUIControl::GetProperties() { +GUIProperties* GUIControl::GetProperties() { return &m_Properties; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControl::ApplyProperties(GUIProperties *Props) { +void GUIControl::ApplyProperties(GUIProperties* Props) { assert(Props); m_Properties.Update(Props); @@ -258,7 +288,7 @@ void GUIControl::ApplyProperties(GUIProperties *Props) { Props->GetValue("Visible", &Visible); // Adjust position from parent - GUIPanel *P = GetPanel(); + GUIPanel* P = GetPanel(); if (P && P->GetParentPanel()) { int px; int py; @@ -286,10 +316,10 @@ bool GUIControl::IsContainer() { void GUIControl::RemoveChild(const std::string Name) { // Note: We do NOT free the children because they are still linked in through their panels. This merely removes the control from the list. // This will cause a small memory leak, but this is only designed for the GUI Editor and is a bit of a hack. - std::vector::iterator it; + std::vector::iterator it; for (it = m_ControlChildren.begin(); it != m_ControlChildren.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; if (C && C->GetName().compare(Name) == 0) { m_ControlChildren.erase(it); break; @@ -302,11 +332,13 @@ void GUIControl::RemoveChild(const std::string Name) { void GUIControl::RemoveChildren() { // Note: We do NOT free the children because they are still linked in through their panels. This merely removes the control from the list. // This will cause a small memory leak, but this is only designed for the GUI Editor and is a bit of a hack. - std::vector::iterator it; + std::vector::iterator it; for (it = m_ControlChildren.begin(); it != m_ControlChildren.end(); it++) { - GUIControl *C = *it; - if (C) { m_ControlManager->RemoveControl(C->GetName(), false); } + GUIControl* C = *it; + if (C) { + m_ControlManager->RemoveControl(C->GetName(), false); + } } m_ControlChildren.clear(); diff --git a/Source/GUI/GUIControl.h b/Source/GUI/GUIControl.h index 084ab2fc3..616942429 100644 --- a/Source/GUI/GUIControl.h +++ b/Source/GUI/GUIControl.h @@ -5,315 +5,283 @@ namespace RTE { -class GUIControlManager; + class GUIControlManager; + + /// + /// A base class inherited by all controls. + /// + class GUIControl { + + public: + // Anchor points + enum { + Anchor_Left = 0x01, + Anchor_Top = 0x02, + Anchor_Right = 0x04, + Anchor_Bottom = 0x08 + } Anchor; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIControl object in + // system memory. + // Arguments: None. + + GUIControl(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position, Size + + virtual void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + virtual void Create(GUIProperties* Props); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + virtual void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Activate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control is activated and ready for use. + // Arguments: None. + + virtual void Activate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + virtual void ChangeSkin(GUISkin* Skin); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddEvent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Add a new event to the queue. + // Arguments: Type, Message, Data. + + void AddEvent(int Type, int Msg, int Data); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control's name. + // Arguments: None. + + std::string GetName(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetToolTip + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the control's tooltip string. + // Arguments: The new ToolTip for this. + + void SetToolTip(const std::string& tip) { m_Properties.SetValue("ToolTip", tip); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetToolTip + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control's tooltip string. + // Arguments: None. + + std::string GetToolTip(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + std::string GetID() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAnchor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the anchor flags. + // Arguments: None. + + int GetAnchor(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddChild + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a child to this control + // Arguments: Control. -/// -/// A base class inherited by all controls. -/// -class GUIControl { + void AddChild(GUIControl* Control); -public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetChildren + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the children lst + // Arguments: None. - // Anchor points - enum { - Anchor_Left = 0x01, - Anchor_Top = 0x02, - Anchor_Right = 0x04, - Anchor_Bottom = 0x08 - } Anchor; + std::vector* GetChildren(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIControl object in -// system memory. -// Arguments: None. + virtual GUIPanel* GetPanel(); - GUIControl(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the control properties. + // Arguments: Writer. + // Returns: True if sucessful + bool Save(GUIWriter* W); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position, Size + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. - virtual void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1); + virtual void StoreProperties(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. + virtual void Move(int X, int Y); - virtual void Create(GUIProperties *Props); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + virtual void Resize(int Width, int Height); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. - virtual void Destroy(); + virtual void GetControlRect(int* X, int* Y, int* Width, int* Height); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: SetVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the visibility of the control. + // Arguments: Visible. + + virtual void SetVisible(bool Visible); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Activate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control is activated and ready for use. -// Arguments: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: GetVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the visibility of the control. + // Arguments: None. + + virtual bool GetVisible(); - virtual void Activate(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: SetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the enabled state of the control. + // Arguments: Enabled. + + virtual void SetEnabled(bool Enabled); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: GetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the enabled state of the control. + // Arguments: None. + + virtual bool GetEnabled(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetParent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the parent of this control. + // Arguments: None. + + GUIControl* GetParent(); - virtual void ChangeSkin(GUISkin *Skin); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control properties. + // Arguments: None. + + GUIProperties* GetProperties(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + virtual void ApplyProperties(GUIProperties* Props); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddEvent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Add a new event to the queue. -// Arguments: Type, Message, Data. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the IsContainer value. + // Arguments: None. + + bool IsContainer(); - void AddEvent(int Type, int Msg, int Data); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveChild + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a child based on name. + // Arguments: Child Name. + + void RemoveChild(const std::string Name); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveChildren + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes all the children. + // Arguments: None. + + void RemoveChildren(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control's name. -// Arguments: None. + protected: + GUISkin* m_Skin; + int m_SkinPreset; + GUIProperties m_Properties; + GUIControl* m_ControlParent; + std::vector m_ControlChildren; - std::string GetName(); + std::string m_ControlID; + bool m_IsContainer; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetToolTip -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the control's tooltip string. -// Arguments: The new ToolTip for this. + // For the GUI editor + int m_MinWidth; + int m_MinHeight; + int m_DefWidth; + int m_DefHeight; - void SetToolTip(const std::string &tip) { m_Properties.SetValue("ToolTip", tip); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetToolTip -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control's tooltip string. -// Arguments: None. - - std::string GetToolTip(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - std::string GetID() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAnchor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the anchor flags. -// Arguments: None. - - int GetAnchor(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddChild -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a child to this control -// Arguments: Control. - - void AddChild(GUIControl *Control); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetChildren -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the children lst -// Arguments: None. - - std::vector * GetChildren(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - virtual GUIPanel * GetPanel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the control properties. -// Arguments: Writer. -// Returns: True if sucessful - - bool Save(GUIWriter *W); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - virtual void StoreProperties(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - virtual void Move(int X, int Y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - virtual void Resize(int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - virtual void GetControlRect(int *X, int *Y, int *Width, int *Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: SetVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the visibility of the control. -// Arguments: Visible. - - virtual void SetVisible(bool Visible); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: GetVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the visibility of the control. -// Arguments: None. - - virtual bool GetVisible(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: SetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the enabled state of the control. -// Arguments: Enabled. - - virtual void SetEnabled(bool Enabled); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: GetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the enabled state of the control. -// Arguments: None. - - virtual bool GetEnabled(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetParent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the parent of this control. -// Arguments: None. - - GUIControl * GetParent(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control properties. -// Arguments: None. - - GUIProperties * GetProperties(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - virtual void ApplyProperties(GUIProperties *Props); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the IsContainer value. -// Arguments: None. - - bool IsContainer(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveChild -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a child based on name. -// Arguments: Child Name. - - void RemoveChild(const std::string Name); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveChildren -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes all the children. -// Arguments: None. - - void RemoveChildren(); - -protected: - - GUISkin *m_Skin; - int m_SkinPreset; - GUIProperties m_Properties; - GUIControl *m_ControlParent; - std::vector m_ControlChildren; - - std::string m_ControlID; - - bool m_IsContainer; - - // For the GUI editor - int m_MinWidth; - int m_MinHeight; - int m_DefWidth; - int m_DefHeight; - - GUIControlManager *m_ControlManager; -}; -}; -#endif \ No newline at end of file + GUIControlManager* m_ControlManager; + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIControlFactory.cpp b/Source/GUI/GUIControlFactory.cpp index 9e9328921..81345990e 100644 --- a/Source/GUI/GUIControlFactory.cpp +++ b/Source/GUI/GUIControlFactory.cpp @@ -18,7 +18,7 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIControl * GUIControlFactory::CreateControl(GUIManager *Manager, GUIControlManager *ControlManager, const std::string &ControlName) { +GUIControl* GUIControlFactory::CreateControl(GUIManager* Manager, GUIControlManager* ControlManager, const std::string& ControlName) { // Button if (ControlName.compare(GUIButton::GetControlID()) == 0) { return new GUIButton(Manager, ControlManager); @@ -73,4 +73,4 @@ GUIControl * GUIControlFactory::CreateControl(GUIManager *Manager, GUIControlMan } // Not Found return 0; -} \ No newline at end of file +} diff --git a/Source/GUI/GUIControlFactory.h b/Source/GUI/GUIControlFactory.h index 4ace52a2b..7b88ad585 100644 --- a/Source/GUI/GUIControlFactory.h +++ b/Source/GUI/GUIControlFactory.h @@ -3,21 +3,19 @@ namespace RTE { -/// -/// A class used to create the different controls based on name. -/// -class GUIControlFactory { + /// + /// A class used to create the different controls based on name. + /// + class GUIControlFactory { -public: + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Method used for creating controls + // Arguments: Control Type Name. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Method used for creating controls -// Arguments: Control Type Name. - - static GUIControl *CreateControl(GUIManager *Manager, GUIControlManager *ControlManager, const std::string &ControlName); - -}; -}; -#endif \ No newline at end of file + static GUIControl* CreateControl(GUIManager* Manager, GUIControlManager* ControlManager, const std::string& ControlName); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIControlManager.cpp b/Source/GUI/GUIControlManager.cpp index f1adacd1e..c7e80cb31 100644 --- a/Source/GUI/GUIControlManager.cpp +++ b/Source/GUI/GUIControlManager.cpp @@ -18,7 +18,7 @@ GUIControlManager::GUIControlManager() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIControlManager::Create(GUIScreen *Screen, GUIInput *Input, const std::string &SkinDir, const std::string &SkinFilename) { +bool GUIControlManager::Create(GUIScreen* Screen, GUIInput* Input, const std::string& SkinDir, const std::string& SkinFilename) { assert(Screen && Input); m_Screen = Screen; @@ -68,11 +68,11 @@ void GUIControlManager::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIControlManager::Clear() { - std::vector::iterator it; + std::vector::iterator it; // Destroy every control for (it = m_ControlList.begin(); it != m_ControlList.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; C->Destroy(); delete C; @@ -83,25 +83,27 @@ void GUIControlManager::Clear() { m_GUIManager->Clear(); // Destroy the event queue - std::vector::iterator ite; + std::vector::iterator ite; for (ite = m_EventQueue.begin(); ite != m_EventQueue.end(); ite++) { - GUIEvent *E = *ite; - if (E) { delete E; } + GUIEvent* E = *ite; + if (E) { + delete E; + } } m_EventQueue.clear(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControlManager::ChangeSkin(const std::string &SkinDir, const std::string &SkinFilename) { - std::vector::iterator it; +void GUIControlManager::ChangeSkin(const std::string& SkinDir, const std::string& SkinFilename) { + std::vector::iterator it; m_Skin->Destroy(); m_Skin->Load(SkinDir, SkinFilename); // Go through every control and change its skin for (it = m_ControlList.begin(); it != m_ControlList.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; C->ChangeSkin(m_Skin); } @@ -109,14 +111,14 @@ void GUIControlManager::ChangeSkin(const std::string &SkinDir, const std::string ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIControl * GUIControlManager::AddControl(const std::string &Name, const std::string &Type, GUIControl *Parent, int X, int Y, int Width, int Height) { +GUIControl* GUIControlManager::AddControl(const std::string& Name, const std::string& Type, GUIControl* Parent, int X, int Y, int Width, int Height) { // Skip if we already have a control of this name if (GetControl(Name)) { return nullptr; } // Create the control - GUIControl *Control = GUIControlFactory::CreateControl(m_GUIManager, this, Type); + GUIControl* Control = GUIControlFactory::CreateControl(m_GUIManager, this, Type); if (!Control) { return nullptr; } @@ -124,7 +126,7 @@ GUIControl * GUIControlManager::AddControl(const std::string &Name, const std::s Control->Create(Name, X, Y, Width, Height); Control->ChangeSkin(m_Skin); - GUIPanel *Pan = nullptr; + GUIPanel* Pan = nullptr; if (Parent) { Pan = Parent->GetPanel(); Parent->AddChild(Control); @@ -145,7 +147,7 @@ GUIControl * GUIControlManager::AddControl(const std::string &Name, const std::s ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIControl * GUIControlManager::AddControl(GUIProperties *Property) { +GUIControl* GUIControlManager::AddControl(GUIProperties* Property) { assert(Property); // Get the control type and name @@ -159,7 +161,7 @@ GUIControl * GUIControlManager::AddControl(GUIProperties *Property) { return nullptr; } // Create the control - GUIControl *Control = GUIControlFactory::CreateControl(m_GUIManager, this, Type); + GUIControl* Control = GUIControlFactory::CreateControl(m_GUIManager, this, Type); if (!Control) { return nullptr; } @@ -171,8 +173,8 @@ GUIControl * GUIControlManager::AddControl(GUIProperties *Property) { std::string Parent; Property->GetValue("Parent", &Parent); - GUIControl *Par = GetControl(Parent); - GUIPanel *Pan = nullptr; + GUIControl* Par = GetControl(Parent); + GUIPanel* Pan = nullptr; if (Par && Parent.compare("None") != 0) { Pan = Par->GetPanel(); Par->AddChild(Control); @@ -195,11 +197,11 @@ GUIControl * GUIControlManager::AddControl(GUIProperties *Property) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIControl * GUIControlManager::GetControl(const std::string &Name) { - std::vector::iterator it; +GUIControl* GUIControlManager::GetControl(const std::string& Name) { + std::vector::iterator it; for (it = m_ControlList.begin(); it != m_ControlList.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; if (C->GetName().compare(Name) == 0) { return C; } @@ -211,15 +213,17 @@ GUIControl * GUIControlManager::GetControl(const std::string &Name) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -std::vector * GUIControlManager::GetControlList() { +std::vector* GUIControlManager::GetControlList() { return &m_ControlList; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIControl * GUIControlManager::GetControlUnderPoint(int pointX, int pointY, GUIControl *pParent, int depth) { +GUIControl* GUIControlManager::GetControlUnderPoint(int pointX, int pointY, GUIControl* pParent, int depth) { // Default to the root object if no parent specified - if (!pParent) { pParent = m_ControlList.front(); } + if (!pParent) { + pParent = m_ControlList.front(); + } if (!pParent) { return nullptr; } @@ -240,8 +244,8 @@ GUIControl * GUIControlManager::GetControlUnderPoint(int pointX, int pointY, GUI } // Check children - std::vector *List = pParent->GetChildren(); - std::vector::reverse_iterator it; + std::vector* List = pParent->GetChildren(); + std::vector::reverse_iterator it; assert(List); @@ -250,7 +254,7 @@ GUIControl * GUIControlManager::GetControlUnderPoint(int pointX, int pointY, GUI for (it = List->rbegin(); it != List->rend(); it++) { // Only check visible controls if ((*it)->GetVisible()) { - GUIControl *C = GetControlUnderPoint(pointX, pointY, *it, depth - 1); + GUIControl* C = GetControlUnderPoint(pointX, pointY, *it, depth - 1); if (C) { return C; } @@ -264,13 +268,13 @@ GUIControl * GUIControlManager::GetControlUnderPoint(int pointX, int pointY, GUI ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControlManager::RemoveControl(const std::string &Name, bool RemoveFromParent) { +void GUIControlManager::RemoveControl(const std::string& Name, bool RemoveFromParent) { // NOTE: We can't simply remove it because some controls need to remove extra panels and it's silly to add 'remove' to every control to remove their extra panels (ie. Combobox). // Signals and stuff are also linked in so we just remove the controls from the list and not from memory. - std::vector::iterator it; + std::vector::iterator it; for (it = m_ControlList.begin(); it != m_ControlList.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; if (C->GetName().compare(Name) == 0) { // Just remove it from the list @@ -281,7 +285,9 @@ void GUIControlManager::RemoveControl(const std::string &Name, bool RemoveFromPa C->RemoveChildren(); // Remove me from my parent - if (C->GetParent() && RemoveFromParent) { C->GetParent()->RemoveChild(Name); } + if (C->GetParent() && RemoveFromParent) { + C->GetParent()->RemoveChild(Name); + } break; } @@ -296,7 +302,6 @@ void GUIControlManager::Update(bool ignoreKeyboardEvents) { // Process the manager m_GUIManager->Update(ignoreKeyboardEvents); - } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -307,13 +312,13 @@ void GUIControlManager::Draw() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControlManager::Draw(GUIScreen *pScreen) { +void GUIControlManager::Draw(GUIScreen* pScreen) { m_GUIManager->Draw(pScreen); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControlManager::DrawMouse(GUIScreen *guiScreen) { +void GUIControlManager::DrawMouse(GUIScreen* guiScreen) { int MouseX; int MouseY; m_Input->GetMousePosition(&MouseX, &MouseY); @@ -340,14 +345,16 @@ void GUIControlManager::DrawMouse(GUIScreen *guiScreen) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIControlManager::GetEvent(GUIEvent *Event) { +bool GUIControlManager::GetEvent(GUIEvent* Event) { if (Event && !m_EventQueue.empty()) { // Copy the event *Event = *m_EventQueue.back(); // Free the event - if (GUIEvent *ptr = m_EventQueue.at(m_EventQueue.size() - 1)) { delete ptr; } + if (GUIEvent* ptr = m_EventQueue.at(m_EventQueue.size() - 1)) { + delete ptr; + } m_EventQueue.pop_back(); return true; @@ -358,9 +365,11 @@ bool GUIControlManager::GetEvent(GUIEvent *Event) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIControlManager::AddEvent(GUIEvent *Event) { +void GUIControlManager::AddEvent(GUIEvent* Event) { // Add the event to the queue - if (Event) { m_EventQueue.push_back(Event); } + if (Event) { + m_EventQueue.push_back(Event); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -371,7 +380,7 @@ void GUIControlManager::SetCursor(int CursorType) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIControlManager::Save(const std::string &Filename) { +bool GUIControlManager::Save(const std::string& Filename) { GUIWriter W; if (W.Create(Filename) != 0) { return false; @@ -385,14 +394,14 @@ bool GUIControlManager::Save(const std::string &Filename) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIControlManager::Save(GUIWriter *W) { +bool GUIControlManager::Save(GUIWriter* W) { assert(W); // Go through each control - std::vector::iterator it; + std::vector::iterator it; for (it = m_ControlList.begin(); it != m_ControlList.end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; C->Save(W); // Separate controls by one line W->NewLine(); @@ -403,7 +412,7 @@ bool GUIControlManager::Save(GUIWriter *W) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIControlManager::Load(const std::string &Filename, bool keepOld) { +bool GUIControlManager::Load(const std::string& Filename, bool keepOld) { GUIReader reader; const std::string pathFile = g_PresetMan.GetFullModulePath(Filename); if (reader.Create(pathFile.c_str()) != 0) { @@ -411,12 +420,14 @@ bool GUIControlManager::Load(const std::string &Filename, bool keepOld) { } // Clear the current layout, IF directed to - if (!keepOld) { Clear(); } + if (!keepOld) { + Clear(); + } - std::vector ControlList; + std::vector ControlList; ControlList.clear(); - GUIProperties *CurProp = nullptr; + GUIProperties* CurProp = nullptr; while (!reader.GetStream()->eof()) { std::string line = reader.ReadLine(); @@ -427,7 +438,7 @@ bool GUIControlManager::Load(const std::string &Filename, bool keepOld) { // Is the line a section? if (line.front() == '[' && line.back() == ']') { - GUIProperties *p = new GUIProperties(line.substr(1, line.size() - 2)); + GUIProperties* p = new GUIProperties(line.substr(1, line.size() - 2)); CurProp = p; ControlList.push_back(p); continue; @@ -450,13 +461,13 @@ bool GUIControlManager::Load(const std::string &Filename, bool keepOld) { } // Go through each control item and create it - std::vector::iterator it; + std::vector::iterator it; for (it = ControlList.begin(); it != ControlList.end(); it++) { - GUIProperties *Prop = *it; + GUIProperties* Prop = *it; AddControl(Prop); // Free the property class delete Prop; } return true; -} \ No newline at end of file +} diff --git a/Source/GUI/GUIControlManager.h b/Source/GUI/GUIControlManager.h index edbf0693b..4bd4224b2 100644 --- a/Source/GUI/GUIControlManager.h +++ b/Source/GUI/GUIControlManager.h @@ -6,294 +6,266 @@ namespace RTE { -/// -/// A class used to manage the GUI as a whole and provide the interface between the GUI and the rest of the system. -/// -class GUIControlManager { - friend class GUIControl; - -public: - - // Cursor types - enum { - Pointer, - Text, - HorSize - } CursorType; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIControlmanager -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIControlManager object in -// system memory. -// Arguments: None. - - GUIControlManager(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: GUIControlmanager -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a GUIControlManager object in -// system memory. -// Arguments: None. - - ~GUIControlManager() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates the data for the control manager -// Arguments: Screen and Input Interfaces, Skin directory - - bool Create(GUIScreen *Screen, GUIInput *Input, const std::string &SkinDir, const std::string &SkinFilename = "skin.ini"); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Frees all the allocated resources. -// Arguments: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the controls. -// Arguments: None. - - void Clear(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes the skin of the controls. -// Arguments: Skin directory. - - void ChangeSkin(const std::string &SkinDir, const std::string &SkinFilename = "skin.ini"); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the Skin object currently in use. -// Arguments: None. -// Returns: A pointer to the currently used skin. Please don't mess it up. - - GUISkin * GetSkin() { return m_Skin; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the GUI every frame -// Arguments: Whether keyboard events should be ignored or not. Used to avoid conflicts when custom keyboard handling for GUI elements is preset. - - void Update(bool ignoreKeyboardEvents = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the GUI to the back buffer. -// Arguments: None. - - void Draw(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the GUI to the back buffer. -// Arguments: The GUIScreen to draw to, overriding the one passed in on construction - - void Draw(GUIScreen *pScreen); - - - /// - /// Draws the mouse to the backbuffer. - /// - /// The GUIScreen to draw to, overriding the one passed in on construction. - void DrawMouse(GUIScreen *guiScreen = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnableMouse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Enables and disables the mouse completely for this. -// Arguments: Enable? - - void EnableMouse(bool enable = true) { m_GUIManager->EnableMouse(enable); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPosOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the absolute position of this entire GUI on the screen. This is -// useful if the UI's are being drawn in a different area of the screen -// than the top left corner. This will adjust the mouse input to match -// the offset screen location. -// Arguments: The position. - - void SetPosOnScreen(int screenPosX, int screenPosY) { m_Input->SetMouseOffset(-screenPosX, -screenPosY); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetManager -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control manager -// Arguments: Name. -// Returns: The manager, ownership is NOT transferred! - - GUIManager * GetManager() { return m_GUIManager; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Manually creates a control. -// Arguments: Name, Type, Position, Size, Parent. -// Returns: GUIControl class created. 0 if not created. - - GUIControl * AddControl(const std::string &Name, const std::string &Type, GUIControl *Parent, int X, int Y, int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Manually creates a control. -// Arguments: Properties. -// Returns: GUIControl class created. 0 if not created. - - GUIControl * AddControl(GUIProperties *Property); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a control -// Arguments: Name. -// Returns: GUIControl class, or 0 if not found. - - GUIControl * GetControl(const std::string &Name); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control list -// Arguments: None. -// Returns: vector Pointer. - - std::vector * GetControlList(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlUnderPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if a control is under a specific point -// Arguments: The absolute point coordinates to check under. -// Parent to check under. Pass null to default to the root control. -// How many levels of children under the parent to look at. If negative, -// goes as far as it can. -// Returns: GUIControl. NULL if no control under the point - - GUIControl * GetControlUnderPoint(int pointX, int pointY, GUIControl *pParent = nullptr, int depth = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a control by name -// Arguments: Name, RemoveFromParent. -// Returns: None. - - void RemoveControl(const std::string &Name, bool RemoveFromParent); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEvent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets an event from the queue. -// Arguments: Pointer to variable receiving the Event. -// Returns: Returns true when an event was grabbed. -// Returns false when there was no more events in the queue -// OR the Event pointer is 0. - - bool GetEvent(GUIEvent *Event); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCursor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the cursor type. -// Arguments: Cursor type. - - void SetCursor(int CursorType); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the layout to a file. -// Arguments: Filename. -// Returns: True if successful. - - bool Save(const std::string &Filename); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the layout to a Writer class. -// Arguments: Writer class. -// Returns: True if successful. - - bool Save(GUIWriter *W); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Load -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads the layout from a file. -// Arguments: Filename. -// Whether to NOT clear out the manager, but just add the controls loaded -// to the existing layout. -// Returns: True if successful. - - bool Load(const std::string &Filename, bool keepOld = false); - - /// - /// Gets the GUIScreen that this GUIControlManager is drawing itself to. + /// A class used to manage the GUI as a whole and provide the interface between the GUI and the rest of the system. /// - /// Pointer to the GUIScreen that this GUIControlManager is drawing itself to. - GUIScreen * GetScreen() const { return m_Screen; } - -private: - - GUIScreen *m_Screen; // Not owned. - GUIInput *m_Input; // Not owned. - GUISkin *m_Skin; - GUIManager *m_GUIManager; - - std::vector m_ControlList; - std::vector m_EventQueue; - - int m_CursorType; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddEvent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Add a new event to the queue. -// Arguments: Event point. - - void AddEvent(GUIEvent *Event); -}; -}; -#endif // _GUICONTROLMANAGER_ \ No newline at end of file + class GUIControlManager { + friend class GUIControl; + + public: + // Cursor types + enum { + Pointer, + Text, + HorSize + } CursorType; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIControlmanager + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIControlManager object in + // system memory. + // Arguments: None. + + GUIControlManager(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: GUIControlmanager + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a GUIControlManager object in + // system memory. + // Arguments: None. + + ~GUIControlManager() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates the data for the control manager + // Arguments: Screen and Input Interfaces, Skin directory + + bool Create(GUIScreen* Screen, GUIInput* Input, const std::string& SkinDir, const std::string& SkinFilename = "skin.ini"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Frees all the allocated resources. + // Arguments: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the controls. + // Arguments: None. + + void Clear(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes the skin of the controls. + // Arguments: Skin directory. + + void ChangeSkin(const std::string& SkinDir, const std::string& SkinFilename = "skin.ini"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the Skin object currently in use. + // Arguments: None. + // Returns: A pointer to the currently used skin. Please don't mess it up. + + GUISkin* GetSkin() { return m_Skin; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the GUI every frame + // Arguments: Whether keyboard events should be ignored or not. Used to avoid conflicts when custom keyboard handling for GUI elements is preset. + + void Update(bool ignoreKeyboardEvents = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the GUI to the back buffer. + // Arguments: None. + + void Draw(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the GUI to the back buffer. + // Arguments: The GUIScreen to draw to, overriding the one passed in on construction + + void Draw(GUIScreen* pScreen); + + /// + /// Draws the mouse to the backbuffer. + /// + /// The GUIScreen to draw to, overriding the one passed in on construction. + void DrawMouse(GUIScreen* guiScreen = nullptr); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableMouse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Enables and disables the mouse completely for this. + // Arguments: Enable? + + void EnableMouse(bool enable = true) { m_GUIManager->EnableMouse(enable); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPosOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the absolute position of this entire GUI on the screen. This is + // useful if the UI's are being drawn in a different area of the screen + // than the top left corner. This will adjust the mouse input to match + // the offset screen location. + // Arguments: The position. + + void SetPosOnScreen(int screenPosX, int screenPosY) { m_Input->SetMouseOffset(-screenPosX, -screenPosY); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetManager + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control manager + // Arguments: Name. + // Returns: The manager, ownership is NOT transferred! + + GUIManager* GetManager() { return m_GUIManager; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Manually creates a control. + // Arguments: Name, Type, Position, Size, Parent. + // Returns: GUIControl class created. 0 if not created. + + GUIControl* AddControl(const std::string& Name, const std::string& Type, GUIControl* Parent, int X, int Y, int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Manually creates a control. + // Arguments: Properties. + // Returns: GUIControl class created. 0 if not created. + + GUIControl* AddControl(GUIProperties* Property); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a control + // Arguments: Name. + // Returns: GUIControl class, or 0 if not found. + + GUIControl* GetControl(const std::string& Name); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control list + // Arguments: None. + // Returns: vector Pointer. + + std::vector* GetControlList(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlUnderPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if a control is under a specific point + // Arguments: The absolute point coordinates to check under. + // Parent to check under. Pass null to default to the root control. + // How many levels of children under the parent to look at. If negative, + // goes as far as it can. + // Returns: GUIControl. NULL if no control under the point + + GUIControl* GetControlUnderPoint(int pointX, int pointY, GUIControl* pParent = nullptr, int depth = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a control by name + // Arguments: Name, RemoveFromParent. + // Returns: None. + + void RemoveControl(const std::string& Name, bool RemoveFromParent); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEvent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets an event from the queue. + // Arguments: Pointer to variable receiving the Event. + // Returns: Returns true when an event was grabbed. + // Returns false when there was no more events in the queue + // OR the Event pointer is 0. + + bool GetEvent(GUIEvent* Event); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCursor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the cursor type. + // Arguments: Cursor type. + + void SetCursor(int CursorType); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the layout to a file. + // Arguments: Filename. + // Returns: True if successful. + + bool Save(const std::string& Filename); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the layout to a Writer class. + // Arguments: Writer class. + // Returns: True if successful. + + bool Save(GUIWriter* W); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Load + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads the layout from a file. + // Arguments: Filename. + // Whether to NOT clear out the manager, but just add the controls loaded + // to the existing layout. + // Returns: True if successful. + + bool Load(const std::string& Filename, bool keepOld = false); + + /// + /// Gets the GUIScreen that this GUIControlManager is drawing itself to. + /// + /// Pointer to the GUIScreen that this GUIControlManager is drawing itself to. + GUIScreen* GetScreen() const { return m_Screen; } + + private: + GUIScreen* m_Screen; // Not owned. + GUIInput* m_Input; // Not owned. + GUISkin* m_Skin; + GUIManager* m_GUIManager; + + std::vector m_ControlList; + std::vector m_EventQueue; + + int m_CursorType; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddEvent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Add a new event to the queue. + // Arguments: Event point. + + void AddEvent(GUIEvent* Event); + }; +}; // namespace RTE +#endif // _GUICONTROLMANAGER_ diff --git a/Source/GUI/GUIEvent.cpp b/Source/GUI/GUIEvent.cpp index 0a6dc56e9..1a3904694 100644 --- a/Source/GUI/GUIEvent.cpp +++ b/Source/GUI/GUIEvent.cpp @@ -13,7 +13,7 @@ GUIEvent::GUIEvent() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIEvent::GUIEvent(GUIControl *Control, int Type, int Msg, int Data) { +GUIEvent::GUIEvent(GUIControl* Control, int Type, int Msg, int Data) { assert(Control); m_Control = Control; m_Type = Type; @@ -29,7 +29,7 @@ int GUIEvent::GetType() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIControl * GUIEvent::GetControl() { +GUIControl* GUIEvent::GetControl() { return m_Control; } diff --git a/Source/GUI/GUIEvent.h b/Source/GUI/GUIEvent.h index 28cd04199..902469840 100644 --- a/Source/GUI/GUIEvent.h +++ b/Source/GUI/GUIEvent.h @@ -3,82 +3,73 @@ namespace RTE { -/// -/// A class to hold event information. -/// -class GUIEvent { - -public: - - // Event Types - enum { - Command = 0, - Notification - } EventType; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIEvent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIEvent object in system -// memory. -// Arguments: None. - - GUIEvent(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIEvent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIEvent object in system -// memory. -// Arguments: Control, Event type, Msg, Data. - - GUIEvent(GUIControl *Control, int Type, int Msg, int Data); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetType -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the event type -// Arguments: None. - - int GetType() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMsg -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the msg. -// Arguments: None. - - int GetMsg() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the data. -// Arguments: None. - - int GetData() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControl -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the event control. -// Arguments: None. - - GUIControl * GetControl(); - -private: - - GUIControl *m_Control; - int m_Type; - int m_Msg; - int m_Data; - -}; -}; -#endif \ No newline at end of file + /// + /// A class to hold event information. + /// + class GUIEvent { + + public: + // Event Types + enum { + Command = 0, + Notification + } EventType; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIEvent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIEvent object in system + // memory. + // Arguments: None. + + GUIEvent(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIEvent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIEvent object in system + // memory. + // Arguments: Control, Event type, Msg, Data. + + GUIEvent(GUIControl* Control, int Type, int Msg, int Data); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetType + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the event type + // Arguments: None. + + int GetType() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMsg + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the msg. + // Arguments: None. + + int GetMsg() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the data. + // Arguments: None. + + int GetData() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControl + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the event control. + // Arguments: None. + + GUIControl* GetControl(); + + private: + GUIControl* m_Control; + int m_Type; + int m_Msg; + int m_Data; + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIFont.cpp b/Source/GUI/GUIFont.cpp index ebfa84034..f30e0de07 100644 --- a/Source/GUI/GUIFont.cpp +++ b/Source/GUI/GUIFont.cpp @@ -4,7 +4,7 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIFont::GUIFont(const std::string &Name) { +GUIFont::GUIFont(const std::string& Name) { m_Screen = nullptr; m_Font = nullptr; m_FontHeight = 0; @@ -22,7 +22,7 @@ GUIFont::GUIFont(const std::string &Name) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIFont::Load(GUIScreen *Screen, const std::string &Filename) { +bool GUIFont::Load(GUIScreen* Screen, const std::string& Filename) { assert(Screen); m_Screen = Screen; @@ -80,7 +80,9 @@ bool GUIFont::Load(GUIScreen *Screen, const std::string &Filename) { for (int j = y; j < y + m_FontHeight; j++) { for (int i = x; i < x + w; i++) { unsigned long Pixel = m_Font->GetPixel(i, j); - if (Pixel != Red && Pixel != BackG) { Height = std::max(Height, j - y); } + if (Pixel != Red && Pixel != BackG) { + Height = std::max(Height, j - y); + } } } @@ -107,16 +109,16 @@ bool GUIFont::Load(GUIScreen *Screen, const std::string &Filename) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIFont::Draw(GUIBitmap *Bitmap, int X, int Y, const std::string &Text, unsigned long Shadow) { +void GUIFont::Draw(GUIBitmap* Bitmap, int X, int Y, const std::string& Text, unsigned long Shadow) { unsigned char c; GUIRect Rect; - GUIBitmap *Surf = m_CurrentBitmap; + GUIBitmap* Surf = m_CurrentBitmap; int initX = X; assert(Surf); // Make the shadow color - FontColor *FSC = nullptr; + FontColor* FSC = nullptr; if (Shadow) { FSC = GetFontColor(Shadow); if (!FSC) { @@ -133,8 +135,12 @@ void GUIFont::Draw(GUIBitmap *Bitmap, int X, int Y, const std::string &Text, uns Y += m_FontHeight; X = initX; } - if (c == '\t') { X += m_Characters[' '].m_Width * 4; } - if (c < 0) { c += m_CharIndexCap; } + if (c == '\t') { + X += m_Characters[' '].m_Width * 4; + } + if (c < 0) { + c += m_CharIndexCap; + } if (c < 32 || c >= m_CharIndexCap) { continue; } @@ -145,7 +151,9 @@ void GUIFont::Draw(GUIBitmap *Bitmap, int X, int Y, const std::string &Text, uns SetRect(&Rect, offX, offY, offX + CharWidth, offY + m_FontHeight); // Draw the shadow - if (Shadow && FSC) { FSC->m_Bitmap->DrawTrans(Bitmap, X + 1, Y + 1, &Rect); } + if (Shadow && FSC) { + FSC->m_Bitmap->DrawTrans(Bitmap, X + 1, Y + 1, &Rect); + } // Draw the main color Surf->DrawTrans(Bitmap, X, Y, &Rect); @@ -157,7 +165,7 @@ void GUIFont::Draw(GUIBitmap *Bitmap, int X, int Y, const std::string &Text, uns ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIFont::DrawAligned(GUIBitmap *Bitmap, int X, int Y, const std::string &Text, int HAlign, int VAlign, int MaxWidth, unsigned long Shadow) { +void GUIFont::DrawAligned(GUIBitmap* Bitmap, int X, int Y, const std::string& Text, int HAlign, int VAlign, int MaxWidth, unsigned long Shadow) { std::string TextLine = Text; int lineStartPos = 0; int lineEndPos = 0; @@ -244,7 +252,7 @@ void GUIFont::SetColor(unsigned long Color) { if (Color != m_CurrentColor) { // Find the cached color - FontColor *FC = GetFontColor(Color); + FontColor* FC = GetFontColor(Color); // Use the cached color, otherwise just draw the default bitmap if (FC) { @@ -256,7 +264,7 @@ void GUIFont::SetColor(unsigned long Color) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int GUIFont::CalculateWidth(const std::string &Text) { +int GUIFont::CalculateWidth(const std::string& Text) { unsigned char c; int Width = 0; int WidestLine = 0; @@ -266,11 +274,15 @@ int GUIFont::CalculateWidth(const std::string &Text) { c = Text.at(i); // Reset line counting if newline encountered if (c == '\n') { - if (Width > WidestLine) { WidestLine = Width; } + if (Width > WidestLine) { + WidestLine = Width; + } Width = 0; continue; } - if (c < 0) { c += m_CharIndexCap; } + if (c < 0) { + c += m_CharIndexCap; + } if (c < 32 || c >= m_CharIndexCap) { continue; @@ -281,7 +293,9 @@ int GUIFont::CalculateWidth(const std::string &Text) { // Add kerning Width += m_Kerning; } - if (Width > WidestLine) { WidestLine = Width; } + if (Width > WidestLine) { + WidestLine = Width; + } return WidestLine; } @@ -297,7 +311,7 @@ int GUIFont::CalculateWidth(const char Character) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int GUIFont::CalculateHeight(const std::string &Text, int MaxWidth) { +int GUIFont::CalculateHeight(const std::string& Text, int MaxWidth) { if (Text.empty()) { return 0; } @@ -319,7 +333,9 @@ int GUIFont::CalculateHeight(const std::string &Text, int MaxWidth) { if (c < 32 || c >= m_CharIndexCap) { continue; } - if (c == ' ') { lastSpacePos = i; } + if (c == ' ') { + lastSpacePos = i; + } Width += m_Characters[c].m_Width + m_Kerning; if (MaxWidth > 0 && Width > MaxWidth) { @@ -365,7 +381,9 @@ void GUIFont::CacheColor(unsigned long Color) { // Go through the bitmap and change the pixels for (int y = 0; y < FC.m_Bitmap->GetHeight(); y++) { for (int x = 0; x < FC.m_Bitmap->GetWidth(); x++) { - if (FC.m_Bitmap->GetPixel(x, y) == m_MainColor) { FC.m_Bitmap->SetPixel(x, y, Color); } + if (FC.m_Bitmap->GetPixel(x, y) == m_MainColor) { + FC.m_Bitmap->SetPixel(x, y, Color); + } } } @@ -375,9 +393,9 @@ void GUIFont::CacheColor(unsigned long Color) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIFont::FontColor * GUIFont::GetFontColor(unsigned long Color) { +GUIFont::FontColor* GUIFont::GetFontColor(unsigned long Color) { std::vector::iterator it; - FontColor *F = nullptr; + FontColor* F = nullptr; for (it = m_ColorCache.begin(); it != m_ColorCache.end(); it++) { F = &(*it); @@ -419,7 +437,7 @@ void GUIFont::Destroy() { // Go through the color cache and destroy the bitmaps std::vector::iterator it; - FontColor *FC = 0; + FontColor* FC = 0; for (it = m_ColorCache.begin(); it != m_ColorCache.end(); it++) { FC = &(*it); if (FC && FC->m_Bitmap) { @@ -428,4 +446,4 @@ void GUIFont::Destroy() { } } m_ColorCache.clear(); -} \ No newline at end of file +} diff --git a/Source/GUI/GUIFont.h b/Source/GUI/GUIFont.h index 6434f9531..94383c0fd 100644 --- a/Source/GUI/GUIFont.h +++ b/Source/GUI/GUIFont.h @@ -3,195 +3,178 @@ namespace RTE { -/// -/// A class to handle the drawing of text. -/// -class GUIFont { - -public: - - // Horizontal Text Alignment, - enum { - Left = 0, - Centre, - Right - } HAlignment; - - // Vertical Text Alignment, - enum { - Top = 0, - Middle, - Bottom - } VAlignment; - - // Character structure - typedef struct { - int m_Width; - int m_Height; - int m_Offset; - } Character; - - // Font Color structure - typedef struct { - unsigned long m_Color; - GUIBitmap *m_Bitmap; - } FontColor; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIFont -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIFont object in system -// memory. -// Arguments: None. - - explicit GUIFont(const std::string &Name); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Load -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads the font from an image file. -// Arguments: Screen class, Filename of image. - - bool Load(GUIScreen *Screen, const std::string &Filename); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CacheColor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Pre-Calculates the font using a specific color. -// Arguments: Color. - - void CacheColor(unsigned long Color); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFontColor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Finds a font color structure from the cache. -// Arguments: Color. - - FontColor * GetFontColor(unsigned long Color); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws text to a bitmap. -// Arguments: Bitmap, Position, Text, Color, Drop-shadow, 0 = none. - - void Draw(GUIBitmap *Bitmap, int X, int Y, const std::string &Text, unsigned long Shadow = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawAligned -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws text to a bitmap aligned. -// Arguments: Bitmap, Position, Text. - - void DrawAligned(GUIBitmap *Bitmap, int X, int Y, const std::string &Text, int HAlign, int VAlign = Top, int maxWidth = 0, unsigned long Shadow = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetColor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current color. -// Arguments: Color. - - void SetColor(unsigned long Color); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the width of a piece of text. -// Arguments: Text. - - int CalculateWidth(const std::string &Text); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the width of a piece of text. -// Arguments: Character. - - int CalculateWidth(const char Character); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the height of a piece of text, if it's wrapped within a -// max width. -// Arguments: Text, and the max width. If 0, no wrapping is done. - - int CalculateHeight(const std::string &Text, int MaxWidth = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFontHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the font height. -// Arguments: None. - - int GetFontHeight() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the name of the font -// Arguments: None. - - std::string GetName() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys the font data -// Arguments: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetKerning -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get the character kerning (spacing) -// Arguments: None. - - int GetKerning() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetKerning -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Set the character kerning (spacing), in pixels. 1 = one empty pixel -// between chars, 0 = chars are touching. -// Arguments: None. - - void SetKerning(int newKerning = 1) { m_Kerning = newKerning; } - -private: - - GUIBitmap *m_Font; - GUIScreen *m_Screen; - std::vector m_ColorCache; - - int m_FontHeight; - unsigned long m_MainColor; - unsigned long m_CurrentColor; - GUIBitmap *m_CurrentBitmap; - std::string m_Name; - Character m_Characters[256]; - - int m_CharIndexCap; // The highest index of valid characters that was read in from the file - - int m_Kerning; // Spacing between characters - int m_Leading; // Spacing between lines -}; -}; -#endif \ No newline at end of file + /// + /// A class to handle the drawing of text. + /// + class GUIFont { + + public: + // Horizontal Text Alignment, + enum { + Left = 0, + Centre, + Right + } HAlignment; + + // Vertical Text Alignment, + enum { + Top = 0, + Middle, + Bottom + } VAlignment; + + // Character structure + typedef struct { + int m_Width; + int m_Height; + int m_Offset; + } Character; + + // Font Color structure + typedef struct { + unsigned long m_Color; + GUIBitmap* m_Bitmap; + } FontColor; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIFont + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIFont object in system + // memory. + // Arguments: None. + + explicit GUIFont(const std::string& Name); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Load + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads the font from an image file. + // Arguments: Screen class, Filename of image. + + bool Load(GUIScreen* Screen, const std::string& Filename); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CacheColor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Pre-Calculates the font using a specific color. + // Arguments: Color. + + void CacheColor(unsigned long Color); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFontColor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Finds a font color structure from the cache. + // Arguments: Color. + + FontColor* GetFontColor(unsigned long Color); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws text to a bitmap. + // Arguments: Bitmap, Position, Text, Color, Drop-shadow, 0 = none. + + void Draw(GUIBitmap* Bitmap, int X, int Y, const std::string& Text, unsigned long Shadow = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawAligned + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws text to a bitmap aligned. + // Arguments: Bitmap, Position, Text. + + void DrawAligned(GUIBitmap* Bitmap, int X, int Y, const std::string& Text, int HAlign, int VAlign = Top, int maxWidth = 0, unsigned long Shadow = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetColor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current color. + // Arguments: Color. + + void SetColor(unsigned long Color); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the width of a piece of text. + // Arguments: Text. + + int CalculateWidth(const std::string& Text); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the width of a piece of text. + // Arguments: Character. + + int CalculateWidth(const char Character); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the height of a piece of text, if it's wrapped within a + // max width. + // Arguments: Text, and the max width. If 0, no wrapping is done. + + int CalculateHeight(const std::string& Text, int MaxWidth = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFontHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the font height. + // Arguments: None. + + int GetFontHeight() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of the font + // Arguments: None. + + std::string GetName() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys the font data + // Arguments: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetKerning + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get the character kerning (spacing) + // Arguments: None. + + int GetKerning() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetKerning + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Set the character kerning (spacing), in pixels. 1 = one empty pixel + // between chars, 0 = chars are touching. + // Arguments: None. + + void SetKerning(int newKerning = 1) { m_Kerning = newKerning; } + + private: + GUIBitmap* m_Font; + GUIScreen* m_Screen; + std::vector m_ColorCache; + + int m_FontHeight; + unsigned long m_MainColor; + unsigned long m_CurrentColor; + GUIBitmap* m_CurrentBitmap; + std::string m_Name; + Character m_Characters[256]; + + int m_CharIndexCap; // The highest index of valid characters that was read in from the file + + int m_Kerning; // Spacing between characters + int m_Leading; // Spacing between lines + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIInput.cpp b/Source/GUI/GUIInput.cpp index 6099b1100..bac777c99 100644 --- a/Source/GUI/GUIInput.cpp +++ b/Source/GUI/GUIInput.cpp @@ -6,12 +6,12 @@ using namespace RTE; bool GUIInput::m_OverrideInput = false; -int GUIInput::m_NetworkMouseButtonsEvents[4][3] = { { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 } }; -int GUIInput::m_NetworkMouseButtonsStates[4][3] = { { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 } }; -int GUIInput::m_PrevNetworkMouseButtonsStates[4][3] = { { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 } }; +int GUIInput::m_NetworkMouseButtonsEvents[4][3] = {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}}; +int GUIInput::m_NetworkMouseButtonsStates[4][3] = {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}}; +int GUIInput::m_PrevNetworkMouseButtonsStates[4][3] = {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}}; -int GUIInput::m_NetworkMouseX[4] = { 0, 0, 0, 0 }; -int GUIInput::m_NetworkMouseY[4] = { 0, 0, 0, 0 }; +int GUIInput::m_NetworkMouseX[4] = {0, 0, 0, 0}; +int GUIInput::m_NetworkMouseY[4] = {0, 0, 0, 0}; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -25,8 +25,8 @@ GUIInput::GUIInput(int whichPlayer, bool keyJoyMouseCursor) { m_TextInput.clear(); m_HasTextInput = false; - //memset(m_NetworkMouseButtonsEvents, -1, sizeof(int) * 3); - //memset(m_NetworkMouseButtonsStates, -1, sizeof(int) * 3); + // memset(m_NetworkMouseButtonsEvents, -1, sizeof(int) * 3); + // memset(m_NetworkMouseButtonsStates, -1, sizeof(int) * 3); m_MouseX = 0; m_MouseY = 0; @@ -50,8 +50,10 @@ void GUIInput::Destroy() {} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIInput::GetKeyboard(unsigned char *Buffer) const { - if (Buffer) { memcpy(Buffer, m_KeyboardBuffer, sizeof(unsigned char) * KEYBOARD_BUFFER_SIZE); } +void GUIInput::GetKeyboard(unsigned char* Buffer) const { + if (Buffer) { + memcpy(Buffer, m_KeyboardBuffer, sizeof(unsigned char) * KEYBOARD_BUFFER_SIZE); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -68,10 +70,14 @@ unsigned char GUIInput::GetScanCodeState(unsigned char scancode) const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIInput::GetMouseButtons(int *Buttons, int *States) const { +void GUIInput::GetMouseButtons(int* Buttons, int* States) const { if (!m_OverrideInput) { - if (Buttons) { memcpy(Buttons, m_MouseButtonsEvents, sizeof(int) * 3); } - if (States) { memcpy(States, m_MouseButtonsStates, sizeof(int) * 3); } + if (Buttons) { + memcpy(Buttons, m_MouseButtonsEvents, sizeof(int) * 3); + } + if (States) { + memcpy(States, m_MouseButtonsStates, sizeof(int) * 3); + } } else { for (int i = 0; i < 3; i++) { Buttons[i] = -1; @@ -109,18 +115,30 @@ void GUIInput::SetNetworkMouseButton(int whichPlayer, int state1, int state2, in ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIInput::GetMousePosition(int *X, int *Y) const { +void GUIInput::GetMousePosition(int* X, int* Y) const { if (m_OverrideInput) { if (m_Player >= 0 && m_Player < 4) { - if (X) { *X = (m_NetworkMouseX[m_Player] + m_MouseOffsetX); } - if (Y) { *Y = (m_NetworkMouseY[m_Player] + m_MouseOffsetY); } + if (X) { + *X = (m_NetworkMouseX[m_Player] + m_MouseOffsetX); + } + if (Y) { + *Y = (m_NetworkMouseY[m_Player] + m_MouseOffsetY); + } } else { - if (X) { *X = (m_NetworkMouseX[0] + m_MouseOffsetX); } - if (Y) { *Y = (m_NetworkMouseY[0] + m_MouseOffsetY); } + if (X) { + *X = (m_NetworkMouseX[0] + m_MouseOffsetX); + } + if (Y) { + *Y = (m_NetworkMouseY[0] + m_MouseOffsetY); + } } } else { - if (X) { *X = (m_MouseX + m_MouseOffsetX); } - if (Y) { *Y = (m_MouseY + m_MouseOffsetY); } + if (X) { + *X = (m_MouseX + m_MouseOffsetX); + } + if (Y) { + *Y = (m_MouseY + m_MouseOffsetY); + } } } diff --git a/Source/GUI/GUIInput.h b/Source/GUI/GUIInput.h index 63102b0b9..932713284 100644 --- a/Source/GUI/GUIInput.h +++ b/Source/GUI/GUIInput.h @@ -3,219 +3,211 @@ namespace RTE { -/// -/// An interface class inherited by the different types of input methods. -/// -class GUIInput { - -public: - - // Mouse & Key events - enum { - None, - Released, // Has just been released - Pushed, // Has just been pushed down - Repeat // Is repeating - } Event; - - // Mouse & Key states - enum { - Up, - Down - } State; - - // Modifiers - enum { - ModNone = 0x00, - ModShift = 0x01, - ModCtrl = 0x02, - ModAlt = 0x04, - ModCommand = 0x08 - } Modifier; - - // Extra keys - enum { - Key_None = 0, - Key_Backspace = 0x00000008, - Key_Tab = 0x00000009, - Key_Enter = 0x0000000D, - Key_Escape = 0x0000001B, - Key_LeftArrow = 0x00000086, - Key_RightArrow = 0x00000087, - Key_UpArrow = 0x00000088, - Key_DownArrow = 0x00000089, - Key_Insert = 0x00000095, - Key_Delete = 0x00000096, - Key_Home = 0x00000097, - Key_End = 0x00000098, - Key_PageUp = 0x00000099, - Key_PageDown = 0x0000009A - } Keys; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIInput -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIInput object in system -// memory. -// Arguments: Whether the keyboard and joysticks also can control the mouse cursor. - - GUIInput(int whichPlayer, bool keyJoyMouseCursor = false); - - virtual ~GUIInput() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroy the screen -// Arguments: None. - - virtual void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMouseOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the offset for the mouse input to be adjusted by. This should -// be used when the GUI is being drawn somewhere else on the screen than -// the upper left corner. These values should be from the GUI to the upper -// left corner. -// Arguments: The new offset. - - void SetMouseOffset(int mouseOffsetX, int mouseOffsetY) { m_MouseOffsetX = mouseOffsetX; m_MouseOffsetY = mouseOffsetY; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMouseOffset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the offset for the mouse input to be adjusted by. This should -// These values should be from the GUI to the upper of the screen. -// left corner. -// Arguments: The new offset. - - void GetMouseOffset(int &mouseOffsetX, int &mouseOffsetY) const { mouseOffsetX = m_MouseOffsetX; mouseOffsetY = m_MouseOffsetY; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Input. -// Arguments: None. - - virtual void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetKeyboard -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Copies the keyboard buffer into an array. The keyboard buffer is -// ordered by ascii code and each entry contains a GUInput::Event enum -// state. -// Arguments: Buffer array. - - void GetKeyboard(unsigned char *Buffer) const; - - unsigned char GetAsciiState(unsigned char ascii) const; - - unsigned char GetScanCodeState(unsigned char scancode) const; - - bool GetTextInput(std::string_view &text) const { text = m_TextInput; return !m_TextInput.empty(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMouseButtons -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Copies the mouse button states into an array -// Arguments: State array. - - void GetMouseButtons(int *Events, int *States) const; - - - static void SetNetworkMouseButton(int whichPlayer, int state1, int state2, int state3); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMousePosition -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the mouse position -// Arguments: Pointers to store the X and Y coordinates in - - void GetMousePosition(int *X, int *Y) const; - - - static void SetNetworkMouseMovement(int whichPlayer, int x, int y); - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetModifier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the key modifiers. -// Arguments: None. - - int GetModifier() const; - - - /// - /// This function returns how much the mouse scroll wheel has moved. Positive integer is scroll up, negative is scroll down. - /// - /// Mouse scroll wheel movement in integer value. - int GetMouseWheelChange() const { - return m_MouseWheelChange; - } - /// - /// Sets whether the keyboard and joysticks also control the mouse. + /// An interface class inherited by the different types of input methods. /// - /// Whether the keyboard and joysticks also control the mouse or not. - void SetKeyJoyMouseCursor(bool enableKeyJoyMouseCursor) { m_KeyJoyMouseCursor = enableKeyJoyMouseCursor; } - + class GUIInput { + + public: + // Mouse & Key events + enum { + None, + Released, // Has just been released + Pushed, // Has just been pushed down + Repeat // Is repeating + } Event; + + // Mouse & Key states + enum { + Up, + Down + } State; + + // Modifiers + enum { + ModNone = 0x00, + ModShift = 0x01, + ModCtrl = 0x02, + ModAlt = 0x04, + ModCommand = 0x08 + } Modifier; + + // Extra keys + enum { + Key_None = 0, + Key_Backspace = 0x00000008, + Key_Tab = 0x00000009, + Key_Enter = 0x0000000D, + Key_Escape = 0x0000001B, + Key_LeftArrow = 0x00000086, + Key_RightArrow = 0x00000087, + Key_UpArrow = 0x00000088, + Key_DownArrow = 0x00000089, + Key_Insert = 0x00000095, + Key_Delete = 0x00000096, + Key_Home = 0x00000097, + Key_End = 0x00000098, + Key_PageUp = 0x00000099, + Key_PageDown = 0x0000009A + } Keys; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIInput + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIInput object in system + // memory. + // Arguments: Whether the keyboard and joysticks also can control the mouse cursor. + + GUIInput(int whichPlayer, bool keyJoyMouseCursor = false); + + virtual ~GUIInput() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroy the screen + // Arguments: None. + + virtual void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMouseOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the offset for the mouse input to be adjusted by. This should + // be used when the GUI is being drawn somewhere else on the screen than + // the upper left corner. These values should be from the GUI to the upper + // left corner. + // Arguments: The new offset. + + void SetMouseOffset(int mouseOffsetX, int mouseOffsetY) { + m_MouseOffsetX = mouseOffsetX; + m_MouseOffsetY = mouseOffsetY; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMouseOffset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the offset for the mouse input to be adjusted by. This should + // These values should be from the GUI to the upper of the screen. + // left corner. + // Arguments: The new offset. + + void GetMouseOffset(int& mouseOffsetX, int& mouseOffsetY) const { + mouseOffsetX = m_MouseOffsetX; + mouseOffsetY = m_MouseOffsetY; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Input. + // Arguments: None. + + virtual void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetKeyboard + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Copies the keyboard buffer into an array. The keyboard buffer is + // ordered by ascii code and each entry contains a GUInput::Event enum + // state. + // Arguments: Buffer array. + + void GetKeyboard(unsigned char* Buffer) const; + + unsigned char GetAsciiState(unsigned char ascii) const; + + unsigned char GetScanCodeState(unsigned char scancode) const; + + bool GetTextInput(std::string_view& text) const { + text = m_TextInput; + return !m_TextInput.empty(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMouseButtons + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Copies the mouse button states into an array + // Arguments: State array. + + void GetMouseButtons(int* Events, int* States) const; + + static void SetNetworkMouseButton(int whichPlayer, int state1, int state2, int state3); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMousePosition + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the mouse position + // Arguments: Pointers to store the X and Y coordinates in + + void GetMousePosition(int* X, int* Y) const; + + static void SetNetworkMouseMovement(int whichPlayer, int x, int y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetModifier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the key modifiers. + // Arguments: None. + + int GetModifier() const; + + /// + /// This function returns how much the mouse scroll wheel has moved. Positive integer is scroll up, negative is scroll down. + /// + /// Mouse scroll wheel movement in integer value. + int GetMouseWheelChange() const { + return m_MouseWheelChange; + } + + /// + /// Sets whether the keyboard and joysticks also control the mouse. + /// + /// Whether the keyboard and joysticks also control the mouse or not. + void SetKeyJoyMouseCursor(bool enableKeyJoyMouseCursor) { m_KeyJoyMouseCursor = enableKeyJoyMouseCursor; } + + protected: + enum Constants { + KEYBOARD_BUFFER_SIZE = 256 + }; + + // Keyboard buffer holding the key states + unsigned char m_KeyboardBuffer[KEYBOARD_BUFFER_SIZE]; + unsigned char m_ScanCodeState[KEYBOARD_BUFFER_SIZE]; + std::string m_TextInput; + bool m_HasTextInput; + + // Mouse button states + // Order: Left, Middle, Right + int m_MouseButtonsEvents[3]; + int m_MouseButtonsStates[3]; -protected: + static int m_NetworkMouseButtonsEvents[4][3]; + static int m_NetworkMouseButtonsStates[4][3]; + static int m_PrevNetworkMouseButtonsStates[4][3]; - enum Constants - { - KEYBOARD_BUFFER_SIZE = 256 - }; - - // Keyboard buffer holding the key states - unsigned char m_KeyboardBuffer[KEYBOARD_BUFFER_SIZE]; - unsigned char m_ScanCodeState[KEYBOARD_BUFFER_SIZE]; - std::string m_TextInput; - bool m_HasTextInput; - - // Mouse button states - // Order: Left, Middle, Right - int m_MouseButtonsEvents[3]; - int m_MouseButtonsStates[3]; + static bool m_OverrideInput; - static int m_NetworkMouseButtonsEvents[4][3]; - static int m_NetworkMouseButtonsStates[4][3]; - static int m_PrevNetworkMouseButtonsStates[4][3]; + int m_MouseX; + int m_MouseY; + int m_LastFrameMouseX; + int m_LastFrameMouseY; - static bool m_OverrideInput; + static int m_NetworkMouseX[4]; + static int m_NetworkMouseY[4]; - int m_MouseX; - int m_MouseY; - int m_LastFrameMouseX; - int m_LastFrameMouseY; + int m_Player; - static int m_NetworkMouseX[4]; - static int m_NetworkMouseY[4]; + int m_MouseWheelChange; //!< the amount and direction that the mouse wheel has moved. - int m_Player; + // These offset the mouse positions so that the cursor is shifted for all events + int m_MouseOffsetX; + int m_MouseOffsetY; - int m_MouseWheelChange; //!< the amount and direction that the mouse wheel has moved. + int m_Modifier; - // These offset the mouse positions so that the cursor is shifted for all events - int m_MouseOffsetX; - int m_MouseOffsetY; - - int m_Modifier; - - // Whether the keyboard and joysticks also control the mouse - bool m_KeyJoyMouseCursor; -}; -}; + // Whether the keyboard and joysticks also control the mouse + bool m_KeyJoyMouseCursor; + }; +}; // namespace RTE #endif diff --git a/Source/GUI/GUIInterface.h b/Source/GUI/GUIInterface.h index 718b5f530..6651320f1 100644 --- a/Source/GUI/GUIInterface.h +++ b/Source/GUI/GUIInterface.h @@ -14,7 +14,6 @@ namespace RTE { class GUIBitmap { public: - #pragma region Creation /// /// Constructor method used to instantiate a GUIBitmap object in system memory. @@ -45,13 +44,13 @@ namespace RTE { /// Gets the underlying BITMAP of this GUIBitmap. /// /// The underlying BITMAP of this GUIBitmap. - virtual BITMAP * GetBitmap() const = 0; + virtual BITMAP* GetBitmap() const = 0; /// /// Sets the underlying BITMAP for this GUIBitmap. /// /// A pointer to the new BITMAP for this GUIBitmap. - virtual void SetBitmap(BITMAP *newBitmap) = 0; + virtual void SetBitmap(BITMAP* newBitmap) = 0; /// /// Gets the width of the bitmap. @@ -104,19 +103,19 @@ namespace RTE { /// Gets the clipping rectangle of the bitmap. /// /// Pointer to a GUIRect to fill out. - virtual void GetClipRect(GUIRect *clippingRect) const = 0; + virtual void GetClipRect(GUIRect* clippingRect) const = 0; /// /// Sets the clipping rectangle of the bitmap. /// /// Pointer to a GUIRect to use as the clipping rectangle, or nullptr for no clipping. - virtual void SetClipRect(GUIRect *clippingRect) = 0; + virtual void SetClipRect(GUIRect* clippingRect) = 0; /// - /// Sets the clipping rectangle of the specified bitmap as the intersection of its current clipping rectangle and the rectangle described by the passed-in GUIRect. + /// Sets the clipping rectangle of the specified bitmap as the intersection of its current clipping rectangle and the rectangle described by the passed-in GUIRect. /// /// Rectangle pointer. - virtual void AddClipRect(GUIRect *rect) = 0; + virtual void AddClipRect(GUIRect* rect) = 0; #pragma endregion #pragma region Drawing @@ -127,7 +126,7 @@ namespace RTE { /// Destination X position. /// Destination Y position. /// Source bitmap position and size rectangle. - virtual void Draw(GUIBitmap *destBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) = 0; + virtual void Draw(GUIBitmap* destBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) = 0; /// /// Draw a section of this bitmap onto another bitmap ignoring color-keyed pixels. @@ -136,7 +135,7 @@ namespace RTE { /// Destination X position. /// Destination Y position. /// Source bitmap position and size rectangle. - virtual void DrawTrans(GUIBitmap *destBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) = 0; + virtual void DrawTrans(GUIBitmap* destBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) = 0; /// /// Draw this bitmap scaled onto another bitmap ignoring color-keyed pixels. @@ -146,7 +145,7 @@ namespace RTE { /// Destination Y position. /// Target width of the bitmap. /// Target height of the bitmap. - virtual void DrawTransScaled(GUIBitmap *destBitmap, int destX, int destY, int width, int height) = 0; + virtual void DrawTransScaled(GUIBitmap* destBitmap, int destX, int destY, int width, int height) = 0; #pragma endregion #pragma region Primitive Drawing @@ -173,7 +172,7 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - GUIBitmap & operator=(const GUIBitmap &rhs) = delete; + GUIBitmap& operator=(const GUIBitmap& rhs) = delete; }; #pragma endregion @@ -184,7 +183,6 @@ namespace RTE { class GUIScreen { public: - #pragma region Creation /// /// Constructor method used to instantiate a GUIScreen object in system memory. @@ -196,7 +194,7 @@ namespace RTE { /// /// File name to create bitmap from. /// Pointer to the created bitmap. - virtual GUIBitmap * CreateBitmap(const std::string &fileName) = 0; + virtual GUIBitmap* CreateBitmap(const std::string& fileName) = 0; /// /// Creates an empty bitmap. @@ -204,7 +202,7 @@ namespace RTE { /// Bitmap width. /// Bitmap height. /// Pointer to the created bitmap. - virtual GUIBitmap * CreateBitmap(int width, int height) = 0; + virtual GUIBitmap* CreateBitmap(int width, int height) = 0; #pragma endregion #pragma region Destruction @@ -224,7 +222,7 @@ namespace RTE { /// Gets the bitmap representing the screen. /// /// Pointer to the bitmap representing the screen. - virtual GUIBitmap * GetBitmap() const = 0; + virtual GUIBitmap* GetBitmap() const = 0; #pragma endregion #pragma region Pure Virtual Methods @@ -235,7 +233,7 @@ namespace RTE { /// Destination X position /// Destination Y position /// Source bitmap position and size rectangle. - virtual void DrawBitmap(GUIBitmap *guiBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) = 0; + virtual void DrawBitmap(GUIBitmap* guiBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) = 0; /// /// Draws a bitmap onto the back buffer ignoring color-keyed pixels. @@ -244,7 +242,7 @@ namespace RTE { /// Destination X position /// Destination Y position /// Source bitmap position and size rectangle. - virtual void DrawBitmapTrans(GUIBitmap *guiBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) = 0; + virtual void DrawBitmapTrans(GUIBitmap* guiBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) = 0; /// /// Converts an 8bit palette index to a valid pixel format color. @@ -256,8 +254,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - GUIScreen & operator=(const GUIScreen &rhs) = delete; + GUIScreen& operator=(const GUIScreen& rhs) = delete; }; #pragma endregion -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/GUI/GUILabel.cpp b/Source/GUI/GUILabel.cpp index 72ff03641..96e9b8e6c 100644 --- a/Source/GUI/GUILabel.cpp +++ b/Source/GUI/GUILabel.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUILabel::GUILabel(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUILabel::GUILabel(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "LABEL"; m_ControlManager = ControlManager; m_Font = nullptr; @@ -21,7 +22,7 @@ GUILabel::GUILabel(GUIManager *Manager, GUIControlManager *ControlManager) : GUI ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUILabel::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUILabel::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -38,8 +39,12 @@ void GUILabel::Create(const std::string &Name, int X, int Y, int Width, int Heig m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the label isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -48,7 +53,7 @@ void GUILabel::Create(const std::string &Name, int X, int Y, int Width, int Heig ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUILabel::Create(GUIProperties *Props) { +void GUILabel::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -71,14 +76,26 @@ void GUILabel::Create(GUIProperties *Props) { std::string alignString; Props->GetValue("HAlignment", &alignString); - if (stricmp(alignString.c_str(), "left") == 0) { m_HAlignment = GUIFont::Left; } - if (stricmp(alignString.c_str(), "centre") == 0 || stricmp(alignString.c_str(), "center") == 0) { m_HAlignment = GUIFont::Centre; } - if (stricmp(alignString.c_str(), "right") == 0) { m_HAlignment = GUIFont::Right; } + if (stricmp(alignString.c_str(), "left") == 0) { + m_HAlignment = GUIFont::Left; + } + if (stricmp(alignString.c_str(), "centre") == 0 || stricmp(alignString.c_str(), "center") == 0) { + m_HAlignment = GUIFont::Centre; + } + if (stricmp(alignString.c_str(), "right") == 0) { + m_HAlignment = GUIFont::Right; + } Props->GetValue("VAlignment", &alignString); - if (stricmp(alignString.c_str(), "top") == 0) { m_VAlignment = GUIFont::Top; } - if (stricmp(alignString.c_str(), "middle") == 0) { m_VAlignment = GUIFont::Middle; } - if (stricmp(alignString.c_str(), "bottom") == 0) { m_VAlignment = GUIFont::Bottom; } + if (stricmp(alignString.c_str(), "top") == 0) { + m_VAlignment = GUIFont::Top; + } + if (stricmp(alignString.c_str(), "middle") == 0) { + m_VAlignment = GUIFont::Middle; + } + if (stricmp(alignString.c_str(), "bottom") == 0) { + m_VAlignment = GUIFont::Bottom; + } Props->GetValue("HorizontalOverflowScroll", &m_HorizontalOverflowScroll); Props->GetValue("VerticalOverflowScroll", &m_VerticalOverflowScroll); @@ -86,7 +103,7 @@ void GUILabel::Create(GUIProperties *Props) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUILabel::ChangeSkin(GUISkin *Skin) { +void GUILabel::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Load the font @@ -103,14 +120,14 @@ void GUILabel::ChangeSkin(GUISkin *Skin) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUILabel::Draw(GUIScreen *Screen) { +void GUILabel::Draw(GUIScreen* Screen) { Draw(Screen->GetBitmap()); GUIPanel::Draw(Screen); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUILabel::Draw(GUIBitmap *Bitmap, bool overwiteFontColorAndKerning) { +void GUILabel::Draw(GUIBitmap* Bitmap, bool overwiteFontColorAndKerning) { // Setup the clipping Bitmap->AddClipRect(GetRect()); @@ -156,8 +173,8 @@ void GUILabel::Draw(GUIBitmap *Bitmap, bool overwiteFontColorAndKerning) { break; case OverflowScrollState::Scrolling: if (m_OverflowScrollTimer.GetRealTimeLimitMS() == -1) { - //TODO Maybe time limits should account for extra size vs width, so it scrolls slower on small labels, since it can be harder to read fast text on smaller areas. I think it's fine as-is though. - // Note - time limits set so 5 characters of fatfont horizontal overflow or one line of fatfont vertical overflow will take 1 second. + // TODO Maybe time limits should account for extra size vs width, so it scrolls slower on small labels, since it can be harder to read fast text on smaller areas. I think it's fine as-is though. + // Note - time limits set so 5 characters of fatfont horizontal overflow or one line of fatfont vertical overflow will take 1 second. if (modifyXPos) { m_OverflowScrollTimer.SetRealTimeLimitMS((1000.0 / 30.0) * static_cast(textFullWidth - m_Width)); } else if (modifyYPos) { @@ -208,14 +225,16 @@ void GUILabel::OnMouseDown(int X, int Y, int Buttons, int Modifier) { void GUILabel::OnMouseUp(int X, int Y, int Buttons, int Modifier) { // If the mouse is over the button, add the clicked notification to the event queue - if (PointInside(X, Y) && (Buttons & MOUSE_LEFT) && IsCaptured()) { AddEvent(GUIEvent::Notification, Clicked, Buttons); } + if (PointInside(X, Y) && (Buttons & MOUSE_LEFT) && IsCaptured()) { + AddEvent(GUIEvent::Notification, Clicked, Buttons); + } ReleaseMouse(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUILabel::GetPanel() { +GUIPanel* GUILabel::GetPanel() { return this; } @@ -246,7 +265,7 @@ int GUILabel::ResizeHeightToFit() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUILabel::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUILabel::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -312,21 +331,33 @@ void GUILabel::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUILabel::ApplyProperties(GUIProperties *Props) { +void GUILabel::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); m_Properties.GetValue("Text", &m_Text); std::string alignString; m_Properties.GetValue("HAlignment", &alignString); - if (stricmp(alignString.c_str(), "left") == 0) { m_HAlignment = GUIFont::Left; } - if (stricmp(alignString.c_str(), "centre") == 0) { m_HAlignment = GUIFont::Centre; } - if (stricmp(alignString.c_str(), "right") == 0) { m_HAlignment = GUIFont::Right; } + if (stricmp(alignString.c_str(), "left") == 0) { + m_HAlignment = GUIFont::Left; + } + if (stricmp(alignString.c_str(), "centre") == 0) { + m_HAlignment = GUIFont::Centre; + } + if (stricmp(alignString.c_str(), "right") == 0) { + m_HAlignment = GUIFont::Right; + } m_Properties.GetValue("VAlignment", &alignString); - if (stricmp(alignString.c_str(), "top") == 0) { m_VAlignment = GUIFont::Top; } - if (stricmp(alignString.c_str(), "middle") == 0) { m_VAlignment = GUIFont::Middle; } - if (stricmp(alignString.c_str(), "bottom") == 0) { m_VAlignment = GUIFont::Bottom; } + if (stricmp(alignString.c_str(), "top") == 0) { + m_VAlignment = GUIFont::Top; + } + if (stricmp(alignString.c_str(), "middle") == 0) { + m_VAlignment = GUIFont::Middle; + } + if (stricmp(alignString.c_str(), "bottom") == 0) { + m_VAlignment = GUIFont::Bottom; + } m_Properties.GetValue("HorizontalOverflowScroll", &m_HorizontalOverflowScroll); m_Properties.GetValue("VerticalOverflowScroll", &m_VerticalOverflowScroll); diff --git a/Source/GUI/GUILabel.h b/Source/GUI/GUILabel.h index d6d7c1ddd..fe2daa4c0 100644 --- a/Source/GUI/GUILabel.h +++ b/Source/GUI/GUILabel.h @@ -7,286 +7,262 @@ namespace RTE { -/// -/// A label control class. -/// -class GUILabel : public GUIControl, public GUIPanel { - -public: - - // Label Notifications - enum { - Clicked = 0, - } Notification; - - enum class OverflowScrollState { - Deactivated = 0, - WaitAtStart, - Scrolling, - WaitAtEnd - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUILabel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUILabel object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUILabel(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - /// - /// Draws the Label to the given GUIBitmap. - /// - /// The GUIBitmap to draw the label to. - /// Whether to overwrite the font's color and kerning with the stored values. Defaults to true, which is usually what you want. - void Draw(GUIBitmap *Bitmap, bool overwiteFontColorAndKerning = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "LABEL"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ResizeHeightToFit -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resize the height of the label to fit the amount of text it has to -// display. -// Arguments: None. -// Returns: The new height in pixels. - - int ResizeHeightToFit(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the text of the label. -// Arguments: text. - - void SetText(const std::string_view &text) { m_Text = text; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the text of the label. -// Arguments: None. - - const std::string & GetText() const { return m_Text; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTextHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows how tall the current text is with the current width and font etc. -// Arguments: None. -// Returns: The text height, in pixels - - int GetTextHeight(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetHAlignment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the horizontal alignment of the text of this label. -// Arguments: The desired alignment. - - void SetHAlignment(int HAlignment = GUIFont::Left) { m_HAlignment = HAlignment; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetVAlignment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the vertical alignment of the text of this label. -// Arguments: The desired alignment. - - void SetVAlignment(int VAlignment = GUIFont::Top) { m_VAlignment = VAlignment; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetHAlignment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the horizontal alignment of the text of this label. -// Arguments: None. - - int GetHAlignment() const { return m_HAlignment; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetVAlignment -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the vertical alignment of the text of this label. -// Arguments: The desired alignment. - - int GetVAlignment() const { return m_VAlignment; } - - /// - /// Gets whether or not this GUILabel should scroll horizontally (right) when it overflows. - /// - /// Whether or not this GUILabel should scroll horizontally when it overflows. - bool GetHorizontalOverflowScroll() const { return m_HorizontalOverflowScroll; } - - /// - /// Sets whether or not this GUILabel should scroll horizontally (right) when it overflows. Mutually exclusive with horizontal overflow scrolling. - /// - /// Whether or not this GUILabel should scroll horizontally when it overflows. - void SetHorizontalOverflowScroll(bool newOverflowScroll); - - /// - /// Gets whether or not this GUILabel should scroll vertically (down) when it overflows. - /// - /// Whether or not this GUILabel should scroll vertically when it overflows. - bool GetVerticalOverflowScroll() const { return m_VerticalOverflowScroll; } - - /// - /// Sets whether or not this GUILabel should scroll vertically (down) when it overflows. Mutually exclusive with horizontal overflow scrolling. - /// - /// Whether or not this GUILabel should scroll vertically when it overflows. - void SetVerticalOverflowScroll(bool newOverflowScroll); - - /// - /// Gets whether or not horizontal or vertical overflow scrolling is turned on. - /// - /// Whether or not horizontal or vertical overflow scrolling is turned on. - bool OverflowScrollIsEnabled() const { return m_HorizontalOverflowScroll || m_VerticalOverflowScroll; } - - /// - /// Gets whether or not horizontal/vertical scrolling is happening. - /// - /// Whether or not horizontal/vertical scrolling is happening. - bool OverflowScrollIsActivated() const { return OverflowScrollIsEnabled() && m_OverflowScrollState != OverflowScrollState::Deactivated; } - - /// - /// Sets whether or not horizontal/vertical scrolling should be happening. When it's deactivated, text will instantly go back to un-scrolled. - /// - /// Whether the overflow scrolling should activate (true) or deactivate (false). - void ActivateDeactivateOverflowScroll(bool activateScroll); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - - std::string m_Text; - int m_HAlignment; - int m_VAlignment; - bool m_HorizontalOverflowScroll; //!< Note that horizontal overflow scrolling means text will always be on one line. - bool m_VerticalOverflowScroll; - OverflowScrollState m_OverflowScrollState; - Timer m_OverflowScrollTimer; -}; -}; -#endif \ No newline at end of file + /// + /// A label control class. + /// + class GUILabel : public GUIControl, public GUIPanel { + + public: + // Label Notifications + enum { + Clicked = 0, + } Notification; + + enum class OverflowScrollState { + Deactivated = 0, + WaitAtStart, + Scrolling, + WaitAtEnd + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUILabel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUILabel object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUILabel(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + /// + /// Draws the Label to the given GUIBitmap. + /// + /// The GUIBitmap to draw the label to. + /// Whether to overwrite the font's color and kerning with the stored values. Defaults to true, which is usually what you want. + void Draw(GUIBitmap* Bitmap, bool overwiteFontColorAndKerning = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "LABEL"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResizeHeightToFit + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resize the height of the label to fit the amount of text it has to + // display. + // Arguments: None. + // Returns: The new height in pixels. + + int ResizeHeightToFit(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the text of the label. + // Arguments: text. + + void SetText(const std::string_view& text) { m_Text = text; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the text of the label. + // Arguments: None. + + const std::string& GetText() const { return m_Text; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTextHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows how tall the current text is with the current width and font etc. + // Arguments: None. + // Returns: The text height, in pixels + + int GetTextHeight(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetHAlignment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the horizontal alignment of the text of this label. + // Arguments: The desired alignment. + + void SetHAlignment(int HAlignment = GUIFont::Left) { m_HAlignment = HAlignment; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetVAlignment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the vertical alignment of the text of this label. + // Arguments: The desired alignment. + + void SetVAlignment(int VAlignment = GUIFont::Top) { m_VAlignment = VAlignment; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetHAlignment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the horizontal alignment of the text of this label. + // Arguments: None. + + int GetHAlignment() const { return m_HAlignment; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetVAlignment + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the vertical alignment of the text of this label. + // Arguments: The desired alignment. + + int GetVAlignment() const { return m_VAlignment; } + + /// + /// Gets whether or not this GUILabel should scroll horizontally (right) when it overflows. + /// + /// Whether or not this GUILabel should scroll horizontally when it overflows. + bool GetHorizontalOverflowScroll() const { return m_HorizontalOverflowScroll; } + + /// + /// Sets whether or not this GUILabel should scroll horizontally (right) when it overflows. Mutually exclusive with horizontal overflow scrolling. + /// + /// Whether or not this GUILabel should scroll horizontally when it overflows. + void SetHorizontalOverflowScroll(bool newOverflowScroll); + + /// + /// Gets whether or not this GUILabel should scroll vertically (down) when it overflows. + /// + /// Whether or not this GUILabel should scroll vertically when it overflows. + bool GetVerticalOverflowScroll() const { return m_VerticalOverflowScroll; } + + /// + /// Sets whether or not this GUILabel should scroll vertically (down) when it overflows. Mutually exclusive with horizontal overflow scrolling. + /// + /// Whether or not this GUILabel should scroll vertically when it overflows. + void SetVerticalOverflowScroll(bool newOverflowScroll); + + /// + /// Gets whether or not horizontal or vertical overflow scrolling is turned on. + /// + /// Whether or not horizontal or vertical overflow scrolling is turned on. + bool OverflowScrollIsEnabled() const { return m_HorizontalOverflowScroll || m_VerticalOverflowScroll; } + + /// + /// Gets whether or not horizontal/vertical scrolling is happening. + /// + /// Whether or not horizontal/vertical scrolling is happening. + bool OverflowScrollIsActivated() const { return OverflowScrollIsEnabled() && m_OverflowScrollState != OverflowScrollState::Deactivated; } + + /// + /// Sets whether or not horizontal/vertical scrolling should be happening. When it's deactivated, text will instantly go back to un-scrolled. + /// + /// Whether the overflow scrolling should activate (true) or deactivate (false). + void ActivateDeactivateOverflowScroll(bool activateScroll); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; + + private: + std::string m_Text; + int m_HAlignment; + int m_VAlignment; + bool m_HorizontalOverflowScroll; //!< Note that horizontal overflow scrolling means text will always be on one line. + bool m_VerticalOverflowScroll; + OverflowScrollState m_OverflowScrollState; + Timer m_OverflowScrollTimer; + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIListBox.cpp b/Source/GUI/GUIListBox.cpp index 5ac9c5870..bea873ea2 100644 --- a/Source/GUI/GUIListBox.cpp +++ b/Source/GUI/GUIListBox.cpp @@ -5,14 +5,15 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIListBox::GUIListBox(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIListPanel(Manager) { +GUIListBox::GUIListBox(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIListPanel(Manager) { m_ControlID = "LISTBOX"; m_ControlManager = ControlManager; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListBox::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIListBox::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -26,8 +27,12 @@ void GUIListBox::Create(const std::string &Name, int X, int Y, int Width, int He // Create the ListPanel int w = m_DefWidth; int h = m_DefHeight; - if (Width != -1) { w = Width; } - if (Height != -1) { h = Height; } + if (Width != -1) { + w = Width; + } + if (Height != -1) { + h = Height; + } // Make sure the control isn't too small w = std::max(w, m_MinWidth); @@ -38,7 +43,7 @@ void GUIListBox::Create(const std::string &Name, int X, int Y, int Width, int He ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListBox::Create(GUIProperties *Props) { +void GUIListBox::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -72,7 +77,7 @@ void GUIListBox::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListBox::ChangeSkin(GUISkin *Skin) { +void GUIListBox::ChangeSkin(GUISkin* Skin) { GUIListPanel::ChangeSkin(Skin); } @@ -94,13 +99,13 @@ void GUIListBox::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIListBox::GetPanel() { +GUIPanel* GUIListBox::GetPanel() { return this; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListBox::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIListBox::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIListPanel::GetRect(X, Y, Width, Height); } @@ -112,7 +117,7 @@ void GUIListBox::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListBox::ReceiveSignal(GUIPanel *Source, int Code, int Data) { +void GUIListBox::ReceiveSignal(GUIPanel* Source, int Code, int Data) { if (Source->GetPanelID() == GetPanelID()) { if (Code == GUIListPanel::MouseMove) { AddEvent(GUIEvent::Notification, MouseMove, Data); @@ -140,7 +145,7 @@ void GUIListBox::ReceiveSignal(GUIPanel *Source, int Code, int Data) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListBox::ApplyProperties(GUIProperties *Props) { +void GUIListBox::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); bool Multi = false; @@ -149,4 +154,4 @@ void GUIListBox::ApplyProperties(GUIProperties *Props) { // Rebuild the bitmap BuildBitmap(true, true); -} \ No newline at end of file +} diff --git a/Source/GUI/GUIListBox.h b/Source/GUI/GUIListBox.h index 4b496d551..e771887dc 100644 --- a/Source/GUI/GUIListBox.h +++ b/Source/GUI/GUIListBox.h @@ -5,133 +5,119 @@ namespace RTE { -/// -/// A ListBox control class. -/// -class GUIListBox : public GUIControl, public GUIListPanel { + /// + /// A ListBox control class. + /// + class GUIListBox : public GUIControl, public GUIListPanel { + + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIListBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIListBox object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUIListBox(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "LISTBOX"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReceiveSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when receiving a signal. + // Arguments: Signal source, Signal code, Signal data. + + void ReceiveSignal(GUIPanel* Source, int Code, int Data) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. -public: + void ApplyProperties(GUIProperties* Props) override; -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIListBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIListBox object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUIListBox(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "LISTBOX"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReceiveSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when receiving a signal. -// Arguments: Signal source, Signal code, Signal data. - - void ReceiveSignal(GUIPanel *Source, int Code, int Data) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - -}; -}; -#endif \ No newline at end of file + private: + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIListPanel.cpp b/Source/GUI/GUIListPanel.cpp index ed9b0fb66..25df8db1d 100644 --- a/Source/GUI/GUIListPanel.cpp +++ b/Source/GUI/GUIListPanel.cpp @@ -7,7 +7,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIListPanel::GUIListPanel(GUIManager *Manager) : GUIPanel(Manager) { +GUIListPanel::GUIListPanel(GUIManager* Manager) : + GUIPanel(Manager) { m_BaseBitmap = nullptr; m_DrawBitmap = nullptr; m_FrameBitmap = nullptr; @@ -37,7 +38,8 @@ GUIListPanel::GUIListPanel(GUIManager *Manager) : GUIPanel(Manager) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIListPanel::GUIListPanel() : GUIPanel() { +GUIListPanel::GUIListPanel() : + GUIPanel() { m_BaseBitmap = nullptr; m_DrawBitmap = nullptr; m_FrameBitmap = nullptr; @@ -100,15 +102,16 @@ void GUIListPanel::Create(int X, int Y, int Width, int Height) { void GUIListPanel::Destroy() { // Destroy the items - std::vector::iterator it; + std::vector::iterator it; for (it = m_Items.begin(); it != m_Items.end(); it++) { - Item *I = *it; - if (I) { delete I; } + Item* I = *it; + if (I) { + delete I; + } } m_Items.clear(); - // Destroy the horizontal scroll panel if (m_HorzScroll) { m_HorzScroll->Destroy(); @@ -149,11 +152,13 @@ void GUIListPanel::Destroy() { void GUIListPanel::ClearList() { // Destroy the items - std::vector::iterator it; + std::vector::iterator it; for (it = m_Items.begin(); it != m_Items.end(); it++) { - Item *I = *it; - if (I) { delete I; } + Item* I = *it; + if (I) { + delete I; + } } m_Items.clear(); @@ -169,8 +174,8 @@ void GUIListPanel::ClearList() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListPanel::AddItem(const std::string &Name, const std::string &rightText, GUIBitmap *pBitmap, const Entity *pEntity, const int extraIndex, const int offsetX) { - Item *I = new Item; +void GUIListPanel::AddItem(const std::string& Name, const std::string& rightText, GUIBitmap* pBitmap, const Entity* pEntity, const int extraIndex, const int offsetX) { + Item* I = new Item; I->m_Name = Name; I->m_RightText = rightText; I->m_ExtraIndex = extraIndex; @@ -198,7 +203,7 @@ void GUIListPanel::AddItem(const std::string &Name, const std::string &rightText ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListPanel::ChangeSkin(GUISkin *Skin) { +void GUIListPanel::ChangeSkin(GUISkin* Skin) { assert(Skin); m_Skin = Skin; @@ -290,10 +295,12 @@ void GUIListPanel::BuildBitmap(bool UpdateBase, bool UpdateText) { void GUIListPanel::BuildDrawBitmap() { // Draw the items - std::vector::iterator it; + std::vector::iterator it; int Count = 0; int Height = m_Height; - if (m_HorzScroll->_GetVisible()) { Height -= m_HorzScroll->GetHeight(); } + if (m_HorzScroll->_GetVisible()) { + Height -= m_HorzScroll->GetHeight(); + } int x = m_HorzScroll->GetValue(); int y = 1 + (m_VertScroll->_GetVisible() ? -m_VertScroll->GetValue() : 0); @@ -308,7 +315,7 @@ void GUIListPanel::BuildDrawBitmap() { continue; } - Item *I = *it; + Item* I = *it; int itemX = x - I->m_OffsetX; int itemY = y; @@ -319,7 +326,7 @@ void GUIListPanel::BuildDrawBitmap() { // Alternate drawing mode // TODO: REMOVE MORE H-CODING if (m_AlternateDrawMode) { - int rightTextWidth = I->m_RightText.empty() ? 0 : RIGHTTEXTWIDTH;//thirdWidth / 2; + int rightTextWidth = I->m_RightText.empty() ? 0 : RIGHTTEXTWIDTH; // thirdWidth / 2; int mainTextWidth = ((thirdWidth * 2) - rightTextWidth) - I->m_OffsetX; int bitmapWidth = I->m_pBitmap ? I->m_pBitmap->GetWidth() : 0; int bitmapHeight = I->m_pBitmap ? I->m_pBitmap->GetHeight() : 0; @@ -366,7 +373,9 @@ void GUIListPanel::BuildDrawBitmap() { } // Draw another line to make sure the last item has two - if (it == m_Items.end() - 1) { m_DrawBitmap->DrawLine(4, itemY + itemHeight + 1, m_Width - 5, itemY + itemHeight + 1, m_UnselectedColorIndex); } + if (it == m_Items.end() - 1) { + m_DrawBitmap->DrawLine(4, itemY + itemHeight + 1, m_Width - 5, itemY + itemHeight + 1, m_UnselectedColorIndex); + } // Save the item height for later use in selection routines etc I->m_Height = itemHeight; @@ -403,7 +412,7 @@ void GUIListPanel::BuildDrawBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListPanel::Draw(GUIScreen *Screen) { +void GUIListPanel::Draw(GUIScreen* Screen) { // Draw the base m_DrawBitmap->Draw(Screen->GetBitmap(), m_X, m_Y, nullptr); @@ -446,7 +455,7 @@ void GUIListPanel::OnMouseWheelChange(int x, int y, int modifier, int mouseWheel } else if ((PointInsideList(x, y) && !m_MultiSelect) || (m_VertScroll->_GetVisible() && m_VertScroll->PointInside(x, y))) { ScrollBarScrolling(mouseWheelChange); } - + if (m_HotTracking && GetItem(x, y) != nullptr && (GetItem(x, y) != GetSelected())) { SelectItem(x, y, modifier); } @@ -455,7 +464,7 @@ void GUIListPanel::OnMouseWheelChange(int x, int y, int modifier, int mouseWheel ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIListPanel::SelectItem(int X, int Y, int Modifier) { - std::vector::iterator it; + std::vector::iterator it; bool Shift = Modifier & MODI_SHIFT; bool Ctrl = Modifier & MODI_CTRL; @@ -472,34 +481,36 @@ void GUIListPanel::SelectItem(int X, int Y, int Modifier) { // Clear the selected items if (ClearSelected) { for (it = m_Items.begin(); it != m_Items.end(); it++) { - Item *I = *it; + Item* I = *it; I->m_Selected = false; } m_SelectedList.clear(); } int Height = m_Height; - if (m_HorzScroll->_GetVisible()) { Height -= m_HorzScroll->GetHeight(); } + if (m_HorzScroll->_GetVisible()) { + Height -= m_HorzScroll->GetHeight(); + } int y = m_Y + 1; if (m_VertScroll->_GetVisible()) y -= m_VertScroll->GetValue(); int Count = 0; - //int stackHeight = 0; + // int stackHeight = 0; for (it = m_Items.begin(); it != m_Items.end(); it++, Count++) { /* stackHeight += GetItemHeight(*it); // Only check the items after the scroll value if (m_VertScroll->_GetVisible() && m_VertScroll->GetValue() > y) { - y += GetItemHeight(*it); - continue; + y += GetItemHeight(*it); + continue; } if (Count < m_VertScroll->GetValue()) {continue;} */ - Item *I = *it; + Item* I = *it; // Select/Deselect the item under the mouse - //if (Y >= y && Y < y+m_Font->GetFontHeight()) { + // if (Y >= y && Y < y+m_Font->GetFontHeight()) { if (Y >= y && Y < y + GetItemHeight(I)) { // If CTRL is down and not shift, AND the item is already selected // Unselect it @@ -523,7 +534,9 @@ void GUIListPanel::SelectItem(int X, int Y, int Modifier) { I->m_Selected = true; m_SelectedList.push_back(I); SendSignal(Select, 0); - if (!Shift) { m_LastSelected = Count; } + if (!Shift) { + m_LastSelected = Count; + } } // Shift key down if (Shift) { @@ -534,19 +547,19 @@ void GUIListPanel::SelectItem(int X, int Y, int Modifier) { m_LastSelected = Count; } else { // Select a list of items - std::vector::iterator sel; + std::vector::iterator sel; int Num = 0; for (sel = m_Items.begin(); sel != m_Items.end(); sel++, Num++) { if (m_LastSelected <= Count) { if (Num >= m_LastSelected && Num <= Count) { - Item *SelItem = *sel; + Item* SelItem = *sel; SelItem->m_Selected = true; m_SelectedList.push_back(SelItem); SendSignal(Select, 0); } } else { if (Num >= Count && Num <= m_LastSelected) { - Item *SelItem = *sel; + Item* SelItem = *sel; SelItem->m_Selected = true; m_SelectedList.push_back(SelItem); SendSignal(Select, 0); @@ -558,7 +571,7 @@ void GUIListPanel::SelectItem(int X, int Y, int Modifier) { } break; } - //y += m_Font->GetFontHeight(); + // y += m_Font->GetFontHeight(); y += GetItemHeight(I); // End of viewable region @@ -578,8 +591,8 @@ void GUIListPanel::OnMouseUp(int X, int Y, int Buttons, int Modifier) { m_HorzScroll->OnMouseUp(X, Y, Buttons, Modifier); } else { if (PointInside(X, Y)) { - //SendSignal(Select, 0); - //} else { + // SendSignal(Select, 0); + //} else { SendSignal(MouseUp, Buttons); } } @@ -594,7 +607,9 @@ void GUIListPanel::OnMouseMove(int X, int Y, int Buttons, int Modifier) { m_HorzScroll->OnMouseMove(X, Y, Buttons, Modifier); } else if (PointInsideList(X, Y)) { // Using Hot-Tracking - if (m_HotTracking && GetItem(X, Y) != nullptr && (GetItem(X, Y) != GetSelected())) { SelectItem(X, Y, Modifier); } + if (m_HotTracking && GetItem(X, Y) != nullptr && (GetItem(X, Y) != GetSelected())) { + SelectItem(X, Y, Modifier); + } SendSignal(MouseMove, Buttons); } } @@ -614,7 +629,9 @@ void GUIListPanel::OnMouseLeave(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIListPanel::OnDoubleClick(int X, int Y, int Buttons, int Modifier) { - if (PointInside(X, Y)) { SendSignal(DoubleClick, Buttons); } + if (PointInside(X, Y)) { + SendSignal(DoubleClick, Buttons); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -634,13 +651,17 @@ void GUIListPanel::EndUpdate() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListPanel::ScrollToItem(Item *pItem) { +void GUIListPanel::ScrollToItem(Item* pItem) { if (pItem && m_VertScroll->_GetVisible()) { int stackHeight = GetStackHeight(pItem); int itemHeight = GetItemHeight(pItem); // Adjust the vertical scroll bar to show the specified item - if (stackHeight < m_VertScroll->GetValue()) { m_VertScroll->SetValue(stackHeight); } - if (stackHeight + itemHeight > m_VertScroll->GetValue() + m_VertScroll->GetPageSize()) { m_VertScroll->SetValue(stackHeight + itemHeight - m_VertScroll->GetPageSize()); } + if (stackHeight < m_VertScroll->GetValue()) { + m_VertScroll->SetValue(stackHeight); + } + if (stackHeight + itemHeight > m_VertScroll->GetValue() + m_VertScroll->GetPageSize()) { + m_VertScroll->SetValue(stackHeight + itemHeight - m_VertScroll->GetPageSize()); + } } BuildBitmap(false, true); } @@ -649,7 +670,9 @@ void GUIListPanel::ScrollToItem(Item *pItem) { void GUIListPanel::ScrollUp() { const int sensitivity = 80; - if (m_VertScroll->_GetVisible()) { m_VertScroll->SetValue(m_VertScroll->GetValue() - sensitivity); } + if (m_VertScroll->_GetVisible()) { + m_VertScroll->SetValue(m_VertScroll->GetValue() - sensitivity); + } BuildBitmap(false, true); } @@ -660,7 +683,7 @@ void GUIListPanel::ScrollDown() { if (m_VertScroll->_GetVisible()) { int scrollValueToAdd = sensitivity; if (!m_Items.empty()) { - RTE::GUIListPanel::Item *item = m_Items.back(); + RTE::GUIListPanel::Item* item = m_Items.back(); int maximumScrollDistance = GetStackHeight(item) + GetItemHeight(item) - (m_VertScroll->GetPageSize() + m_VertScroll->GetValue()); scrollValueToAdd = std::clamp(maximumScrollDistance, 0, scrollValueToAdd); } @@ -675,11 +698,13 @@ void GUIListPanel::ScrollTo(int position) { if (m_VertScroll->_GetVisible()) { m_VertScroll->SetValue(position); - //TODO this was copied from MaxShadow's work. I'm not quite sure of the point of it tbh. + // TODO this was copied from MaxShadow's work. I'm not quite sure of the point of it tbh. if (!m_Items.empty()) { - RTE::GUIListPanel::Item *item = m_Items.back(); + RTE::GUIListPanel::Item* item = m_Items.back(); int allItemsHeight = GetStackHeight(item) + GetItemHeight(item); - if (position + m_VertScroll->GetPageSize() > allItemsHeight) { m_VertScroll->SetValue(allItemsHeight - m_VertScroll->GetPageSize()); } + if (position + m_VertScroll->GetPageSize() > allItemsHeight) { + m_VertScroll->SetValue(allItemsHeight - m_VertScroll->GetPageSize()); + } } } BuildBitmap(false, true); @@ -781,8 +806,12 @@ void GUIListPanel::AdjustScrollbars() { if (!m_Font) { return; } - if (!m_HorzScrollEnabled) { m_HorzScroll->_SetVisible(false); } - if (!m_VertScrollEnabled) { m_VertScroll->_SetVisible(false); } + if (!m_HorzScrollEnabled) { + m_HorzScroll->_SetVisible(false); + } + if (!m_VertScrollEnabled) { + m_VertScroll->_SetVisible(false); + } // Re-adjust the scrollbar positions & sizes, just to be safe m_HorzScroll->SetPositionAbs(m_X + m_ScrollBarPadding, m_Y + m_Height - m_ScrollBarThickness - m_ScrollBarPadding); @@ -792,14 +821,16 @@ void GUIListPanel::AdjustScrollbars() { // If there are items wider than the listpanel, make the horizontal scrollpanel visible int Width = m_Width - 4; - if (m_VertScroll->_GetVisible()) { Width -= m_VertScroll->GetWidth(); } + if (m_VertScroll->_GetVisible()) { + Width -= m_VertScroll->GetWidth(); + } m_HorzScroll->_SetVisible(false); if (m_LargestWidth > Width && m_HorzScrollEnabled) { m_HorzScroll->_SetVisible(true); m_HorzScroll->SetMaximum(m_LargestWidth); m_HorzScroll->SetMinimum(0); m_HorzScroll->SetPageSize(Width); - m_HorzScroll->SetSmallChange(m_Font->CalculateWidth("W")); // W is one of the largest characters + m_HorzScroll->SetSmallChange(m_Font->CalculateWidth("W")); // W is one of the largest characters } if (m_Items.size() > 0) { @@ -809,9 +840,9 @@ void GUIListPanel::AdjustScrollbars() { int Height = m_Height - (m_HorzScroll->_GetVisible() ? m_HorzScroll->GetHeight() : 0); // TODO: remove the page subtraciton? - // Subtract the frame size + // Subtract the frame size int Page = Height - 4; - int Max = itemStackHeight/* - Page*/; + int Max = itemStackHeight /* - Page*/; Max = std::max(Max, 0); // Setup the vertical scrollbar @@ -820,7 +851,7 @@ void GUIListPanel::AdjustScrollbars() { m_VertScroll->SetMinimum(0); // m_VertScroll->SetSmallChange(itemHeight); - // If there is too many items, make the scrollbar visible + // If there is too many items, make the scrollbar visible m_VertScroll->_SetVisible(false); if (itemStackHeight > Height && m_VertScrollEnabled) { m_VertScroll->_SetVisible(true); @@ -834,7 +865,7 @@ void GUIListPanel::AdjustScrollbars() { m_HorzScroll->SetMaximum(m_LargestWidth); m_HorzScroll->SetMinimum(0); m_HorzScroll->SetPageSize(Width); - m_HorzScroll->SetSmallChange(m_Font->CalculateWidth("W")); // W is one of the largest characters + m_HorzScroll->SetSmallChange(m_Font->CalculateWidth("W")); // W is one of the largest characters } } } else { @@ -848,8 +879,12 @@ void GUIListPanel::AdjustScrollbars() { m_HorzScroll->SetSize(m_Width - m_VertScroll->GetWidth() - (m_ScrollBarPadding * 2), m_HorzScroll->GetHeight()); } else { // Normal size - if (m_VertScroll->_GetVisible()) { m_VertScroll->SetSize(m_VertScroll->GetWidth(), m_Height - (m_ScrollBarPadding * 2)); } - if (m_HorzScroll->_GetVisible()) { m_HorzScroll->SetSize(m_Width - (m_ScrollBarPadding * 2), m_HorzScroll->GetHeight()); } + if (m_VertScroll->_GetVisible()) { + m_VertScroll->SetSize(m_VertScroll->GetWidth(), m_Height - (m_ScrollBarPadding * 2)); + } + if (m_HorzScroll->_GetVisible()) { + m_HorzScroll->SetSize(m_Width - (m_ScrollBarPadding * 2), m_HorzScroll->GetHeight()); + } } } @@ -899,9 +934,9 @@ void GUIListPanel::OnKeyPress(int KeyCode, int Modifier) { } // Clear all the items - std::vector::iterator it; + std::vector::iterator it; for (it = m_Items.begin(); it != m_Items.end(); it++) { - Item *I = *it; + Item* I = *it; I->m_Selected = false; } m_SelectedList.clear(); @@ -910,9 +945,8 @@ void GUIListPanel::OnKeyPress(int KeyCode, int Modifier) { m_LastSelected = std::max(m_LastSelected, 0); m_LastSelected = std::min(m_LastSelected, static_cast(m_Items.size() - 1)); - // Select the new item - Item *I = m_Items[m_LastSelected]; + Item* I = m_Items[m_LastSelected]; I->m_Selected = true; m_SelectedList.push_back(I); SendSignal(Select, 0); @@ -937,7 +971,9 @@ void GUIListPanel::OnKeyDown(int KeyCode, int Modifier) { bool GUIListPanel::PointInsideList(int X, int Y) { bool inside = PointInside(X, Y); // Exclude the scrollbars if we are meant to - if (inside && m_HorzScroll->PointInside(X, Y) || m_VertScroll->PointInside(X, Y)) { inside = false; } + if (inside && m_HorzScroll->PointInside(X, Y) || m_VertScroll->PointInside(X, Y)) { + inside = false; + } return inside; } @@ -990,7 +1026,9 @@ void GUIListPanel::SetMultiSelect(bool MultiSelect) { m_MultiSelect = MultiSelect; // Multi-select & Hot-Tracking are mutually exclusive - if (m_MultiSelect) { m_HotTracking = false; } + if (m_MultiSelect) { + m_HotTracking = false; + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1005,12 +1043,14 @@ void GUIListPanel::SetHotTracking(bool HotTrack) { m_HotTracking = HotTrack; // Multi-select & Hot-Tracking are mutually exclusive - if (m_HotTracking) { m_MultiSelect = false; } + if (m_HotTracking) { + m_MultiSelect = false; + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIListPanel::Item * GUIListPanel::GetSelected() { +GUIListPanel::Item* GUIListPanel::GetSelected() { // Nothing in the list if (m_SelectedList.empty()) { return nullptr; @@ -1021,19 +1061,19 @@ GUIListPanel::Item * GUIListPanel::GetSelected() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -std::vector * GUIListPanel::GetSelectionList() { +std::vector* GUIListPanel::GetSelectionList() { return &m_SelectedList; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -std::vector * GUIListPanel::GetItemList() { +std::vector* GUIListPanel::GetItemList() { return &m_Items; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIListPanel::Item * GUIListPanel::GetItem(int Index) { +GUIListPanel::Item* GUIListPanel::GetItem(int Index) { if (Index >= 0 && Index < m_Items.size()) { return m_Items.at(Index); } @@ -1042,15 +1082,19 @@ GUIListPanel::Item * GUIListPanel::GetItem(int Index) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIListPanel::Item * GUIListPanel::GetItem(int X, int Y) { +GUIListPanel::Item* GUIListPanel::GetItem(int X, int Y) { int Height = m_Height; - if (m_HorzScroll->_GetVisible()) { Height -= m_HorzScroll->GetHeight(); } + if (m_HorzScroll->_GetVisible()) { + Height -= m_HorzScroll->GetHeight(); + } int y = m_Y + 1; - if (m_VertScroll->_GetVisible()) { y -= m_VertScroll->GetValue(); } + if (m_VertScroll->_GetVisible()) { + y -= m_VertScroll->GetValue(); + } int Count = 0; - for (std::vector::iterator it = m_Items.begin(); it != m_Items.end(); it++, Count++) { - Item *pItem = *it; + for (std::vector::iterator it = m_Items.begin(); it != m_Items.end(); it++, Count++) { + Item* pItem = *it; // Return the item under the mouse if (Y >= y && Y < y + GetItemHeight(pItem)) { @@ -1068,7 +1112,7 @@ GUIListPanel::Item * GUIListPanel::GetItem(int X, int Y) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int GUIListPanel::GetItemHeight(Item *pItem) { +int GUIListPanel::GetItemHeight(Item* pItem) { int height = 0; if (pItem && m_Font) { @@ -1078,7 +1122,7 @@ int GUIListPanel::GetItemHeight(Item *pItem) { } else if (m_AlternateDrawMode && pItem->m_pBitmap) { // Have to calculate the height if in advanced drawing mode, since the bitmap can be of different heights int thirdWidth = m_Width / 3; - int rightTextWidth = pItem->m_RightText.empty() ? 0 : RIGHTTEXTWIDTH;//thirdWidth / 2; + int rightTextWidth = pItem->m_RightText.empty() ? 0 : RIGHTTEXTWIDTH; // thirdWidth / 2; int mainTextWidth = (thirdWidth * 2) - rightTextWidth; int bitmapWidth = pItem->m_pBitmap ? pItem->m_pBitmap->GetWidth() : 0; int bitmapHeight = pItem->m_pBitmap ? pItem->m_pBitmap->GetHeight() : 0; @@ -1098,10 +1142,10 @@ int GUIListPanel::GetItemHeight(Item *pItem) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int GUIListPanel::GetStackHeight(Item *pItem) { +int GUIListPanel::GetStackHeight(Item* pItem) { int height = 0; - for (std::vector::iterator iitr = m_Items.begin(); iitr != m_Items.end(); ++iitr) { + for (std::vector::iterator iitr = m_Items.begin(); iitr != m_Items.end(); ++iitr) { if ((*iitr) == pItem) { break; } @@ -1112,8 +1156,10 @@ int GUIListPanel::GetStackHeight(Item *pItem) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIListPanel::SetItemValues(int Index, Item &item) { - if (Index >= 0 && Index < m_Items.size()) { *(m_Items.at(Index)) = item; } +void GUIListPanel::SetItemValues(int Index, Item& item) { + if (Index >= 0 && Index < m_Items.size()) { + *(m_Items.at(Index)) = item; + } BuildBitmap(false, true); } @@ -1125,7 +1171,7 @@ int GUIListPanel::GetSelectedIndex() { return -1; } // Get the first item - const Item *I = m_SelectedList.at(0); + const Item* I = m_SelectedList.at(0); return I->m_ID; } @@ -1134,16 +1180,16 @@ int GUIListPanel::GetSelectedIndex() { void GUIListPanel::SetSelectedIndex(int Index) { // Clear the old selection - std::vector::iterator it; + std::vector::iterator it; for (it = m_Items.begin(); it != m_Items.end(); it++) { - Item *I = *it; + Item* I = *it; I->m_Selected = false; } m_SelectedList.clear(); // Select the item if (Index >= 0 && Index < m_Items.size()) { - Item *I = m_Items.at(Index); + Item* I = m_Items.at(Index); I->m_Selected = true; m_SelectedList.push_back(I); SendSignal(Select, 0); @@ -1161,12 +1207,12 @@ void GUIListPanel::SetSelectedIndex(int Index) { void GUIListPanel::DeleteItem(int Index) { if (Index >= 0 && Index < m_Items.size()) { - const Item *I = m_Items.at(Index); + const Item* I = m_Items.at(Index); // If this item was selected, remove it from the selection list if (I->m_Selected) { // Find the item - std::vector::iterator it; + std::vector::iterator it; for (it = m_SelectedList.begin(); it != m_SelectedList.end(); it++) { if (I->m_ID == (*it)->m_ID) { m_SelectedList.erase(it); @@ -1180,10 +1226,10 @@ void GUIListPanel::DeleteItem(int Index) { m_Items.erase(m_Items.begin() + Index); // Reset the id's - std::vector::iterator it; + std::vector::iterator it; int Count = 0; for (it = m_Items.begin(); it != m_Items.end(); it++) { - Item *item = *it; + Item* item = *it; item->m_ID = Count++; } diff --git a/Source/GUI/GUIListPanel.h b/Source/GUI/GUIListPanel.h index ce972b594..d5cc21c78 100644 --- a/Source/GUI/GUIListPanel.h +++ b/Source/GUI/GUIListPanel.h @@ -4,613 +4,565 @@ #include "GUIScrollPanel.h" #include "GUIInterface.h" - namespace RTE { -class Entity; - -/// -/// A listbox panel class used for controls requiring a listbox. -/// -class GUIListPanel : public GUIPanel { - -public: - - // Signals - enum { - Click, // Mouse click. Not just inside the panel - MouseDown, // Mouse down inside the panel - MouseUp, // Mouse up inside the panel - Select, // Selected (on mouse down) an item - MouseMove, // Mouse moved over the panel - MouseEnter, // Mouse left the panel - MouseLeave, // Mouse left the panel - DoubleClick,// Double click - KeyDown, // Key Down - EdgeHit //!< Tried scrolling the selection past the first or last item. data = 0 for top edge, data = 1 for bottom edge. - } Signal; - - // Item structure - struct Item - { - int m_ID = 0; - std::string m_Name; - // Extra text field displayed right-justified in the item - std::string m_RightText; - // Extra index for special indexing or reference that the item is associated with. Menu-specific - int m_ExtraIndex = 0; - bool m_Selected = false; - // Can contain a bitmap to display in the list - // This is OWNED - GUIBitmap *m_pBitmap = nullptr; - // Extra data associated with the item - // This is NOT OWNED - const Entity *m_pEntity = nullptr; - int m_Height = 0; - // An x offset to apply to the item (to allow nesting) - int m_OffsetX = 0; - - Item() { } - ~Item() { delete m_pBitmap; m_pBitmap = 0; } - - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIListPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIListPanel object in -// system memory. -// Arguments: GUIManager. - - GUIListPanel(GUIManager *Manager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIListPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIListPanel object in -// system memory. -// Arguments: None. - - GUIListPanel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the listpanel -// Arguments: Position, Size. - - void Create(int X, int Y, int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel has been destroyed. -// Arguments: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Add an item to the list. -// Arguments: Name, extraText, Text which will be displayed right-justified in the item. -// a Bitmap object pointer alternatively pointing to a bitmap to display -// in the list. Ownership IS transferred! -// An Extra menu-specific index that this item may be associated with. -// Object instance associated with the item. Ownership is NOT TRANSFERRED! - - void AddItem(const std::string &Name, const std::string &rightText = "", GUIBitmap *pBitmap = nullptr, const Entity *pEntity = 0, const int extraIndex = -1, const int offsetX = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the list. -// Arguments: None. - - void ClearList(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseEnter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse enters the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseLeave -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse leaves the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnDoubleClick -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse has double-clicked on the pane. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnDoubleClick(int X, int Y, int Buttons, int Modifier) override; - - - /// - /// Called when the mouse scroll wheel is moved. - /// - /// Mouse X position. - /// Mouse Y position. - /// Activated modifier buttons. - /// The amount of wheel movement. Positive is scroll up, negative is scroll down. - void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnKeyPress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when a key is pressed (OnDown & repeating). -// Arguments: KeyCode, Modifier. - - void OnKeyPress(int KeyCode, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnKeyDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when a key goes down. -// Arguments: KeyCode, Modifier. - - void OnKeyDown(int KeyCode, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PointInsideList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if a point is inside the panel, but not on the scrollbars if -// they are visible -// Arguments: X, Y Coordinates of point -// Return value: A boolean of the check result - - bool PointInsideList(int X, int Y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnGainFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel gains focus. -// Arguments: None. - - void OnGainFocus() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnLoseFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel looses focus. -// Arguments: None. - - void OnLoseFocus() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReceiveSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when receiving a signal. -// Arguments: Signal source, Signal code, Signal data. - - void ReceiveSignal(GUIPanel *Source, int Code, int Data) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BeginUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Locks the control from updating every time a new item is added. -// Arguments: None. - - void BeginUpdate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EndUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: UnLocks the control from updating every time a new item is added. -// Will automatically update the control. -// Arguments: None. - - void EndUpdate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMultiSelect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the multi-selection value. -// Arguments: MultiSelect - - void SetMultiSelect(bool MultiSelect); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMultiSelect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the multi-selection value. -// Arguments: None. - - bool GetMultiSelect() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetHotTracking -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the hot tracking value. -// Arguments: HotTrack. - - void SetHotTracking(bool HotTrack); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelected -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the selected (or first in the selected list) item. -// Arguments: None. - - Item * GetSelected(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetItemList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the item list. -// Arguments: None. - - std::vector * GetItemList(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets an item at the index. -// Arguments: Index. - - Item * GetItem(int Index); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets an item at a specific absolute screen coordinate, if any. -// Arguments: The absolute screen coordinates to get the item from. - - Item * GetItem(int X, int Y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetItemHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the drawing height of the item passed in. -// Arguments: Pointer to the Item to get the height of. Ownership is NOT transferred! - - int GetItemHeight(Item *pItem); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetStackHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the height, in pixels, of the stack of items up to a specific one. -// E.g. If the specified one is the first (top) in the list, 0 is returned. -// If the second one is specified, the height of the first is returned. -// If the third is specified, the sum of the first and second items' heights -// is returned. If 0 is passed, the entire stack's height is returned. -// Arguments: Pointer to the Item to get the height up to. Ownership is NOT transferred! -// If 0 is passed, the entire stack's height is returned. - - int GetStackHeight(Item *pItem = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetScrollVerticalValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the scroll value, in pixels, of the vertical axis. -// Arguments: The scroll value in pixels. - - int GetScrollVerticalValue() const { return m_VertScroll->GetValue(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetItemValues -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the values of a specific Item. -// Arguments: Index and Item reference. - - void SetItemValues(int Index, Item &item); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelectedIndex -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the selected (or first in the selected list) index. -// Arguments: None. -// Returns: Index, or -1 if there is no items selected. - - int GetSelectedIndex(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSelectedIndex -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Selects the item at the index. -// Arguments: Index. - - void SetSelectedIndex(int Index); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetAlternateDrawMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Selects this to draw its items differently, with lines instead of -// rectangles, etc -// Arguments: The new mode setting. - - void SetAlternateDrawMode(bool enableAltDrawMode = true) { m_AlternateDrawMode = enableAltDrawMode; } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelectionList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the selection list. -// Arguments: None. - - std::vector * GetSelectionList(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DeleteItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Deletes an item at the index. -// Arguments: Index. - - void DeleteItem(int Index); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the size of the panel. -// Arguments: Width, Height. - - void SetSize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPositionAbs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the position of the panel. -// Arguments: X, Y. - - void SetPositionAbs(int X, int Y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnableScrollbars -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the enabled state of both scrollbars. -// Arguments: Horz, Vert - - void EnableScrollbars(bool Horizontal, bool Vertical); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ScrollToItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the vertical scrollbar to show the specific item in the list. -// Arguments: The item you want to show. - - void ScrollToItem(Item *pItem); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ScrollToSelected -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the vertical scrollbar to show the first selected item in the -// list. -// Arguments: None. - - void ScrollToSelected(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ScrollToTop -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the vertical scrollbar to show the top of the list -// Arguments: None. - - void ScrollToTop(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ScrollToBottom -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the vertical scrollbar to show the bottom of the list -// Arguments: None. - - void ScrollToBottom(); - - /// - /// Scrolls the GUIListPanel up. - /// - void ScrollUp(); - - /// - /// Scrolls the GUIListPanel down. - /// - void ScrollDown(); - - /// - /// Scrolls the the GUIListPanel to a specific position - /// - /// The position to scroll to. - void ScrollTo(int position); - - /// - /// Sets whether the scroll panel scrolls in a loop or not. - /// - /// True to scroll in a loop, false to scroll with edge stopping. - void SetSelectionScrollingLoop(bool scrollLoop); - - - /// - /// Sets whether the list panel can be scrolled with the mouse scroll wheel. - /// - /// True to enable scrolling, false to disable. - void SetMouseScrolling(bool mouseScroll); - - /// - /// Sets the thickness (width on vertical, height on horizontal) of the ListPanel's scroll bars and adjusts them to the new thickness. - /// - /// The new scroll bar thickness, in pixels. - void SetScrollBarThickness(int newThickness) { m_ScrollBarThickness = newThickness; AdjustScrollbars(); } - - /// - /// Sets the padding around the ListPanel's scrollbars and adjusts them to the new padding. Used to better size and position scrollbars within panel bounds, allowing to not overdraw on panel borders. - /// - /// The new scrollbar padding, in pixels. - void SetScrollBarPadding(int newPadding) { m_ScrollBarPadding = newPadding; AdjustScrollbars(); } - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: BuildBitmap - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Build the bitmap. - // Arguments: UpdateBase, UpdateText. - - void BuildBitmap(bool UpdateBase, bool UpdateText); - -private: - - GUISkin *m_Skin; - GUIBitmap *m_BaseBitmap; - GUIBitmap *m_DrawBitmap; - GUIBitmap *m_FrameBitmap; - unsigned long m_FontSelectColor; - - bool m_UpdateLocked; - - GUIScrollPanel *m_HorzScroll; - GUIScrollPanel *m_VertScroll; - bool m_HorzScrollEnabled; - bool m_VertScrollEnabled; - int m_ScrollBarThickness; //!< The thickness (width on vertical, height on horizontal) of the ListPanel's scroll bars, in pixels. - int m_ScrollBarPadding; //!< The padding around the scrollbars, in pixels. Used to better size and position scrollbars within panel bounds, allowing to not overdraw on panel borders. - - bool m_CapturedHorz; - bool m_CapturedVert; - bool m_ExternalCapture; - - int m_LargestWidth; - bool m_MultiSelect; - bool m_HotTracking; - int m_LastSelected; - bool m_LoopSelectionScroll; //!< Whether the list panel scrolls in a loop or not, while scrolling the selection list (as opposed to the scrollbar). - bool m_MouseScroll; //!< Whether the list panel enables scrolling with the mouse scroll wheel. - - bool m_AlternateDrawMode; // This draws items differently, not with boxes etc. - - std::vector m_Items; - std::vector m_SelectedList; - unsigned long m_SelectedColorIndex; - unsigned long m_UnselectedColorIndex; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildDrawBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Build the drawing bitmap. -// Arguments: None. - - void BuildDrawBitmap(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AdjustScrollbars -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the scrollbars. -// Arguments: None. - - void AdjustScrollbars(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SelectItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Selects an item based on mouse position. -// Arguments: Mouse Position, Modifier. - - void SelectItem(int X, int Y, int Modifier); - - - /// - /// Perform list scrolling through the scrollbar. - /// - /// Amount and direction of scrolling. Positive to scroll up, negative to scroll down. - void ScrollBarScrolling(int mouseWheelChange); - + class Entity; /// - /// Perform list scrolling by changing the currently selected list item. + /// A listbox panel class used for controls requiring a listbox. /// - /// Amount and direction of scrolling. Positive to scroll up, negative to scroll down. - void SelectionListScrolling(int mouseWheelChange); -}; -}; -#endif \ No newline at end of file + class GUIListPanel : public GUIPanel { + + public: + // Signals + enum { + Click, // Mouse click. Not just inside the panel + MouseDown, // Mouse down inside the panel + MouseUp, // Mouse up inside the panel + Select, // Selected (on mouse down) an item + MouseMove, // Mouse moved over the panel + MouseEnter, // Mouse left the panel + MouseLeave, // Mouse left the panel + DoubleClick, // Double click + KeyDown, // Key Down + EdgeHit //!< Tried scrolling the selection past the first or last item. data = 0 for top edge, data = 1 for bottom edge. + } Signal; + + // Item structure + struct Item { + int m_ID = 0; + std::string m_Name; + // Extra text field displayed right-justified in the item + std::string m_RightText; + // Extra index for special indexing or reference that the item is associated with. Menu-specific + int m_ExtraIndex = 0; + bool m_Selected = false; + // Can contain a bitmap to display in the list + // This is OWNED + GUIBitmap* m_pBitmap = nullptr; + // Extra data associated with the item + // This is NOT OWNED + const Entity* m_pEntity = nullptr; + int m_Height = 0; + // An x offset to apply to the item (to allow nesting) + int m_OffsetX = 0; + + Item() {} + ~Item() { + delete m_pBitmap; + m_pBitmap = 0; + } + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIListPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIListPanel object in + // system memory. + // Arguments: GUIManager. + + GUIListPanel(GUIManager* Manager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIListPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIListPanel object in + // system memory. + // Arguments: None. + + GUIListPanel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the listpanel + // Arguments: Position, Size. + + void Create(int X, int Y, int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel has been destroyed. + // Arguments: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Add an item to the list. + // Arguments: Name, extraText, Text which will be displayed right-justified in the item. + // a Bitmap object pointer alternatively pointing to a bitmap to display + // in the list. Ownership IS transferred! + // An Extra menu-specific index that this item may be associated with. + // Object instance associated with the item. Ownership is NOT TRANSFERRED! + + void AddItem(const std::string& Name, const std::string& rightText = "", GUIBitmap* pBitmap = nullptr, const Entity* pEntity = 0, const int extraIndex = -1, const int offsetX = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the list. + // Arguments: None. + + void ClearList(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseEnter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse enters the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseLeave + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse leaves the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnDoubleClick + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse has double-clicked on the pane. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnDoubleClick(int X, int Y, int Buttons, int Modifier) override; + + /// + /// Called when the mouse scroll wheel is moved. + /// + /// Mouse X position. + /// Mouse Y position. + /// Activated modifier buttons. + /// The amount of wheel movement. Positive is scroll up, negative is scroll down. + void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnKeyPress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when a key is pressed (OnDown & repeating). + // Arguments: KeyCode, Modifier. + + void OnKeyPress(int KeyCode, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnKeyDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when a key goes down. + // Arguments: KeyCode, Modifier. + + void OnKeyDown(int KeyCode, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PointInsideList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if a point is inside the panel, but not on the scrollbars if + // they are visible + // Arguments: X, Y Coordinates of point + // Return value: A boolean of the check result + + bool PointInsideList(int X, int Y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnGainFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel gains focus. + // Arguments: None. + + void OnGainFocus() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnLoseFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel looses focus. + // Arguments: None. + + void OnLoseFocus() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReceiveSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when receiving a signal. + // Arguments: Signal source, Signal code, Signal data. + + void ReceiveSignal(GUIPanel* Source, int Code, int Data) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BeginUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Locks the control from updating every time a new item is added. + // Arguments: None. + + void BeginUpdate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EndUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: UnLocks the control from updating every time a new item is added. + // Will automatically update the control. + // Arguments: None. + + void EndUpdate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMultiSelect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the multi-selection value. + // Arguments: MultiSelect + + void SetMultiSelect(bool MultiSelect); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMultiSelect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the multi-selection value. + // Arguments: None. + + bool GetMultiSelect() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetHotTracking + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the hot tracking value. + // Arguments: HotTrack. + + void SetHotTracking(bool HotTrack); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelected + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the selected (or first in the selected list) item. + // Arguments: None. + + Item* GetSelected(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetItemList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the item list. + // Arguments: None. + + std::vector* GetItemList(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets an item at the index. + // Arguments: Index. + + Item* GetItem(int Index); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets an item at a specific absolute screen coordinate, if any. + // Arguments: The absolute screen coordinates to get the item from. + + Item* GetItem(int X, int Y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetItemHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the drawing height of the item passed in. + // Arguments: Pointer to the Item to get the height of. Ownership is NOT transferred! + + int GetItemHeight(Item* pItem); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetStackHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the height, in pixels, of the stack of items up to a specific one. + // E.g. If the specified one is the first (top) in the list, 0 is returned. + // If the second one is specified, the height of the first is returned. + // If the third is specified, the sum of the first and second items' heights + // is returned. If 0 is passed, the entire stack's height is returned. + // Arguments: Pointer to the Item to get the height up to. Ownership is NOT transferred! + // If 0 is passed, the entire stack's height is returned. + + int GetStackHeight(Item* pItem = nullptr); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetScrollVerticalValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the scroll value, in pixels, of the vertical axis. + // Arguments: The scroll value in pixels. + + int GetScrollVerticalValue() const { return m_VertScroll->GetValue(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetItemValues + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the values of a specific Item. + // Arguments: Index and Item reference. + + void SetItemValues(int Index, Item& item); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelectedIndex + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the selected (or first in the selected list) index. + // Arguments: None. + // Returns: Index, or -1 if there is no items selected. + + int GetSelectedIndex(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSelectedIndex + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Selects the item at the index. + // Arguments: Index. + + void SetSelectedIndex(int Index); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetAlternateDrawMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Selects this to draw its items differently, with lines instead of + // rectangles, etc + // Arguments: The new mode setting. + + void SetAlternateDrawMode(bool enableAltDrawMode = true) { m_AlternateDrawMode = enableAltDrawMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelectionList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the selection list. + // Arguments: None. + + std::vector* GetSelectionList(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DeleteItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Deletes an item at the index. + // Arguments: Index. + + void DeleteItem(int Index); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the size of the panel. + // Arguments: Width, Height. + + void SetSize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPositionAbs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the position of the panel. + // Arguments: X, Y. + + void SetPositionAbs(int X, int Y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableScrollbars + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the enabled state of both scrollbars. + // Arguments: Horz, Vert + + void EnableScrollbars(bool Horizontal, bool Vertical); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ScrollToItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the vertical scrollbar to show the specific item in the list. + // Arguments: The item you want to show. + + void ScrollToItem(Item* pItem); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ScrollToSelected + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the vertical scrollbar to show the first selected item in the + // list. + // Arguments: None. + + void ScrollToSelected(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ScrollToTop + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the vertical scrollbar to show the top of the list + // Arguments: None. + + void ScrollToTop(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ScrollToBottom + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the vertical scrollbar to show the bottom of the list + // Arguments: None. + + void ScrollToBottom(); + + /// + /// Scrolls the GUIListPanel up. + /// + void ScrollUp(); + + /// + /// Scrolls the GUIListPanel down. + /// + void ScrollDown(); + + /// + /// Scrolls the the GUIListPanel to a specific position + /// + /// The position to scroll to. + void ScrollTo(int position); + + /// + /// Sets whether the scroll panel scrolls in a loop or not. + /// + /// True to scroll in a loop, false to scroll with edge stopping. + void SetSelectionScrollingLoop(bool scrollLoop); + + /// + /// Sets whether the list panel can be scrolled with the mouse scroll wheel. + /// + /// True to enable scrolling, false to disable. + void SetMouseScrolling(bool mouseScroll); + + /// + /// Sets the thickness (width on vertical, height on horizontal) of the ListPanel's scroll bars and adjusts them to the new thickness. + /// + /// The new scroll bar thickness, in pixels. + void SetScrollBarThickness(int newThickness) { + m_ScrollBarThickness = newThickness; + AdjustScrollbars(); + } + + /// + /// Sets the padding around the ListPanel's scrollbars and adjusts them to the new padding. Used to better size and position scrollbars within panel bounds, allowing to not overdraw on panel borders. + /// + /// The new scrollbar padding, in pixels. + void SetScrollBarPadding(int newPadding) { + m_ScrollBarPadding = newPadding; + AdjustScrollbars(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Build the bitmap. + // Arguments: UpdateBase, UpdateText. + + void BuildBitmap(bool UpdateBase, bool UpdateText); + + private: + GUISkin* m_Skin; + GUIBitmap* m_BaseBitmap; + GUIBitmap* m_DrawBitmap; + GUIBitmap* m_FrameBitmap; + unsigned long m_FontSelectColor; + + bool m_UpdateLocked; + + GUIScrollPanel* m_HorzScroll; + GUIScrollPanel* m_VertScroll; + bool m_HorzScrollEnabled; + bool m_VertScrollEnabled; + int m_ScrollBarThickness; //!< The thickness (width on vertical, height on horizontal) of the ListPanel's scroll bars, in pixels. + int m_ScrollBarPadding; //!< The padding around the scrollbars, in pixels. Used to better size and position scrollbars within panel bounds, allowing to not overdraw on panel borders. + + bool m_CapturedHorz; + bool m_CapturedVert; + bool m_ExternalCapture; + + int m_LargestWidth; + bool m_MultiSelect; + bool m_HotTracking; + int m_LastSelected; + bool m_LoopSelectionScroll; //!< Whether the list panel scrolls in a loop or not, while scrolling the selection list (as opposed to the scrollbar). + bool m_MouseScroll; //!< Whether the list panel enables scrolling with the mouse scroll wheel. + + bool m_AlternateDrawMode; // This draws items differently, not with boxes etc. + + std::vector m_Items; + std::vector m_SelectedList; + unsigned long m_SelectedColorIndex; + unsigned long m_UnselectedColorIndex; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildDrawBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Build the drawing bitmap. + // Arguments: None. + + void BuildDrawBitmap(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AdjustScrollbars + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the scrollbars. + // Arguments: None. + + void AdjustScrollbars(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SelectItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Selects an item based on mouse position. + // Arguments: Mouse Position, Modifier. + + void SelectItem(int X, int Y, int Modifier); + + /// + /// Perform list scrolling through the scrollbar. + /// + /// Amount and direction of scrolling. Positive to scroll up, negative to scroll down. + void ScrollBarScrolling(int mouseWheelChange); + + /// + /// Perform list scrolling by changing the currently selected list item. + /// + /// Amount and direction of scrolling. Positive to scroll up, negative to scroll down. + void SelectionListScrolling(int mouseWheelChange); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIManager.cpp b/Source/GUI/GUIManager.cpp index bf0f26f96..97195ec31 100644 --- a/Source/GUI/GUIManager.cpp +++ b/Source/GUI/GUIManager.cpp @@ -5,7 +5,7 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIManager::GUIManager(GUIInput *input) { +GUIManager::GUIManager(GUIInput* input) { m_Input = input; m_MouseEnabled = true; m_UseValidation = false; @@ -14,9 +14,9 @@ GUIManager::GUIManager(GUIInput *input) { // Maximum time allowed between two clicks for a double click // In milliseconds - //m_DoubleClickTime = GetDoubleClickTime(); // Use windows' system value + // m_DoubleClickTime = GetDoubleClickTime(); // Use windows' system value m_DoubleClickTime = 500; - //m_DoubleClickSize = GetSystemMetrics(SM_CXDOUBLECLK)/2; // Use windows' system value + // m_DoubleClickSize = GetSystemMetrics(SM_CXDOUBLECLK)/2; // Use windows' system value m_DoubleClickSize = 2; m_DoubleClickButtons = GUIPanel::MOUSE_NONE; @@ -52,13 +52,13 @@ void GUIManager::Clear() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIManager::AddPanel(GUIPanel *panel) { +void GUIManager::AddPanel(GUIPanel* panel) { if (panel) { int Z = 0; // Get the last panel in the list if (!m_PanelList.empty()) { - const GUIPanel *p = m_PanelList.at(m_PanelList.size() - 1); + const GUIPanel* p = m_PanelList.at(m_PanelList.size() - 1); Z = p->GetZPos() + 1; } @@ -95,10 +95,18 @@ void GUIManager::Update(bool ignoreKeyboardEvents) { // Build the modifier state Modifier = m_Input->GetModifier(); - if (Modifier & GUIInput::ModShift) { Mod |= GUIPanel::MODI_SHIFT; } - if (Modifier & GUIInput::ModCtrl) { Mod |= GUIPanel::MODI_CTRL; } - if (Modifier & GUIInput::ModAlt) { Mod |= GUIPanel::MODI_ALT; } - if (Modifier & GUIInput::ModCommand) { Mod |= GUIPanel::MODI_COMMAND; } + if (Modifier & GUIInput::ModShift) { + Mod |= GUIPanel::MODI_SHIFT; + } + if (Modifier & GUIInput::ModCtrl) { + Mod |= GUIPanel::MODI_CTRL; + } + if (Modifier & GUIInput::ModAlt) { + Mod |= GUIPanel::MODI_ALT; + } + if (Modifier & GUIInput::ModCommand) { + Mod |= GUIPanel::MODI_COMMAND; + } // Get the mouse data if (m_MouseEnabled) { @@ -114,10 +122,12 @@ void GUIManager::Update(bool ignoreKeyboardEvents) { // Panels that have captured the mouse get the events over anything else // Regardless where the mouse currently is - GUIPanel *CurPanel = m_CapturedPanel; + GUIPanel* CurPanel = m_CapturedPanel; // Find the lowest panel in the tree that the mouse is over - if (!CurPanel) { CurPanel = FindTopPanel(MouseX, MouseY); } + if (!CurPanel) { + CurPanel = FindTopPanel(MouseX, MouseY); + } // Build the states for (i = 0; i < 3; i++) { @@ -138,7 +148,9 @@ void GUIManager::Update(bool ignoreKeyboardEvents) { // Double click (on the mouse up) if (Released != GUIPanel::MOUSE_NONE && m_DoubleClickButtons != GUIPanel::MOUSE_NONE) { - if (CurPanel) { CurPanel->OnDoubleClick(MouseX, MouseY, m_DoubleClickButtons, Mod); } + if (CurPanel) { + CurPanel->OnDoubleClick(MouseX, MouseY, m_DoubleClickButtons, Mod); + } m_LastMouseDown[0] = m_LastMouseDown[1] = m_LastMouseDown[2] = -99999.0f; } @@ -166,7 +178,9 @@ void GUIManager::Update(bool ignoreKeyboardEvents) { } // OnMouseDown event - if (CurPanel) { CurPanel->OnMouseDown(MouseX, MouseY, Pushed, Mod); } + if (CurPanel) { + CurPanel->OnMouseDown(MouseX, MouseY, Pushed, Mod); + } } // Mouse move @@ -179,30 +193,39 @@ void GUIManager::Update(bool ignoreKeyboardEvents) { // Disable it (panel will have to re-enable it if it wants to continue) m_HoverTrack = false; - if (m_HoverPanel && m_HoverPanel->PointInside(MouseX, MouseY)/*GetPanelID() == CurPanel->GetPanelID()*/) { + if (m_HoverPanel && m_HoverPanel->PointInside(MouseX, MouseY) /*GetPanelID() == CurPanel->GetPanelID()*/) { // call the OnMouseHover event m_HoverPanel->OnMouseHover(MouseX, MouseY, Buttons, Mod); } } - // Mouse enter & leave bool Enter = false; bool Leave = false; - if (!m_MouseOverPanel && CurPanel) { Enter = true; } - if (!CurPanel && m_MouseOverPanel) { Leave = true; } + if (!m_MouseOverPanel && CurPanel) { + Enter = true; + } + if (!CurPanel && m_MouseOverPanel) { + Leave = true; + } if (m_MouseOverPanel && CurPanel && m_MouseOverPanel->GetPanelID() != CurPanel->GetPanelID()) { Enter = true; Leave = true; } // OnMouseEnter - if (Enter && CurPanel) { CurPanel->OnMouseEnter(MouseX, MouseY, Buttons, Mod); } + if (Enter && CurPanel) { + CurPanel->OnMouseEnter(MouseX, MouseY, Buttons, Mod); + } // OnMouseLeave - if (Leave &&m_MouseOverPanel) { m_MouseOverPanel->OnMouseLeave(MouseX, MouseY, Buttons, Mod); } + if (Leave && m_MouseOverPanel) { + m_MouseOverPanel->OnMouseLeave(MouseX, MouseY, Buttons, Mod); + } - if (MouseWheelChange &&CurPanel) { CurPanel->OnMouseWheelChange(MouseX, MouseY, Mod, MouseWheelChange); } + if (MouseWheelChange && CurPanel) { + CurPanel->OnMouseWheelChange(MouseX, MouseY, Mod, MouseWheelChange); + } m_MouseOverPanel = CurPanel; } @@ -221,7 +244,6 @@ void GUIManager::Update(bool ignoreKeyboardEvents) { return; } - for (i = 1; i < 256; i++) { switch (KeyboardBuffer[i]) { // KeyDown & KeyPress @@ -252,21 +274,23 @@ void GUIManager::Update(bool ignoreKeyboardEvents) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIManager::Draw(GUIScreen *Screen) { +void GUIManager::Draw(GUIScreen* Screen) { // Go through drawing panels that are invalid - std::vector::iterator it; + std::vector::iterator it; for (it = m_PanelList.begin(); it != m_PanelList.end(); it++) { - GUIPanel *p = *it; + GUIPanel* p = *it; // Draw the panel - if ((!p->IsValid() || !m_UseValidation) && p->_GetVisible()) { p->Draw(Screen); } + if ((!p->IsValid() || !m_UseValidation) && p->_GetVisible()) { + p->Draw(Screen); + } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIManager::CaptureMouse(GUIPanel *Panel) { +void GUIManager::CaptureMouse(GUIPanel* Panel) { assert(Panel); // Release any old capture @@ -280,20 +304,22 @@ void GUIManager::CaptureMouse(GUIPanel *Panel) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIManager::ReleaseMouse() { - if (m_CapturedPanel) { m_CapturedPanel->SetCaptureState(false); } + if (m_CapturedPanel) { + m_CapturedPanel->SetCaptureState(false); + } m_CapturedPanel = nullptr; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIManager::FindBottomPanel(int X, int Y) { - std::vector::iterator it; +GUIPanel* GUIManager::FindBottomPanel(int X, int Y) { + std::vector::iterator it; for (it = m_PanelList.begin(); it != m_PanelList.end(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; if (P) { - GUIPanel *CurPanel = P->BottomPanelUnderPoint(X, Y); + GUIPanel* CurPanel = P->BottomPanelUnderPoint(X, Y); if (CurPanel) { return CurPanel; } @@ -305,13 +331,13 @@ GUIPanel * GUIManager::FindBottomPanel(int X, int Y) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIManager::FindTopPanel(int X, int Y) { - std::vector::reverse_iterator it; +GUIPanel* GUIManager::FindTopPanel(int X, int Y) { + std::vector::reverse_iterator it; for (it = m_PanelList.rbegin(); it != m_PanelList.rend(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; if (P) { - GUIPanel *CurPanel = P->TopPanelUnderPoint(X, Y); + GUIPanel* CurPanel = P->TopPanelUnderPoint(X, Y); if (CurPanel) { return CurPanel; } @@ -329,7 +355,7 @@ int GUIManager::GetPanelID() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIManager::MouseInRect(const GUIRect *Rect, int X, int Y) { +bool GUIManager::MouseInRect(const GUIRect* Rect, int X, int Y) { if (!Rect) { return false; } @@ -341,21 +367,27 @@ bool GUIManager::MouseInRect(const GUIRect *Rect, int X, int Y) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIManager::TrackMouseHover(GUIPanel *Pan, bool Enabled, int Delay) { +void GUIManager::TrackMouseHover(GUIPanel* Pan, bool Enabled, int Delay) { assert(Pan); m_HoverTrack = Enabled; m_HoverPanel = Pan; - if (m_HoverTrack) { m_HoverTime = m_pTimer->GetElapsedRealTimeMS() + ((float)Delay / 1000.0F); } + if (m_HoverTrack) { + m_HoverTime = m_pTimer->GetElapsedRealTimeMS() + ((float)Delay / 1000.0F); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIManager::SetFocus(GUIPanel *Pan) { +void GUIManager::SetFocus(GUIPanel* Pan) { // Send the LoseFocus event to the old panel (if there is one) - if (m_FocusPanel) { m_FocusPanel->OnLoseFocus(); } + if (m_FocusPanel) { + m_FocusPanel->OnLoseFocus(); + } m_FocusPanel = Pan; // Send the GainFocus event to the new panel - if (m_FocusPanel) { m_FocusPanel->OnGainFocus(); } + if (m_FocusPanel) { + m_FocusPanel->OnGainFocus(); + } } diff --git a/Source/GUI/GUIManager.h b/Source/GUI/GUIManager.h index e3a5f4bb4..31c5a81e3 100644 --- a/Source/GUI/GUIManager.h +++ b/Source/GUI/GUIManager.h @@ -3,189 +3,170 @@ namespace RTE { -class Timer; + class Timer; + + /// + /// The main manager that handles all the panels and inputs. + /// + class GUIManager { -/// -/// The main manager that handles all the panels and inputs. -/// -class GUIManager { + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIManager + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIManager object in system + // memory. + // Arguments: Input Interface -public: + explicit GUIManager(GUIInput* input); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: GUIManager + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a GUIManager object. + // Arguments: None. + + ~GUIManager(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the manager. + // Arguments: None. + + void Clear(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a panel to the list. + // Arguments: Pointer to a panel. - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIManager -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIManager object in system -// memory. -// Arguments: Input Interface - - explicit GUIManager(GUIInput *input); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: GUIManager -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a GUIManager object. -// Arguments: None. - - ~GUIManager(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the manager. -// Arguments: None. - - void Clear(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a panel to the list. -// Arguments: Pointer to a panel. - - void AddPanel(GUIPanel *panel); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the GUI. -// Arguments: Whether keyboard events should be ignored or not. Used to avoid conflicts when custom keyboard handling for GUI elements is preset. - - void Update(bool ignoreKeyboardEvents = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draw all the panels -// Arguments: Screen. - - void Draw(GUIScreen *Screen); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnableMouse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Enables and disables the mouse completely for this. -// Arguments: Enable? - - void EnableMouse(bool enable = true) { m_MouseEnabled = enable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CaptureMouse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets up capturing a mouse for a panel. -// Arguments: Panel. - - void CaptureMouse(GUIPanel *Panel); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReleaseMouse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Releases a mouse capture. -// Arguments: None. - - void ReleaseMouse(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanelID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a unique ID for a panel. -// Arguments: None. - - int GetPanelID(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetInputController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the input controller object -// Arguments: None. - - GUIInput * GetInputController() { return m_Input; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TrackMouseHover -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets up the manager to enable/disable hover tracking of this panel -// Arguments: Panel, Enabled, Delay (milliseconds) - - void TrackMouseHover(GUIPanel *Pan, bool Enabled, int Delay); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Give focus to a panel. -// Arguments: Panel. - - void SetFocus(GUIPanel *Pan); - - -private: - - std::vector m_PanelList; - GUIPanel *m_CapturedPanel; - GUIPanel *m_FocusPanel; - GUIPanel *m_MouseOverPanel; - - GUIInput *m_Input; - bool m_MouseEnabled; - int m_OldMouseX; - int m_OldMouseY; - - int m_DoubleClickTime; - int m_DoubleClickSize; - int m_DoubleClickButtons; - float m_LastMouseDown[3]; - GUIRect m_DoubleClickRect; - - bool m_HoverTrack; - GUIPanel *m_HoverPanel; - float m_HoverTime; - - bool m_UseValidation; - int m_UniqueIDCount; - - Timer *m_pTimer; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FindBottomPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through the panel list and selects the bottommost -// ('first', render wise) panel on a specific point. -// Arguments: Mouse Position. - - GUIPanel *FindBottomPanel(int X, int Y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FindTopPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through the panel list and selects the topmost ('last', render -// wise) panel on a specific point. -// Arguments: Mouse Position. - - GUIPanel *FindTopPanel(int X, int Y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: MouseInRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if the mouse point is inside a rectangle. -// Arguments: Rectangle, Mouse position. - - bool MouseInRect(const GUIRect *Rect, int X, int Y); - -}; -}; -#endif \ No newline at end of file + void AddPanel(GUIPanel* panel); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the GUI. + // Arguments: Whether keyboard events should be ignored or not. Used to avoid conflicts when custom keyboard handling for GUI elements is preset. + + void Update(bool ignoreKeyboardEvents = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draw all the panels + // Arguments: Screen. + + void Draw(GUIScreen* Screen); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableMouse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Enables and disables the mouse completely for this. + // Arguments: Enable? + + void EnableMouse(bool enable = true) { m_MouseEnabled = enable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CaptureMouse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets up capturing a mouse for a panel. + // Arguments: Panel. + + void CaptureMouse(GUIPanel* Panel); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReleaseMouse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Releases a mouse capture. + // Arguments: None. + + void ReleaseMouse(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanelID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a unique ID for a panel. + // Arguments: None. + + int GetPanelID(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetInputController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the input controller object + // Arguments: None. + + GUIInput* GetInputController() { return m_Input; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TrackMouseHover + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets up the manager to enable/disable hover tracking of this panel + // Arguments: Panel, Enabled, Delay (milliseconds) + + void TrackMouseHover(GUIPanel* Pan, bool Enabled, int Delay); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Give focus to a panel. + // Arguments: Panel. + + void SetFocus(GUIPanel* Pan); + + private: + std::vector m_PanelList; + GUIPanel* m_CapturedPanel; + GUIPanel* m_FocusPanel; + GUIPanel* m_MouseOverPanel; + + GUIInput* m_Input; + bool m_MouseEnabled; + int m_OldMouseX; + int m_OldMouseY; + + int m_DoubleClickTime; + int m_DoubleClickSize; + int m_DoubleClickButtons; + float m_LastMouseDown[3]; + GUIRect m_DoubleClickRect; + + bool m_HoverTrack; + GUIPanel* m_HoverPanel; + float m_HoverTime; + + bool m_UseValidation; + int m_UniqueIDCount; + + Timer* m_pTimer; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FindBottomPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through the panel list and selects the bottommost + // ('first', render wise) panel on a specific point. + // Arguments: Mouse Position. + + GUIPanel* FindBottomPanel(int X, int Y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FindTopPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through the panel list and selects the topmost ('last', render + // wise) panel on a specific point. + // Arguments: Mouse Position. + + GUIPanel* FindTopPanel(int X, int Y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: MouseInRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if the mouse point is inside a rectangle. + // Arguments: Rectangle, Mouse position. + + bool MouseInRect(const GUIRect* Rect, int X, int Y); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIPanel.cpp b/Source/GUI/GUIPanel.cpp index d10e8faad..6bde68721 100644 --- a/Source/GUI/GUIPanel.cpp +++ b/Source/GUI/GUIPanel.cpp @@ -4,7 +4,7 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel::GUIPanel(GUIManager *Manager) { +GUIPanel::GUIPanel(GUIManager* Manager) { Clear(); m_Manager = Manager; m_Font = nullptr; @@ -48,7 +48,7 @@ void GUIPanel::Clear() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::Setup(GUIManager *manager, int ZPos) { +void GUIPanel::Setup(GUIManager* manager, int ZPos) { m_Manager = manager; m_ZPos = ZPos; @@ -57,9 +57,9 @@ void GUIPanel::Setup(GUIManager *manager, int ZPos) { // Set the manager for all the children int Z = 0; - std::vector::iterator it; + std::vector::iterator it; for (it = m_Children.begin(); it != m_Children.end(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; if (P) { Z++; P->Setup(manager, Z); @@ -69,7 +69,7 @@ void GUIPanel::Setup(GUIManager *manager, int ZPos) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::AddChild(GUIPanel *child, bool convertToAbsolutePos) { +void GUIPanel::AddChild(GUIPanel* child, bool convertToAbsolutePos) { if (child) { // Convert the child's coordinates into absolute coordinates if (convertToAbsolutePos) { @@ -83,12 +83,14 @@ void GUIPanel::AddChild(GUIPanel *child, bool convertToAbsolutePos) { int zPos = 0; if (!m_Children.empty()) { - const GUIPanel *lastChild = m_Children.back(); + const GUIPanel* lastChild = m_Children.back(); zPos = lastChild->GetZPos() + 1; } // Remove the child from any previous parent - if (child->GetParentPanel()) { child->GetParentPanel()->GUIPanel::RemoveChild(child); } + if (child->GetParentPanel()) { + child->GetParentPanel()->GUIPanel::RemoveChild(child); + } // Setup the inherited values child->m_Parent = this; @@ -101,12 +103,12 @@ void GUIPanel::AddChild(GUIPanel *child, bool convertToAbsolutePos) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::RemoveChild(const GUIPanel *pChild) { +void GUIPanel::RemoveChild(const GUIPanel* pChild) { // Note: We do NOT free the children because they are still linked in through their controls. This merely removes the panel from the list. // This will cause a small memory leak, but this is only designed for the GUI Editor and is a bit of a hack - for (std::vector::iterator itr = m_Children.begin(); itr != m_Children.end(); itr++) { - const GUIPanel *pPanel = *itr; + for (std::vector::iterator itr = m_Children.begin(); itr != m_Children.end(); itr++) { + const GUIPanel* pPanel = *itr; if (pPanel && pPanel == pChild) { m_Children.erase(itr); break; @@ -116,7 +118,7 @@ void GUIPanel::RemoveChild(const GUIPanel *pChild) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::LoadProperties(GUIProperties *Props) { +void GUIPanel::LoadProperties(GUIProperties* Props) { assert(Props); Props->GetValue("X", &m_X); @@ -142,7 +144,7 @@ bool GUIPanel::IsValid() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::Draw(GUIScreen *Screen) { +void GUIPanel::Draw(GUIScreen* Screen) { // Validate this panel m_ValidRegion = true; @@ -154,9 +156,9 @@ void GUIPanel::Draw(GUIScreen *Screen) { Screen->GetBitmap()->GetClipRect(&thisClip); // Draw children - std::vector::iterator it; + std::vector::iterator it; for (it = m_Children.begin(); it != m_Children.end(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; if (P->_GetVisible()) { // Re-set the clipping rect of this panel since the last child has messed with it @@ -239,7 +241,7 @@ void GUIPanel::ReleaseMouse() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIPanel::BottomPanelUnderPoint(int x, int y) { +GUIPanel* GUIPanel::BottomPanelUnderPoint(int x, int y) { if (!PointInside(x, y)) { return nullptr; } @@ -249,10 +251,10 @@ GUIPanel * GUIPanel::BottomPanelUnderPoint(int x, int y) { } // Go through the children - GUIPanel *CurPanel = nullptr; - std::vector::iterator it; + GUIPanel* CurPanel = nullptr; + std::vector::iterator it; for (it = m_Children.begin(); it != m_Children.end(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; if (P) { CurPanel = P->BottomPanelUnderPoint(x, y); if (CurPanel != nullptr) { @@ -266,7 +268,7 @@ GUIPanel * GUIPanel::BottomPanelUnderPoint(int x, int y) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIPanel::TopPanelUnderPoint(int x, int y) { +GUIPanel* GUIPanel::TopPanelUnderPoint(int x, int y) { if (!PointInside(x, y)) { return nullptr; } @@ -276,10 +278,10 @@ GUIPanel * GUIPanel::TopPanelUnderPoint(int x, int y) { } // Go through the children - GUIPanel *CurPanel = nullptr; - std::vector::reverse_iterator it; + GUIPanel* CurPanel = nullptr; + std::vector::reverse_iterator it; for (it = m_Children.rbegin(); it != m_Children.rend(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; if (P) { CurPanel = P->TopPanelUnderPoint(x, y); if (CurPanel != nullptr) { @@ -327,9 +329,9 @@ void GUIPanel::SetPositionAbs(int X, int Y, bool moveChildren) { // Move children if (moveChildren) { - std::vector::iterator it; + std::vector::iterator it; for (it = m_Children.begin(); it != m_Children.end(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; P->SetPositionAbs(P->m_X + DX, P->m_Y + DY); } } @@ -348,9 +350,9 @@ void GUIPanel::SetPositionRel(int X, int Y) { m_Y = Y; // Move children - std::vector::iterator it; + std::vector::iterator it; for (it = m_Children.begin(); it != m_Children.end(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; P->SetPositionAbs(P->m_X + DX, P->m_Y + DY); } } @@ -362,9 +364,9 @@ void GUIPanel::MoveRelative(int dX, int dY) { m_Y += dY; // Move children - std::vector::iterator it; + std::vector::iterator it; for (it = m_Children.begin(); it != m_Children.end(); it++) { - GUIPanel *P = *it; + GUIPanel* P = *it; P->SetPositionAbs(P->m_X + dX, P->m_Y + dY); } } @@ -375,8 +377,12 @@ void GUIPanel::CenterInParent(bool centerX, bool centerY) { int newRelX = m_X - m_Parent->GetXPos(); int newRelY = m_Y - m_Parent->GetYPos(); - if (centerX) { newRelX = (m_Parent->GetWidth() / 2) - (GetWidth() / 2); } - if (centerY) { newRelY = (m_Parent->GetHeight() / 2) - (GetHeight() / 2); } + if (centerX) { + newRelX = (m_Parent->GetWidth() / 2) - (GetWidth() / 2); + } + if (centerY) { + newRelY = (m_Parent->GetHeight() / 2) - (GetHeight() / 2); + } SetPositionRel(newRelX, newRelY); } @@ -419,7 +425,7 @@ int GUIPanel::GetHeight() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIRect * GUIPanel::GetRect() { +GUIRect* GUIPanel::GetRect() { SetRect(&m_Rect, m_X, m_Y, m_X + m_Width, m_Y + m_Height); return &m_Rect; @@ -427,11 +433,19 @@ GUIRect * GUIPanel::GetRect() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::GetRect(int *X, int *Y, int *Width, int *Height) const { - if (X) { *X = m_X; } - if (Y) { *Y = m_Y; } - if (Width) { *Width = m_Width; } - if (Height) { *Height = m_Height; } +void GUIPanel::GetRect(int* X, int* Y, int* Width, int* Height) const { + if (X) { + *X = m_X; + } + if (Y) { + *Y = m_Y; + } + if (Width) { + *Width = m_Width; + } + if (Height) { + *Height = m_Height; + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -479,22 +493,26 @@ bool GUIPanel::IsEnabled() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIPanel::SendSignal(int Code, int Data) { - if (m_SignalTarget) { m_SignalTarget->ReceiveSignal(this, Code, Data); } + if (m_SignalTarget) { + m_SignalTarget->ReceiveSignal(this, Code, Data); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::ReceiveSignal(GUIPanel *Source, int Code, int Data) {} +void GUIPanel::ReceiveSignal(GUIPanel* Source, int Code, int Data) {} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::SetSignalTarget(GUIPanel *Target) { - if (Target) { m_SignalTarget = Target; } +void GUIPanel::SetSignalTarget(GUIPanel* Target) { + if (Target) { + m_SignalTarget = Target; + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIPanel::GetParentPanel() { +GUIPanel* GUIPanel::GetParentPanel() { return m_Parent; } @@ -515,7 +533,7 @@ int GUIPanel::GetZPos() const { void GUIPanel::ChangeZPosition(int Type) { // If we don't have a parent, get the manager to alter the Z Position if (!m_Parent) { - //m_Manager->ChangeZPosition(this, Type); + // m_Manager->ChangeZPosition(this, Type); return; } @@ -525,16 +543,16 @@ void GUIPanel::ChangeZPosition(int Type) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::_ChangeZ(GUIPanel *Child, int Type) { +void GUIPanel::_ChangeZ(GUIPanel* Child, int Type) { assert(Child); int Index = -1; // Find the child in our children list - std::vector::iterator it; + std::vector::iterator it; int Count = 0; for (it = m_Children.begin(); it != m_Children.end(); it++, Count++) { - const GUIPanel *P = *it; + const GUIPanel* P = *it; if (P && P->GetPanelID() == Child->GetPanelID()) { Index = Count; break; @@ -565,8 +583,10 @@ void GUIPanel::_ChangeZ(GUIPanel *Child, int Type) { // Go through and re-order the Z positions Count = 0; for (it = m_Children.begin(); it != m_Children.end(); it++, Count++) { - GUIPanel *P = *it; - if (P) { P->SetZPos(Count); } + GUIPanel* P = *it; + if (P) { + P->SetZPos(Count); + } } } @@ -596,7 +616,7 @@ std::string GUIPanel::ToString() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::BuildProperties(GUIProperties *Prop) { +void GUIPanel::BuildProperties(GUIProperties* Prop) { assert(Prop); // Subtract the position from the parent @@ -618,7 +638,7 @@ void GUIPanel::BuildProperties(GUIProperties *Prop) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -std::string GUIPanel::WriteValue(const std::string &Name, int Value) { +std::string GUIPanel::WriteValue(const std::string& Name, int Value) { char buf[32]; std::string OutString = Name; @@ -633,7 +653,7 @@ std::string GUIPanel::WriteValue(const std::string &Name, int Value) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -std::string GUIPanel::WriteValue(const std::string &Name, bool Value) { +std::string GUIPanel::WriteValue(const std::string& Name, bool Value) { std::string OutString = Name; OutString += " = "; OutString += (Value ? "True" : "False"); @@ -644,7 +664,7 @@ std::string GUIPanel::WriteValue(const std::string &Name, bool Value) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPanel::_ApplyProperties(GUIProperties *Props) { +void GUIPanel::_ApplyProperties(GUIProperties* Props) { assert(Props); Props->GetValue("Visible", &m_Visible); diff --git a/Source/GUI/GUIPanel.h b/Source/GUI/GUIPanel.h index 2331242f1..73136196e 100644 --- a/Source/GUI/GUIPanel.h +++ b/Source/GUI/GUIPanel.h @@ -3,674 +3,608 @@ namespace RTE { -class GUIPanel; -class GUIManager; - -/// -/// A rectangle 'window' in the GUI that recieves mouse and keyboard events. -/// -class GUIPanel { - -public: - - // Mouse buttons - enum { - MOUSE_NONE = 0x00, - MOUSE_LEFT = 0x01, - MOUSE_MIDDLE = 0x02, - MOUSE_RIGHT = 0x04, - } MouseButtons; - - // Mouse Modifiers - enum { - MODI_NONE = 0x00, - MODI_SHIFT = 0x01, - MODI_CTRL = 0x02, - MODI_ALT = 0x04, - MODI_COMMAND = 0x08 - } MouseModifiers; - - // Z Change - enum { - TopMost=0, - BottomMost, - } ZChange; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIPanel object in system -// memory. -// Arguments: Manager. - - explicit GUIPanel(GUIManager *Manager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIPanel object in system -// memory. -// Arguments: None. - - GUIPanel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the settings. -// Arguments: None. - - void Clear(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BottomPanelUnderPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Recursively goes down the tree to check the last panel under a point -// Arguments: X, Y Coordinates of point -// Return value: A pointer to the panel. 0 if no panel is under the point - - GUIPanel *BottomPanelUnderPoint(int x, int y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TopPanelUnderPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Recursively goes up the tree from to check the first panel under a point -// Arguments: X, Y Coordinates of point -// Return value: A pointer to the panel. 0 if no panel is under the point - - GUIPanel *TopPanelUnderPoint(int x, int y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddChild -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a child to this panel -// Arguments: Pointer to the panel to add - - void AddChild(GUIPanel *child, bool convertToAbsolutePos = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveChild -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a child based on name. -// Arguments: Child Name. - - void RemoveChild(const GUIPanel *pChild); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Setup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets up the panel for use with the manager. -// Arguments: Pointer to the manager to use, ZPosition. - - void Setup(GUIManager *manager, int ZPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads the base data from a properties page -// Arguments: Pointer to the properties class - - void LoadProperties(GUIProperties *Props); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Invalidate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Invalidates the panel -// Arguments: None. - - void Invalidate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsValid -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if the panel is valid -// Arguments: None. - - bool IsValid() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - virtual void Draw(GUIScreen *Screen); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - virtual void OnMouseDown(int X, int Y, int Buttons, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - virtual void OnMouseUp(int X, int Y, int Buttons, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnDoubleClick -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse has double-clicked on the pane. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - virtual void OnDoubleClick(int X, int Y, int Buttons, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - virtual void OnMouseMove(int X, int Y, int Buttons, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnMouseEnter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse enters the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - virtual void OnMouseEnter(int X, int Y, int Buttons, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnMouseLeave -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse leaves the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - virtual void OnMouseLeave(int X, int Y, int Buttons, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnMouseHover -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse is hovering over the panel (has to be enabled) -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - virtual void OnMouseHover(int X, int Y, int Buttons, int Modifier); - - - /// - /// Called when the mouse scroll wheel is moved. - /// - /// Mouse X position. - /// Mouse Y position. - /// Activated modifier buttons. - /// The amount of wheel movement. Positive is scroll up, negative is scroll down. - virtual void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange) {}; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnKeyDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when a key goes down. -// Arguments: KeyCode, Modifier. - - virtual void OnKeyDown(int KeyCode, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnKeyUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when a key goes up. -// Arguments: KeyCode, Modifier. - - virtual void OnKeyUp(int KeyCode, int Modifier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnKeyPress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when a key is pressed (OnDown & repeating). -// Arguments: KeyCode, Modifier. - - virtual void OnKeyPress(int KeyCode, int Modifier); + class GUIPanel; + class GUIManager; /// - /// Called when text input is received. + /// A rectangle 'window' in the GUI that recieves mouse and keyboard events. /// - /// The input text being received. - virtual void OnTextInput(std::string_view inputText); - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnGainFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel gains focus. -// Arguments: None. - - virtual void OnGainFocus(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: OnLoseFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel looses focus. -// Arguments: None. - - virtual void OnLoseFocus(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: SetSize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the size of the panel. -// Arguments: Width, Height. - - virtual void SetSize(int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: SetPositionAbs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the absolute position of the panel. -// Arguments: X, Y, and whether to move the children too - - virtual void SetPositionAbs(int X, int Y, bool moveChildren = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: SetPositionRel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the position of the panel, relative to its parent. -// Arguments: X, Y. - - virtual void SetPositionRel(int X, int Y); + class GUIPanel { + + public: + // Mouse buttons + enum { + MOUSE_NONE = 0x00, + MOUSE_LEFT = 0x01, + MOUSE_MIDDLE = 0x02, + MOUSE_RIGHT = 0x04, + } MouseButtons; + + // Mouse Modifiers + enum { + MODI_NONE = 0x00, + MODI_SHIFT = 0x01, + MODI_CTRL = 0x02, + MODI_ALT = 0x04, + MODI_COMMAND = 0x08 + } MouseModifiers; + + // Z Change + enum { + TopMost = 0, + BottomMost, + } ZChange; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIPanel object in system + // memory. + // Arguments: Manager. + + explicit GUIPanel(GUIManager* Manager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIPanel object in system + // memory. + // Arguments: None. + + GUIPanel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the settings. + // Arguments: None. + + void Clear(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BottomPanelUnderPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Recursively goes down the tree to check the last panel under a point + // Arguments: X, Y Coordinates of point + // Return value: A pointer to the panel. 0 if no panel is under the point + + GUIPanel* BottomPanelUnderPoint(int x, int y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TopPanelUnderPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Recursively goes up the tree from to check the first panel under a point + // Arguments: X, Y Coordinates of point + // Return value: A pointer to the panel. 0 if no panel is under the point + + GUIPanel* TopPanelUnderPoint(int x, int y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddChild + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a child to this panel + // Arguments: Pointer to the panel to add + + void AddChild(GUIPanel* child, bool convertToAbsolutePos = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveChild + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a child based on name. + // Arguments: Child Name. + + void RemoveChild(const GUIPanel* pChild); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Setup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets up the panel for use with the manager. + // Arguments: Pointer to the manager to use, ZPosition. + + void Setup(GUIManager* manager, int ZPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads the base data from a properties page + // Arguments: Pointer to the properties class + + void LoadProperties(GUIProperties* Props); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Invalidate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Invalidates the panel + // Arguments: None. + + void Invalidate(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsValid + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if the panel is valid + // Arguments: None. + + bool IsValid() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + virtual void Draw(GUIScreen* Screen); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + virtual void OnMouseDown(int X, int Y, int Buttons, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + virtual void OnMouseUp(int X, int Y, int Buttons, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnDoubleClick + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse has double-clicked on the pane. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + virtual void OnDoubleClick(int X, int Y, int Buttons, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + virtual void OnMouseMove(int X, int Y, int Buttons, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnMouseEnter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse enters the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + virtual void OnMouseEnter(int X, int Y, int Buttons, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnMouseLeave + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse leaves the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + virtual void OnMouseLeave(int X, int Y, int Buttons, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnMouseHover + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse is hovering over the panel (has to be enabled) + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + virtual void OnMouseHover(int X, int Y, int Buttons, int Modifier); + + /// + /// Called when the mouse scroll wheel is moved. + /// + /// Mouse X position. + /// Mouse Y position. + /// Activated modifier buttons. + /// The amount of wheel movement. Positive is scroll up, negative is scroll down. + virtual void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange){}; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnKeyDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when a key goes down. + // Arguments: KeyCode, Modifier. + + virtual void OnKeyDown(int KeyCode, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnKeyUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when a key goes up. + // Arguments: KeyCode, Modifier. + + virtual void OnKeyUp(int KeyCode, int Modifier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnKeyPress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when a key is pressed (OnDown & repeating). + // Arguments: KeyCode, Modifier. + + virtual void OnKeyPress(int KeyCode, int Modifier); + + /// + /// Called when text input is received. + /// + /// The input text being received. + virtual void OnTextInput(std::string_view inputText); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnGainFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel gains focus. + // Arguments: None. + + virtual void OnGainFocus(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: OnLoseFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel looses focus. + // Arguments: None. + + virtual void OnLoseFocus(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: SetSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the size of the panel. + // Arguments: Width, Height. + + virtual void SetSize(int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: SetPositionAbs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the absolute position of the panel. + // Arguments: X, Y, and whether to move the children too + + virtual void SetPositionAbs(int X, int Y, bool moveChildren = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: SetPositionRel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the position of the panel, relative to its parent. + // Arguments: X, Y. + + virtual void SetPositionRel(int X, int Y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: MoveRelative + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Moves the position of the panel by a relative amount. + // Arguments: X, Y, relative. + + virtual void MoveRelative(int dX, int dY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: CenterInParent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Centers this in its parent, taking this' dimensions into consideration. + // Arguments: Which axes to center. + + virtual void CenterInParent(bool centerX, bool centerY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: ReceiveSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when receiving a signal. + // Arguments: Signal source, Signal code, Signal data. + + virtual void ReceiveSignal(GUIPanel* Source, int Code, int Data); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CaptureMouse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Captures the mouse. + // Arguments: None. + + void CaptureMouse(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReleaseMouse + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Releases the mouse. + // Arguments: None. + + void ReleaseMouse(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual Method: SetFont + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the font this panel will be using + // Arguments: The new font, ownership is NOT transferred! + + virtual void SetFont(GUIFont* pFont) { + m_Font = pFont; + m_ValidRegion = false; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: _SetVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the visibility of the panel. + // Arguments: Visible. + + void _SetVisible(bool Visible); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: _GetVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the visibility of the panel. + // Arguments: None. + bool _GetVisible() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: _SetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the enabled state of the panel. + // Arguments: Enabled. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: MoveRelative -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Moves the position of the panel by a relative amount. -// Arguments: X, Y, relative. + void _SetEnabled(bool Enabled); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: _GetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the enabled state of the panel. + // Arguments: None. - virtual void MoveRelative(int dX, int dY); + bool _GetEnabled() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the width of the panel. + // Arguments: None. + int GetWidth() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the height of the panel. + // Arguments: None. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: CenterInParent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Centers this in its parent, taking this' dimensions into consideration. -// Arguments: Which axes to center. + int GetHeight() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetXPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the x position of the panel + // Arguments: None. - virtual void CenterInParent(bool centerX, bool centerY); + int GetXPos() const { return m_X; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetYPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the y position of the panel + // Arguments: None. + int GetYPos() const { return m_Y; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRelXPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the x position of the panel, relative to its parent + // Arguments: None. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: ReceiveSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when receiving a signal. -// Arguments: Signal source, Signal code, Signal data. + int GetRelXPos() const { return m_X - m_Parent->GetXPos(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRelYPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the y position of the panel, relative to its parent + // Arguments: None. - virtual void ReceiveSignal(GUIPanel *Source, int Code, int Data); + int GetRelYPos() const { return m_Y - m_Parent->GetYPos(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the panel. + // Arguments: None. + GUIRect* GetRect(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the panel. + // Arguments: X, Y, Width, Height -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CaptureMouse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Captures the mouse. -// Arguments: None. + void GetRect(int* X, int* Y, int* Width, int* Height) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetParentPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the parent of this panel. + // Arguments: None. - void CaptureMouse(); + GUIPanel* GetParentPanel(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanelID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the panel's ID. + // Arguments: None. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReleaseMouse -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Releases the mouse. -// Arguments: None. + int GetPanelID() const; - void ReleaseMouse(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCaptureState + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the panel's captured state. + // Arguments: Captured. + + void SetCaptureState(bool Captured); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsCaptured + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the panel's captured state. + // Arguments: None. + + bool IsCaptured() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the panel's enabled state. + // Arguments: None. + + bool IsEnabled() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSignalTarget + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the target panel to receive signals. + // Arguments: Target panel. + + void SetSignalTarget(GUIPanel* Target); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PointInside + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if a point is inside the panel + // Arguments: X, Y Coordinates of point + // Return value: A boolean of the check result + + virtual bool PointInside(int X, int Y); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the focus of this panel. + // Arguments: None. + + void SetFocus(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the focus value of the panel. + // Arguments: None. + + bool HasFocus() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetZPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the Z index of the panel. + // Arguments: ZPos. + + void SetZPos(int Z); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetZPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the Z index of the panel. + // Arguments: None. + + int GetZPos() const; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual Method: SetFont -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the font this panel will be using -// Arguments: The new font, ownership is NOT transferred! + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeZPosition + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes the Z Position of the panel. + // Arguments: Change type. + + void ChangeZPosition(int Type); - virtual void SetFont(GUIFont *pFont) { m_Font = pFont; m_ValidRegion = false; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ToString + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Convert the properties in the panel to a string. + // Arguments: None. + + std::string ToString(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds this panels properties to a properties class. + // Arguments: GUIProperties. + + void BuildProperties(GUIProperties* Prop); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: _SetVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the visibility of the panel. -// Arguments: Visible. + protected: + int m_X; // absolute coordinates + int m_Y; + int m_Width; + int m_Height; + + bool m_Visible; + bool m_Enabled; + bool m_GotFocus; + bool m_Captured; + GUIManager* m_Manager; + GUIPanel* m_Parent; + + GUIFont* m_Font; + unsigned long m_FontColor; + unsigned long m_FontShadow; + int m_FontKerning; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SendSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sends a signal to the target. + // Arguments: Signal code, Data. - void _SetVisible(bool Visible); + void SendSignal(int Code, int Data); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TrackMouseHover + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets up the manager to enable/disable hover tracking of this panel + // Arguments: Enabled, Delay (milliseconds) + void TrackMouseHover(bool Enabled, int Delay); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: _ChangeZ + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes the Z position of a child panel. + // Arguments: Child panel, Change type. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: _GetVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the visibility of the panel. -// Arguments: None. + void _ChangeZ(GUIPanel* Child, int Type); - bool _GetVisible() const; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WriteValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Writes a single value to string. + // Arguments: Value name, Value. + std::string WriteValue(const std::string& Name, int Value); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: _SetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the enabled state of the panel. -// Arguments: Enabled. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WriteValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Writes a single value to string. + // Arguments: Value name, Value. - void _SetEnabled(bool Enabled); + std::string WriteValue(const std::string& Name, bool Value); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: _ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the panel. + // Arguments: GUIProperties. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: _GetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the enabled state of the panel. -// Arguments: None. - - bool _GetEnabled() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the width of the panel. -// Arguments: None. - - int GetWidth() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the height of the panel. -// Arguments: None. - - int GetHeight() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetXPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the x position of the panel -// Arguments: None. - - int GetXPos() const { return m_X; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetYPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the y position of the panel -// Arguments: None. - - int GetYPos() const { return m_Y; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRelXPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the x position of the panel, relative to its parent -// Arguments: None. - - int GetRelXPos() const { return m_X - m_Parent->GetXPos(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRelYPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the y position of the panel, relative to its parent -// Arguments: None. - - int GetRelYPos() const { return m_Y - m_Parent->GetYPos(); } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the panel. -// Arguments: None. - - GUIRect * GetRect(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the panel. -// Arguments: X, Y, Width, Height - - void GetRect(int *X, int *Y, int *Width, int *Height) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetParentPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the parent of this panel. -// Arguments: None. - - GUIPanel * GetParentPanel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanelID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the panel's ID. -// Arguments: None. - - int GetPanelID() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCaptureState -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the panel's captured state. -// Arguments: Captured. - - void SetCaptureState(bool Captured); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsCaptured -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the panel's captured state. -// Arguments: None. - - bool IsCaptured() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the panel's enabled state. -// Arguments: None. - - bool IsEnabled() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSignalTarget -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the target panel to receive signals. -// Arguments: Target panel. - - void SetSignalTarget(GUIPanel *Target); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PointInside -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if a point is inside the panel -// Arguments: X, Y Coordinates of point -// Return value: A boolean of the check result - - virtual bool PointInside(int X, int Y); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the focus of this panel. -// Arguments: None. - - void SetFocus(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the focus value of the panel. -// Arguments: None. - - bool HasFocus() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetZPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the Z index of the panel. -// Arguments: ZPos. - - void SetZPos(int Z); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetZPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the Z index of the panel. -// Arguments: None. - - int GetZPos() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeZPosition -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes the Z Position of the panel. -// Arguments: Change type. - - void ChangeZPosition(int Type); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ToString -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Convert the properties in the panel to a string. -// Arguments: None. - - std::string ToString(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds this panels properties to a properties class. -// Arguments: GUIProperties. - - void BuildProperties(GUIProperties *Prop); - -protected: - - int m_X; // absolute coordinates - int m_Y; - int m_Width; - int m_Height; - - bool m_Visible; - bool m_Enabled; - bool m_GotFocus; - bool m_Captured; - GUIManager *m_Manager; - GUIPanel *m_Parent; - - GUIFont *m_Font; - unsigned long m_FontColor; - unsigned long m_FontShadow; - int m_FontKerning; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SendSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sends a signal to the target. -// Arguments: Signal code, Data. - - void SendSignal(int Code, int Data); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TrackMouseHover -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets up the manager to enable/disable hover tracking of this panel -// Arguments: Enabled, Delay (milliseconds) - - void TrackMouseHover(bool Enabled, int Delay); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: _ChangeZ -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes the Z position of a child panel. -// Arguments: Child panel, Change type. - - void _ChangeZ(GUIPanel *Child, int Type); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WriteValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Writes a single value to string. -// Arguments: Value name, Value. - - std::string WriteValue(const std::string &Name, int Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WriteValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Writes a single value to string. -// Arguments: Value name, Value. - - std::string WriteValue(const std::string &Name, bool Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: _ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the panel. -// Arguments: GUIProperties. - - void _ApplyProperties(GUIProperties *Props); + void _ApplyProperties(GUIProperties* Props); private: - - std::vector m_Children; + std::vector m_Children; GUIRect m_Rect; int m_ID; bool m_ValidRegion; int m_ZPos; - GUIPanel *m_SignalTarget; -}; -}; + GUIPanel* m_SignalTarget; + }; +}; // namespace RTE #endif diff --git a/Source/GUI/GUIProgressBar.cpp b/Source/GUI/GUIProgressBar.cpp index 0e0b340df..70ce7566c 100644 --- a/Source/GUI/GUIProgressBar.cpp +++ b/Source/GUI/GUIProgressBar.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIProgressBar::GUIProgressBar(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUIProgressBar::GUIProgressBar(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "PROGRESSBAR"; m_DrawBitmap = nullptr; m_IndicatorImage = nullptr; @@ -18,7 +19,7 @@ GUIProgressBar::GUIProgressBar(GUIManager *Manager, GUIControlManager *ControlMa ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProgressBar::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIProgressBar::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -35,8 +36,12 @@ void GUIProgressBar::Create(const std::string &Name, int X, int Y, int Width, in m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the control isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -45,7 +50,7 @@ void GUIProgressBar::Create(const std::string &Name, int X, int Y, int Width, in ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProgressBar::Create(GUIProperties *Props) { +void GUIProgressBar::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -92,7 +97,7 @@ void GUIProgressBar::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProgressBar::ChangeSkin(GUISkin *Skin) { +void GUIProgressBar::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Build the progressbar bitmap @@ -123,7 +128,7 @@ void GUIProgressBar::BuildBitmap() { // Build the indicator std::string Filename; m_Skin->GetValue("ProgressBar_Indicator", "Filename", &Filename); - GUIBitmap *Src = m_Skin->CreateBitmap(Filename); + GUIBitmap* Src = m_Skin->CreateBitmap(Filename); if (!Src) { return; } @@ -160,7 +165,7 @@ void GUIProgressBar::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProgressBar::Draw(GUIScreen *Screen) { +void GUIProgressBar::Draw(GUIScreen* Screen) { // Draw the base Screen->DrawBitmap(m_DrawBitmap, m_X, m_Y, nullptr); @@ -172,9 +177,11 @@ void GUIProgressBar::Draw(GUIScreen *Screen) { float Count = 0; if (m_Maximum - m_Minimum > 0) { float V = (float)(m_Value - m_Minimum) / (float)(m_Maximum - m_Minimum); - Count = (float)m_Width*V; + Count = (float)m_Width * V; + } + if (m_IndicatorImage->GetWidth() + m_Spacing > 0) { + Count = Count / (float)(m_IndicatorImage->GetWidth() + m_Spacing); } - if (m_IndicatorImage->GetWidth() + m_Spacing > 0) { Count = Count / (float)(m_IndicatorImage->GetWidth() + m_Spacing); } // Setup the clipping GUIRect Rect = *GetRect(); @@ -204,7 +211,9 @@ void GUIProgressBar::OnMouseDown(int X, int Y, int Buttons, int Modifier) { void GUIProgressBar::OnMouseUp(int X, int Y, int Buttons, int Modifier) { ReleaseMouse(); - if (PointInside(X, Y)) { AddEvent(GUIEvent::Notification, Clicked, Buttons); } + if (PointInside(X, Y)) { + AddEvent(GUIEvent::Notification, Clicked, Buttons); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -213,7 +222,7 @@ void GUIProgressBar::OnMouseMove(int X, int Y, int Buttons, int Modifier) {} ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIProgressBar::GetPanel() { +GUIPanel* GUIProgressBar::GetPanel() { return this; } @@ -238,7 +247,7 @@ void GUIProgressBar::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProgressBar::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIProgressBar::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -261,7 +270,9 @@ void GUIProgressBar::SetValue(int Value) { m_Value = std::max(m_Value, m_Minimum); // Changed? - if (m_Value != OldValue) { AddEvent(GUIEvent::Notification, Changed, 0); } + if (m_Value != OldValue) { + AddEvent(GUIEvent::Notification, Changed, 0); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -296,7 +307,7 @@ int GUIProgressBar::GetMaximum() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProgressBar::ApplyProperties(GUIProperties *Props) { +void GUIProgressBar::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); m_Properties.GetValue("Minimum", &m_Minimum); @@ -306,4 +317,4 @@ void GUIProgressBar::ApplyProperties(GUIProperties *Props) { // Clamp the value m_Value = std::max(m_Value, m_Minimum); m_Value = std::min(m_Value, m_Maximum); -} \ No newline at end of file +} diff --git a/Source/GUI/GUIProgressBar.h b/Source/GUI/GUIProgressBar.h index 4df813a6e..278145448 100644 --- a/Source/GUI/GUIProgressBar.h +++ b/Source/GUI/GUIProgressBar.h @@ -3,236 +3,212 @@ namespace RTE { -/// -/// A progressbar control class. -/// -class GUIProgressBar : public GUIControl, public GUIPanel { + /// + /// A progressbar control class. + /// + class GUIProgressBar : public GUIControl, public GUIPanel { + + public: + // Progressbar Notifications + enum { + Clicked = 0, + Changed + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIProgressBar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIProgressBar object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUIProgressBar(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "PROGRESSBAR"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the value. + // Arguments: Value. + + void SetValue(int Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the value. + // Arguments: None. + + int GetValue() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMinimum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the minimum. + // Arguments: Minimum. + + void SetMinimum(int Minimum); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMinimum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the minimum. + // Arguments: None. + + int GetMinimum() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMaximum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the maximum. + // Arguments: Maximum. + + void SetMaximum(int Maximum); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaximum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the maximum. + // Arguments: None. + + int GetMaximum() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; + + private: + GUIBitmap* m_DrawBitmap; + GUIBitmap* m_IndicatorImage; + + int m_Minimum; + int m_Maximum; + int m_Value; + int m_Spacing; -public: - - // Progressbar Notifications - enum { - Clicked = 0, - Changed - } Notification; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIProgressBar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIProgressBar object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUIProgressBar(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "PROGRESSBAR"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the value. -// Arguments: Value. - - void SetValue(int Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the value. -// Arguments: None. - - int GetValue() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMinimum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the minimum. -// Arguments: Minimum. - - void SetMinimum(int Minimum); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMinimum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the minimum. -// Arguments: None. - - int GetMinimum() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMaximum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the maximum. -// Arguments: Maximum. - - void SetMaximum(int Maximum); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaximum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the maximum. -// Arguments: None. - - int GetMaximum() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - - GUIBitmap *m_DrawBitmap; - GUIBitmap *m_IndicatorImage; - - int m_Minimum; - int m_Maximum; - int m_Value; - int m_Spacing; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the progressbar bitmap to draw. -// Arguments: None. - - void BuildBitmap(); -}; -}; -#endif \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the progressbar bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIProperties.cpp b/Source/GUI/GUIProperties.cpp index 406abdf72..622320d54 100644 --- a/Source/GUI/GUIProperties.cpp +++ b/Source/GUI/GUIProperties.cpp @@ -4,7 +4,7 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIProperties::GUIProperties(const std::string &Name) { +GUIProperties::GUIProperties(const std::string& Name) { m_Name = Name; m_VariableList.clear(); } @@ -26,10 +26,10 @@ GUIProperties::~GUIProperties() { void GUIProperties::Clear() { // Free the list - std::vector ::iterator it; + std::vector::iterator it; for (it = m_VariableList.begin(); it != m_VariableList.end(); it++) { - PropVariable *p = *it; + PropVariable* p = *it; // Free the property delete p; @@ -39,7 +39,7 @@ void GUIProperties::Clear() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProperties::AddVariable(const std::string &Variable, const std::string &Value) { +void GUIProperties::AddVariable(const std::string& Variable, const std::string& Value) { // If this property already exists, just update it std::string Val; if (GetValue(Variable, &Val)) { @@ -47,7 +47,7 @@ void GUIProperties::AddVariable(const std::string &Variable, const std::string & return; } - PropVariable *Prop = new PropVariable; + PropVariable* Prop = new PropVariable; Prop->m_Name = Variable; Prop->m_Value = Value; @@ -57,7 +57,7 @@ void GUIProperties::AddVariable(const std::string &Variable, const std::string & ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProperties::AddVariable(const std::string &Variable, char *Value) { +void GUIProperties::AddVariable(const std::string& Variable, char* Value) { std::string Val = Value; AddVariable(Variable, Val); @@ -65,7 +65,7 @@ void GUIProperties::AddVariable(const std::string &Variable, char *Value) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProperties::AddVariable(const std::string &Variable, int Value) { +void GUIProperties::AddVariable(const std::string& Variable, int Value) { char buf[32]; std::snprintf(buf, sizeof(buf), "%i", Value); std::string Val(buf); @@ -74,19 +74,19 @@ void GUIProperties::AddVariable(const std::string &Variable, int Value) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProperties::AddVariable(const std::string &Variable, bool Value) { +void GUIProperties::AddVariable(const std::string& Variable, bool Value) { std::string Val = Value ? "True" : "False"; AddVariable(Variable, Val); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::SetValue(const std::string &Variable, const std::string &Value) { +bool GUIProperties::SetValue(const std::string& Variable, const std::string& Value) { // Find the property - std::vector ::iterator it; + std::vector::iterator it; for (it = m_VariableList.begin(); it != m_VariableList.end(); it++) { - PropVariable *p = *it; + PropVariable* p = *it; // Matching name? if (stricmp(p->m_Name.c_str(), Variable.c_str()) == 0) { @@ -101,7 +101,7 @@ bool GUIProperties::SetValue(const std::string &Variable, const std::string &Val ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::SetValue(const std::string &Variable, int Value) { +bool GUIProperties::SetValue(const std::string& Variable, int Value) { char buf[64]; std::snprintf(buf, sizeof(buf), "%i", Value); @@ -110,27 +110,29 @@ bool GUIProperties::SetValue(const std::string &Variable, int Value) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIProperties::Update(GUIProperties *Props, bool Add) { +void GUIProperties::Update(GUIProperties* Props, bool Add) { assert(Props); - std::vector ::iterator it1; + std::vector::iterator it1; for (it1 = Props->m_VariableList.begin(); it1 != Props->m_VariableList.end(); it1++) { - const PropVariable *Src = *it1; + const PropVariable* Src = *it1; // Set the variable - if (!SetValue(Src->m_Name, Src->m_Value) && Add) { AddVariable(Src->m_Name, Src->m_Value); } + if (!SetValue(Src->m_Name, Src->m_Value) && Add) { + AddVariable(Src->m_Name, Src->m_Value); + } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::GetValue(const std::string &Variable, std::string *Value) { +bool GUIProperties::GetValue(const std::string& Variable, std::string* Value) { // Find the property - std::vector ::iterator it; + std::vector::iterator it; for (it = m_VariableList.begin(); it != m_VariableList.end(); it++) { - const PropVariable *p = *it; + const PropVariable* p = *it; // Matching name? if (stricmp(p->m_Name.c_str(), Variable.c_str()) == 0) { @@ -145,7 +147,7 @@ bool GUIProperties::GetValue(const std::string &Variable, std::string *Value) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int GUIProperties::GetValue(const std::string &Variable, std::string *Array, int MaxArraySize) { +int GUIProperties::GetValue(const std::string& Variable, std::string* Array, int MaxArraySize) { assert(Array); std::string Value; @@ -155,13 +157,13 @@ int GUIProperties::GetValue(const std::string &Variable, std::string *Array, int return 0; } // Create a c string version of the value for tokenizing - char *str = new char[Value.length() + 1]; + char* str = new char[Value.length() + 1]; if (!str) { return 0; } // Tokenize the string strcpy(str, Value.c_str()); - char *tok = strtok(str, ","); + char* tok = strtok(str, ","); int count = 0; while (tok && count < MaxArraySize) { @@ -177,7 +179,7 @@ int GUIProperties::GetValue(const std::string &Variable, std::string *Array, int ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int GUIProperties::GetValue(const std::string &Variable, int *Array, int MaxArraySize) { +int GUIProperties::GetValue(const std::string& Variable, int* Array, int MaxArraySize) { assert(Array); std::string Value; @@ -187,13 +189,13 @@ int GUIProperties::GetValue(const std::string &Variable, int *Array, int MaxArra return 0; } // Create a c string version of the value for tokenizing - char *str = new char[Value.length() + 1]; + char* str = new char[Value.length() + 1]; if (!str) { return 0; } // Tokenize the string strcpy(str, Value.c_str()); - char *tok = strtok(str, ","); + char* tok = strtok(str, ","); int count = 0; while (tok && count < MaxArraySize) { @@ -209,7 +211,7 @@ int GUIProperties::GetValue(const std::string &Variable, int *Array, int MaxArra ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::GetValue(const std::string &Variable, int *Value) { +bool GUIProperties::GetValue(const std::string& Variable, int* Value) { assert(Value); std::string val; @@ -226,7 +228,7 @@ bool GUIProperties::GetValue(const std::string &Variable, int *Value) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::GetValue(const std::string &Variable, unsigned long *Value) { +bool GUIProperties::GetValue(const std::string& Variable, unsigned long* Value) { assert(Value); std::string val; @@ -243,7 +245,7 @@ bool GUIProperties::GetValue(const std::string &Variable, unsigned long *Value) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::GetValue(const std::string &Variable, bool *Value) { +bool GUIProperties::GetValue(const std::string& Variable, bool* Value) { assert(Value); std::string val; @@ -256,7 +258,9 @@ bool GUIProperties::GetValue(const std::string &Variable, bool *Value) { *Value = false; // Convert the string into a boolean - if (stricmp(val.c_str(), "true") == 0) { *Value = true; } + if (stricmp(val.c_str(), "true") == 0) { + *Value = true; + } // Found the value return true; @@ -274,9 +278,9 @@ std::string GUIProperties::ToString() { std::string OutString = ""; // Go through each value - std::vector ::iterator it; + std::vector::iterator it; for (it = m_VariableList.begin(); it != m_VariableList.end(); it++) { - const PropVariable *V = *it; + const PropVariable* V = *it; OutString += V->m_Name; OutString.append(" = "); @@ -294,27 +298,31 @@ int GUIProperties::GetCount() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::GetVariable(int Index, std::string *Name, std::string *Value) { +bool GUIProperties::GetVariable(int Index, std::string* Name, std::string* Value) { // Check for a bad index if (Index < 0 || Index >= m_VariableList.size()) { return false; } - const PropVariable *P = (PropVariable *)m_VariableList.at(Index); - if (Name) { *Name = P->m_Name; } - if (Value) { *Value = P->m_Value; } + const PropVariable* P = (PropVariable*)m_VariableList.at(Index); + if (Name) { + *Name = P->m_Name; + } + if (Value) { + *Value = P->m_Value; + } return true; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUIProperties::SetVariable(int Index, const std::string &Name, const std::string &Value) { +bool GUIProperties::SetVariable(int Index, const std::string& Name, const std::string& Value) { // Check for a bad index if (Index < 0 || Index >= m_VariableList.size()) { return false; } - PropVariable *P = m_VariableList.at(Index); + PropVariable* P = m_VariableList.at(Index); P->m_Name = Name; P->m_Value = Value; @@ -330,8 +338,8 @@ void GUIProperties::Sort(bool Ascending) { for (int j = 0; j < m_VariableList.size() - 1 - i; j++) { - PropVariable *V = m_VariableList.at(j); - PropVariable *V2 = m_VariableList.at(j + 1); + PropVariable* V = m_VariableList.at(j); + PropVariable* V2 = m_VariableList.at(j + 1); if ((V->m_Name.compare(V2->m_Name) > 0 && Ascending) || (V->m_Name.compare(V2->m_Name) < 0 && !Ascending)) { // Swap em diff --git a/Source/GUI/GUIProperties.h b/Source/GUI/GUIProperties.h index 3086a8c5e..e5af9ea1b 100644 --- a/Source/GUI/GUIProperties.h +++ b/Source/GUI/GUIProperties.h @@ -3,233 +3,208 @@ namespace RTE { -/// -/// A class containing properties for controls and skins. -/// -class GUIProperties { + /// + /// A class containing properties for controls and skins. + /// + class GUIProperties { + + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIProperties object in + // system memory. + // Arguments: Name of section. + + explicit GUIProperties(const std::string& Name); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIProperties object in + // system memory. + // Arguments: None. + + GUIProperties(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: GUIProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to free a GUIProperties object in system + // memory. + // Arguments: None. + + ~GUIProperties(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the properties. + // Arguments: None. + + void Clear(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddVariable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a new variable to the properties + // Arguments: Variable, Value + + void AddVariable(const std::string& Variable, const std::string& Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddVariable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a new variable to the properties + // Arguments: Variable, Value + + void AddVariable(const std::string& Variable, char* Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddVariable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a new variable to the properties + // Arguments: Variable, Value + + void AddVariable(const std::string& Variable, int Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddVariable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a new variable to the properties + // Arguments: Variable, Value + + void AddVariable(const std::string& Variable, bool Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes the value of a property. + // Arguments: Variable, Value + // Returns: True if the variable was set. Otherwise false. + + bool SetValue(const std::string& Variable, const std::string& Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes the value of a property. + // Arguments: Variable, Value + // Returns: True if the variable was set. Otherwise false. + + bool SetValue(const std::string& Variable, int Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the properties with properties from another instance. + // Arguments: Pointer to a Properties class, whether to add variables. + + void Update(GUIProperties* Props, bool Add = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a string value + // Arguments: Variable, String pointer + + bool GetValue(const std::string& Variable, std::string* Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a string array of values + // Arguments: Variable, String array, max size of array + // Returns: Number of elements read + + int GetValue(const std::string& Variable, std::string* Array, int MaxArraySize); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets an integer array of values + // Arguments: Variable, Integer array, max size of array + // Returns: Number of elements read -public: + int GetValue(const std::string& Variable, int* Array, int MaxArraySize); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a single interger + // Arguments: Variable, Integer pointer + bool GetValue(const std::string& Variable, int* Value); -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIProperties object in -// system memory. -// Arguments: Name of section. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a single unsigned interger + // Arguments: Variable, Unsigned Integer pointer - explicit GUIProperties(const std::string &Name); + bool GetValue(const std::string& Variable, unsigned long* Value); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a boolean value + // Arguments: Variable, Boolean pointer -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIProperties object in -// system memory. -// Arguments: None. + bool GetValue(const std::string& Variable, bool* Value); - GUIProperties(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the property name + std::string GetName() const; -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: GUIProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to free a GUIProperties object in system -// memory. -// Arguments: None. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ToString + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Converts the properties to a string - ~GUIProperties(); + std::string ToString(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the variable count in the properties -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the properties. -// Arguments: None. + int GetCount() const; - void Clear(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetVariable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a variable based on index + bool GetVariable(int Index, std::string* Name, std::string* Value); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddVariable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a new variable to the properties -// Arguments: Variable, Value + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetVariable + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets a variable based on index - void AddVariable(const std::string &Variable, const std::string &Value); + bool SetVariable(int Index, const std::string& Name, const std::string& Value); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Sort + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sorts the list by variable name + // Arguments: True for ascending, False for descending -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddVariable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a new variable to the properties -// Arguments: Variable, Value + void Sort(bool Ascending); - void AddVariable(const std::string &Variable, char *Value); + private: + // Variable structure + typedef struct { + std::string m_Name; + std::string m_Value; + } PropVariable; + std::string m_Name; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddVariable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a new variable to the properties -// Arguments: Variable, Value - - void AddVariable(const std::string &Variable, int Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddVariable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a new variable to the properties -// Arguments: Variable, Value - - void AddVariable(const std::string &Variable, bool Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes the value of a property. -// Arguments: Variable, Value -// Returns: True if the variable was set. Otherwise false. - - bool SetValue(const std::string &Variable, const std::string &Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes the value of a property. -// Arguments: Variable, Value -// Returns: True if the variable was set. Otherwise false. - - bool SetValue(const std::string &Variable, int Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the properties with properties from another instance. -// Arguments: Pointer to a Properties class, whether to add variables. - - void Update(GUIProperties *Props, bool Add = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a string value -// Arguments: Variable, String pointer - - bool GetValue(const std::string &Variable, std::string *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a string array of values -// Arguments: Variable, String array, max size of array -// Returns: Number of elements read - - int GetValue(const std::string &Variable, std::string *Array, int MaxArraySize); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets an integer array of values -// Arguments: Variable, Integer array, max size of array -// Returns: Number of elements read - - int GetValue(const std::string &Variable, int *Array, int MaxArraySize); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a single interger -// Arguments: Variable, Integer pointer - - bool GetValue(const std::string &Variable, int *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a single unsigned interger -// Arguments: Variable, Unsigned Integer pointer - - bool GetValue(const std::string &Variable, unsigned long *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a boolean value -// Arguments: Variable, Boolean pointer - - bool GetValue(const std::string &Variable, bool *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the property name - - std::string GetName() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ToString -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Converts the properties to a string - - std::string ToString(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the variable count in the properties - - int GetCount() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetVariable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a variable based on index - - bool GetVariable(int Index, std::string *Name, std::string *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetVariable -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets a variable based on index - - bool SetVariable(int Index, const std::string &Name, const std::string &Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Sort -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sorts the list by variable name -// Arguments: True for ascending, False for descending - - void Sort(bool Ascending); - -private: - - // Variable structure - typedef struct { - std::string m_Name; - std::string m_Value; - } PropVariable; - - std::string m_Name; - - std::vector m_VariableList; -}; -}; -#endif \ No newline at end of file + std::vector m_VariableList; + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIPropertyPage.cpp b/Source/GUI/GUIPropertyPage.cpp index a2d90e1a0..f26d85ff1 100644 --- a/Source/GUI/GUIPropertyPage.cpp +++ b/Source/GUI/GUIPropertyPage.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPropertyPage::GUIPropertyPage(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUIPropertyPage::GUIPropertyPage(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "PROPERTYPAGE"; m_DrawBitmap = nullptr; m_ControlManager = ControlManager; @@ -19,7 +20,7 @@ GUIPropertyPage::GUIPropertyPage(GUIManager *Manager, GUIControlManager *Control ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPropertyPage::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIPropertyPage::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -36,8 +37,12 @@ void GUIPropertyPage::Create(const std::string &Name, int X, int Y, int Width, i m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the control isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -59,8 +64,8 @@ void GUIPropertyPage::Create(const std::string &Name, int X, int Y, int Width, i int Spacer = 0; int Size = m_Height / H; for (int i = 0; i < Size; i++) { - GUITextPanel *T = new GUITextPanel(m_Manager); - T->Create(m_Width / 2, i*H + Spacer, m_Width / 2, H); + GUITextPanel* T = new GUITextPanel(m_Manager); + T->Create(m_Width / 2, i * H + Spacer, m_Width / 2, H); T->_SetVisible(false); T->SetSignalTarget(this); GUIPanel::AddChild(T); @@ -71,7 +76,7 @@ void GUIPropertyPage::Create(const std::string &Name, int X, int Y, int Width, i ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPropertyPage::Create(GUIProperties *Props) { +void GUIPropertyPage::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -105,8 +110,8 @@ void GUIPropertyPage::Create(GUIProperties *Props) { int Spacer = 0; int Size = m_Height / H; for (int i = 0; i < Size; i++) { - GUITextPanel *T = new GUITextPanel(m_Manager); - T->Create(m_Width / 2, i*H + Spacer, m_Width / 2, H); + GUITextPanel* T = new GUITextPanel(m_Manager); + T->Create(m_Width / 2, i * H + Spacer, m_Width / 2, H); T->_SetVisible(false); T->SetSignalTarget(this); GUIPanel::AddChild(T); @@ -135,11 +140,11 @@ void GUIPropertyPage::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPropertyPage::ChangeSkin(GUISkin *Skin) { +void GUIPropertyPage::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Change the skin of the text panels - for (GUITextPanel *textPanel : m_TextPanelList) { + for (GUITextPanel* textPanel: m_TextPanelList) { textPanel->ChangeSkin(Skin); } @@ -162,8 +167,6 @@ void GUIPropertyPage::BuildBitmap() { m_Skin->BuildStandardRect(m_DrawBitmap, "PropertyPage", 0, 0, m_Width, m_Height); - - // Pre-cache the font std::string Filename; m_Skin->GetValue("PropertyPage", "Font", &Filename); @@ -174,7 +177,9 @@ void GUIPropertyPage::BuildBitmap() { m_FontColor = m_Skin->ConvertColor(m_FontColor, m_DrawBitmap->GetColorDepth()); m_Font = m_Skin->GetFont(Filename); - if (m_Font) { m_Font->CacheColor(m_FontColor); } + if (m_Font) { + m_Font->CacheColor(m_FontColor); + } m_Skin->GetValue("PropertyPage", "LineColor", &m_LineColor); m_LineColor = m_Skin->ConvertColor(m_LineColor, m_DrawBitmap->GetColorDepth()); @@ -182,8 +187,10 @@ void GUIPropertyPage::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPropertyPage::Draw(GUIScreen *Screen) { - if (m_DrawBitmap) { m_DrawBitmap->Draw(Screen->GetBitmap(), m_X, m_Y, nullptr); } +void GUIPropertyPage::Draw(GUIScreen* Screen) { + if (m_DrawBitmap) { + m_DrawBitmap->Draw(Screen->GetBitmap(), m_X, m_Y, nullptr); + } // Check the font first if (!m_Font) { @@ -217,10 +224,10 @@ void GUIPropertyPage::Draw(GUIScreen *Screen) { void GUIPropertyPage::OnMouseDown(int X, int Y, int Buttons, int Modifier) { if (Buttons & MOUSE_LEFT) { // Push the button down - //m_Pushed = true; - //CaptureMouse(); + // m_Pushed = true; + // CaptureMouse(); - //AddEvent(GUIEvent::Notification, Pushed, 0); + // AddEvent(GUIEvent::Notification, Pushed, 0); } SetFocus(); } @@ -249,13 +256,13 @@ void GUIPropertyPage::OnMouseMove(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIPropertyPage::GetPanel() { +GUIPanel* GUIPropertyPage::GetPanel() { return this; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPropertyPage::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIPropertyPage::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -287,13 +294,13 @@ void GUIPropertyPage::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPropertyPage::SetPropertyValues(GUIProperties *Props) { +void GUIPropertyPage::SetPropertyValues(GUIProperties* Props) { m_PageValues.Clear(); m_PageValues.Update(Props, true); // Update the text panels for (int i = 0; i < m_TextPanelList.size(); i++) { - GUITextPanel *T = m_TextPanelList.at(i); + GUITextPanel* T = m_TextPanelList.at(i); T->_SetVisible(false); T->SetText(""); @@ -301,28 +308,30 @@ void GUIPropertyPage::SetPropertyValues(GUIProperties *Props) { T->_SetVisible(true); std::string Name; std::string Value; - if (m_PageValues.GetVariable(i, &Name, &Value)) { T->SetText(Value); } + if (m_PageValues.GetVariable(i, &Name, &Value)) { + T->SetText(Value); + } } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIProperties * GUIPropertyPage::GetPropertyValues() { +GUIProperties* GUIPropertyPage::GetPropertyValues() { return &m_PageValues; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIPropertyPage::ReceiveSignal(GUIPanel *Source, int Code, int Data) { +void GUIPropertyPage::ReceiveSignal(GUIPanel* Source, int Code, int Data) { assert(Source); bool TextSignal = false; // Is this a text panel? - std::vector::iterator it; + std::vector::iterator it; for (it = m_TextPanelList.begin(); it != m_TextPanelList.end(); it++) { - const GUITextPanel *T = *it; + const GUITextPanel* T = *it; if (Source->GetPanelID() == T->GetPanelID()) { TextSignal = true; @@ -350,13 +359,15 @@ bool GUIPropertyPage::InvokeUpdate() { bool Changed = false; for (int i = 0; i < m_TextPanelList.size(); i++) { - const GUITextPanel *T = m_TextPanelList.at(i); + const GUITextPanel* T = m_TextPanelList.at(i); if (i < m_PageValues.GetCount()) { std::string Name; std::string Value; if (m_PageValues.GetVariable(i, &Name, &Value)) { - if (T->GetText().compare(Value) != 0) { Changed = true; } + if (T->GetText().compare(Value) != 0) { + Changed = true; + } // Set the value m_PageValues.SetVariable(i, Name, T->GetText()); } @@ -372,9 +383,9 @@ void GUIPropertyPage::ClearValues() { m_PageValues.Clear(); // Hide the text panels - std::vector::iterator it; + std::vector::iterator it; for (it = m_TextPanelList.begin(); it != m_TextPanelList.end(); it++) { - GUITextPanel *T = *it; + GUITextPanel* T = *it; T->_SetVisible(false); } } @@ -382,9 +393,9 @@ void GUIPropertyPage::ClearValues() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIPropertyPage::HasTextFocus() { - std::vector::iterator it; + std::vector::iterator it; for (it = m_TextPanelList.begin(); it != m_TextPanelList.end(); it++) { - const GUITextPanel *T = *it; + const GUITextPanel* T = *it; // Visible & has focus?? if (T->_GetVisible() && T->HasFocus()) { diff --git a/Source/GUI/GUIPropertyPage.h b/Source/GUI/GUIPropertyPage.h index da59102a8..8e1b32d85 100644 --- a/Source/GUI/GUIPropertyPage.h +++ b/Source/GUI/GUIPropertyPage.h @@ -6,245 +6,220 @@ namespace RTE { -/// -/// A property page control class. -/// -class GUIPropertyPage : public GUIControl, public GUIPanel { + /// + /// A property page control class. + /// + class GUIPropertyPage : public GUIControl, public GUIPanel { + + public: + // PropertyPage Notifications + enum { + Changed = 0, // Any text panel has changed. Property values are NOT updated + Enter // A text panel has lost focus or the enter key was hit + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIPropertyPage + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIPropertyPage object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUIPropertyPage(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseEnter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse enters the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseLeave + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse leaves the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "PROPERTYPAGE"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPropertyValues + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Refreshes the page with new variables & values. + // Arguments: GUIProperties. + + void SetPropertyValues(GUIProperties* Props); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPropertyValues + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the properties in the page. + // Arguments: None. + + GUIProperties* GetPropertyValues(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReceiveSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when receiving a signal. + // Arguments: Signal source, Signal code, Signal data. + + void ReceiveSignal(GUIPanel* Source, int Code, int Data) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearValues + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the property page values. + // Arguments: None. + + void ClearValues(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: InvokeUpdate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Invokes an explicit update on text panels to property page. + // Arguments: None. + // Returns: Boolean whether or not any values have changed. + + bool InvokeUpdate(); -public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HasTextFocus + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks if any of the visible text panels have focus. + // Arguments: None. + + bool HasTextFocus(); - // PropertyPage Notifications - enum { - Changed = 0, // Any text panel has changed. Property values are NOT updated - Enter // A text panel has lost focus or the enter key was hit - } Notification; + private: + GUIBitmap* m_DrawBitmap; + unsigned long m_LineColor; + + GUIProperties m_PageValues; + std::vector m_TextPanelList; + GUIScrollPanel* m_VertScroll; - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIPropertyPage -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIPropertyPage object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUIPropertyPage(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseEnter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse enters the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseLeave -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse leaves the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "PROPERTYPAGE"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPropertyValues -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Refreshes the page with new variables & values. -// Arguments: GUIProperties. - - void SetPropertyValues(GUIProperties *Props); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPropertyValues -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the properties in the page. -// Arguments: None. - - GUIProperties * GetPropertyValues(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReceiveSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when receiving a signal. -// Arguments: Signal source, Signal code, Signal data. - - void ReceiveSignal(GUIPanel *Source, int Code, int Data) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearValues -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the property page values. -// Arguments: None. - - void ClearValues(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: InvokeUpdate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Invokes an explicit update on text panels to property page. -// Arguments: None. -// Returns: Boolean whether or not any values have changed. - - bool InvokeUpdate(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HasTextFocus -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks if any of the visible text panels have focus. -// Arguments: None. - - bool HasTextFocus(); - -private: - - GUIBitmap *m_DrawBitmap; - unsigned long m_LineColor; - - GUIProperties m_PageValues; - std::vector m_TextPanelList; - GUIScrollPanel *m_VertScroll; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: BuildBitmap - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Create the property page bitmap to draw. - // Arguments: None. - - void BuildBitmap(); -}; -}; -#endif \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the property page bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIRadioButton.cpp b/Source/GUI/GUIRadioButton.cpp index 5ba54eb5d..605ac2872 100644 --- a/Source/GUI/GUIRadioButton.cpp +++ b/Source/GUI/GUIRadioButton.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIRadioButton::GUIRadioButton(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUIRadioButton::GUIRadioButton(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "RADIOBUTTON"; m_Image = nullptr; m_ControlManager = ControlManager; @@ -18,7 +19,7 @@ GUIRadioButton::GUIRadioButton(GUIManager *Manager, GUIControlManager *ControlMa ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIRadioButton::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIRadioButton::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -35,8 +36,12 @@ void GUIRadioButton::Create(const std::string &Name, int X, int Y, int Width, in m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the button isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -45,7 +50,7 @@ void GUIRadioButton::Create(const std::string &Name, int X, int Y, int Width, in ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIRadioButton::Create(GUIProperties *Props) { +void GUIRadioButton::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -70,7 +75,7 @@ void GUIRadioButton::Create(GUIProperties *Props) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIRadioButton::ChangeSkin(GUISkin *Skin) { +void GUIRadioButton::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Build the checkbox bitmap @@ -126,7 +131,7 @@ void GUIRadioButton::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIRadioButton::Draw(GUIScreen *Screen) { +void GUIRadioButton::Draw(GUIScreen* Screen) { if (!m_Image) { return; } @@ -147,13 +152,15 @@ void GUIRadioButton::Draw(GUIScreen *Screen) { if (m_Checked) { if (m_Enabled) { m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[2]); - } //else { - //m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[3]); + } // else { + // m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[3]); //} } // Should show as grayed out and disabled when it is, regardless of checked or not - if (!m_Enabled) { m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[3]); } + if (!m_Enabled) { + m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[3]); + } // Draw the text @@ -190,7 +197,9 @@ void GUIRadioButton::OnMouseUp(int X, int Y, int Buttons, int Modifier) { ReleaseMouse(); // If the mouse is over the button, add the command to the event queue - if (PointInside(X, Y) && Buttons & MOUSE_LEFT) { SetCheck(true); } + if (PointInside(X, Y) && Buttons & MOUSE_LEFT) { + SetCheck(true); + } AddEvent(GUIEvent::Notification, UnPushed, 0); } @@ -209,7 +218,7 @@ void GUIRadioButton::OnMouseLeave(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIRadioButton::GetPanel() { +GUIPanel* GUIRadioButton::GetPanel() { return this; } @@ -234,7 +243,7 @@ void GUIRadioButton::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIRadioButton::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIRadioButton::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -264,11 +273,11 @@ void GUIRadioButton::SetCheck(bool Check) { // Go through all my RadioButton siblings and un-check them if (m_ControlParent) { - std::vector::iterator it; - std::vector *Children = m_ControlParent->GetChildren(); + std::vector::iterator it; + std::vector* Children = m_ControlParent->GetChildren(); for (it = Children->begin(); it != Children->end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; if (C) { // Make sure this is not me if (C->GetPanel() && GetPanel() && C->GetPanel()->GetPanelID() == GetPanel()->GetPanelID()) { @@ -277,7 +286,7 @@ void GUIRadioButton::SetCheck(bool Check) { // Make sure the control is a radio button if (C->GetID().compare(GetID()) == 0) { - GUIRadioButton *R = (GUIRadioButton *)C; + GUIRadioButton* R = (GUIRadioButton*)C; R->SetCheck(false); } } @@ -293,7 +302,7 @@ bool GUIRadioButton::GetCheck() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIRadioButton::SetText(const std::string &Text) { +void GUIRadioButton::SetText(const std::string& Text) { m_Text = Text; } @@ -305,9 +314,9 @@ std::string GUIRadioButton::GetText() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIRadioButton::ApplyProperties(GUIProperties *Props) { +void GUIRadioButton::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); m_Properties.GetValue("Text", &m_Text); m_Properties.GetValue("Checked", &m_Checked); -} \ No newline at end of file +} diff --git a/Source/GUI/GUIRadioButton.h b/Source/GUI/GUIRadioButton.h index 855cf2831..1d4bc69f5 100644 --- a/Source/GUI/GUIRadioButton.h +++ b/Source/GUI/GUIRadioButton.h @@ -3,218 +3,196 @@ namespace RTE { -/// -/// A radiobutton control class. -/// -class GUIRadioButton : public GUIControl, public GUIPanel { + /// + /// A radiobutton control class. + /// + class GUIRadioButton : public GUIControl, public GUIPanel { + + public: + // RadioButton Notifications + enum { + Pushed = 0, + UnPushed, + Changed, + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIRadioButton + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIRadioButton object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUIRadioButton(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseEnter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse enters the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseLeave + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse leaves the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "RADIOBUTTON"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; -public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; - // RadioButton Notifications - enum { - Pushed = 0, - UnPushed, - Changed, - } Notification; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the check state. + // Arguments: State. + + void SetCheck(bool Check); -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIRadioButton -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIRadioButton object in -// system memory. -// Arguments: GUIManager, GUIControlManager. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the check state. + // Arguments: None. + + bool GetCheck() const; - GUIRadioButton(GUIManager *Manager, GUIControlManager *ControlManager); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the text. + // Arguments: Text. + + void SetText(const std::string& Text); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the text. + // Arguments: None. + + std::string GetText() const; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; + private: + GUIBitmap* m_Image; + GUIRect m_ImageRects[4]; + + bool m_Checked; + int m_Mouseover; + std::string m_Text; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseEnter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse enters the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseLeave -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse leaves the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "RADIOBUTTON"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the check state. -// Arguments: State. - - void SetCheck(bool Check); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the check state. -// Arguments: None. - - bool GetCheck() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the text. -// Arguments: Text. - - void SetText(const std::string &Text); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the text. -// Arguments: None. - - std::string GetText() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - - GUIBitmap *m_Image; - GUIRect m_ImageRects[4]; - - bool m_Checked; - int m_Mouseover; - std::string m_Text; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: BuildBitmap - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Create the checkbox bitmap to draw. - // Arguments: None. - - void BuildBitmap(); -}; -}; -#endif \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the checkbox bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIReader.cpp b/Source/GUI/GUIReader.cpp index a47e33e0a..4b26e02f3 100644 --- a/Source/GUI/GUIReader.cpp +++ b/Source/GUI/GUIReader.cpp @@ -3,11 +3,12 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader::StreamInfo::StreamInfo(std::ifstream *stream, const std::string &filePath, int currentLine, int prevIndent) : Stream(stream), FilePath(filePath), CurrentLine(currentLine), PreviousIndent(prevIndent) {} + GUIReader::StreamInfo::StreamInfo(std::ifstream* stream, const std::string& filePath, int currentLine, int prevIndent) : + Stream(stream), FilePath(filePath), CurrentLine(currentLine), PreviousIndent(prevIndent) {} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIReader::Clear() { m_Stream = nullptr; @@ -22,15 +23,15 @@ namespace RTE { m_SkipIncludes = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// GUIReader::GUIReader() { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GUIReader::Create(const std::string &fileName) { + int GUIReader::Create(const std::string& fileName) { m_FilePath = std::filesystem::path(fileName).generic_string(); if (m_FilePath.empty()) { @@ -43,37 +44,37 @@ namespace RTE { return m_Stream->good() ? 0 : -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::istream * GUIReader::GetStream() const { + std::istream* GUIReader::GetStream() const { return m_Stream.get(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIReader::GetCurrentFilePath() const { return m_FilePath; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIReader::GetCurrentFileLine() const { return std::to_string(m_CurrentLine); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIReader::GetSkipIncludes() const { return m_SkipIncludes; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIReader::SetSkipIncludes(bool skip) { m_SkipIncludes = skip; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIReader::ReadLine() { DiscardEmptySpace(); @@ -91,8 +92,12 @@ namespace RTE { break; } - if (m_Stream->eof()) { break; } - if (!m_Stream->good()) { ReportError("Stream failed for some reason"); } + if (m_Stream->eof()) { + break; + } + if (!m_Stream->good()) { + ReportError("Stream failed for some reason"); + } retString.append(1, temp); peek = static_cast(m_Stream->peek()); @@ -100,7 +105,7 @@ namespace RTE { return TrimString(retString); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIReader::ReadPropName() { DiscardEmptySpace(); @@ -123,7 +128,9 @@ namespace RTE { EndIncludeFile(); break; } - if (!m_Stream->good()) { ReportError("Stream failed for some reason"); } + if (!m_Stream->good()) { + ReportError("Stream failed for some reason"); + } retString.append(1, temp); } // Trim the string of whitespace @@ -146,7 +153,7 @@ namespace RTE { return retString; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIReader::ReadPropValue() { std::string fullLine = ReadLine(); @@ -155,7 +162,7 @@ namespace RTE { return TrimString(propValue); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIReader::NextProperty() { if (!DiscardEmptySpace() || m_EndOfStreams) { @@ -170,9 +177,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string GUIReader::TrimString(const std::string &stringToTrim) const { + std::string GUIReader::TrimString(const std::string& stringToTrim) const { if (stringToTrim.empty()) { return ""; } @@ -182,7 +189,7 @@ namespace RTE { return stringToTrim.substr(start, (end - start + 1)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIReader::DiscardEmptySpace() { char peek; @@ -197,42 +204,52 @@ namespace RTE { return EndIncludeFile(); } // Not end-of-file but still got junk back... something went to shit - if (peek == -1) { ReportError("Something went wrong reading the line; make sure it is providing the expected type"); } + if (peek == -1) { + ReportError("Something went wrong reading the line; make sure it is providing the expected type"); + } // Discard spaces if (peek == ' ') { m_Stream->ignore(1); - // Discard tabs, and count them + // Discard tabs, and count them } else if (peek == '\t') { indent++; m_Stream->ignore(1); - // Discard newlines and reset the tab count for the new line, also count the lines + // Discard newlines and reset the tab count for the new line, also count the lines } else if (peek == '\n' || peek == '\r') { // So we don't count lines twice when there are both newline and carriage return at the end of lines - if (peek == '\n') { m_CurrentLine++; } + if (peek == '\n') { + m_CurrentLine++; + } indent = 0; discardedLine = true; m_Stream->ignore(1); - // Comment line? + // Comment line? } else if (m_Stream->peek() == '/') { char temp = static_cast(m_Stream->get()); char temp2; // Confirm that it's a comment line, if so discard it and continue if (m_Stream->peek() == '/') { - while (m_Stream->peek() != '\n' && m_Stream->peek() != '\r' && !m_Stream->eof()) { m_Stream->ignore(1); } - // Block comment + while (m_Stream->peek() != '\n' && m_Stream->peek() != '\r' && !m_Stream->eof()) { + m_Stream->ignore(1); + } + // Block comment } else if (m_Stream->peek() == '*') { // Find the matching "*/" while (!((temp2 = static_cast(m_Stream->get())) == '*' && m_Stream->peek() == '/') && !m_Stream->eof()) { // Count the lines within the comment though - if (temp2 == '\n') { ++m_CurrentLine; } + if (temp2 == '\n') { + ++m_CurrentLine; + } } // Discard that final '/' - if (!m_Stream->eof()) { m_Stream->ignore(1); } + if (!m_Stream->eof()) { + m_Stream->ignore(1); + } - // Not a comment, so it's data, so quit. + // Not a comment, so it's data, so quit. } else { m_Stream->putback(temp); break; @@ -252,19 +269,19 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIReader::ReaderOK() const { return m_Stream.get() && !m_Stream->fail() && m_Stream->is_open(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void GUIReader::ReportError(const std::string &errorDesc) const { + void GUIReader::ReportError(const std::string& errorDesc) const { GUIAbort(errorDesc + "\nError happened in " + m_FilePath + " at line " + std::to_string(m_CurrentLine) + "!"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIReader::StartIncludeFile() { // Get the file path from the current stream before pushing it into the StreamStack, otherwise we can't open a new stream after releasing it because we can't read. @@ -298,7 +315,7 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIReader::EndIncludeFile() { if (m_StreamStack.empty()) { @@ -322,25 +339,25 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(bool &var) { + GUIReader& GUIReader::operator>>(bool& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(char &var) { + GUIReader& GUIReader::operator>>(char& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(unsigned char &var) { + GUIReader& GUIReader::operator>>(unsigned char& var) { DiscardEmptySpace(); int temp; *m_Stream >> temp; @@ -348,59 +365,59 @@ namespace RTE { return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(short &var) { + GUIReader& GUIReader::operator>>(short& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(unsigned short &var) { + GUIReader& GUIReader::operator>>(unsigned short& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(int &var) { + GUIReader& GUIReader::operator>>(int& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(unsigned int &var) { + GUIReader& GUIReader::operator>>(unsigned int& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(long &var) { + GUIReader& GUIReader::operator>>(long& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(unsigned long &var) { + GUIReader& GUIReader::operator>>(unsigned long& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Yeah, this is dumb - read as double and cast. + // Yeah, this is dumb - read as double and cast. // This is because, for whatever fucking reason, iostream can save out floats at a precision that it's then unable to read... - GUIReader & GUIReader::operator>>(float &var) { + GUIReader& GUIReader::operator>>(float& var) { DiscardEmptySpace(); double var2; *m_Stream >> var2; @@ -408,18 +425,18 @@ namespace RTE { return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(double &var) { + GUIReader& GUIReader::operator>>(double& var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIReader & GUIReader::operator>>(std::string &var) { + GUIReader& GUIReader::operator>>(std::string& var) { var.assign(ReadLine()); return *this; } -} +} // namespace RTE diff --git a/Source/GUI/GUIReader.h b/Source/GUI/GUIReader.h index 12362ef81..579ed6ddd 100644 --- a/Source/GUI/GUIReader.h +++ b/Source/GUI/GUIReader.h @@ -9,7 +9,6 @@ namespace RTE { class GUIReader { public: - #pragma region Creation /// /// Constructor method used to instantiate a GUIReader object in system memory. Create() should be called before using the object. @@ -21,7 +20,7 @@ namespace RTE { /// /// Path to the file to open for reading. If the file doesn't exist the stream will fail to open. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const std::string &fileName); + int Create(const std::string& fileName); #pragma endregion #pragma region Getters and Setters @@ -29,7 +28,7 @@ namespace RTE { /// Gets a pointer to the istream of this reader. /// /// A pointer to the istream object for this reader. - std::istream * GetStream() const; + std::istream* GetStream() const; /// /// Gets the path of the current file this reader is reading from. @@ -88,7 +87,7 @@ namespace RTE { /// /// String to remove whitespace from. /// The string that was passed in, sans whitespace in the front and end. - std::string TrimString(const std::string &stringToTrim) const; + std::string TrimString(const std::string& stringToTrim) const; /// /// Discards all whitespace, newlines and comment lines (which start with '//') so that the next thing to be read will be actual data. @@ -108,7 +107,7 @@ namespace RTE { /// Makes an error message box pop up for the user that tells them something went wrong with the reading, and where. /// /// The message describing what's wrong. - void ReportError(const std::string &errorDesc) const; + void ReportError(const std::string& errorDesc) const; #pragma endregion #pragma region Operator Overloads @@ -117,22 +116,21 @@ namespace RTE { /// /// A reference to the variable that will be filled by the extracted data. /// A GUIReader reference for further use in an expression. - GUIReader & operator>>(bool &var); - GUIReader & operator>>(char &var); - GUIReader & operator>>(unsigned char &var); - GUIReader & operator>>(short &var); - GUIReader & operator>>(unsigned short &var); - GUIReader & operator>>(int &var); - GUIReader & operator>>(unsigned int &var); - GUIReader & operator>>(long &var); - GUIReader & operator>>(unsigned long &var); - GUIReader & operator>>(float &var); - GUIReader & operator>>(double &var); - GUIReader & operator>>(std::string &var); + GUIReader& operator>>(bool& var); + GUIReader& operator>>(char& var); + GUIReader& operator>>(unsigned char& var); + GUIReader& operator>>(short& var); + GUIReader& operator>>(unsigned short& var); + GUIReader& operator>>(int& var); + GUIReader& operator>>(unsigned int& var); + GUIReader& operator>>(long& var); + GUIReader& operator>>(unsigned long& var); + GUIReader& operator>>(float& var); + GUIReader& operator>>(double& var); + GUIReader& operator>>(std::string& var); #pragma endregion protected: - /// /// A struct containing information from the currently used stream. /// @@ -140,10 +138,10 @@ namespace RTE { /// /// Constructor method used to instantiate a StreamInfo object in system memory. /// - StreamInfo(std::ifstream *stream, const std::string &filePath, int currentLine, int prevIndent); + StreamInfo(std::ifstream* stream, const std::string& filePath, int currentLine, int prevIndent); // NOTE: These members are owned by the reader that owns this struct, so are not deleted when this is destroyed. - std::ifstream *Stream; //!< Currently used stream, is not on the StreamStack until a new stream is opened. + std::ifstream* Stream; //!< Currently used stream, is not on the StreamStack until a new stream is opened. std::string FilePath; //!< Currently used stream's filepath. int CurrentLine; //!< The line number the stream is on. int PreviousIndent; //!< Count of tabs encountered on the last line DiscardEmptySpace() discarded. @@ -170,7 +168,6 @@ namespace RTE { int m_ObjectEndings; private: - #pragma region Reading Operations /// /// When ReadPropName encounters the property name "IncludeFile", it will automatically call this function to get started reading on that file. @@ -193,8 +190,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - GUIReader(const GUIReader &reference) = delete; - GUIReader & operator=(const GUIReader &rhs) = delete; + GUIReader(const GUIReader& reference) = delete; + GUIReader& operator=(const GUIReader& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/GUI/GUIScrollPanel.cpp b/Source/GUI/GUIScrollPanel.cpp index e6563739e..e6f9dcf6b 100644 --- a/Source/GUI/GUIScrollPanel.cpp +++ b/Source/GUI/GUIScrollPanel.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIScrollPanel::GUIScrollPanel(GUIManager *Manager) : GUIPanel(Manager) { +GUIScrollPanel::GUIScrollPanel(GUIManager* Manager) : + GUIPanel(Manager) { m_Skin = nullptr; m_DrawBitmap[0] = m_DrawBitmap[1] = m_DrawBitmap[2] = nullptr; m_ButtonSize = 17; @@ -21,7 +22,8 @@ GUIScrollPanel::GUIScrollPanel(GUIManager *Manager) : GUIPanel(Manager) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIScrollPanel::GUIScrollPanel() : GUIPanel() { +GUIScrollPanel::GUIScrollPanel() : + GUIPanel() { m_Skin = nullptr; m_DrawBitmap[0] = m_DrawBitmap[1] = m_DrawBitmap[2] = nullptr; m_ButtonSize = 17; @@ -69,26 +71,30 @@ void GUIScrollPanel::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollPanel::LoadProps(GUIProperties *Props) { +void GUIScrollPanel::LoadProps(GUIProperties* Props) { assert(Props); std::string Ori; Props->GetValue("Orientation", &Ori); m_Orientation = Horizontal; - if (stricmp(Ori.c_str(), "Vertical") == 0) { m_Orientation = Vertical; } + if (stricmp(Ori.c_str(), "Vertical") == 0) { + m_Orientation = Vertical; + } Props->GetValue("Minimum", &m_Minimum); Props->GetValue("Maximum", &m_Maximum); Props->GetValue("Value", &m_Value); Props->GetValue("PageSize", &m_PageSize); Props->GetValue("SmallChange", &m_SmallChange); - if (!Props->GetValue("ValueResolution", &m_ValueResolution)) { m_ValueResolution = std::max((m_Maximum - m_Minimum) / 100, 1); } + if (!Props->GetValue("ValueResolution", &m_ValueResolution)) { + m_ValueResolution = std::max((m_Maximum - m_Minimum) / 100, 1); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollPanel::ChangeSkin(GUISkin *Skin) { +void GUIScrollPanel::ChangeSkin(GUISkin* Skin) { assert(Skin); m_Skin = Skin; @@ -106,7 +112,9 @@ void GUIScrollPanel::BuildBitmap(bool UpdateSize, bool UpdateKnob) { } // If we update the size, the knob is automatically updated - if (UpdateSize) { UpdateKnob = true; } + if (UpdateSize) { + UpdateKnob = true; + } // Free the old bitmaps if (UpdateSize) { @@ -132,7 +140,6 @@ void GUIScrollPanel::BuildBitmap(bool UpdateSize, bool UpdateKnob) { // Calculate the knob size & position CalculateKnob(); - // Create the 3 bitmaps if (m_Orientation == Vertical) { // Vertical @@ -140,14 +147,18 @@ void GUIScrollPanel::BuildBitmap(bool UpdateSize, bool UpdateKnob) { m_DrawBitmap[ButtonStates] = m_Skin->CreateBitmap(m_Width * 2, m_ButtonSize * 2); m_DrawBitmap[Back] = m_Skin->CreateBitmap(m_Width, m_Height); } - if (UpdateKnob) { m_DrawBitmap[KnobStates] = m_Skin->CreateBitmap(m_Width * 2, m_KnobLength); } + if (UpdateKnob) { + m_DrawBitmap[KnobStates] = m_Skin->CreateBitmap(m_Width * 2, m_KnobLength); + } } else { // Horizontal if (UpdateSize) { m_DrawBitmap[ButtonStates] = m_Skin->CreateBitmap(m_ButtonSize * 2, m_Height * 2); m_DrawBitmap[Back] = m_Skin->CreateBitmap(m_Width, m_Height); } - if (UpdateKnob) { m_DrawBitmap[KnobStates] = m_Skin->CreateBitmap(m_KnobLength, m_Height * 2); } + if (UpdateKnob) { + m_DrawBitmap[KnobStates] = m_Skin->CreateBitmap(m_KnobLength, m_Height * 2); + } } // Update the buttons and the background @@ -165,7 +176,6 @@ void GUIScrollPanel::BuildBitmap(bool UpdateSize, bool UpdateKnob) { BuildBackground(); } - // Update the knob if (UpdateKnob && m_KnobLength > 0) { if (m_Orientation == Vertical) { @@ -186,7 +196,7 @@ void GUIScrollPanel::BuildBitmap(bool UpdateSize, bool UpdateKnob) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollPanel::BuildButton(const std::string &ArrowName, int Y, int Width, int Height) { +void GUIScrollPanel::BuildButton(const std::string& ArrowName, int Y, int Width, int Height) { // Create the buttons m_Skin->BuildStandardRect(m_DrawBitmap[ButtonStates], "ScrollButton_Up", 0, Y, Width, Height); @@ -199,7 +209,7 @@ void GUIScrollPanel::BuildButton(const std::string &ArrowName, int Y, int Width, // Load the image file std::string Filename; m_Skin->GetValue(ArrowName, "Filename", &Filename); - GUIBitmap *Arrow = m_Skin->CreateBitmap(Filename); + GUIBitmap* Arrow = m_Skin->CreateBitmap(Filename); if (!Arrow) { return; } @@ -224,7 +234,7 @@ void GUIScrollPanel::BuildBackground() { std::string Filename; m_Skin->GetValue("ScrollBackground", "Filename", &Filename); - GUIBitmap *Background = m_Skin->CreateBitmap(Filename); + GUIBitmap* Background = m_Skin->CreateBitmap(Filename); if (!Background) { return; } @@ -244,8 +254,10 @@ void GUIScrollPanel::BuildBackground() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollPanel::BuildKnob(const std::string &Section, int X, int Y, int Width, int Height) { - if (m_DrawBitmap[KnobStates]) { m_Skin->BuildStandardRect(m_DrawBitmap[KnobStates], Section, X, Y, Width, Height); } +void GUIScrollPanel::BuildKnob(const std::string& Section, int X, int Y, int Width, int Height) { + if (m_DrawBitmap[KnobStates]) { + m_Skin->BuildStandardRect(m_DrawBitmap[KnobStates], Section, X, Y, Width, Height); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -316,13 +328,15 @@ void GUIScrollPanel::SetSmallChange(int SmallChange) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollPanel::Draw(GUIScreen *Screen) { +void GUIScrollPanel::Draw(GUIScreen* Screen) { GUIRect Rect; // Do we need to rebuild? - if (m_RebuildKnob || m_RebuildSize) { BuildBitmap(m_RebuildSize, m_RebuildKnob); } + if (m_RebuildKnob || m_RebuildSize) { + BuildBitmap(m_RebuildSize, m_RebuildKnob); + } - GUIBitmap *Dest = Screen->GetBitmap(); + GUIBitmap* Dest = Screen->GetBitmap(); // Draw the background m_DrawBitmap[Back]->Draw(Dest, m_X, m_Y, 0); @@ -528,7 +542,9 @@ void GUIScrollPanel::OnMouseMove(int X, int Y, int Buttons, int Modifier) { m_Value = std::max(m_Value, m_Minimum); m_Value = std::min(m_Value, m_Maximum - m_PageSize); - if (OldValue != m_Value) { SendSignal(ChangeValue, 0); } + if (OldValue != m_Value) { + SendSignal(ChangeValue, 0); + } } } } @@ -638,8 +654,12 @@ void GUIScrollPanel::CalculateKnob() { int MoveLength = 1; // Calculate the length of the movable area (panel minus buttons) - if (m_Orientation == Vertical) { MoveLength = m_Height - m_ButtonSize * 2; } - if (m_Orientation == Horizontal) { MoveLength = m_Width - m_ButtonSize * 2; } + if (m_Orientation == Vertical) { + MoveLength = m_Height - m_ButtonSize * 2; + } + if (m_Orientation == Horizontal) { + MoveLength = m_Width - m_ButtonSize * 2; + } // Calculate the knob length m_KnobLength = 0; @@ -650,8 +670,12 @@ void GUIScrollPanel::CalculateKnob() { } // Make sure the knob is not too small m_KnobLength = std::max(m_KnobLength, m_MinimumKnobSize); - if (MoveLength > 0) { m_KnobLength = std::min(m_KnobLength, MoveLength); } - if (m_KnobLength < 0) { m_KnobLength = 0; } + if (MoveLength > 0) { + m_KnobLength = std::min(m_KnobLength, MoveLength); + } + if (m_KnobLength < 0) { + m_KnobLength = 0; + } // Calculate the knob position m_KnobPosition = 0; @@ -681,12 +705,14 @@ void GUIScrollPanel::AdjustValue(int Delta) { // Calculate the new knob position CalculateKnob(); - if (OldValue != m_Value) { SendSignal(ChangeValue, 0); } + if (OldValue != m_Value) { + SendSignal(ChangeValue, 0); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollPanel::SaveProps(GUIProperties *Props) const { +void GUIScrollPanel::SaveProps(GUIProperties* Props) const { assert(Props); Props->AddVariable("Orientation", m_Orientation == Horizontal ? "Horizontal" : "Vertical"); @@ -725,4 +751,4 @@ int GUIScrollPanel::GetSmallChange() const { int GUIScrollPanel::GetValueResolution() const { return m_ValueResolution; -} \ No newline at end of file +} diff --git a/Source/GUI/GUIScrollPanel.h b/Source/GUI/GUIScrollPanel.h index 1e484c545..1d2899375 100644 --- a/Source/GUI/GUIScrollPanel.h +++ b/Source/GUI/GUIScrollPanel.h @@ -3,346 +3,314 @@ namespace RTE { -/// -/// A scrollbar panel class used for controls requiring a scrollbar. -/// -class GUIScrollPanel : public GUIPanel { - -public: - - // Scroll panel orientation - enum { - Horizontal, - Vertical - }; - - // Pre-built draw bitmaps - enum { - ButtonStates=0, - KnobStates, - Back - }; - - // Signals - enum { - ChangeValue=0, - Grab, - Release - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIScrollPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIScrollPanel object in -// system memory. -// Arguments: GUIManager. - - explicit GUIScrollPanel(GUIManager *Manager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIScrollPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIScrollPanel object in -// system memory. -// Arguments: None. - - GUIScrollPanel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the scrollpanel -// Arguments: Position, Size. - - void Create(int X, int Y, int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the panel has been destroyed. -// Arguments: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseHover -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse is hovering over the panel (has to be enabled) -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseHover(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the size of the panel. -// Arguments: Width, Height. - - void SetSize(int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMinimum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the minimum value for the scrollpanel -// Arguments: Minimum value. - - void SetMinimum(int Min); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMinimum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the minimum value for the scrollpanel -// Arguments: None. - - int GetMinimum() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMaximum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the maximum value for the scrollpanel -// Arguments: Maximum value. - - void SetMaximum(int Max); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaximum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the maximum value for the scrollpanel -// Arguments: None. - - int GetMaximum() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current value for the scrollpanel -// Arguments: Value. - - void SetValue(int Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current value of the scrollpanel. -// Arguments: None. - - int GetValue() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPageSize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the page size value for the scrollpanel. -// Arguments: PageSize. - - void SetPageSize(int PageSize); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPageSize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the size of the page. -// Arguments: None. - - int GetPageSize() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOrientation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the orientation of the scrollpanel. -// Arguments: Orientation. - - void SetOrientation(int Orientation); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOrientation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the orientation of the scrollpanel. -// Arguments: None. - - int GetOrientation() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSmallChange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the small change value. -// Arguments: SmallChange. - - void SetSmallChange(int SmallChange); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSmallChange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the small change value. -// Arguments: None. - - int GetSmallChange() const; - /// - /// Gets the value resolution for this scroll panel. + /// A scrollbar panel class used for controls requiring a scrollbar. /// - /// The value resolution - int GetValueResolution() const; - -protected: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadProps -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Load values from a property class. -// Arguments: Properties. - - void LoadProps(GUIProperties *Props); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveProps -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Save values to a property class. -// Arguments: Properties. - - void SaveProps(GUIProperties *Props) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Build the bitmap. -// Arguments: None. - - void BuildBitmap(bool UpdateSize, bool UpdateKnob); - -private: - - GUISkin *m_Skin; - GUIBitmap *m_DrawBitmap[3]; - - // User attributes - int m_Orientation; - int m_Minimum; - int m_Maximum; - int m_Value; - int m_PageSize; - int m_SmallChange; - - // Internal attributes - bool m_RebuildSize; - bool m_RebuildKnob; - int m_ButtonSize; - int m_MinimumKnobSize; - int m_KnobPosition; - int m_KnobLength; - bool m_ButtonPushed[2]; - bool m_GrabbedKnob; - bool m_GrabbedBackg; - int m_GrabbedPos; - int m_GrabbedSide; - int m_ValueResolution; //!< How much the value increases/decreases on each mouse wheel change when scrolling. - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildButton -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Build a button. -// Arguments: ArrowName, Width, Height. - - void BuildButton(const std::string &ArrowName, int Y, int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBackground -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Build the background. -// Arguments: None. - - void BuildBackground(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildKnob -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Build the knob. -// Arguments: None. - - void BuildKnob(const std::string &Section, int X, int Y, int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateKnob -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculate the knob size and position. -// Arguments: None. - - void CalculateKnob(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AdjustValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adjusts the value. -// Arguments: Delta movement. + class GUIScrollPanel : public GUIPanel { + + public: + // Scroll panel orientation + enum { + Horizontal, + Vertical + }; + + // Pre-built draw bitmaps + enum { + ButtonStates = 0, + KnobStates, + Back + }; + + // Signals + enum { + ChangeValue = 0, + Grab, + Release + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIScrollPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIScrollPanel object in + // system memory. + // Arguments: GUIManager. + + explicit GUIScrollPanel(GUIManager* Manager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIScrollPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIScrollPanel object in + // system memory. + // Arguments: None. + + GUIScrollPanel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the scrollpanel + // Arguments: Position, Size. + + void Create(int X, int Y, int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the panel has been destroyed. + // Arguments: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseHover + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse is hovering over the panel (has to be enabled) + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseHover(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the size of the panel. + // Arguments: Width, Height. + + void SetSize(int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMinimum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the minimum value for the scrollpanel + // Arguments: Minimum value. + + void SetMinimum(int Min); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMinimum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the minimum value for the scrollpanel + // Arguments: None. + + int GetMinimum() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMaximum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the maximum value for the scrollpanel + // Arguments: Maximum value. + + void SetMaximum(int Max); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaximum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the maximum value for the scrollpanel + // Arguments: None. + + int GetMaximum() const; - void AdjustValue(int Delta); -}; -}; -#endif \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current value for the scrollpanel + // Arguments: Value. + + void SetValue(int Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current value of the scrollpanel. + // Arguments: None. + + int GetValue() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPageSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the page size value for the scrollpanel. + // Arguments: PageSize. + + void SetPageSize(int PageSize); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPageSize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the size of the page. + // Arguments: None. + + int GetPageSize() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOrientation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the orientation of the scrollpanel. + // Arguments: Orientation. + + void SetOrientation(int Orientation); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOrientation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the orientation of the scrollpanel. + // Arguments: None. + + int GetOrientation() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSmallChange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the small change value. + // Arguments: SmallChange. + + void SetSmallChange(int SmallChange); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSmallChange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the small change value. + // Arguments: None. + + int GetSmallChange() const; + + /// + /// Gets the value resolution for this scroll panel. + /// + /// The value resolution + int GetValueResolution() const; + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadProps + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Load values from a property class. + // Arguments: Properties. + + void LoadProps(GUIProperties* Props); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveProps + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Save values to a property class. + // Arguments: Properties. + + void SaveProps(GUIProperties* Props) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Build the bitmap. + // Arguments: None. + + void BuildBitmap(bool UpdateSize, bool UpdateKnob); + + private: + GUISkin* m_Skin; + GUIBitmap* m_DrawBitmap[3]; + + // User attributes + int m_Orientation; + int m_Minimum; + int m_Maximum; + int m_Value; + int m_PageSize; + int m_SmallChange; + + // Internal attributes + bool m_RebuildSize; + bool m_RebuildKnob; + int m_ButtonSize; + int m_MinimumKnobSize; + int m_KnobPosition; + int m_KnobLength; + bool m_ButtonPushed[2]; + bool m_GrabbedKnob; + bool m_GrabbedBackg; + int m_GrabbedPos; + int m_GrabbedSide; + int m_ValueResolution; //!< How much the value increases/decreases on each mouse wheel change when scrolling. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildButton + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Build a button. + // Arguments: ArrowName, Width, Height. + + void BuildButton(const std::string& ArrowName, int Y, int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBackground + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Build the background. + // Arguments: None. + + void BuildBackground(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildKnob + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Build the knob. + // Arguments: None. + + void BuildKnob(const std::string& Section, int X, int Y, int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateKnob + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculate the knob size and position. + // Arguments: None. + + void CalculateKnob(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AdjustValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adjusts the value. + // Arguments: Delta movement. + + void AdjustValue(int Delta); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUIScrollbar.cpp b/Source/GUI/GUIScrollbar.cpp index 1154f7277..3f4ba3f82 100644 --- a/Source/GUI/GUIScrollbar.cpp +++ b/Source/GUI/GUIScrollbar.cpp @@ -5,14 +5,15 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIScrollbar::GUIScrollbar(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIScrollPanel(Manager) { +GUIScrollbar::GUIScrollbar(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIScrollPanel(Manager) { m_ControlID = "SCROLLBAR"; m_ControlManager = ControlManager; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollbar::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUIScrollbar::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -27,8 +28,12 @@ void GUIScrollbar::Create(const std::string &Name, int X, int Y, int Width, int // Create the ListPanel int w = m_DefWidth; int h = m_DefHeight; - if (Width != -1) { w = Width; } - if (Height != -1) { h = Height; } + if (Width != -1) { + w = Width; + } + if (Height != -1) { + h = Height; + } // Make sure the scroll panel isn't too small w = std::max(w, m_MinWidth); @@ -39,7 +44,7 @@ void GUIScrollbar::Create(const std::string &Name, int X, int Y, int Width, int ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollbar::Create(GUIProperties *Props) { +void GUIScrollbar::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -70,19 +75,19 @@ void GUIScrollbar::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollbar::ChangeSkin(GUISkin *Skin) { +void GUIScrollbar::ChangeSkin(GUISkin* Skin) { GUIScrollPanel::ChangeSkin(Skin); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUIScrollbar::GetPanel() { +GUIPanel* GUIScrollbar::GetPanel() { return this; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollbar::ReceiveSignal(GUIPanel *Source, int Code, int Data) { +void GUIScrollbar::ReceiveSignal(GUIPanel* Source, int Code, int Data) { assert(Source); // Should be our scroll panel @@ -138,7 +143,7 @@ void GUIScrollbar::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollbar::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUIScrollbar::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIScrollPanel::GetRect(X, Y, Width, Height); } @@ -150,11 +155,11 @@ void GUIScrollbar::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUIScrollbar::ApplyProperties(GUIProperties *Props) { +void GUIScrollbar::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); GUIScrollPanel::LoadProps(&m_Properties); // Rebuild the bitmap BuildBitmap(true, true); -} \ No newline at end of file +} diff --git a/Source/GUI/GUIScrollbar.h b/Source/GUI/GUIScrollbar.h index 2c57b0168..e9efa3cbd 100644 --- a/Source/GUI/GUIScrollbar.h +++ b/Source/GUI/GUIScrollbar.h @@ -5,167 +5,150 @@ namespace RTE { -/// -/// A Scrollbar control class. -/// -class GUIScrollbar : public GUIControl, public GUIScrollPanel { - -public: - - // Notifications - enum { - ChangeValue=0, - - } Notifications; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUIScrollbar -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUIScrollbar object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUIScrollbar(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - /// - /// Called when the mouse scroll wheel is moved. + /// A Scrollbar control class. /// - /// Mouse X position. - /// Mouse Y position. - /// Activated modifier buttons. - /// The amount of wheel movement. Positive is scroll up, negative is scroll down. - void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "SCROLLBAR"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReceiveSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when receiving a signal. -// Arguments: Signal source, Signal code, Signal data. - - void ReceiveSignal(GUIPanel *Source, int Code, int Data) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - -}; -}; -#endif \ No newline at end of file + class GUIScrollbar : public GUIControl, public GUIScrollPanel { + + public: + // Notifications + enum { + ChangeValue = 0, + + } Notifications; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUIScrollbar + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUIScrollbar object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUIScrollbar(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + /// + /// Called when the mouse scroll wheel is moved. + /// + /// Mouse X position. + /// Mouse Y position. + /// Activated modifier buttons. + /// The amount of wheel movement. Positive is scroll up, negative is scroll down. + void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "SCROLLBAR"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReceiveSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when receiving a signal. + // Arguments: Signal source, Signal code, Signal data. + + void ReceiveSignal(GUIPanel* Source, int Code, int Data) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; + + private: + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUISkin.cpp b/Source/GUI/GUISkin.cpp index afc5c4ee4..00ff282c2 100644 --- a/Source/GUI/GUISkin.cpp +++ b/Source/GUI/GUISkin.cpp @@ -6,7 +6,7 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUISkin::GUISkin(GUIScreen *Screen) { +GUISkin::GUISkin(GUIScreen* Screen) { m_Screen = Screen; m_FontCache.clear(); @@ -34,7 +34,7 @@ void GUISkin::Clear() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUISkin::Load(const std::string &directory, const std::string &fileName) { +bool GUISkin::Load(const std::string& directory, const std::string& fileName) { // Destroy any previous instances Destroy(); @@ -57,7 +57,7 @@ bool GUISkin::Load(const std::string &directory, const std::string &fileName) { } // Go through the skin file adding the sections and properties - GUIProperties *CurProp = nullptr; + GUIProperties* CurProp = nullptr; while (!skinFile.GetStream()->eof()) { std::string line = skinFile.ReadLine(); @@ -68,7 +68,7 @@ bool GUISkin::Load(const std::string &directory, const std::string &fileName) { // Is the line a section? if (line.front() == '[' && line.back() == ']') { - GUIProperties *p = new GUIProperties(line.substr(1, line.size() - 2)); + GUIProperties* p = new GUIProperties(line.substr(1, line.size() - 2)); CurProp = p; m_PropList.push_back(p); continue; @@ -100,12 +100,12 @@ bool GUISkin::Load(const std::string &directory, const std::string &fileName) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUISkin::GetValue(const std::string &Section, const std::string &Variable, std::string *Value) { - std::vector ::iterator it; +bool GUISkin::GetValue(const std::string& Section, const std::string& Variable, std::string* Value) { + std::vector::iterator it; // Find the property for (it = m_PropList.begin(); it != m_PropList.end(); it++) { - GUIProperties *p = *it; + GUIProperties* p = *it; if (stricmp(p->GetName().c_str(), Section.c_str()) == 0 && p->GetValue(Variable, Value)) { return true; @@ -118,12 +118,12 @@ bool GUISkin::GetValue(const std::string &Section, const std::string &Variable, ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int GUISkin::GetValue(const std::string &Section, const std::string &Variable, int *Array, int MaxArraySize) { - std::vector ::iterator it; +int GUISkin::GetValue(const std::string& Section, const std::string& Variable, int* Array, int MaxArraySize) { + std::vector::iterator it; // Find the property for (it = m_PropList.begin(); it != m_PropList.end(); it++) { - GUIProperties *p = *it; + GUIProperties* p = *it; if (stricmp(p->GetName().c_str(), Section.c_str()) == 0 && p->GetValue(Variable, Array, MaxArraySize)) { return true; @@ -136,12 +136,12 @@ int GUISkin::GetValue(const std::string &Section, const std::string &Variable, i ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUISkin::GetValue(const std::string &Section, const std::string &Variable, int *Value) { - std::vector ::iterator it; +bool GUISkin::GetValue(const std::string& Section, const std::string& Variable, int* Value) { + std::vector::iterator it; // Find the property for (it = m_PropList.begin(); it != m_PropList.end(); it++) { - GUIProperties *p = *it; + GUIProperties* p = *it; if (stricmp(p->GetName().c_str(), Section.c_str()) == 0 && p->GetValue(Variable, Value)) { return true; @@ -154,12 +154,12 @@ bool GUISkin::GetValue(const std::string &Section, const std::string &Variable, ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool GUISkin::GetValue(const std::string &Section, const std::string &Variable, unsigned long *Value) { - std::vector ::iterator it; +bool GUISkin::GetValue(const std::string& Section, const std::string& Variable, unsigned long* Value) { + std::vector::iterator it; // Find the property for (it = m_PropList.begin(); it != m_PropList.end(); it++) { - GUIProperties *p = *it; + GUIProperties* p = *it; if (stricmp(p->GetName().c_str(), Section.c_str()) == 0 && p->GetValue(Variable, Value)) { return true; @@ -173,22 +173,24 @@ bool GUISkin::GetValue(const std::string &Section, const std::string &Variable, ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUISkin::Destroy() { - std::vector ::iterator it; + std::vector::iterator it; // Free the properties for (it = m_PropList.begin(); it != m_PropList.end(); it++) { - GUIProperties *p = *it; + GUIProperties* p = *it; - if (p) { delete p; } + if (p) { + delete p; + } } m_PropList.clear(); // Destroy the fonts in the list - std::vector::iterator itf; + std::vector::iterator itf; for (itf = m_FontCache.begin(); itf != m_FontCache.end(); itf++) { - GUIFont *F = *itf; + GUIFont* F = *itf; if (F) { F->Destroy(); delete F; @@ -197,12 +199,11 @@ void GUISkin::Destroy() { m_FontCache.clear(); - // Destroy the images in the image cache - std::vector::iterator iti; + std::vector::iterator iti; for (iti = m_ImageCache.begin(); iti != m_ImageCache.end(); iti++) { - GUIBitmap *Surf = *iti; + GUIBitmap* Surf = *iti; if (Surf) { Surf->Destroy(); delete Surf; @@ -214,20 +215,20 @@ void GUISkin::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIBitmap * GUISkin::CreateBitmap(int Width, int Height) { +GUIBitmap* GUISkin::CreateBitmap(int Width, int Height) { return m_Screen->CreateBitmap(Width, Height); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIBitmap * GUISkin::CreateBitmap(const std::string &Filename) { +GUIBitmap* GUISkin::CreateBitmap(const std::string& Filename) { // Add the filename onto the current directory std::string File = m_Directory + Filename; // Check if the image is in our cache - std::vector::iterator it; + std::vector::iterator it; for (it = m_ImageCache.begin(); it != m_ImageCache.end(); it++) { - GUIBitmap *Surf = *it; + GUIBitmap* Surf = *it; if (stricmp(File.c_str(), Surf->GetDataPath().c_str()) == 0) { return Surf; @@ -235,7 +236,7 @@ GUIBitmap * GUISkin::CreateBitmap(const std::string &Filename) { } // Not found in cache, so we create a new bitmap from the file - GUIBitmap *Bitmap = m_Screen->CreateBitmap(File); + GUIBitmap* Bitmap = m_Screen->CreateBitmap(File); if (!Bitmap) { return nullptr; } @@ -247,19 +248,19 @@ GUIBitmap * GUISkin::CreateBitmap(const std::string &Filename) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIFont * GUISkin::GetFont(const std::string &Name) { +GUIFont* GUISkin::GetFont(const std::string& Name) { // Check if the font is already in the list - std::vector::iterator it; + std::vector::iterator it; for (it = m_FontCache.begin(); it != m_FontCache.end(); it++) { - GUIFont *F = *it; + GUIFont* F = *it; if (stricmp(F->GetName().c_str(), Name.c_str()) == 0) { return F; } } // Not found, so we create the font - GUIFont *Font = new GUIFont(Name); + GUIFont* Font = new GUIFont(Name); if (!Font->Load(m_Screen, m_Directory + Name)) { delete Font; return nullptr; @@ -272,7 +273,7 @@ GUIFont * GUISkin::GetFont(const std::string &Name) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIBitmap * GUISkin::LoadMousePointer(const std::string &Section) { +GUIBitmap* GUISkin::LoadMousePointer(const std::string& Section) { std::string File; int ColorKey; @@ -282,7 +283,7 @@ GUIBitmap * GUISkin::LoadMousePointer(const std::string &Section) { if (!GetValue(Section, "ColorKeyIndex", &ColorKey)) { return nullptr; } - GUIBitmap *Bitmap = CreateBitmap(File); + GUIBitmap* Bitmap = CreateBitmap(File); if (!Bitmap) { return nullptr; } @@ -292,17 +293,19 @@ GUIBitmap * GUISkin::LoadMousePointer(const std::string &Section) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISkin::DrawMouse(int Image, int X, int Y, GUIScreen *guiScreenOverride) { +void GUISkin::DrawMouse(int Image, int X, int Y, GUIScreen* guiScreenOverride) { assert(Image >= 0 && Image <= 2); - GUIScreen *targetScreen = guiScreenOverride ? guiScreenOverride : m_Screen; + GUIScreen* targetScreen = guiScreenOverride ? guiScreenOverride : m_Screen; - if (m_MousePointers[Image]) { targetScreen->DrawBitmapTrans(m_MousePointers[Image], X - 1, Y - 1, nullptr); } + if (m_MousePointers[Image]) { + targetScreen->DrawBitmapTrans(m_MousePointers[Image], X - 1, Y - 1, nullptr); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISkin::BuildStandardRect(GUIBitmap *Dest, const std::string &Section, int X, int Y, int Width, int Height, bool buildBG, bool buildFrame, GUIRect *borderSizes) { +void GUISkin::BuildStandardRect(GUIBitmap* Dest, const std::string& Section, int X, int Y, int Width, int Height, bool buildBG, bool buildFrame, GUIRect* borderSizes) { // Note: For a control to use a 'Standard Rect' it must use the 8 side names, a filler name and a filename property. int VTopLeft[4]; @@ -321,7 +324,7 @@ void GUISkin::BuildStandardRect(GUIBitmap *Dest, const std::string &Section, int // Load the filename std::string Filename; GetValue(Section, "Filename", &Filename); - GUIBitmap *SrcBitmap = CreateBitmap(Filename); + GUIBitmap* SrcBitmap = CreateBitmap(Filename); // Set the color key to be the same color as the Top-Right hand corner pixel SrcBitmap->SetColorKey(SrcBitmap->GetPixel(SrcBitmap->GetWidth() - 1, 0)); @@ -393,11 +396,13 @@ void GUISkin::BuildStandardRect(GUIBitmap *Dest, const std::string &Section, int SrcBitmap->DrawTrans(Dest, X, Y + Height - VBottomLeft[3], &Rect); } - if (borderSizes) { SetRect(borderSizes, VLeft[2], VTop[3], VRight[2], VBottom[3]); } + if (borderSizes) { + SetRect(borderSizes, VLeft[2], VTop[3], VRight[2], VBottom[3]); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// unsigned long GUISkin::ConvertColor(unsigned long color, int targetDepth) { return m_Screen->ConvertColor(color, targetDepth); -} \ No newline at end of file +} diff --git a/Source/GUI/GUISkin.h b/Source/GUI/GUISkin.h index 6deda8f3c..24e07e0c7 100644 --- a/Source/GUI/GUISkin.h +++ b/Source/GUI/GUISkin.h @@ -3,175 +3,157 @@ namespace RTE { -/// -/// Skin class used for the controls to get skin details. -/// -class GUISkin { - -public: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUISkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUISkin object in system -// memory. -// Arguments: GUIScreen Interface. - - explicit GUISkin(GUIScreen *Screen); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: GUISkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to free a GUISkin object in system -// memory. -// Arguments: None. - - ~GUISkin(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Load -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads a skin for a directory -// Arguments: Skin directory and the file within to use - - bool Load(const std::string &directory, const std::string &fileName = "skin.ini"); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the data -// Arguments: None. - - void Clear(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Frees the allocated data. -// Arguments: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a string value -// Arguments: Section, Variable, String pointer - - bool GetValue(const std::string &Section, const std::string &Variable, std::string *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets an integer array of values -// Arguments: Section, Variable, Integer array, max size of array -// Returns: Number of elements read - - int GetValue(const std::string &Section, const std::string &Variable, int *Array, int MaxArraySize); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a single integer value. -// Arguments: Section, Variable, Integer pointer - - bool GetValue(const std::string &Section, const std::string &Variable, int *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a single unsigned integer value. -// Arguments: Section, Variable, Unsigned Integer pointer - - bool GetValue(const std::string &Section, const std::string &Variable, unsigned long *Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a blank bitmap. -// Arguments: Width, Height. - - GUIBitmap * CreateBitmap(int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CreateBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a bitmap from a filename. -// Arguments: Filename. - - GUIBitmap * CreateBitmap(const std::string &Filename); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFont -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a cached copy of a font. Ownership is NOT transferred! -// Arguments: None. - - GUIFont * GetFont(const std::string &Name); - - - /// - /// Draws the mouse onto the screen. - /// - /// Mouse image ID. - /// Horizontal position on the screen. - /// Vertical position on the screen. - /// The GUIScreen to draw to, overriding the one passed in on construction. - void DrawMouse(int Image, int X, int Y, GUIScreen *guiScreenOverride = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildStandardRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Builds a bitmap from a standard skin property section. -// Arguments: Destination bitmap, Section name, Position, Size. Whether to draw the -// background and frame, a GUIRect to be filled in with the border sizes of the four sides of the built standard rect. - - void BuildStandardRect(GUIBitmap *Dest, const std::string &Section, int X, int Y, int Width, int Height, bool buildBG = true, bool buildFrame = true, GUIRect *borderSizes = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ConvertColor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Converts an 8bit palette index to a valid pixel format. -// Primarily used for development in windowed mode. -// Arguments: Color value in any bit depth. Will be converted to the format specified. -// An optional target color depth that will determine what format the color -// should be converted to. If this is 0, then the current video color depth -// will be used as target. - - unsigned long ConvertColor(unsigned long color, int targetDepth = 0); - - -private: - - std::string m_Directory; - GUIScreen *m_Screen; - GUIBitmap *m_MousePointers[3]; - - std::vector m_PropList; - std::vector m_ImageCache; - std::vector m_FontCache; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: LoadMousePointer - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Loads a mouse pointer image & details - // Arguments: Section name. - - GUIBitmap * LoadMousePointer(const std::string &Section); -}; -}; -#endif \ No newline at end of file + /// + /// Skin class used for the controls to get skin details. + /// + class GUISkin { + + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUISkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUISkin object in system + // memory. + // Arguments: GUIScreen Interface. + + explicit GUISkin(GUIScreen* Screen); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: GUISkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to free a GUISkin object in system + // memory. + // Arguments: None. + + ~GUISkin(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Load + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads a skin for a directory + // Arguments: Skin directory and the file within to use + + bool Load(const std::string& directory, const std::string& fileName = "skin.ini"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the data + // Arguments: None. + + void Clear(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Frees the allocated data. + // Arguments: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a string value + // Arguments: Section, Variable, String pointer + + bool GetValue(const std::string& Section, const std::string& Variable, std::string* Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets an integer array of values + // Arguments: Section, Variable, Integer array, max size of array + // Returns: Number of elements read + + int GetValue(const std::string& Section, const std::string& Variable, int* Array, int MaxArraySize); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a single integer value. + // Arguments: Section, Variable, Integer pointer + + bool GetValue(const std::string& Section, const std::string& Variable, int* Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a single unsigned integer value. + // Arguments: Section, Variable, Unsigned Integer pointer + + bool GetValue(const std::string& Section, const std::string& Variable, unsigned long* Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a blank bitmap. + // Arguments: Width, Height. + + GUIBitmap* CreateBitmap(int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CreateBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a bitmap from a filename. + // Arguments: Filename. + + GUIBitmap* CreateBitmap(const std::string& Filename); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFont + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a cached copy of a font. Ownership is NOT transferred! + // Arguments: None. + + GUIFont* GetFont(const std::string& Name); + + /// + /// Draws the mouse onto the screen. + /// + /// Mouse image ID. + /// Horizontal position on the screen. + /// Vertical position on the screen. + /// The GUIScreen to draw to, overriding the one passed in on construction. + void DrawMouse(int Image, int X, int Y, GUIScreen* guiScreenOverride = nullptr); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildStandardRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Builds a bitmap from a standard skin property section. + // Arguments: Destination bitmap, Section name, Position, Size. Whether to draw the + // background and frame, a GUIRect to be filled in with the border sizes of the four sides of the built standard rect. + + void BuildStandardRect(GUIBitmap* Dest, const std::string& Section, int X, int Y, int Width, int Height, bool buildBG = true, bool buildFrame = true, GUIRect* borderSizes = nullptr); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ConvertColor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Converts an 8bit palette index to a valid pixel format. + // Primarily used for development in windowed mode. + // Arguments: Color value in any bit depth. Will be converted to the format specified. + // An optional target color depth that will determine what format the color + // should be converted to. If this is 0, then the current video color depth + // will be used as target. + + unsigned long ConvertColor(unsigned long color, int targetDepth = 0); + + private: + std::string m_Directory; + GUIScreen* m_Screen; + GUIBitmap* m_MousePointers[3]; + + std::vector m_PropList; + std::vector m_ImageCache; + std::vector m_FontCache; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadMousePointer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads a mouse pointer image & details + // Arguments: Section name. + + GUIBitmap* LoadMousePointer(const std::string& Section); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUISlider.cpp b/Source/GUI/GUISlider.cpp index 2afb49cc3..ea6b7e069 100644 --- a/Source/GUI/GUISlider.cpp +++ b/Source/GUI/GUISlider.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUISlider::GUISlider(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUISlider::GUISlider(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "SLIDER"; m_DrawBitmap = nullptr; m_KnobImage = nullptr; @@ -23,7 +24,7 @@ GUISlider::GUISlider(GUIManager *Manager, GUIControlManager *ControlManager) : G ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISlider::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUISlider::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -40,8 +41,12 @@ void GUISlider::Create(const std::string &Name, int X, int Y, int Width, int Hei m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Re-Calculate the knob info CalculateKnob(); @@ -49,7 +54,7 @@ void GUISlider::Create(const std::string &Name, int X, int Y, int Width, int Hei ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISlider::Create(GUIProperties *Props) { +void GUISlider::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -67,7 +72,6 @@ void GUISlider::Create(GUIProperties *Props) { m_Width = std::max(m_Width, m_MinWidth); m_Height = std::max(m_Height, m_MinHeight); - // Get the values std::string ori; Props->GetValue("Orientation", &ori); @@ -87,7 +91,9 @@ void GUISlider::Create(GUIProperties *Props) { Props->GetValue("Minimum", &m_Minimum); Props->GetValue("Maximum", &m_Maximum); Props->GetValue("Value", &m_Value); - if (!Props->GetValue("ValueResolution", &m_ValueResolution)) { m_ValueResolution = std::max((m_Maximum - m_Minimum) / 100, 1); } + if (!Props->GetValue("ValueResolution", &m_ValueResolution)) { + m_ValueResolution = std::max((m_Maximum - m_Minimum) / 100, 1); + } m_Value = std::clamp(m_Value, m_Minimum, m_Maximum); @@ -115,7 +121,7 @@ void GUISlider::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISlider::ChangeSkin(GUISkin *Skin) { +void GUISlider::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Build the progressbar bitmap @@ -147,7 +153,7 @@ void GUISlider::BuildBitmap() { // Load the source image std::string Filename; m_Skin->GetValue(Section, "Filename", &Filename); - GUIBitmap *SrcImage = m_Skin->CreateBitmap(Filename); + GUIBitmap* SrcImage = m_Skin->CreateBitmap(Filename); if (!SrcImage) { return; } @@ -184,7 +190,7 @@ void GUISlider::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISlider::BuildLine(const std::string &Section, GUIBitmap *SrcImage) { +void GUISlider::BuildLine(const std::string& Section, GUIBitmap* SrcImage) { int Values[4]; GUIRect Rect; @@ -231,7 +237,7 @@ void GUISlider::BuildLine(const std::string &Section, GUIBitmap *SrcImage) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISlider::Draw(GUIScreen *Screen) { +void GUISlider::Draw(GUIScreen* Screen) { int X = 0; int Y = 0; @@ -306,7 +312,9 @@ void GUISlider::OnMouseDown(int X, int Y, int Buttons, int Modifier) { m_Value = std::clamp(m_Value, m_Minimum, m_Maximum); // If the value has changed, add the "Changed" notification - if (m_Value != m_OldValue) { AddEvent(GUIEvent::Notification, Changed, 0); } + if (m_Value != m_OldValue) { + AddEvent(GUIEvent::Notification, Changed, 0); + } AddEvent(GUIEvent::Notification, Clicked, 0); } @@ -319,7 +327,9 @@ void GUISlider::OnMouseUp(int X, int Y, int Buttons, int Modifier) { m_KnobGrabbed = false; // If the value has changed, add the "Changed" notification - if (m_Value != m_OldValue) { AddEvent(GUIEvent::Notification, Changed, 0); } + if (m_Value != m_OldValue) { + AddEvent(GUIEvent::Notification, Changed, 0); + } AddEvent(GUIEvent::Notification, Clicked, 0); } @@ -371,7 +381,9 @@ void GUISlider::OnMouseMove(int X, int Y, int Buttons, int Modifier) { m_KnobPosition = std::min(m_KnobPosition, Size - m_KnobSize - m_EndThickness); // If the value has changed, add the "Changed" notification - if (m_Value != m_OldValue) { AddEvent(GUIEvent::Notification, Changed, 0); } + if (m_Value != m_OldValue) { + AddEvent(GUIEvent::Notification, Changed, 0); + } m_OldValue = m_Value; } @@ -396,7 +408,7 @@ void GUISlider::OnMouseWheelChange(int x, int y, int modifier, int mouseWheelCha ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUISlider::GetPanel() { +GUIPanel* GUISlider::GetPanel() { return this; } @@ -437,7 +449,7 @@ void GUISlider::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISlider::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUISlider::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -536,7 +548,7 @@ void GUISlider::StoreProperties() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUISlider::ApplyProperties(GUIProperties *Props) { +void GUISlider::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); // Get the values @@ -569,5 +581,7 @@ void GUISlider::ApplyProperties(GUIProperties *Props) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUISlider::SetValueResolution(int valueRes) { - if (valueRes >= 1 && valueRes <= m_Maximum - m_Minimum) { m_ValueResolution = valueRes; } -} \ No newline at end of file + if (valueRes >= 1 && valueRes <= m_Maximum - m_Minimum) { + m_ValueResolution = valueRes; + } +} diff --git a/Source/GUI/GUISlider.h b/Source/GUI/GUISlider.h index 34acc0470..0a478372d 100644 --- a/Source/GUI/GUISlider.h +++ b/Source/GUI/GUISlider.h @@ -3,331 +3,298 @@ namespace RTE { -/// -/// A slider control class. -/// -class GUISlider : public GUIControl, public GUIPanel { - -public: - - // Slider orientation - enum { - Horizontal, - Vertical - } Orientation; - - // Tick Direction - enum { - TopLeft, - BottomRight - } TickDirection; - - // Slider Notifications - enum { - Changed = 0, - Clicked - } Notification; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUISlider -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUISlider object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUISlider(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - /// - /// Called when the mouse scroll wheel is moved. + /// A slider control class. /// - /// Mouse X position. - /// Mouse Y position. - /// Activated modifier buttons. - /// The amount of wheel movement. Positive is scroll up, negative is scroll down. - void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "SLIDER"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOrientation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the orientation of the slider. -// Arguments: Orientation. - - void SetOrientation(int Orientation); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOrientation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the orientation of the slider. -// Arguments: None. - - int GetOrientation() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetTickDirection -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the direction of the ticks. -// Arguments: TickDir. - - void SetTickDirection(int TickDir); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTickDirection -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the direction of the ticks. -// Arguments: None. - - int GetTickDirection() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMinimum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the minimum value. -// Arguments: Minimum. - - void SetMinimum(int Minimum); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMinimum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the minimum value. -// Arguments: None. - - int GetMinimum() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMaximum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the maximum value. -// Arguments: Maximum. - - void SetMaximum(int Maximum); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaximum -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the maximum value. -// Arguments: None. - - int GetMaximum() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the value. -// Arguments: Value. - - void SetValue(int Value); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetValue -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the value. -// Arguments: None. - - int GetValue() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - - - /// - /// Sets the value resolution for this slider. - /// - /// The new value resolution - void SetValueResolution(int valueRes); - -private: - - GUIBitmap *m_DrawBitmap; - GUIBitmap *m_KnobImage; - - // Properties - int m_Orientation; - int m_TickDirection; - int m_Minimum; - int m_Maximum; - int m_Value; - int m_ValueResolution; - - // Internal variables - int m_KnobPosition; - int m_KnobSize; - bool m_KnobGrabbed; - int m_KnobGrabPos; - int m_EndThickness; - int m_OldValue; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the slider bitmap to draw. -// Arguments: None. - - void BuildBitmap(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildLine -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Builds the background line for the slider -// Arguments: Section, SrcImage. - - void BuildLine(const std::string &Section, GUIBitmap *SrcImage); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CalculateKnob -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the knob position and size. -// Arguments: None. - - void CalculateKnob(); -}; -}; -#endif \ No newline at end of file + class GUISlider : public GUIControl, public GUIPanel { + + public: + // Slider orientation + enum { + Horizontal, + Vertical + } Orientation; + + // Tick Direction + enum { + TopLeft, + BottomRight + } TickDirection; + + // Slider Notifications + enum { + Changed = 0, + Clicked + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUISlider + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUISlider object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUISlider(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + /// + /// Called when the mouse scroll wheel is moved. + /// + /// Mouse X position. + /// Mouse Y position. + /// Activated modifier buttons. + /// The amount of wheel movement. Positive is scroll up, negative is scroll down. + void OnMouseWheelChange(int x, int y, int modifier, int mouseWheelChange) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "SLIDER"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOrientation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the orientation of the slider. + // Arguments: Orientation. + + void SetOrientation(int Orientation); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOrientation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the orientation of the slider. + // Arguments: None. + + int GetOrientation() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetTickDirection + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the direction of the ticks. + // Arguments: TickDir. + + void SetTickDirection(int TickDir); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTickDirection + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the direction of the ticks. + // Arguments: None. + + int GetTickDirection() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMinimum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the minimum value. + // Arguments: Minimum. + + void SetMinimum(int Minimum); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMinimum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the minimum value. + // Arguments: None. + + int GetMinimum() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMaximum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the maximum value. + // Arguments: Maximum. + + void SetMaximum(int Maximum); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaximum + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the maximum value. + // Arguments: None. + + int GetMaximum() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the value. + // Arguments: Value. + + void SetValue(int Value); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetValue + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the value. + // Arguments: None. + + int GetValue() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; + + /// + /// Sets the value resolution for this slider. + /// + /// The new value resolution + void SetValueResolution(int valueRes); + + private: + GUIBitmap* m_DrawBitmap; + GUIBitmap* m_KnobImage; + + // Properties + int m_Orientation; + int m_TickDirection; + int m_Minimum; + int m_Maximum; + int m_Value; + int m_ValueResolution; + + // Internal variables + int m_KnobPosition; + int m_KnobSize; + bool m_KnobGrabbed; + int m_KnobGrabPos; + int m_EndThickness; + int m_OldValue; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the slider bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildLine + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Builds the background line for the slider + // Arguments: Section, SrcImage. + + void BuildLine(const std::string& Section, GUIBitmap* SrcImage); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CalculateKnob + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the knob position and size. + // Arguments: None. + + void CalculateKnob(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUISound.cpp b/Source/GUI/GUISound.cpp index c96a95918..597412987 100644 --- a/Source/GUI/GUISound.cpp +++ b/Source/GUI/GUISound.cpp @@ -2,7 +2,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUISound::Clear() { m_SplashSound.Reset(); @@ -34,7 +34,7 @@ namespace RTE { m_PlacementGravel.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUISound::Initialize() { // Interface sounds should not be pitched to reinforce the appearance of time decoupling between simulation and UI. @@ -111,4 +111,4 @@ namespace RTE { m_PlacementGravel.GetTopLevelSoundSet().AddSound("Base.rte/Sounds/GUIs/PlacementGravel3.flac", true); m_PlacementGravel.GetTopLevelSoundSet().AddSound("Base.rte/Sounds/GUIs/PlacementGravel4.flac", true); } -} +} // namespace RTE diff --git a/Source/GUI/GUISound.h b/Source/GUI/GUISound.h index de17ad9fa..2a94a0439 100644 --- a/Source/GUI/GUISound.h +++ b/Source/GUI/GUISound.h @@ -12,9 +12,8 @@ namespace RTE { /// The singleton loader for all GUI sound effects. /// class GUISound : public Singleton { - - public: + public: #pragma region Creation /// /// Constructor method used to instantiate a GUISound object in system memory. Create() should be called before using the object. @@ -44,163 +43,163 @@ namespace RTE { /// Gets juicy logo signature jingle Sound. /// /// Juicy logo signature jingle Sound. - SoundContainer *SplashSound() { return &m_SplashSound; } + SoundContainer* SplashSound() { return &m_SplashSound; } /// /// Gets SoundContainer for enabling menu. /// /// SoundContainer for enabling menu. - SoundContainer *EnterMenuSound() { return &m_EnterMenuSound; } + SoundContainer* EnterMenuSound() { return &m_EnterMenuSound; } /// /// Gets SoundContainer for disabling menu. /// /// SoundContainer for disabling menu. - SoundContainer *ExitMenuSound() { return &m_ExitMenuSound; } + SoundContainer* ExitMenuSound() { return &m_ExitMenuSound; } /// /// Gets SoundContainer for changing focus. /// /// SoundContainer for changing focus. - SoundContainer *FocusChangeSound() { return &m_FocusChangeSound; } + SoundContainer* FocusChangeSound() { return &m_FocusChangeSound; } /// /// Gets SoundContainer for selecting items in list, etc. /// /// SoundContainer for selecting items in list, etc. - SoundContainer *SelectionChangeSound() { return &m_SelectionChangeSound; } + SoundContainer* SelectionChangeSound() { return &m_SelectionChangeSound; } /// /// Gets SoundContainer for adding or deleting items in list. /// /// SoundContainer for adding or deleting items in list. - SoundContainer *ItemChangeSound() { return &m_ItemChangeSound; } + SoundContainer* ItemChangeSound() { return &m_ItemChangeSound; } /// /// Gets SoundContainer for button press. /// /// SoundContainer for button press. - SoundContainer *ButtonPressSound() { return &m_ButtonPressSound; } + SoundContainer* ButtonPressSound() { return &m_ButtonPressSound; } /// /// Gets SoundContainer for button press of going back button. /// /// SoundContainer for button press of going back button. - SoundContainer *BackButtonPressSound() { return &m_BackButtonPressSound; } + SoundContainer* BackButtonPressSound() { return &m_BackButtonPressSound; } /// /// Gets SoundContainer for confirming a selection. /// /// SoundContainer for confirming a selection. - SoundContainer *ConfirmSound() { return &m_ConfirmSound; } + SoundContainer* ConfirmSound() { return &m_ConfirmSound; } /// /// Gets SoundContainer for erroneous input. /// /// SoundContainer for erroneous input. - SoundContainer *UserErrorSound() { return &m_UserErrorSound; } + SoundContainer* UserErrorSound() { return &m_UserErrorSound; } /// /// Gets SoundContainer for testing volume when adjusting volume sliders. /// /// SoundContainer for testing volume when adjusting volume sliders. - SoundContainer *TestSound() { return &m_TestSound; } + SoundContainer* TestSound() { return &m_TestSound; } /// /// Gets SoundContainer for opening pie menu. /// /// SoundContainer for opening pie menu. - SoundContainer *PieMenuEnterSound() { return &m_PieMenuEnterSound; } + SoundContainer* PieMenuEnterSound() { return &m_PieMenuEnterSound; } /// /// Gets SoundContainer for closing pie menu. /// /// SoundContainer for closing pie menu. - SoundContainer *PieMenuExitSound() { return &m_PieMenuExitSound; } + SoundContainer* PieMenuExitSound() { return &m_PieMenuExitSound; } /// /// Gets SoundContainer for when PieMenu hover arrow appears or changes slice. /// /// SoundContainer for when PieMenu hover arrow appears or changes slice. - SoundContainer *HoverChangeSound() { return &m_HoverChangeSound; } + SoundContainer* HoverChangeSound() { return &m_HoverChangeSound; } /// /// Gets SoundContainer for when PieMenu hover arrow appears or changes to a disabled slice. /// /// SoundContainer for when PieMenu hover arrow appears or changes to a disabled slice. - SoundContainer *HoverDisabledSound() { return &m_HoverDisabledSound; } + SoundContainer* HoverDisabledSound() { return &m_HoverDisabledSound; } /// /// Gets SoundContainer for picking a valid PieMenu slice. /// /// SoundContainer for picking a valid PieMenu slice. - SoundContainer *SlicePickedSound() { return &m_SlicePickedSound; } + SoundContainer* SlicePickedSound() { return &m_SlicePickedSound; } /// /// Gets SoundContainer for erroneous input in PieMenu. /// /// SoundContainer for erroneous input in PieMenu. - SoundContainer *DisabledPickedSound() { return &m_DisabledPickedSound; } + SoundContainer* DisabledPickedSound() { return &m_DisabledPickedSound; } /// /// Gets SoundContainer for when the funds of a team changes. /// /// SoundContainer for when the funds of a team changes. - SoundContainer *FundsChangedSound() { return &m_FundsChangedSound; } + SoundContainer* FundsChangedSound() { return &m_FundsChangedSound; } /// /// Gets SoundContainer for switching between regular (non-brain) actors. /// /// SoundContainer for switching between regular (non-brain) actors. - SoundContainer *ActorSwitchSound() { return &m_ActorSwitchSound; } + SoundContainer* ActorSwitchSound() { return &m_ActorSwitchSound; } /// /// Gets SoundContainer for switching to the brain shortcut. /// /// SoundContainer for switching to the brain shortcut. - SoundContainer *BrainSwitchSound() { return &m_BrainSwitchSound; } + SoundContainer* BrainSwitchSound() { return &m_BrainSwitchSound; } /// /// Gets SoundContainer when camera is traveling between actors. /// /// SoundContainer when camera is traveling between actors. - SoundContainer *CameraTravelSound() { return &m_CameraTravelSound; } + SoundContainer* CameraTravelSound() { return &m_CameraTravelSound; } /// /// Gets SoundContainer for making an area focus. /// /// SoundContainer for making an area focus. - SoundContainer *AreaPickedSound() { return &m_AreaPickedSound; } + SoundContainer* AreaPickedSound() { return &m_AreaPickedSound; } /// /// Gets SoundContainer for making an object focus. /// /// SoundContainer for making an object focus. - SoundContainer *ObjectPickedSound() { return &m_ObjectPickedSound; } + SoundContainer* ObjectPickedSound() { return &m_ObjectPickedSound; } /// /// Gets SoundContainer for making a purchase. /// /// SoundContainer for making a purchase. - SoundContainer *PurchaseMadeSound() { return &m_PurchaseMadeSound; } + SoundContainer* PurchaseMadeSound() { return &m_PurchaseMadeSound; } /// /// Gets SoundContainer for placement of object to scene. /// /// SoundContainer for placement of object to scene. - SoundContainer *PlacementBlip() { return &m_PlacementBlip; } + SoundContainer* PlacementBlip() { return &m_PlacementBlip; } /// /// Gets SoundContainer for placement of object to scene. /// /// SoundContainer for placement of object to scene. - SoundContainer *PlacementThud() { return &m_PlacementThud; } + SoundContainer* PlacementThud() { return &m_PlacementThud; } /// /// Gets SoundContainer for gravely placement of object to scene. /// /// SoundContainer for gravely placement of object to scene. - SoundContainer *PlacementGravel() { return &m_PlacementGravel; } + SoundContainer* PlacementGravel() { return &m_PlacementGravel; } #pragma endregion protected: @@ -248,5 +247,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/GUI/GUITab.cpp b/Source/GUI/GUITab.cpp index f81a38d09..411ad986f 100644 --- a/Source/GUI/GUITab.cpp +++ b/Source/GUI/GUITab.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUITab::GUITab(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUIPanel(Manager) { +GUITab::GUITab(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUIPanel(Manager) { m_ControlID = "TAB"; m_Image = nullptr; m_ControlManager = ControlManager; @@ -18,7 +19,7 @@ GUITab::GUITab(GUIManager *Manager, GUIControlManager *ControlManager) : GUICont ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITab::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUITab::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -35,8 +36,12 @@ void GUITab::Create(const std::string &Name, int X, int Y, int Width, int Height m_Width = m_DefWidth; m_Height = m_DefHeight; - if (Width != -1) { m_Width = Width; } - if (Height != -1) { m_Height = Height; } + if (Width != -1) { + m_Width = Width; + } + if (Height != -1) { + m_Height = Height; + } // Make sure the button isn't too small m_Width = std::max(m_Width, m_MinWidth); @@ -45,7 +50,7 @@ void GUITab::Create(const std::string &Name, int X, int Y, int Width, int Height ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITab::Create(GUIProperties *Props) { +void GUITab::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -70,7 +75,7 @@ void GUITab::Create(GUIProperties *Props) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITab::ChangeSkin(GUISkin *Skin) { +void GUITab::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Build the checkbox bitmap @@ -127,7 +132,7 @@ void GUITab::BuildBitmap() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITab::Draw(GUIScreen *Screen) { +void GUITab::Draw(GUIScreen* Screen) { if (!m_Image) { return; } @@ -147,7 +152,7 @@ void GUITab::Draw(GUIScreen *Screen) { if (m_Enabled) { m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[2]); } // else - //m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[3]); + // m_Image->DrawTrans(Screen->GetBitmap(), m_X, YPos, &m_ImageRects[3]); //} } @@ -195,7 +200,9 @@ void GUITab::OnMouseUp(int X, int Y, int Buttons, int Modifier) { ReleaseMouse(); // If the mouse is over the button, add the command to the event queue - if (PointInside(X, Y) && Buttons & MOUSE_LEFT) { SetCheck(true); } + if (PointInside(X, Y) && Buttons & MOUSE_LEFT) { + SetCheck(true); + } AddEvent(GUIEvent::Notification, UnPushed, 0); } @@ -215,7 +222,7 @@ void GUITab::OnMouseLeave(int X, int Y, int Buttons, int Modifier) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUITab::GetPanel() { +GUIPanel* GUITab::GetPanel() { return this; } @@ -240,7 +247,7 @@ void GUITab::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITab::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUITab::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUIPanel::GetRect(X, Y, Width, Height); } @@ -269,11 +276,11 @@ void GUITab::SetCheck(bool Check) { // Go through all my RadioButton siblings and un-check them if (m_ControlParent) { - std::vector::iterator it; - std::vector *Children = m_ControlParent->GetChildren(); + std::vector::iterator it; + std::vector* Children = m_ControlParent->GetChildren(); for (it = Children->begin(); it != Children->end(); it++) { - GUIControl *C = *it; + GUIControl* C = *it; if (C) { // Make sure this is not me if (C->GetPanel() && GetPanel() && C->GetPanel()->GetPanelID() == GetPanel()->GetPanelID()) { @@ -281,7 +288,7 @@ void GUITab::SetCheck(bool Check) { } // Make sure the control is a radio button if (C->GetID().compare(GetID()) == 0) { - GUITab *R = (GUITab *)C; + GUITab* R = (GUITab*)C; R->SetCheck(false); } } @@ -297,7 +304,7 @@ bool GUITab::GetCheck() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITab::SetText(const std::string &Text) { +void GUITab::SetText(const std::string& Text) { m_Text = Text; } @@ -309,9 +316,9 @@ std::string GUITab::GetText() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITab::ApplyProperties(GUIProperties *Props) { +void GUITab::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); m_Properties.GetValue("Text", &m_Text); m_Properties.GetValue("Selected", &m_Selected); -} \ No newline at end of file +} diff --git a/Source/GUI/GUITab.h b/Source/GUI/GUITab.h index e1fd9cffc..ce44aa25e 100644 --- a/Source/GUI/GUITab.h +++ b/Source/GUI/GUITab.h @@ -3,219 +3,197 @@ namespace RTE { -/// -/// A tab control class. -/// -class GUITab : public GUIControl, public GUIPanel { + /// + /// A tab control class. + /// + class GUITab : public GUIControl, public GUIPanel { + + public: + // Tab Notifications + enum { + Hovered = 0, + Pushed, + UnPushed, + Changed, + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUITab + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUITab object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUITab(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseEnter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse enters the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseLeave + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse leaves the panel. + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "TAB"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; -public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; - // Tab Notifications - enum { - Hovered = 0, - Pushed, - UnPushed, - Changed, - } Notification; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StoreProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the control to store the values into properties. + // Arguments: None. + + void StoreProperties() override; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the check state. + // Arguments: State. + + void SetCheck(bool Check); -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUITab -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUITab object in -// system memory. -// Arguments: GUIManager, GUIControlManager. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the check state. + // Arguments: None. + + bool GetCheck() const; - GUITab(GUIManager *Manager, GUIControlManager *ControlManager); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the text. + // Arguments: Text. + + void SetText(const std::string& Text); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the text. + // Arguments: None. + + std::string GetText() const; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; + private: + GUIBitmap* m_Image; + GUIRect m_ImageRects[4]; + + bool m_Selected; + int m_Mouseover; + std::string m_Text; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseEnter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse enters the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseEnter(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseLeave -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse leaves the panel. -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseLeave(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "TAB"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StoreProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the control to store the values into properties. -// Arguments: None. - - void StoreProperties() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the check state. -// Arguments: State. - - void SetCheck(bool Check); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the check state. -// Arguments: None. - - bool GetCheck() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the text. -// Arguments: Text. - - void SetText(const std::string &Text); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the text. -// Arguments: None. - - std::string GetText() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - - GUIBitmap *m_Image; - GUIRect m_ImageRects[4]; - - bool m_Selected; - int m_Mouseover; - std::string m_Text; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BuildBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the checkbox bitmap to draw. -// Arguments: None. - - void BuildBitmap(); -}; -}; -#endif \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BuildBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the checkbox bitmap to draw. + // Arguments: None. + + void BuildBitmap(); + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUITextBox.cpp b/Source/GUI/GUITextBox.cpp index 152e7835e..f5e0a83e6 100644 --- a/Source/GUI/GUITextBox.cpp +++ b/Source/GUI/GUITextBox.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUITextBox::GUITextBox(GUIManager *Manager, GUIControlManager *ControlManager) : GUIControl(), GUITextPanel(Manager) { +GUITextBox::GUITextBox(GUIManager* Manager, GUIControlManager* ControlManager) : + GUIControl(), GUITextPanel(Manager) { m_ControlID = "TEXTBOX"; m_ControlManager = ControlManager; m_DrawBitmap = nullptr; @@ -15,7 +16,7 @@ GUITextBox::GUITextBox(GUIManager *Manager, GUIControlManager *ControlManager) : ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextBox::Create(const std::string &Name, int X, int Y, int Width, int Height) { +void GUITextBox::Create(const std::string& Name, int X, int Y, int Width, int Height) { GUIControl::Create(Name, X, Y, Width, Height); // Minimum size of the control @@ -29,15 +30,19 @@ void GUITextBox::Create(const std::string &Name, int X, int Y, int Width, int He // Create the ListPanel int w = m_DefWidth; int h = m_DefHeight; - if (Width != -1) { w = Width; } - if (Height != -1) { h = Height; } + if (Width != -1) { + w = Width; + } + if (Height != -1) { + h = Height; + } GUITextPanel::Create(X, Y, w, h); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextBox::Create(GUIProperties *Props) { +void GUITextBox::Create(GUIProperties* Props) { GUIControl::Create(Props); // Minimum size of the control @@ -59,14 +64,26 @@ void GUITextBox::Create(GUIProperties *Props) { // Alignment values - these don't affect anything as of yet std::string alignString; Props->GetValue("HAlignment", &alignString); - if (stricmp(alignString.c_str(), "left") == 0) { m_HAlignment = GUIFont::Left; } - if (stricmp(alignString.c_str(), "centre") == 0 || stricmp(alignString.c_str(), "center") == 0) { m_HAlignment = GUIFont::Centre; } - if (stricmp(alignString.c_str(), "right") == 0) { m_HAlignment = GUIFont::Right; } + if (stricmp(alignString.c_str(), "left") == 0) { + m_HAlignment = GUIFont::Left; + } + if (stricmp(alignString.c_str(), "centre") == 0 || stricmp(alignString.c_str(), "center") == 0) { + m_HAlignment = GUIFont::Centre; + } + if (stricmp(alignString.c_str(), "right") == 0) { + m_HAlignment = GUIFont::Right; + } Props->GetValue("VAlignment", &alignString); - if (stricmp(alignString.c_str(), "top") == 0) { m_VAlignment = GUIFont::Top; } - if (stricmp(alignString.c_str(), "middle") == 0) { m_VAlignment = GUIFont::Middle; } - if (stricmp(alignString.c_str(), "bottom") == 0) { m_VAlignment = GUIFont::Bottom; } + if (stricmp(alignString.c_str(), "top") == 0) { + m_VAlignment = GUIFont::Top; + } + if (stricmp(alignString.c_str(), "middle") == 0) { + m_VAlignment = GUIFont::Middle; + } + if (stricmp(alignString.c_str(), "bottom") == 0) { + m_VAlignment = GUIFont::Bottom; + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -82,7 +99,7 @@ void GUITextBox::Destroy() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextBox::ChangeSkin(GUISkin *Skin) { +void GUITextBox::ChangeSkin(GUISkin* Skin) { GUIControl::ChangeSkin(Skin); // Free any old bitmap @@ -104,7 +121,7 @@ void GUITextBox::ChangeSkin(GUISkin *Skin) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextBox::Draw(GUIScreen *Screen) { +void GUITextBox::Draw(GUIScreen* Screen) { // Draw the background m_DrawBitmap->Draw(Screen->GetBitmap(), m_X, m_Y, nullptr); @@ -113,7 +130,7 @@ void GUITextBox::Draw(GUIScreen *Screen) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUIPanel * GUITextBox::GetPanel() { +GUIPanel* GUITextBox::GetPanel() { return this; } @@ -138,28 +155,34 @@ void GUITextBox::Resize(int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextBox::GetControlRect(int *X, int *Y, int *Width, int *Height) { +void GUITextBox::GetControlRect(int* X, int* Y, int* Width, int* Height) { GUITextPanel::GetRect(X, Y, Width, Height); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextBox::ReceiveSignal(GUIPanel *Source, int Code, int Data) { +void GUITextBox::ReceiveSignal(GUIPanel* Source, int Code, int Data) { // Clicked - if (Code == GUITextPanel::Clicked) { AddEvent(GUIEvent::Notification, Clicked, Data); } + if (Code == GUITextPanel::Clicked) { + AddEvent(GUIEvent::Notification, Clicked, Data); + } // Changed - if (Code == GUITextPanel::Changed) { AddEvent(GUIEvent::Notification, Changed, 0); } + if (Code == GUITextPanel::Changed) { + AddEvent(GUIEvent::Notification, Changed, 0); + } // Enter - if (Code == GUITextPanel::Enter) { AddEvent(GUIEvent::Notification, Enter, 0); } + if (Code == GUITextPanel::Enter) { + AddEvent(GUIEvent::Notification, Enter, 0); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextBox::ApplyProperties(GUIProperties *Props) { +void GUITextBox::ApplyProperties(GUIProperties* Props) { GUIControl::ApplyProperties(Props); // Force a rebuild of the bitmap ChangeSkin(m_Skin); -} \ No newline at end of file +} diff --git a/Source/GUI/GUITextBox.h b/Source/GUI/GUITextBox.h index 4af403038..1aead6dd8 100644 --- a/Source/GUI/GUITextBox.h +++ b/Source/GUI/GUITextBox.h @@ -5,144 +5,129 @@ namespace RTE { -/// -/// A TextBox control class. -/// -class GUITextBox : public GUIControl, public GUITextPanel { - -public: - - // Notifications - enum { - Changed = 0, - Clicked, - Enter - } Notification; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUITextBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUITextBox object in -// system memory. -// Arguments: GUIManager, GUIControlManager. - - GUITextBox(GUIManager *Manager, GUIControlManager *ControlManager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Name, Position. - - void Create(const std::string &Name, int X, int Y, int Width = -1, int Height = -1) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been created. -// Arguments: Properties. - - void Create(GUIProperties *Props) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control has been destroyed. -// Arguments: None. - - void Destroy() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the panel of the control. -// Arguments: None. -// Returns: 0 if the control does not have a panel, otherwise the topmost panel. - - GUIPanel * GetPanel() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a string representing the control's ID -// Arguments: None. - - static std::string GetControlID() { return "TEXTBOX"; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Move -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be moved. -// Arguments: New position. - - void Move(int X, int Y) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Resize -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the control needs to be resized. -// Arguments: New size. - - void Resize(int Width, int Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetControlRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the rectangle of the control. -// Arguments: Position, Size. - - void GetControlRect(int *X, int *Y, int *Width, int *Height) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReceiveSignal -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when receiving a signal. -// Arguments: Signal source, Signal code, Signal data. - - void ReceiveSignal(GUIPanel *Source, int Code, int Data) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ApplyProperties -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Applies new properties to the control. -// Arguments: GUIProperties. - - void ApplyProperties(GUIProperties *Props) override; - -private: - - GUIBitmap *m_DrawBitmap; - int m_HAlignment; - int m_VAlignment; -}; -}; -#endif \ No newline at end of file + /// + /// A TextBox control class. + /// + class GUITextBox : public GUIControl, public GUITextPanel { + + public: + // Notifications + enum { + Changed = 0, + Clicked, + Enter + } Notification; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUITextBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUITextBox object in + // system memory. + // Arguments: GUIManager, GUIControlManager. + + GUITextBox(GUIManager* Manager, GUIControlManager* ControlManager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Name, Position. + + void Create(const std::string& Name, int X, int Y, int Width = -1, int Height = -1) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been created. + // Arguments: Properties. + + void Create(GUIProperties* Props) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control has been destroyed. + // Arguments: None. + + void Destroy() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the panel of the control. + // Arguments: None. + // Returns: 0 if the control does not have a panel, otherwise the topmost panel. + + GUIPanel* GetPanel() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a string representing the control's ID + // Arguments: None. + + static std::string GetControlID() { return "TEXTBOX"; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Move + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be moved. + // Arguments: New position. + + void Move(int X, int Y) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Resize + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the control needs to be resized. + // Arguments: New size. + + void Resize(int Width, int Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetControlRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the rectangle of the control. + // Arguments: Position, Size. + + void GetControlRect(int* X, int* Y, int* Width, int* Height) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReceiveSignal + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when receiving a signal. + // Arguments: Signal source, Signal code, Signal data. + + void ReceiveSignal(GUIPanel* Source, int Code, int Data) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ApplyProperties + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Applies new properties to the control. + // Arguments: GUIProperties. + + void ApplyProperties(GUIProperties* Props) override; + + private: + GUIBitmap* m_DrawBitmap; + int m_HAlignment; + int m_VAlignment; + }; +}; // namespace RTE +#endif diff --git a/Source/GUI/GUITextPanel.cpp b/Source/GUI/GUITextPanel.cpp index 6f70d8373..f34b85ea7 100644 --- a/Source/GUI/GUITextPanel.cpp +++ b/Source/GUI/GUITextPanel.cpp @@ -5,7 +5,8 @@ using namespace RTE; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUITextPanel::GUITextPanel(GUIManager *Manager) : GUIPanel(Manager) { +GUITextPanel::GUITextPanel(GUIManager* Manager) : + GUIPanel(Manager) { m_Font = nullptr; m_CursorX = m_CursorY = 0; m_CursorIndex = 0; @@ -30,7 +31,8 @@ GUITextPanel::GUITextPanel(GUIManager *Manager) : GUIPanel(Manager) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -GUITextPanel::GUITextPanel() : GUIPanel() { +GUITextPanel::GUITextPanel() : + GUIPanel() { m_Font = nullptr; m_Text = ""; m_CursorX = m_CursorY = 0; @@ -65,7 +67,7 @@ void GUITextPanel::Create(int X, int Y, int Width, int Height) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextPanel::ChangeSkin(GUISkin *Skin) { +void GUITextPanel::ChangeSkin(GUISkin* Skin) { // Load the font std::string Filename; Skin->GetValue("TextBox", "Font", &Filename); @@ -91,12 +93,11 @@ void GUITextPanel::ChangeSkin(GUISkin *Skin) { // Get the cursor color Skin->GetValue("TextBox", "CursorColorIndex", &m_CursorColor); m_CursorColor = Skin->ConvertColor(m_CursorColor); - } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextPanel::Draw(GUIScreen *Screen) { +void GUITextPanel::Draw(GUIScreen* Screen) { if (!m_Font) return; @@ -130,15 +131,18 @@ void GUITextPanel::Draw(GUIScreen *Screen) { int End = std::max(m_StartSelection, m_EndSelection); // Selection - if (m_StartIndex > Start) { Start = m_StartIndex; } + if (m_StartIndex > Start) { + Start = m_StartIndex; + } m_Font->Draw(Screen->GetBitmap(), m_X + wSpacer + m_SelectionX, m_Y + hSpacer, Text.substr(Start - m_StartIndex, End - Start)); } - // If we have focus, draw the blinking cursor const int blinkInterval = 250; bool shouldBlink = static_cast(m_BlinkTimer.GetElapsedRealTimeMS()) % (blinkInterval * 2) > blinkInterval; - if (m_GotFocus && shouldBlink) { Screen->GetBitmap()->DrawRectangle(m_X + m_CursorX + 2, m_Y + hSpacer + m_CursorY + 2, 1, FontHeight - 3, m_CursorColor, true); } + if (m_GotFocus && shouldBlink) { + Screen->GetBitmap()->DrawRectangle(m_X + m_CursorX + 2, m_Y + hSpacer + m_CursorY + 2, 1, FontHeight - 3, m_CursorColor, true); + } // Restore normal clipping Screen->GetBitmap()->SetClipRect(nullptr); @@ -253,7 +257,9 @@ void GUITextPanel::OnKeyPress(int KeyCode, int Modifier) { // ModKey-C (Copy) if (KeyCode == 'c' && ModKey) { - if (m_GotSelection) { GUIUtil::SetClipboardText(GetSelectionText()); } + if (m_GotSelection) { + GUIUtil::SetClipboardText(GetSelectionText()); + } return; } @@ -293,7 +299,7 @@ void GUITextPanel::OnTextInput(std::string_view inputText) { maxValidKeyCode = 57; } - for (auto characterIterator = inputText.begin(); characterIterator < inputText.end(); ++characterIterator){ + for (auto characterIterator = inputText.begin(); characterIterator < inputText.end(); ++characterIterator) { char character = *characterIterator; if (character >= minValidKeyCode && character <= maxValidKeyCode) { RemoveSelectionText(); @@ -336,7 +342,9 @@ void GUITextPanel::OnMouseDown(int X, int Y, int Buttons, int Modifier) { std::string Text = m_Text.substr(m_StartIndex, m_Text.size() - m_StartIndex); m_CursorIndex = m_Text.size(); - if (!(Modifier & MODI_SHIFT)) { m_GotSelection = false; } + if (!(Modifier & MODI_SHIFT)) { + m_GotSelection = false; + } // Go through each character until we to the mouse point int TX = m_X; @@ -404,10 +412,14 @@ void GUITextPanel::UpdateText(bool Typing, bool DoIncrement) { int Increment = 4; int Spacer = 2; - if (Typing) { Increment = 1; } + if (Typing) { + Increment = 1; + } // Make sure the cursor is greater or equal to the start index - if (m_CursorIndex <= m_StartIndex && DoIncrement) { m_StartIndex = m_CursorIndex - Increment; } + if (m_CursorIndex <= m_StartIndex && DoIncrement) { + m_StartIndex = m_CursorIndex - Increment; + } // Clamp it m_StartIndex = std::max(m_StartIndex, 0); @@ -426,7 +438,9 @@ void GUITextPanel::UpdateText(bool Typing, bool DoIncrement) { m_CursorX = m_Font->CalculateWidth(m_Text.substr(m_StartIndex, m_CursorIndex - m_StartIndex)); // Update the selection - if (m_GotSelection) { DoSelection(m_StartSelection, m_EndSelection); } + if (m_GotSelection) { + DoSelection(m_StartSelection, m_EndSelection); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -467,7 +481,7 @@ void GUITextPanel::DoSelection(int Start, int End) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int RTE::GUITextPanel::GetStartOfNextCharacterGroup(const std::string_view &stringToCheck, int currentIndex) const { +int RTE::GUITextPanel::GetStartOfNextCharacterGroup(const std::string_view& stringToCheck, int currentIndex) const { auto isNormalCharacter = [](char charToCheck) { return (std::isalnum(charToCheck) || charToCheck == '_'); }; @@ -479,17 +493,17 @@ int RTE::GUITextPanel::GetStartOfNextCharacterGroup(const std::string_view &stri }; std::string_view::const_iterator currentIterator = stringToCheck.cbegin() + currentIndex; - currentIterator = isNormalCharacter(*currentIterator) ? - std::find_if(currentIterator, stringToCheck.cend(), isSpecialCharacterOrSpace) : - std::find_if(currentIterator, stringToCheck.cend(), isNormalCharacterOrSpace); + currentIterator = isNormalCharacter(*currentIterator) ? std::find_if(currentIterator, stringToCheck.cend(), isSpecialCharacterOrSpace) : std::find_if(currentIterator, stringToCheck.cend(), isNormalCharacterOrSpace); - if (currentIterator != stringToCheck.cend() && std::isspace(*currentIterator)) { currentIterator = std::find_if_not(currentIterator, stringToCheck.cend(), isspace); } + if (currentIterator != stringToCheck.cend() && std::isspace(*currentIterator)) { + currentIterator = std::find_if_not(currentIterator, stringToCheck.cend(), isspace); + } return std::distance(stringToCheck.cbegin(), currentIterator); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int RTE::GUITextPanel::GetStartOfPreviousCharacterGroup(const std::string_view &stringToCheck, int currentIndex) const { +int RTE::GUITextPanel::GetStartOfPreviousCharacterGroup(const std::string_view& stringToCheck, int currentIndex) const { auto isNormalCharacter = [](char charToCheck) { return (std::isalnum(charToCheck) || charToCheck == '_'); }; @@ -501,12 +515,12 @@ int RTE::GUITextPanel::GetStartOfPreviousCharacterGroup(const std::string_view & }; std::string_view::reverse_iterator currentIterator = stringToCheck.crbegin() + (m_Text.size() - currentIndex); - if (std::isspace(*currentIterator)) { currentIterator = std::find_if_not(currentIterator, stringToCheck.crend(), isspace); } + if (std::isspace(*currentIterator)) { + currentIterator = std::find_if_not(currentIterator, stringToCheck.crend(), isspace); + } if (currentIterator != stringToCheck.crend()) { - currentIterator = isNormalCharacter(*currentIterator) ? - std::find_if(currentIterator, stringToCheck.crend(), isSpecialCharacterOrSpace) : - std::find_if(currentIterator, stringToCheck.crend(), isNormalCharacterOrSpace); + currentIterator = isNormalCharacter(*currentIterator) ? std::find_if(currentIterator, stringToCheck.crend(), isSpecialCharacterOrSpace) : std::find_if(currentIterator, stringToCheck.crend(), isNormalCharacterOrSpace); } return std::distance(stringToCheck.cbegin(), currentIterator.base()); } @@ -538,8 +552,12 @@ void GUITextPanel::RemoveSelectionText() { void GUITextPanel::SetCursorPos(int cursorPos) { m_GotSelection = false; - if (cursorPos <= 0) { cursorPos = 0; } - if (cursorPos > m_Text.size()) { cursorPos = m_Text.size(); } + if (cursorPos <= 0) { + cursorPos = 0; + } + if (cursorPos > m_Text.size()) { + cursorPos = m_Text.size(); + } m_CursorIndex = m_Text.size(); @@ -563,7 +581,7 @@ std::string GUITextPanel::GetSelectionText() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextPanel::SetText(const std::string &Text) { +void GUITextPanel::SetText(const std::string& Text) { m_Text = Text; // Clear the selection @@ -581,7 +599,7 @@ void GUITextPanel::SetText(const std::string &Text) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void GUITextPanel::SetRightText(const std::string &rightText) { +void GUITextPanel::SetRightText(const std::string& rightText) { m_RightText = rightText; SendSignal(Changed, 0); } @@ -632,7 +650,9 @@ void GUITextPanel::SetLocked(bool Locked) { m_Locked = Locked; // Clear the selection if we are now locked - if (m_Locked) { ClearSelection(); } + if (m_Locked) { + ClearSelection(); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Source/GUI/GUITextPanel.h b/Source/GUI/GUITextPanel.h index 413ce0dda..dbd42a31d 100644 --- a/Source/GUI/GUITextPanel.h +++ b/Source/GUI/GUITextPanel.h @@ -3,311 +3,286 @@ namespace RTE { -/// -/// A text panel class. -/// -class GUITextPanel : public GUIPanel { - -public: - - // Text panel signals - enum { - Clicked = 0, - MouseDown, - Changed, - Enter - } Signals; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUITextPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUITextPanel object in -// system memory. -// Arguments: GUIManager. - - explicit GUITextPanel(GUIManager *Manager); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GUITextPanel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GUITextPanel object in -// system memory. -// Arguments: None. - - GUITextPanel(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Create the panel. -// Arguments: Position, Size. - - void Create(int X, int Y, int Width, int Height); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeSkin -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the skin has been changed. -// Arguments: New skin pointer. - - void ChangeSkin(GUISkin *Skin); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the panel -// Arguments: Screen class - - void Draw(GUIScreen *Screen) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseDown -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes down on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseUp -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse goes up on the panel -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnMouseMove -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when the mouse moves (over the panel, or when captured). -// Arguments: Mouse Position, Mouse Buttons, Modifier. - - void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnKeyPress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Called when a key is pressed (OnDown & repeating). -// Arguments: KeyCode, Modifier. - - void OnKeyPress(int KeyCode, int Modifier) override; - - void OnTextInput(std::string_view inputText) override; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the text in the textpanel. -// Arguments: Text. - - void SetText(const std::string &Text); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetRightText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the extra text which appears right-justified in the textpanel. -// Arguments: Text. - - void SetRightText(const std::string &rightText); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the text in the textpanel. -// Arguments: None. - - std::string GetText() const { return m_Text; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRightText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the extra text which appears right-justified in the textpanel. -// Arguments: None. - - std::string GetRightText() const { return m_RightText; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSelection -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the start and end indexes of the selection text. -// Arguments: Start, End. - - void SetSelection(int Start, int End); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelectionStart -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the start index of the selection. -// Arguments: None. -// Returns: Index of the start of the selection. -1 if no selection - - int GetSelectionStart() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelectionEnd -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the end index of the selection. -// Arguments: None. -// Returns: Index of the end of the selection. -1 if no selection - - int GetSelectionEnd() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearSelection -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the selection. Does NOT remove the selection text though. -// Arguments: None. - - void ClearSelection(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSelectionText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the selection text. -// Arguments: None. - - std::string GetSelectionText() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveSelectionText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes the characters in the selection. -// Arguments: None. - - void RemoveSelectionText(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCursorPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where the cursor should be. This will clear any selection. -// Arguments: The index of the new cursor position. - - void SetCursorPos(int cursorPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLocked -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the locked state on the textbox. -// Arguments: Locked. - - void SetLocked(bool Locked); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLocked -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the locked state on the textbox. -// Arguments: None. - - bool GetLocked() const; - /// - /// Sets this text panel to accept numeric symbols only. + /// A text panel class. /// - /// Whether to accept numeric symbols only or not. - void SetNumericOnly(bool numericOnly) { m_NumericOnly = numericOnly; } + class GUITextPanel : public GUIPanel { + + public: + // Text panel signals + enum { + Clicked = 0, + MouseDown, + Changed, + Enter + } Signals; - /// - /// Sets this text panel's maximum numeric value when in numeric only mode. - /// - /// The maximum numeric value. 0 means no maximum value. - void SetMaxNumericValue(int maxValue) { m_MaxNumericValue = maxValue; } + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUITextPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUITextPanel object in + // system memory. + // Arguments: GUIManager. + + explicit GUITextPanel(GUIManager* Manager); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GUITextPanel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GUITextPanel object in + // system memory. + // Arguments: None. - /// - /// Sets the maximum length of the text this text panel can contain. - /// - /// The maximum length of the text this text panel can contain. - void SetMaxTextLength(int maxLength) { m_MaxTextLength = maxLength; } - - -private: - - unsigned long m_FontSelectColor; - - std::string m_Text; - std::string m_RightText; // Appears right-justified in the text field - bool m_Focus; - bool m_Locked; - - // The distance from the side and top of the text box, to the side and top of the first line of text - int m_WidthMargin; - int m_HeightMargin; - - // Cursor - int m_CursorX; - int m_CursorY; - int m_CursorIndex; - unsigned long m_CursorColor; - Timer m_BlinkTimer; - - int m_StartIndex; - - // Selection - bool m_GotSelection; - int m_StartSelection; - int m_EndSelection; - unsigned long m_SelectedColorIndex; - int m_SelectionX; - int m_SelectionWidth; - - int m_MaxTextLength; //!< The maximum length of the text this text panel can contain. - bool m_NumericOnly; //!< Whether this text panel only accepts numeric symbols. - int m_MaxNumericValue; //!< The maximum numeric value when in numeric only mode. 0 means no maximum value. - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateText -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the cursor and start positions. -// Arguments: Typing, Increment. - - void UpdateText(bool Typing = false, bool DoIncrement = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DoSelection -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Update the selection. -// Arguments: Start, End. - - void DoSelection(int Start, int End); - - /// - /// Gets the index of the start of the next contiguous group of letters or special characters in the given string, or the end of the string if there is none. - /// Generally used to deal with ctrl + arrows style behavior. - /// - /// A string_view of the string to look for the next word in. - /// The index in the string to start looking from. - /// The index of the start of the next contiguous group of letters or special characters in the given string, or the end of the string if there is none. - int GetStartOfNextCharacterGroup(const std::string_view &stringToCheck, int currentIndex) const; - - /// - /// Gets the index of the start of the previous contiguous group of letters or special characters in the given string, or the end of the string if there is none. - /// Generally used to deal with ctrl + arrows style behavior. - /// - /// A string_view of the string to look for the next word in. - /// The index in the string to start looking from. - /// The index of the start of the previous contiguous group of letters or special characters in the given string, or the end of the string if there is none. - int GetStartOfPreviousCharacterGroup(const std::string_view &stringToCheck, int currentIndex) const; -}; -}; + GUITextPanel(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Create the panel. + // Arguments: Position, Size. + + void Create(int X, int Y, int Width, int Height); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeSkin + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the skin has been changed. + // Arguments: New skin pointer. + + void ChangeSkin(GUISkin* Skin); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the panel + // Arguments: Screen class + + void Draw(GUIScreen* Screen) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseDown + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes down on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseDown(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseUp + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse goes up on the panel + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseUp(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnMouseMove + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when the mouse moves (over the panel, or when captured). + // Arguments: Mouse Position, Mouse Buttons, Modifier. + + void OnMouseMove(int X, int Y, int Buttons, int Modifier) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnKeyPress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Called when a key is pressed (OnDown & repeating). + // Arguments: KeyCode, Modifier. + + void OnKeyPress(int KeyCode, int Modifier) override; + + void OnTextInput(std::string_view inputText) override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the text in the textpanel. + // Arguments: Text. + + void SetText(const std::string& Text); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetRightText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the extra text which appears right-justified in the textpanel. + // Arguments: Text. + + void SetRightText(const std::string& rightText); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the text in the textpanel. + // Arguments: None. + + std::string GetText() const { return m_Text; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRightText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the extra text which appears right-justified in the textpanel. + // Arguments: None. + + std::string GetRightText() const { return m_RightText; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSelection + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the start and end indexes of the selection text. + // Arguments: Start, End. + + void SetSelection(int Start, int End); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelectionStart + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the start index of the selection. + // Arguments: None. + // Returns: Index of the start of the selection. -1 if no selection + + int GetSelectionStart() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelectionEnd + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the end index of the selection. + // Arguments: None. + // Returns: Index of the end of the selection. -1 if no selection + + int GetSelectionEnd() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearSelection + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the selection. Does NOT remove the selection text though. + // Arguments: None. + + void ClearSelection(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSelectionText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the selection text. + // Arguments: None. + + std::string GetSelectionText() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveSelectionText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes the characters in the selection. + // Arguments: None. + + void RemoveSelectionText(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCursorPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where the cursor should be. This will clear any selection. + // Arguments: The index of the new cursor position. + + void SetCursorPos(int cursorPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLocked + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the locked state on the textbox. + // Arguments: Locked. + + void SetLocked(bool Locked); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLocked + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the locked state on the textbox. + // Arguments: None. + + bool GetLocked() const; + + /// + /// Sets this text panel to accept numeric symbols only. + /// + /// Whether to accept numeric symbols only or not. + void SetNumericOnly(bool numericOnly) { m_NumericOnly = numericOnly; } + + /// + /// Sets this text panel's maximum numeric value when in numeric only mode. + /// + /// The maximum numeric value. 0 means no maximum value. + void SetMaxNumericValue(int maxValue) { m_MaxNumericValue = maxValue; } + + /// + /// Sets the maximum length of the text this text panel can contain. + /// + /// The maximum length of the text this text panel can contain. + void SetMaxTextLength(int maxLength) { m_MaxTextLength = maxLength; } + + private: + unsigned long m_FontSelectColor; + + std::string m_Text; + std::string m_RightText; // Appears right-justified in the text field + bool m_Focus; + bool m_Locked; + + // The distance from the side and top of the text box, to the side and top of the first line of text + int m_WidthMargin; + int m_HeightMargin; + + // Cursor + int m_CursorX; + int m_CursorY; + int m_CursorIndex; + unsigned long m_CursorColor; + Timer m_BlinkTimer; + + int m_StartIndex; + + // Selection + bool m_GotSelection; + int m_StartSelection; + int m_EndSelection; + unsigned long m_SelectedColorIndex; + int m_SelectionX; + int m_SelectionWidth; + + int m_MaxTextLength; //!< The maximum length of the text this text panel can contain. + bool m_NumericOnly; //!< Whether this text panel only accepts numeric symbols. + int m_MaxNumericValue; //!< The maximum numeric value when in numeric only mode. 0 means no maximum value. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateText + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the cursor and start positions. + // Arguments: Typing, Increment. + + void UpdateText(bool Typing = false, bool DoIncrement = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DoSelection + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Update the selection. + // Arguments: Start, End. + + void DoSelection(int Start, int End); + + /// + /// Gets the index of the start of the next contiguous group of letters or special characters in the given string, or the end of the string if there is none. + /// Generally used to deal with ctrl + arrows style behavior. + /// + /// A string_view of the string to look for the next word in. + /// The index in the string to start looking from. + /// The index of the start of the next contiguous group of letters or special characters in the given string, or the end of the string if there is none. + int GetStartOfNextCharacterGroup(const std::string_view& stringToCheck, int currentIndex) const; + + /// + /// Gets the index of the start of the previous contiguous group of letters or special characters in the given string, or the end of the string if there is none. + /// Generally used to deal with ctrl + arrows style behavior. + /// + /// A string_view of the string to look for the next word in. + /// The index in the string to start looking from. + /// The index of the start of the previous contiguous group of letters or special characters in the given string, or the end of the string if there is none. + int GetStartOfPreviousCharacterGroup(const std::string_view& stringToCheck, int currentIndex) const; + }; +}; // namespace RTE #endif diff --git a/Source/GUI/GUIUtil.cpp b/Source/GUI/GUIUtil.cpp index ba0a38e86..1a5785746 100644 --- a/Source/GUI/GUIUtil.cpp +++ b/Source/GUI/GUIUtil.cpp @@ -4,10 +4,10 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - char * GUIUtil::TrimString(char *String) { - char *ptr = String; + char* GUIUtil::TrimString(char* String) { + char* ptr = String; // Find the first non-space character while (*ptr) { if (*ptr != ' ') { @@ -25,9 +25,9 @@ namespace RTE { return ptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool GUIUtil::GetClipboardText(std::string *text) { + bool GUIUtil::GetClipboardText(std::string* text) { if (SDL_HasClipboardText()) { *text = SDL_GetClipboardText(); return true; @@ -35,10 +35,10 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool GUIUtil::SetClipboardText(const std::string &text) { + bool GUIUtil::SetClipboardText(const std::string& text) { int result = SDL_SetClipboardText(text.c_str()); return result == 0; } -} +} // namespace RTE diff --git a/Source/GUI/GUIUtil.h b/Source/GUI/GUIUtil.h index c5f510649..b953f7061 100644 --- a/Source/GUI/GUIUtil.h +++ b/Source/GUI/GUIUtil.h @@ -9,27 +9,26 @@ namespace RTE { class GUIUtil { public: - /// /// Removes the preceding and ending spaces from a c type string. /// /// String to trim. /// Trimmed string. - static char * TrimString(char *String); + static char* TrimString(char* String); /// /// Gets the text from the clipboard. /// /// Pointer to string receiving the text. /// True if text was available in the clipboard. - static bool GetClipboardText(std::string *text); + static bool GetClipboardText(std::string* text); /// /// Sets the text in the clipboard. /// /// String to put into the clipboard. /// True if text was added to the clipboard. - static bool SetClipboardText(const std::string &text); + static bool SetClipboardText(const std::string& text); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/GUI/GUIWriter.cpp b/Source/GUI/GUIWriter.cpp index ef3f2d2d5..37c074e74 100644 --- a/Source/GUI/GUIWriter.cpp +++ b/Source/GUI/GUIWriter.cpp @@ -2,7 +2,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIWriter::Clear() { m_Stream = nullptr; @@ -12,15 +12,15 @@ namespace RTE { m_IndentCount = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// GUIWriter::GUIWriter() { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GUIWriter::Create(const std::string &fileName, bool append) { + int GUIWriter::Create(const std::string& fileName, bool append) { m_FilePath = fileName; // Extract filename and folder path @@ -36,183 +36,188 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIWriter::GetFilePath() const { return m_FilePath; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIWriter::GetFileName() const { return m_FileName; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string GUIWriter::GetFolderPath() const { return m_FolderPath; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void GUIWriter::ObjectStart(const std::string &className) { - *m_Stream << className; ++m_IndentCount; + void GUIWriter::ObjectStart(const std::string& className) { + *m_Stream << className; + ++m_IndentCount; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIWriter::ObjectEnd() { --m_IndentCount; - if (m_IndentCount == 0) { NewLine(false, 2); } + if (m_IndentCount == 0) { + NewLine(false, 2); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIWriter::NewLine(bool toIndent, int lineCount) const { for (int lines = 0; lines < lineCount; ++lines) { *m_Stream << "\n"; - if (toIndent) { *m_Stream << std::string(m_IndentCount, '\t'); } + if (toIndent) { + *m_Stream << std::string(m_IndentCount, '\t'); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void GUIWriter::NewLineString(const std::string &textString, bool toIndent) const { + void GUIWriter::NewLineString(const std::string& textString, bool toIndent) const { NewLine(toIndent); *m_Stream << textString; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIWriter::NewDivider(bool toIndent, int dividerLength) const { NewLine(toIndent); *m_Stream << std::string(dividerLength, '/'); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void GUIWriter::NewProperty(const std::string &propName) const { + void GUIWriter::NewProperty(const std::string& propName) const { NewLine(); *m_Stream << propName + " = "; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool GUIWriter::WriterOK() const { return m_Stream.get() && !m_Stream->fail() && m_Stream->is_open(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIWriter::EndWrite() const { m_Stream->flush(); m_Stream->close(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const bool &var) { + GUIWriter& GUIWriter::operator<<(const bool& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const char &var) { + GUIWriter& GUIWriter::operator<<(const char& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const unsigned char &var) { + GUIWriter& GUIWriter::operator<<(const unsigned char& var) { int temp = var; *m_Stream << temp; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const short &var) { + GUIWriter& GUIWriter::operator<<(const short& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const unsigned short &var) { + GUIWriter& GUIWriter::operator<<(const unsigned short& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const int &var) { + GUIWriter& GUIWriter::operator<<(const int& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const unsigned int &var) { + GUIWriter& GUIWriter::operator<<(const unsigned int& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const long &var) { + GUIWriter& GUIWriter::operator<<(const long& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const long long &var) { + GUIWriter& GUIWriter::operator<<(const long long& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const unsigned long &var) { + GUIWriter& GUIWriter::operator<<(const unsigned long& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const unsigned long long &var) { + GUIWriter& GUIWriter::operator<<(const unsigned long long& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const float &var) { + GUIWriter& GUIWriter::operator<<(const float& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const double &var) { + GUIWriter& GUIWriter::operator<<(const double& var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const char *var) { + GUIWriter& GUIWriter::operator<<(const char* var) { *m_Stream << var; return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIWriter & GUIWriter::operator<<(const std::string &var) { + GUIWriter& GUIWriter::operator<<(const std::string& var) { *m_Stream << var; return *this; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/GUI/GUIWriter.h b/Source/GUI/GUIWriter.h index 522e1022a..2f01ac5c9 100644 --- a/Source/GUI/GUIWriter.h +++ b/Source/GUI/GUIWriter.h @@ -9,7 +9,6 @@ namespace RTE { class GUIWriter { public: - #pragma region Creation /// /// Constructor method used to instantiate a GUIWriter object in system memory. Create() should be called before using the object. @@ -22,7 +21,7 @@ namespace RTE { /// Path to the file to open for writing. If the directory doesn't exist the stream will fail to open. /// Whether to append to the file if it exists, or to overwrite it. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const std::string &fileName, bool append = false); + int Create(const std::string& fileName, bool append = false); #pragma endregion #pragma region Getters @@ -50,7 +49,7 @@ namespace RTE { /// Used to specify the start of an object to be written. /// /// The class name of the object about to be written. - void ObjectStart(const std::string &className); + void ObjectStart(const std::string& className); /// /// Used to specify the end of an object that has just been written. @@ -69,7 +68,7 @@ namespace RTE { /// /// The text string to write to the new line. /// Whether to indent the new line or not. - void NewLineString(const std::string &textString, bool toIndent = true) const; + void NewLineString(const std::string& textString, bool toIndent = true) const; /// /// Creates a new line and fills it with slashes to create a divider line for INI. @@ -82,7 +81,7 @@ namespace RTE { /// Creates a new line and writes the name of the property in preparation to writing it's value. /// /// The name of the property to be written. - void NewProperty(const std::string &propName) const; + void NewProperty(const std::string& propName) const; #pragma endregion #pragma region Writer Status @@ -104,25 +103,24 @@ namespace RTE { /// /// A reference to the variable that will be written to the ostream. /// A GUIWriter reference for further use in an expression. - GUIWriter & operator<<(const bool &var); - GUIWriter & operator<<(const char &var); - GUIWriter & operator<<(const unsigned char &var); - GUIWriter & operator<<(const short &var); - GUIWriter & operator<<(const unsigned short &var); - GUIWriter & operator<<(const int &var); - GUIWriter & operator<<(const unsigned int &var); - GUIWriter & operator<<(const long &var); - GUIWriter & operator<<(const long long &var); - GUIWriter & operator<<(const unsigned long &var); - GUIWriter & operator<<(const unsigned long long &var); - GUIWriter & operator<<(const float &var); - GUIWriter & operator<<(const double &var); - GUIWriter & operator<<(const char *var); - GUIWriter & operator<<(const std::string &var); + GUIWriter& operator<<(const bool& var); + GUIWriter& operator<<(const char& var); + GUIWriter& operator<<(const unsigned char& var); + GUIWriter& operator<<(const short& var); + GUIWriter& operator<<(const unsigned short& var); + GUIWriter& operator<<(const int& var); + GUIWriter& operator<<(const unsigned int& var); + GUIWriter& operator<<(const long& var); + GUIWriter& operator<<(const long long& var); + GUIWriter& operator<<(const unsigned long& var); + GUIWriter& operator<<(const unsigned long long& var); + GUIWriter& operator<<(const float& var); + GUIWriter& operator<<(const double& var); + GUIWriter& operator<<(const char* var); + GUIWriter& operator<<(const std::string& var); #pragma endregion protected: - std::unique_ptr m_Stream; //!< Stream used for writing to files. std::string m_FilePath; //!< Currently used stream's filepath. std::string m_FolderPath; //!< Only the path to the folder that we are writing a file in, excluding the filename. @@ -130,15 +128,14 @@ namespace RTE { int m_IndentCount; //!< Indentation counter. private: - /// /// Clears all the member variables of this GUIWriter, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - GUIWriter(const GUIWriter &reference) = delete; - GUIWriter & operator=(const GUIWriter &rhs) = delete; + GUIWriter(const GUIWriter& reference) = delete; + GUIWriter& operator=(const GUIWriter& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/GUI/Wrappers/AllegroBitmap.cpp b/Source/GUI/Wrappers/AllegroBitmap.cpp index e2b779057..925e10bcc 100644 --- a/Source/GUI/Wrappers/AllegroBitmap.cpp +++ b/Source/GUI/Wrappers/AllegroBitmap.cpp @@ -4,7 +4,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AllegroBitmap::Clear() { m_Bitmap = nullptr; @@ -12,9 +12,9 @@ namespace RTE { m_SelfCreated = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroBitmap::Create(const std::string &fileName) { + void AllegroBitmap::Create(const std::string& fileName) { m_BitmapFile.Create(fileName.c_str()); m_Bitmap = m_BitmapFile.GetAsBitmap(); @@ -23,7 +23,7 @@ namespace RTE { m_SelfCreated = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AllegroBitmap::Create(int width, int height, int colorDepth) { m_BitmapFile.Reset(); @@ -35,47 +35,49 @@ namespace RTE { m_SelfCreated = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AllegroBitmap::Destroy() { - if (m_SelfCreated && m_Bitmap) { destroy_bitmap(m_Bitmap); } + if (m_SelfCreated && m_Bitmap) { + destroy_bitmap(m_Bitmap); + } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int AllegroBitmap::GetWidth() const { return m_Bitmap ? m_Bitmap->w : 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int AllegroBitmap::GetHeight() const { return m_Bitmap ? m_Bitmap->h : 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int AllegroBitmap::GetColorDepth() const { return m_Bitmap ? bitmap_color_depth(m_Bitmap) : 8; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// unsigned long AllegroBitmap::GetPixel(int posX, int posY) const { return m_Bitmap ? getpixel(m_Bitmap, posX, posY) : 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AllegroBitmap::SetPixel(int posX, int posY, unsigned long pixelColor) { RTEAssert(m_Bitmap, "Trying to set a pixel on a null bitmap!"); putpixel(m_Bitmap, posX, posY, pixelColor); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroBitmap::GetClipRect(GUIRect *clippingRect) const { + void AllegroBitmap::GetClipRect(GUIRect* clippingRect) const { if (m_Bitmap && clippingRect) { int x1; int y1; @@ -89,9 +91,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroBitmap::SetClipRect(GUIRect *clippingRect) { + void AllegroBitmap::SetClipRect(GUIRect* clippingRect) { if (!m_Bitmap) { return; } @@ -104,9 +106,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroBitmap::AddClipRect(GUIRect *clippingRect) { + void AllegroBitmap::AddClipRect(GUIRect* clippingRect) { if (!m_Bitmap) { return; } @@ -119,48 +121,48 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroBitmap::Draw(GUIBitmap *destBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) { + void AllegroBitmap::Draw(GUIBitmap* destBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) { if (!m_Bitmap) { return; } - RTEAssert(destBitmap && dynamic_cast(destBitmap)->GetBitmap(), "Null destination bitmap passed when trying to draw AllegroBitmap"); + RTEAssert(destBitmap && dynamic_cast(destBitmap)->GetBitmap(), "Null destination bitmap passed when trying to draw AllegroBitmap"); if (srcPosAndSizeRect) { - blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), srcPosAndSizeRect->left, srcPosAndSizeRect->top, destX, destY, srcPosAndSizeRect->right - srcPosAndSizeRect->left, srcPosAndSizeRect->bottom - srcPosAndSizeRect->top); + blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), srcPosAndSizeRect->left, srcPosAndSizeRect->top, destX, destY, srcPosAndSizeRect->right - srcPosAndSizeRect->left, srcPosAndSizeRect->bottom - srcPosAndSizeRect->top); } else { - blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), 0, 0, destX, destY, destBitmap->GetWidth(), destBitmap->GetHeight()); + blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), 0, 0, destX, destY, destBitmap->GetWidth(), destBitmap->GetHeight()); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroBitmap::DrawTrans(GUIBitmap *destBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) { + void AllegroBitmap::DrawTrans(GUIBitmap* destBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) { if (!m_Bitmap) { return; } - RTEAssert(destBitmap && dynamic_cast(destBitmap)->GetBitmap(), "Null destination bitmap passed when trying to draw AllegroBitmap"); + RTEAssert(destBitmap && dynamic_cast(destBitmap)->GetBitmap(), "Null destination bitmap passed when trying to draw AllegroBitmap"); if (srcPosAndSizeRect) { - masked_blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), srcPosAndSizeRect->left, srcPosAndSizeRect->top, destX, destY, srcPosAndSizeRect->right - srcPosAndSizeRect->left, srcPosAndSizeRect->bottom - srcPosAndSizeRect->top); + masked_blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), srcPosAndSizeRect->left, srcPosAndSizeRect->top, destX, destY, srcPosAndSizeRect->right - srcPosAndSizeRect->left, srcPosAndSizeRect->bottom - srcPosAndSizeRect->top); } else { - masked_blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), 0, 0, destX, destY, destBitmap->GetWidth(), destBitmap->GetHeight()); + masked_blit(m_Bitmap, dynamic_cast(destBitmap)->GetBitmap(), 0, 0, destX, destY, destBitmap->GetWidth(), destBitmap->GetHeight()); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroBitmap::DrawTransScaled(GUIBitmap *destBitmap, int destX, int destY, int width, int height) { + void AllegroBitmap::DrawTransScaled(GUIBitmap* destBitmap, int destX, int destY, int width, int height) { if (!m_Bitmap) { return; } - RTEAssert(destBitmap && dynamic_cast(destBitmap)->GetBitmap(), "Null destination bitmap passed when trying to draw AllegroBitmap"); + RTEAssert(destBitmap && dynamic_cast(destBitmap)->GetBitmap(), "Null destination bitmap passed when trying to draw AllegroBitmap"); - stretch_sprite(dynamic_cast(destBitmap)->GetBitmap(), m_Bitmap, destX, destY, width, height); + stretch_sprite(dynamic_cast(destBitmap)->GetBitmap(), m_Bitmap, destX, destY, width, height); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AllegroBitmap::DrawLine(int x1, int y1, int x2, int y2, unsigned long color) { if (!m_Bitmap) { @@ -169,7 +171,7 @@ namespace RTE { line(m_Bitmap, x1, y1, x2, y2, color); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AllegroBitmap::DrawRectangle(int posX, int posY, int width, int height, unsigned long color, bool filled) { if (!m_Bitmap) { @@ -181,4 +183,4 @@ namespace RTE { rect(m_Bitmap, posX, posY, posX + width - 1, posY + height - 1, color); } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/GUI/Wrappers/AllegroBitmap.h b/Source/GUI/Wrappers/AllegroBitmap.h index aaa4f5c41..386bd2fe8 100644 --- a/Source/GUI/Wrappers/AllegroBitmap.h +++ b/Source/GUI/Wrappers/AllegroBitmap.h @@ -12,7 +12,6 @@ namespace RTE { class AllegroBitmap : public GUIBitmap { public: - #pragma region Creation /// /// Constructor method used to instantiate an AllegroBitmap object in system memory. @@ -23,13 +22,16 @@ namespace RTE { /// Constructor method used to instantiate an AllegroBitmap object in system memory and make it ready for use. /// /// The underlaying BITMAP of this AllegroBitmap. Ownership is NOT transferred! - explicit AllegroBitmap(BITMAP *bitmap) { Clear(); m_Bitmap = bitmap; } + explicit AllegroBitmap(BITMAP* bitmap) { + Clear(); + m_Bitmap = bitmap; + } /// /// Creates an AllegroBitmap from a file. /// /// File name to get the underlaying BITMAP from. Ownership is NOT transferred! - void Create(const std::string &fileName); + void Create(const std::string& fileName); /// /// Creates an empty BITMAP that is owned by this AllegroBitmap. @@ -63,13 +65,16 @@ namespace RTE { /// Gets the underlying BITMAP of this AllegroBitmap. /// /// The underlying BITMAP of this AllegroBitmap. - BITMAP * GetBitmap() const override { return m_Bitmap; } + BITMAP* GetBitmap() const override { return m_Bitmap; } /// /// Sets the underlying BITMAP for this AllegroBitmap. Ownership is NOT transferred. /// /// A pointer to the new BITMAP for this AllegroBitmap. - void SetBitmap(BITMAP *newBitmap) override { Destroy(); m_Bitmap = newBitmap; } + void SetBitmap(BITMAP* newBitmap) override { + Destroy(); + m_Bitmap = newBitmap; + } /// /// Gets the width of the bitmap. @@ -111,19 +116,19 @@ namespace RTE { /// Gets the clipping rectangle of the bitmap. /// /// Pointer to a GUIRect to fill out. - void GetClipRect(GUIRect *clippingRect) const override; + void GetClipRect(GUIRect* clippingRect) const override; /// /// Sets the clipping rectangle of the bitmap. /// /// Pointer to a GUIRect to use as the clipping rectangle, or nullptr for no clipping. - void SetClipRect(GUIRect *clippingRect) override; + void SetClipRect(GUIRect* clippingRect) override; /// /// Sets the clipping rectangle of the bitmap as the intersection of its current clipping rectangle and the passed-in rectangle. /// /// Pointer to a GUIRect to add to the existing clipping rectangle. - void AddClipRect(GUIRect *clippingRect) override; + void AddClipRect(GUIRect* clippingRect) override; #pragma endregion #pragma region Drawing @@ -134,7 +139,7 @@ namespace RTE { /// Destination X position. /// Destination Y position. /// Source bitmap position and size rectangle. - void Draw(GUIBitmap *destBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) override; + void Draw(GUIBitmap* destBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) override; /// /// Draw a section of this bitmap onto another bitmap ignoring color-keyed pixels. @@ -143,7 +148,7 @@ namespace RTE { /// Destination X position. /// Destination Y position. /// Source bitmap position and size rectangle. - void DrawTrans(GUIBitmap *destBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) override; + void DrawTrans(GUIBitmap* destBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) override; /// /// Draw this bitmap scaled onto another bitmap ignoring color-keyed pixels. @@ -153,7 +158,7 @@ namespace RTE { /// Destination Y position. /// Target width of the bitmap. /// Target height of the bitmap. - void DrawTransScaled(GUIBitmap *destBitmap, int destX, int destY, int width, int height) override; + void DrawTransScaled(GUIBitmap* destBitmap, int destX, int destY, int width, int height) override; #pragma endregion #pragma region Primitive Drawing @@ -180,8 +185,7 @@ namespace RTE { #pragma endregion private: - - BITMAP *m_Bitmap; //!< The underlaying BITMAP. + BITMAP* m_Bitmap; //!< The underlaying BITMAP. ContentFile m_BitmapFile; //!< The ContentFile the underlaying BITMAP was created from, if created from a file. bool m_SelfCreated; //!< Whether the underlaying BITMAP was created by this and is owned. @@ -191,7 +195,7 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - AllegroBitmap & operator=(const AllegroBitmap &rhs) = delete; + AllegroBitmap& operator=(const AllegroBitmap& rhs) = delete; }; -}; -#endif \ No newline at end of file +}; // namespace RTE +#endif diff --git a/Source/GUI/Wrappers/AllegroScreen.cpp b/Source/GUI/Wrappers/AllegroScreen.cpp index 842d4a5c4..f6a3bb029 100644 --- a/Source/GUI/Wrappers/AllegroScreen.cpp +++ b/Source/GUI/Wrappers/AllegroScreen.cpp @@ -5,9 +5,9 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIBitmap * AllegroScreen::CreateBitmap(const std::string &fileName) { + GUIBitmap* AllegroScreen::CreateBitmap(const std::string& fileName) { std::unique_ptr newAllegroBitmap; newAllegroBitmap.reset(new AllegroBitmap()); @@ -15,9 +15,9 @@ namespace RTE { return newAllegroBitmap.release(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIBitmap * AllegroScreen::CreateBitmap(int width, int height) { + GUIBitmap* AllegroScreen::CreateBitmap(int width, int height) { std::unique_ptr newAllegroBitmap; newAllegroBitmap.reset(new AllegroBitmap()); @@ -25,13 +25,13 @@ namespace RTE { return newAllegroBitmap.release(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroScreen::DrawBitmap(GUIBitmap *guiBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) { + void AllegroScreen::DrawBitmap(GUIBitmap* guiBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) { if (!guiBitmap) { return; } - if (BITMAP *sourceBitmap = dynamic_cast(guiBitmap)->GetBitmap()) { + if (BITMAP* sourceBitmap = dynamic_cast(guiBitmap)->GetBitmap()) { if (srcPosAndSizeRect) { blit(sourceBitmap, m_BackBufferBitmap->GetBitmap(), srcPosAndSizeRect->left, srcPosAndSizeRect->top, destX, destY, srcPosAndSizeRect->right - srcPosAndSizeRect->left, srcPosAndSizeRect->bottom - srcPosAndSizeRect->top); } else { @@ -40,13 +40,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AllegroScreen::DrawBitmapTrans(GUIBitmap *guiBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) { + void AllegroScreen::DrawBitmapTrans(GUIBitmap* guiBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) { if (!guiBitmap) { return; } - if (BITMAP *sourceBitmap = dynamic_cast(guiBitmap)->GetBitmap()) { + if (BITMAP* sourceBitmap = dynamic_cast(guiBitmap)->GetBitmap()) { if (srcPosAndSizeRect) { masked_blit(sourceBitmap, m_BackBufferBitmap->GetBitmap(), srcPosAndSizeRect->left, srcPosAndSizeRect->top, destX, destY, srcPosAndSizeRect->right - srcPosAndSizeRect->left, srcPosAndSizeRect->bottom - srcPosAndSizeRect->top); } else { @@ -55,14 +55,18 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// unsigned long AllegroScreen::ConvertColor(unsigned long color, int targetColorDepth) { - if (targetColorDepth == 0) { targetColorDepth = get_color_depth(); } + if (targetColorDepth == 0) { + targetColorDepth = get_color_depth(); + } if (targetColorDepth == 8) { // Isn't indexed, don't convert - if (!(color >= 0 && color <= 255)) { color = makecol8(getr32(color), getg32(color), getb32(color)); } + if (!(color >= 0 && color <= 255)) { + color = makecol8(getr32(color), getg32(color), getb32(color)); + } } else { if (color >= 0 && color <= 255) { RGB rgbEntry; @@ -73,4 +77,4 @@ namespace RTE { } return color; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/GUI/Wrappers/AllegroScreen.h b/Source/GUI/Wrappers/AllegroScreen.h index 21729c5d2..64cac1b21 100644 --- a/Source/GUI/Wrappers/AllegroScreen.h +++ b/Source/GUI/Wrappers/AllegroScreen.h @@ -11,20 +11,19 @@ namespace RTE { class AllegroScreen : public GUIScreen { public: - #pragma region Creation /// /// Constructor method used to instantiate an AllegroScreen object in system memory and make it ready for use. /// /// A bitmap that represents the back buffer. Ownership is NOT transferred! - explicit AllegroScreen(BITMAP *backBuffer) { m_BackBufferBitmap = std::make_unique(backBuffer); } + explicit AllegroScreen(BITMAP* backBuffer) { m_BackBufferBitmap = std::make_unique(backBuffer); } /// /// Creates a bitmap from a file. /// /// File name to create bitmap from. /// Pointer to the created bitmap. Ownership IS transferred! - GUIBitmap * CreateBitmap(const std::string &fileName) override; + GUIBitmap* CreateBitmap(const std::string& fileName) override; /// /// Creates an empty bitmap. @@ -32,7 +31,7 @@ namespace RTE { /// Bitmap width. /// Bitmap height. /// Pointer to the created bitmap. Ownership IS transferred! - GUIBitmap * CreateBitmap(int width, int height) override; + GUIBitmap* CreateBitmap(int width, int height) override; #pragma endregion #pragma region Destruction @@ -52,7 +51,7 @@ namespace RTE { /// Gets the bitmap representing the screen. /// /// Pointer to the bitmap representing the screen. Ownership is NOT transferred! - GUIBitmap * GetBitmap() const override { return m_BackBufferBitmap.get(); } + GUIBitmap* GetBitmap() const override { return m_BackBufferBitmap.get(); } #pragma endregion #pragma region Drawing @@ -63,7 +62,7 @@ namespace RTE { /// Destination X position /// Destination Y position /// Source bitmap position and size rectangle. - void DrawBitmap(GUIBitmap *guiBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) override; + void DrawBitmap(GUIBitmap* guiBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) override; /// /// Draws a bitmap onto the back buffer ignoring color-keyed pixels. @@ -72,7 +71,7 @@ namespace RTE { /// Destination X position /// Destination Y position /// Source bitmap position and size rectangle. - void DrawBitmapTrans(GUIBitmap *guiBitmap, int destX, int destY, GUIRect *srcPosAndSizeRect) override; + void DrawBitmapTrans(GUIBitmap* guiBitmap, int destX, int destY, GUIRect* srcPosAndSizeRect) override; #pragma endregion #pragma region Virtual Override Methods @@ -86,11 +85,10 @@ namespace RTE { #pragma endregion private: - std::unique_ptr m_BackBufferBitmap; //!< The AllegroBitmap that makes this AllegroScreen. // Disallow the use of some implicit methods. - AllegroScreen & operator=(const AllegroScreen &rhs) = delete; + AllegroScreen& operator=(const AllegroScreen& rhs) = delete; }; -}; -#endif \ No newline at end of file +}; // namespace RTE +#endif diff --git a/Source/GUI/Wrappers/GUIInputWrapper.cpp b/Source/GUI/Wrappers/GUIInputWrapper.cpp index 05675f7db..a4838e936 100644 --- a/Source/GUI/Wrappers/GUIInputWrapper.cpp +++ b/Source/GUI/Wrappers/GUIInputWrapper.cpp @@ -8,9 +8,10 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIInputWrapper::GUIInputWrapper(int whichPlayer, bool keyJoyMouseCursor) : GUIInput(whichPlayer, keyJoyMouseCursor) { + GUIInputWrapper::GUIInputWrapper(int whichPlayer, bool keyJoyMouseCursor) : + GUIInput(whichPlayer, keyJoyMouseCursor) { m_KeyTimer = std::make_unique(); m_CursorAccelTimer = std::make_unique(); @@ -20,11 +21,11 @@ namespace RTE { m_KeyHoldDuration.fill(-1); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIInputWrapper::ConvertKeyEvent(SDL_Scancode sdlKey, int guilibKey, float elapsedS) { int nKeys; - const Uint8 *sdlKeyState = SDL_GetKeyboardState(&nKeys); + const Uint8* sdlKeyState = SDL_GetKeyboardState(&nKeys); if (sdlKeyState[sdlKey]) { if (m_KeyHoldDuration[guilibKey] < 0) { m_KeyboardBuffer[guilibKey] = GUIInput::Pushed; @@ -46,7 +47,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIInputWrapper::Update() { float keyElapsedTime = static_cast(m_KeyTimer->GetElapsedRealTimeS()); @@ -56,7 +57,9 @@ namespace RTE { UpdateMouseInput(); // If joysticks and keyboard can control the mouse cursor too. - if (m_KeyJoyMouseCursor) { UpdateKeyJoyMouseInput(keyElapsedTime); } + if (m_KeyJoyMouseCursor) { + UpdateKeyJoyMouseInput(keyElapsedTime); + } // Update the mouse position of this GUIInput, based on the SDL mouse vars (which may have been altered by joystick or keyboard input). Vector mousePos = g_UInputMan.GetAbsoluteMousePosition(); @@ -64,7 +67,7 @@ namespace RTE { m_MouseY = static_cast(mousePos.GetY() / static_cast(g_WindowMan.GetResMultiplier())); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIInputWrapper::UpdateKeyboardInput(float keyElapsedTime) { // Clear the keyboard buffer, we need it to check for changes. @@ -100,13 +103,21 @@ namespace RTE { m_Modifier = GUIInput::ModNone; SDL_Keymod keyShifts = SDL_GetModState(); - if (keyShifts & KMOD_SHIFT) { m_Modifier |= GUIInput::ModShift; } - if (keyShifts & KMOD_ALT) { m_Modifier |= GUIInput::ModAlt; } - if (keyShifts & KMOD_CTRL) { m_Modifier |= GUIInput::ModCtrl; } - if (keyShifts & KMOD_GUI) { m_Modifier |= GUIInput::ModCommand; } + if (keyShifts & KMOD_SHIFT) { + m_Modifier |= GUIInput::ModShift; + } + if (keyShifts & KMOD_ALT) { + m_Modifier |= GUIInput::ModAlt; + } + if (keyShifts & KMOD_CTRL) { + m_Modifier |= GUIInput::ModCtrl; + } + if (keyShifts & KMOD_GUI) { + m_Modifier |= GUIInput::ModCommand; + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIInputWrapper::UpdateMouseInput() { int discard; @@ -209,15 +220,17 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void GUIInputWrapper::UpdateKeyJoyMouseInput(float keyElapsedTime) { - //TODO Try to not use magic numbers throughout this method. + // TODO Try to not use magic numbers throughout this method. float mouseDenominator = g_WindowMan.GetResMultiplier(); Vector joyKeyDirectional = g_UInputMan.GetMenuDirectional() * 5; // See how much to accelerate the joystick input based on how long the stick has been pushed around. - if (joyKeyDirectional.MagnitudeIsLessThan(0.95F)) { m_CursorAccelTimer->Reset(); } + if (joyKeyDirectional.MagnitudeIsLessThan(0.95F)) { + m_CursorAccelTimer->Reset(); + } float acceleration = 0.25F + static_cast(std::min(m_CursorAccelTimer->GetElapsedRealTimeS(), 0.5)) * 20.0F; Vector newMousePos = g_UInputMan.GetAbsoluteMousePosition(); @@ -248,4 +261,4 @@ namespace RTE { m_MouseButtonsEvents[0] = GUIInput::None; } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/GUI/Wrappers/GUIInputWrapper.h b/Source/GUI/Wrappers/GUIInputWrapper.h index 54af485d0..cc458d1c0 100644 --- a/Source/GUI/Wrappers/GUIInputWrapper.h +++ b/Source/GUI/Wrappers/GUIInputWrapper.h @@ -14,7 +14,6 @@ namespace RTE { class GUIInputWrapper : public GUIInput { public: - #pragma region Creation /// /// Constructor method used to instantiate a GUIInputWrapper object in system memory. @@ -39,7 +38,6 @@ namespace RTE { #pragma endregion private: - const float m_KeyRepeatDelay = 0.10F; //!< The delay a key needs to be held to be considered a repeating input. TODO: Make this use proper OS repeating instead of this shit... std::array m_KeyHoldDuration; //!< How long each key has been held in order to set repeating inputs. @@ -72,8 +70,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - GUIInputWrapper(const GUIInputWrapper &reference) = delete; - GUIInputWrapper & operator=(const GUIInputWrapper &rhs) = delete; + GUIInputWrapper(const GUIInputWrapper& reference) = delete; + GUIInputWrapper& operator=(const GUIInputWrapper& rhs) = delete; }; -}; +}; // namespace RTE #endif diff --git a/Source/GUI/meson.build b/Source/GUI/meson.build index a4d7071f0..2c164dd55 100644 --- a/Source/GUI/meson.build +++ b/Source/GUI/meson.build @@ -33,4 +33,4 @@ sources += files( 'GUITextPanel.cpp', 'GUIUtil.cpp', 'GUIWriter.cpp' -) \ No newline at end of file +) diff --git a/Source/Lua/LuaAdapterDefinitions.h b/Source/Lua/LuaAdapterDefinitions.h index 1b7d7526a..5d5690b4e 100644 --- a/Source/Lua/LuaAdapterDefinitions.h +++ b/Source/Lua/LuaAdapterDefinitions.h @@ -91,18 +91,18 @@ namespace RTE { #pragma region Entity Lua Adapter Macros struct LuaAdaptersEntityCreate { - /// - /// Convenience macro to generate preset clone-create adapter functions that will return the exact pre-cast types, so we don't have to do: myNewActor = ToActor(PresetMan:GetPreset("AHuman", "Soldier Light", "All")):Clone() - /// But can instead do: myNewActor = CreateActor("Soldier Light", "All"); - /// Or even: myNewActor = CreateActor("Soldier Light"); - /// Or for a randomly selected Preset within a group: myNewActor = RandomActor("Light Troops"); - /// - #define LuaEntityCreateFunctionsDeclarationsForType(TYPE) \ - static TYPE * Create##TYPE(std::string preseName, std::string moduleName); \ - static TYPE * Create##TYPE(std::string preset); \ - static TYPE * Random##TYPE(std::string groupName, int moduleSpaceID); \ - static TYPE * Random##TYPE(std::string groupName, std::string dataModuleName); \ - static TYPE * Random##TYPE(std::string groupName) +/// +/// Convenience macro to generate preset clone-create adapter functions that will return the exact pre-cast types, so we don't have to do: myNewActor = ToActor(PresetMan:GetPreset("AHuman", "Soldier Light", "All")):Clone() +/// But can instead do: myNewActor = CreateActor("Soldier Light", "All"); +/// Or even: myNewActor = CreateActor("Soldier Light"); +/// Or for a randomly selected Preset within a group: myNewActor = RandomActor("Light Troops"); +/// +#define LuaEntityCreateFunctionsDeclarationsForType(TYPE) \ + static TYPE* Create##TYPE(std::string preseName, std::string moduleName); \ + static TYPE* Create##TYPE(std::string preset); \ + static TYPE* Random##TYPE(std::string groupName, int moduleSpaceID); \ + static TYPE* Random##TYPE(std::string groupName, std::string dataModuleName); \ + static TYPE* Random##TYPE(std::string groupName) LuaEntityCreateFunctionsDeclarationsForType(SoundContainer); LuaEntityCreateFunctionsDeclarationsForType(Attachable); @@ -135,11 +135,11 @@ namespace RTE { }; struct LuaAdaptersEntityClone { - /// - /// Convenience macro to generate a preset clone adapter function for a type. - /// - #define LuaEntityCloneFunctionDeclarationForType(TYPE) \ - static TYPE * Clone##TYPE(const TYPE *thisEntity) +/// +/// Convenience macro to generate a preset clone adapter function for a type. +/// +#define LuaEntityCloneFunctionDeclarationForType(TYPE) \ + static TYPE* Clone##TYPE(const TYPE* thisEntity) LuaEntityCloneFunctionDeclarationForType(Entity); LuaEntityCloneFunctionDeclarationForType(SoundContainer); @@ -176,16 +176,16 @@ namespace RTE { }; struct LuaAdaptersEntityCast { - /// - /// Convenience macro to generate type casting adapter functions for a type. - /// - #define LuaEntityCastFunctionsDeclarationsForType(TYPE) \ - static TYPE * To##TYPE(Entity *entity); \ - static const TYPE * ToConst##TYPE(const Entity *entity); \ - static bool Is##TYPE(Entity *entity); \ - static LuabindObjectWrapper * ToLuabindObject##TYPE(Entity *entity, lua_State *luaState) +/// +/// Convenience macro to generate type casting adapter functions for a type. +/// +#define LuaEntityCastFunctionsDeclarationsForType(TYPE) \ + static TYPE* To##TYPE(Entity* entity); \ + static const TYPE* ToConst##TYPE(const Entity* entity); \ + static bool Is##TYPE(Entity* entity); \ + static LuabindObjectWrapper* ToLuabindObject##TYPE(Entity* entity, lua_State* luaState) - static std::unordered_map> s_EntityToLuabindObjectCastFunctions; //!< Map of preset names to casting methods for ensuring objects are downcast properly when passed into Lua. + static std::unordered_map> s_EntityToLuabindObjectCastFunctions; //!< Map of preset names to casting methods for ensuring objects are downcast properly when passed into Lua. LuaEntityCastFunctionsDeclarationsForType(Entity); LuaEntityCastFunctionsDeclarationsForType(SoundContainer); @@ -227,12 +227,12 @@ namespace RTE { }; struct LuaAdaptersPropertyOwnershipSafetyFaker { - /// - /// Special handling for passing ownership through properties. If you try to pass null to this normally, LuaJIT crashes. - /// This handling avoids that, and is a bit safer since there's no actual ownership transfer from Lua to C++. - /// - #define LuaPropertyOwnershipSafetyFakerFunctionDeclaration(OBJECTTYPE, PROPERTYTYPE, SETTERFUNCTION) \ - static void OBJECTTYPE##SETTERFUNCTION(OBJECTTYPE *luaSelfObject, PROPERTYTYPE *objectToSet) +/// +/// Special handling for passing ownership through properties. If you try to pass null to this normally, LuaJIT crashes. +/// This handling avoids that, and is a bit safer since there's no actual ownership transfer from Lua to C++. +/// +#define LuaPropertyOwnershipSafetyFakerFunctionDeclaration(OBJECTTYPE, PROPERTYTYPE, SETTERFUNCTION) \ + static void OBJECTTYPE##SETTERFUNCTION(OBJECTTYPE* luaSelfObject, PROPERTYTYPE* objectToSet) LuaPropertyOwnershipSafetyFakerFunctionDeclaration(MOSRotating, SoundContainer, SetGibSound); LuaPropertyOwnershipSafetyFakerFunctionDeclaration(Attachable, AEmitter, SetBreakWound); @@ -303,98 +303,98 @@ namespace RTE { #pragma region Entity Lua Adapters struct LuaAdaptersEntity { // TODO this is a temporary fix for lua PresetName setting causing scripts to have to rerun. It should be replaced with a DisplayName property someday. - static void SetPresetName(Entity *luaSelfObject, const std::string &presetName); + static void SetPresetName(Entity* luaSelfObject, const std::string& presetName); }; #pragma endregion #pragma region Scene Lua Adapters struct LuaAdaptersScene { - static int CalculatePath1(Scene *luaSelfObject, const Vector &start, const Vector &end, bool movePathToGround, float digStrength) { return CalculatePath2(luaSelfObject, start, end, movePathToGround, digStrength, Activity::Teams::NoTeam); } - static int CalculatePath2(Scene *luaSelfObject, const Vector &start, const Vector &end, bool movePathToGround, float digStrength, Activity::Teams team); + static int CalculatePath1(Scene* luaSelfObject, const Vector& start, const Vector& end, bool movePathToGround, float digStrength) { return CalculatePath2(luaSelfObject, start, end, movePathToGround, digStrength, Activity::Teams::NoTeam); } + static int CalculatePath2(Scene* luaSelfObject, const Vector& start, const Vector& end, bool movePathToGround, float digStrength, Activity::Teams team); - static void CalculatePathAsync1(Scene *luaSelfObject, const luabind::object &callback, const Vector &start, const Vector &end, bool movePathToGround, float digStrength) { return CalculatePathAsync2(luaSelfObject, callback, start, end, movePathToGround, digStrength, Activity::Teams::NoTeam); } - static void CalculatePathAsync2(Scene *luaSelfObject, const luabind::object &callback, const Vector &start, const Vector &end, bool movePathToGround, float digStrength, Activity::Teams team); + static void CalculatePathAsync1(Scene* luaSelfObject, const luabind::object& callback, const Vector& start, const Vector& end, bool movePathToGround, float digStrength) { return CalculatePathAsync2(luaSelfObject, callback, start, end, movePathToGround, digStrength, Activity::Teams::NoTeam); } + static void CalculatePathAsync2(Scene* luaSelfObject, const luabind::object& callback, const Vector& start, const Vector& end, bool movePathToGround, float digStrength, Activity::Teams team); }; #pragma endregion #pragma region Actor Lua Adapters struct LuaAdaptersActor { - static std::vector * GetSceneWaypoints(Actor *luaSelfObject); + static std::vector* GetSceneWaypoints(Actor* luaSelfObject); }; #pragma endregion #pragma region AHuman Lua Adapters struct LuaAdaptersAHuman { - static void ReloadFirearms(AHuman *luaSelfObject); + static void ReloadFirearms(AHuman* luaSelfObject); }; #pragma endregion #pragma region Attachable Lua Adapters struct LuaAdaptersAttachable { - static Attachable * RemoveFromParent1(Attachable *luaSelfObject); - static Attachable * RemoveFromParent2(Attachable *luaSelfObject, bool addToMovableMan, bool addBreakWounds); + static Attachable* RemoveFromParent1(Attachable* luaSelfObject); + static Attachable* RemoveFromParent2(Attachable* luaSelfObject, bool addToMovableMan, bool addBreakWounds); }; #pragma endregion #pragma region GlobalScript Lua Adapters struct LuaAdaptersGlobalScript { - static void Deactivate(GlobalScript *luaSelfObject); + static void Deactivate(GlobalScript* luaSelfObject); }; #pragma endregion #pragma region Activity Lua Adapters struct LuaAdaptersActivity { - static void SendMessage1(Activity *luaSelfObject, const std::string &message); - static void SendMessage2(Activity *luaSelfObject, const std::string &message, luabind::object context); + static void SendMessage1(Activity* luaSelfObject, const std::string& message); + static void SendMessage2(Activity* luaSelfObject, const std::string& message, luabind::object context); }; #pragma endregion #pragma region MovableObject Lua Adapters struct LuaAdaptersMovableObject { - static bool HasScript(MovableObject *luaSelfObject, const std::string &scriptPath); - static bool AddScript(MovableObject *luaSelfObject, const std::string &scriptPath); - static bool EnableScript(MovableObject *luaSelfObject, const std::string &scriptPath); - static bool DisableScript1(MovableObject *luaSelfObject); - static bool DisableScript2(MovableObject *luaSelfObject, const std::string &scriptPath); - static void SendMessage1(MovableObject *luaSelfObject, const std::string &message); - static void SendMessage2(MovableObject *luaSelfObject, const std::string &message, luabind::object context); + static bool HasScript(MovableObject* luaSelfObject, const std::string& scriptPath); + static bool AddScript(MovableObject* luaSelfObject, const std::string& scriptPath); + static bool EnableScript(MovableObject* luaSelfObject, const std::string& scriptPath); + static bool DisableScript1(MovableObject* luaSelfObject); + static bool DisableScript2(MovableObject* luaSelfObject, const std::string& scriptPath); + static void SendMessage1(MovableObject* luaSelfObject, const std::string& message); + static void SendMessage2(MovableObject* luaSelfObject, const std::string& message, luabind::object context); }; #pragma endregion #pragma region MOSRotating Lua Adapters struct LuaAdaptersMOSRotating { - static void GibThis(MOSRotating *luaSelfObject); - static std::vector * GetWounds1(const MOSRotating *luaSelfObject); - static std::vector * GetWounds2(const MOSRotating *luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables); + static void GibThis(MOSRotating* luaSelfObject); + static std::vector* GetWounds1(const MOSRotating* luaSelfObject); + static std::vector* GetWounds2(const MOSRotating* luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables); // Need a seperate implementation function without the return so we can safely recurse. - static void GetWoundsImpl(const MOSRotating *luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables, std::vector &wounds); + static void GetWoundsImpl(const MOSRotating* luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables, std::vector& wounds); }; #pragma endregion #pragma region BuyMenuGUI Lua Adapters struct LuaAdaptersBuyMenuGUI { - static std::list * GetOrderList(const BuyMenuGUI *luaSelfObject); + static std::list* GetOrderList(const BuyMenuGUI* luaSelfObject); }; #pragma endregion #pragma region PieMenu Lua Adapters struct LuaAdaptersPieMenu { - static bool AddPieSlice(PieMenu *luaSelfObject, PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource); - static bool AddPieSliceIfPresetNameIsUnique1(PieMenu *luaSelfObject, PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource); - static bool AddPieSliceIfPresetNameIsUnique2(PieMenu *luaSelfObject, PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource); + static bool AddPieSlice(PieMenu* luaSelfObject, PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource); + static bool AddPieSliceIfPresetNameIsUnique1(PieMenu* luaSelfObject, PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource); + static bool AddPieSliceIfPresetNameIsUnique2(PieMenu* luaSelfObject, PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource); }; #pragma endregion #pragma region SceneObject Lua Adapters struct LuaAdaptersSceneObject { - static float GetTotalValue(const SceneObject *luaSelfObject, int nativeModule, float foreignMult); - static int GetBuyableMode(const SceneObject *luaSelfObject); + static float GetTotalValue(const SceneObject* luaSelfObject, int nativeModule, float foreignMult); + static int GetBuyableMode(const SceneObject* luaSelfObject); }; #pragma endregion #pragma region Turret Lua Adapters struct LuaAdaptersTurret { - static void AddMountedFirearm(Turret *luaSelfObject, HDFirearm *newMountedDevice); + static void AddMountedFirearm(Turret* luaSelfObject, HDFirearm* newMountedDevice); }; #pragma endregion @@ -405,31 +405,31 @@ namespace RTE { /// /// A reference to MovableMan, provided by Lua. /// A pointer to the MovableObject to be added. - static void AddMO(MovableMan &movableMan, MovableObject *movableObject); + static void AddMO(MovableMan& movableMan, MovableObject* movableObject); /// /// Adds the given Actor to MovableMan if it doesn't already exist in there, or prints an error if it does. /// /// A reference to MovableMan, provided by Lua. /// A pointer to the Actor to be added. - static void AddActor(MovableMan &movableMan, Actor *actor); + static void AddActor(MovableMan& movableMan, Actor* actor); /// /// Adds the given item MovableObject (generally a HeldDevice) to MovableMan if it doesn't already exist in there, or prints an error if it does. /// /// A reference to MovableMan, provided by Lua. /// A pointer to the item to be added. - static void AddItem(MovableMan &movableMan, HeldDevice *item); + static void AddItem(MovableMan& movableMan, HeldDevice* item); /// /// Adds the given particle MovableObject to MovableMan if it doesn't already exist in there, or prints an error if it does. /// /// A reference to MovableMan, provided by Lua. /// A pointer to the particle to be added. - static void AddParticle(MovableMan &movableMan, MovableObject *particle); + static void AddParticle(MovableMan& movableMan, MovableObject* particle); - static void SendGlobalMessage1(MovableMan &movableMan, const std::string& message); - static void SendGlobalMessage2(MovableMan &movableMan, const std::string& message, luabind::object context); + static void SendGlobalMessage1(MovableMan& movableMan, const std::string& message); + static void SendGlobalMessage2(MovableMan& movableMan, const std::string& message, luabind::object context); }; #pragma endregion @@ -439,13 +439,13 @@ namespace RTE { /// Gets the current number of ticks that the simulation should be updating with. Lua can't handle int64 (or long long apparently) so we'll expose this specialized function. /// /// The current fixed delta time that the simulation should be updating with, in ticks. - static double GetDeltaTimeTicks(const TimerMan &timerMan); + static double GetDeltaTimeTicks(const TimerMan& timerMan); /// /// Gets the number of ticks per second. Lua can't handle int64 (or long long apparently) so we'll expose this specialized function. /// /// The number of ticks per second. - static double GetTicksPerSecond(const TimerMan &timerMan); + static double GetTicksPerSecond(const TimerMan& timerMan); }; #pragma endregion @@ -456,21 +456,21 @@ namespace RTE { /// /// Which button to check for. /// Whether the mouse button is held or not. - static bool MouseButtonHeld(const UInputMan &uinputMan, int whichButton); + static bool MouseButtonHeld(const UInputMan& uinputMan, int whichButton); /// /// Gets whether a mouse button was pressed between the last update and the one previous to it. /// /// Which button to check for. /// Whether the mouse button is pressed or not. - static bool MouseButtonPressed(const UInputMan &uinputMan, int whichButton); + static bool MouseButtonPressed(const UInputMan& uinputMan, int whichButton); /// /// Gets whether a mouse button was released between the last update and the one previous to it. /// /// Which button to check for. /// Whether the mouse button is released or not. - static bool MouseButtonReleased(const UInputMan &uinputMan, int whichButton); + static bool MouseButtonReleased(const UInputMan& uinputMan, int whichButton); }; #pragma endregion @@ -483,7 +483,7 @@ namespace RTE { /// The class name of the Entity to reload. /// The module name of the Entity to reload. /// Whether or not the Entity was reloaded. - static bool ReloadEntityPreset1(PresetMan &presetMan, const std::string &presetName, const std::string &className, const std::string &moduleName); + static bool ReloadEntityPreset1(PresetMan& presetMan, const std::string& presetName, const std::string& className, const std::string& moduleName); /// /// Reloads the specified Entity preset in PresetMan. @@ -491,7 +491,7 @@ namespace RTE { /// The preset name of the Entity to reload. /// The class name of the Entity to reload. /// Whether or not the Entity was reloaded. - static bool ReloadEntityPreset2(PresetMan &presetMan, const std::string &presetName, const std::string &className); + static bool ReloadEntityPreset2(PresetMan& presetMan, const std::string& presetName, const std::string& className); /// /// Gets a list all previously read in (defined) Entities which are associated with a specific group. @@ -500,15 +500,15 @@ namespace RTE { /// The name of the least common denominator type of the Entities you want. "All" will look at all types. /// Whether to only get those of one specific DataModule (0-n), or all (-1). /// The list of all Entities with the given group and type in the module. - static std::list * GetAllEntitiesOfGroup(PresetMan &presetMan, const std::string &group, const std::string &type, int whichModule); - static std::list * GetAllEntitiesOfGroup2(PresetMan &presetMan, const std::string &group, const std::string &type) { return GetAllEntitiesOfGroup(presetMan, group, type, -1); } - static std::list * GetAllEntitiesOfGroup3(PresetMan &presetMan, const std::string &group) { return GetAllEntitiesOfGroup2(presetMan, group, "All"); } - + static std::list* GetAllEntitiesOfGroup(PresetMan& presetMan, const std::string& group, const std::string& type, int whichModule); + static std::list* GetAllEntitiesOfGroup2(PresetMan& presetMan, const std::string& group, const std::string& type) { return GetAllEntitiesOfGroup(presetMan, group, type, -1); } + static std::list* GetAllEntitiesOfGroup3(PresetMan& presetMan, const std::string& group) { return GetAllEntitiesOfGroup2(presetMan, group, "All"); } + /// /// Gets a list all previously read in (defined) Entities. /// /// The list of all Entities. - static std::list * GetAllEntities(PresetMan &presetMan) { return GetAllEntitiesOfGroup3(presetMan, "All"); } + static std::list* GetAllEntities(PresetMan& presetMan) { return GetAllEntitiesOfGroup3(presetMan, "All"); } }; #pragma endregion @@ -519,7 +519,7 @@ namespace RTE { /// /// The Box to wrap. /// A list of Boxes that make up the Box to wrap, wrapped appropriately for the current Scene. - static const std::list * WrapBoxes(SceneMan &sceneMan, const Box &boxToWrap); + static const std::list* WrapBoxes(SceneMan& sceneMan, const Box& boxToWrap); }; #pragma endregion @@ -532,7 +532,7 @@ namespace RTE { /// Position of primitive's center in Scene coordinates. /// Color to draw primitive with. /// A Lua table that contains the positions of the primitive's vertices, relative to the center position. - static void DrawPolygonPrimitive(PrimitiveMan &primitiveMan, const Vector ¢erPos, int color, const luabind::object &verticesTable); + static void DrawPolygonPrimitive(PrimitiveMan& primitiveMan, const Vector& centerPos, int color, const luabind::object& verticesTable); /// /// Schedule to draw a polygon primitive visible only to a specified player. @@ -542,7 +542,7 @@ namespace RTE { /// Position of primitive's center in Scene coordinates. /// Color to draw primitive with. /// A Lua table that contains the positions of the primitive's vertices, relative to the center position. - static void DrawPolygonPrimitiveForPlayer(PrimitiveMan &primitiveMan, int player, const Vector ¢erPos, int color, const luabind::object &verticesTable); + static void DrawPolygonPrimitiveForPlayer(PrimitiveMan& primitiveMan, int player, const Vector& centerPos, int color, const luabind::object& verticesTable); /// /// Schedule to draw a filled polygon primitive. @@ -551,7 +551,7 @@ namespace RTE { /// Start position of the primitive in Scene coordinates. /// Color to draw primitive with. /// A Lua table that contains the positions of the primitive's vertices, relative to the center position. - static void DrawPolygonFillPrimitive(PrimitiveMan &primitiveMan, const Vector &startPos, int color, const luabind::object &verticesTable); + static void DrawPolygonFillPrimitive(PrimitiveMan& primitiveMan, const Vector& startPos, int color, const luabind::object& verticesTable); /// /// Schedule to draw a filled polygon primitive visible only to a specified player. @@ -561,7 +561,7 @@ namespace RTE { /// Start position of the primitive in Scene coordinates. /// Color to draw primitive with. /// A Lua table that contains the positions of the primitive's vertices, relative to the center position. - static void DrawPolygonFillPrimitiveForPlayer(PrimitiveMan &primitiveMan, int player, const Vector &startPos, int color, const luabind::object &verticesTable); + static void DrawPolygonFillPrimitiveForPlayer(PrimitiveMan& primitiveMan, int player, const Vector& startPos, int color, const luabind::object& verticesTable); /// /// Schedules to draw multiple primitives of varying type with transparency enabled. @@ -569,7 +569,7 @@ namespace RTE { /// A reference to PrimitiveMan, provided by Lua. /// The transparency value the primitives should be drawn at. From 0 (opaque) to 100 (transparent). /// A Lua table of primitives to schedule drawing for. - static void DrawPrimitivesWithTransparency(PrimitiveMan &primitiveMan, int transValue, const luabind::object &primitivesTable); + static void DrawPrimitivesWithTransparency(PrimitiveMan& primitiveMan, int transValue, const luabind::object& primitivesTable); /// /// Schedule to draw multiple primitives of varying type with blending enabled. @@ -578,7 +578,7 @@ namespace RTE { /// The blending mode the primitives should be drawn with. See DrawBlendMode enumeration. /// The blending amount for all the channels. 0-100. /// A Lua table of primitives to schedule drawing for. - static void DrawPrimitivesWithBlending(PrimitiveMan &primitiveMan, int blendMode, int blendAmount, const luabind::object &primitivesTable); + static void DrawPrimitivesWithBlending(PrimitiveMan& primitiveMan, int blendMode, int blendAmount, const luabind::object& primitivesTable); /// /// Schedule to draw multiple primitives of varying type with blending enabled. @@ -590,7 +590,7 @@ namespace RTE { /// The blending amount for the Blue channel. 0-100. /// The blending amount for the Alpha channel. 0-100. /// A Lua table of primitives to schedule drawing for. - static void DrawPrimitivesWithBlendingPerChannel(PrimitiveMan &primitiveMan, int blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const luabind::object &primitivesTable); + static void DrawPrimitivesWithBlendingPerChannel(PrimitiveMan& primitiveMan, int blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const luabind::object& primitivesTable); }; #pragma endregion @@ -630,10 +630,10 @@ namespace RTE { /// Explicit deletion of any Entity instance that Lua owns. It will probably be handled by the GC, but this makes it instantaneous. /// /// The Entity to delete. - static void DeleteEntity(Entity *entityToDelete); + static void DeleteEntity(Entity* entityToDelete); }; #pragma endregion -} +} // namespace RTE #ifndef _MSC_VER #pragma GCC diagnostic pop diff --git a/Source/Lua/LuaAdapters.cpp b/Source/Lua/LuaAdapters.cpp index 57d421115..242087162 100644 --- a/Source/Lua/LuaAdapters.cpp +++ b/Source/Lua/LuaAdapters.cpp @@ -5,44 +5,52 @@ namespace RTE { - std::unordered_map> LuaAdaptersEntityCast::s_EntityToLuabindObjectCastFunctions = {}; + std::unordered_map> LuaAdaptersEntityCast::s_EntityToLuabindObjectCastFunctions = {}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define LuaEntityCreateFunctionsDefinitionsForType(TYPE) \ - TYPE * LuaAdaptersEntityCreate::Create##TYPE(std::string preseName, std::string moduleName) { \ - const Entity *entityPreset = g_PresetMan.GetEntityPreset(#TYPE, preseName, moduleName); \ + TYPE* LuaAdaptersEntityCreate::Create##TYPE(std::string preseName, std::string moduleName) { \ + const Entity* entityPreset = g_PresetMan.GetEntityPreset(#TYPE, preseName, moduleName); \ if (!entityPreset) { \ g_ConsoleMan.PrintString(std::string("ERROR: There is no ") + std::string(#TYPE) + std::string(" of the Preset name \"") + preseName + std::string("\" defined in the \"") + moduleName + std::string("\" Data Module!")); \ return nullptr; \ } \ - return dynamic_cast(entityPreset->Clone()); \ + return dynamic_cast(entityPreset->Clone()); \ } \ - TYPE * LuaAdaptersEntityCreate::Create##TYPE(std::string preset) { \ + TYPE* LuaAdaptersEntityCreate::Create##TYPE(std::string preset) { \ return Create##TYPE(preset, "All"); \ } \ - TYPE * LuaAdaptersEntityCreate::Random##TYPE(std::string groupName, int moduleSpaceID) { \ - const Entity *entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, moduleSpaceID); \ - if (!entityPreset) { entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, g_PresetMan.GetModuleID("Base.rte")); } \ - if (!entityPreset) { entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech("Any", #TYPE, moduleSpaceID); } \ + TYPE* LuaAdaptersEntityCreate::Random##TYPE(std::string groupName, int moduleSpaceID) { \ + const Entity* entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, moduleSpaceID); \ if (!entityPreset) { \ - g_ConsoleMan.PrintString(std::string("WARNING: Could not find any ") + std::string(#TYPE) + std::string(" defined in a Group called \"") + groupName + std::string("\" in module ") + g_PresetMan.GetDataModuleName(moduleSpaceID) + "!"); \ + entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, g_PresetMan.GetModuleID("Base.rte")); \ + } \ + if (!entityPreset) { \ + entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech("Any", #TYPE, moduleSpaceID); \ + } \ + if (!entityPreset) { \ + g_ConsoleMan.PrintString(std::string("WARNING: Could not find any ") + std::string(#TYPE) + std::string(" defined in a Group called \"") + groupName + std::string("\" in module ") + g_PresetMan.GetDataModuleName(moduleSpaceID) + "!"); \ return nullptr; \ } \ - return dynamic_cast(entityPreset->Clone()); \ + return dynamic_cast(entityPreset->Clone()); \ } \ - TYPE * LuaAdaptersEntityCreate::Random##TYPE(std::string groupName, std::string dataModuleName) { \ + TYPE* LuaAdaptersEntityCreate::Random##TYPE(std::string groupName, std::string dataModuleName) { \ int moduleSpaceID = g_PresetMan.GetModuleID(dataModuleName); \ - const Entity *entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, moduleSpaceID); \ - if (!entityPreset) { entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, g_PresetMan.GetModuleID("Base.rte")); } \ - if (!entityPreset) { entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech("Any", #TYPE, moduleSpaceID); } \ + const Entity* entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, moduleSpaceID); \ + if (!entityPreset) { \ + entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech(groupName, #TYPE, g_PresetMan.GetModuleID("Base.rte")); \ + } \ + if (!entityPreset) { \ + entityPreset = g_PresetMan.GetRandomBuyableOfGroupFromTech("Any", #TYPE, moduleSpaceID); \ + } \ if (!entityPreset) { \ g_ConsoleMan.PrintString(std::string("WARNING: Could not find any ") + std::string(#TYPE) + std::string(" defined in a Group called \"") + groupName + std::string("\" in module ") + dataModuleName + "!"); \ return nullptr; \ } \ - return dynamic_cast(entityPreset->Clone()); \ + return dynamic_cast(entityPreset->Clone()); \ } \ - TYPE * LuaAdaptersEntityCreate::Random##TYPE(std::string groupName) { \ + TYPE* LuaAdaptersEntityCreate::Random##TYPE(std::string groupName) { \ return Random##TYPE(groupName, "All"); \ } @@ -75,12 +83,12 @@ namespace RTE { LuaEntityCreateFunctionsDefinitionsForType(PieSlice); LuaEntityCreateFunctionsDefinitionsForType(PieMenu); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define LuaEntityCloneFunctionDefinitionForType(TYPE) \ - TYPE * LuaAdaptersEntityClone::Clone##TYPE(const TYPE *thisEntity) { \ + TYPE* LuaAdaptersEntityClone::Clone##TYPE(const TYPE* thisEntity) { \ if (thisEntity) { \ - return dynamic_cast(thisEntity->Clone()); \ + return dynamic_cast(thisEntity->Clone()); \ } \ g_ConsoleMan.PrintString(std::string("ERROR: Tried to clone a ") + std::string(#TYPE) + std::string(" reference that is nil!")); \ return nullptr; \ @@ -119,24 +127,28 @@ namespace RTE { LuaEntityCloneFunctionDefinitionForType(PieSlice); LuaEntityCloneFunctionDefinitionForType(PieMenu); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define LuaEntityCastFunctionsDefinitionsForType(TYPE) \ - TYPE * LuaAdaptersEntityCast::To##TYPE(Entity *entity) { \ - TYPE *targetType = dynamic_cast(entity); \ - if (!targetType) { g_ConsoleMan.PrintString(std::string("ERROR: Tried to convert a non-") + std::string(#TYPE) + std::string(" Entity reference to an ") + std::string(#TYPE) + std::string(" reference! Entity was ") + (entity ? entity->GetPresetName() : "nil")); } \ + TYPE* LuaAdaptersEntityCast::To##TYPE(Entity* entity) { \ + TYPE* targetType = dynamic_cast(entity); \ + if (!targetType) { \ + g_ConsoleMan.PrintString(std::string("ERROR: Tried to convert a non-") + std::string(#TYPE) + std::string(" Entity reference to an ") + std::string(#TYPE) + std::string(" reference! Entity was ") + (entity ? entity->GetPresetName() : "nil")); \ + } \ return targetType; \ } \ - const TYPE * LuaAdaptersEntityCast::ToConst##TYPE(const Entity *entity) { \ - const TYPE *targetType = dynamic_cast(entity); \ - if (!targetType) { g_ConsoleMan.PrintString(std::string("ERROR: Tried to convert a non-") + std::string(#TYPE) + std::string(" Entity reference to an ") + std::string(#TYPE) + std::string(" reference! Entity was ") + (entity ? entity->GetPresetName() : "nil")); } \ + const TYPE* LuaAdaptersEntityCast::ToConst##TYPE(const Entity* entity) { \ + const TYPE* targetType = dynamic_cast(entity); \ + if (!targetType) { \ + g_ConsoleMan.PrintString(std::string("ERROR: Tried to convert a non-") + std::string(#TYPE) + std::string(" Entity reference to an ") + std::string(#TYPE) + std::string(" reference! Entity was ") + (entity ? entity->GetPresetName() : "nil")); \ + } \ return targetType; \ } \ - bool LuaAdaptersEntityCast::Is##TYPE(Entity *entity) { \ - return dynamic_cast(entity) ? true : false; \ + bool LuaAdaptersEntityCast::Is##TYPE(Entity* entity) { \ + return dynamic_cast(entity) ? true : false; \ } \ - LuabindObjectWrapper * LuaAdaptersEntityCast::ToLuabindObject##TYPE (Entity *entity, lua_State *luaState) { \ - return new LuabindObjectWrapper(new luabind::object(luaState, dynamic_cast(entity)), ""); \ + LuabindObjectWrapper* LuaAdaptersEntityCast::ToLuabindObject##TYPE(Entity* entity, lua_State* luaState) { \ + return new LuabindObjectWrapper(new luabind::object(luaState, dynamic_cast(entity)), ""); \ } \ /* Bullshit semi-hack to automatically populate the Luabind Object cast function map that is used in LuaMan::RunScriptFunctionObject */ \ static const bool EntityToLuabindObjectCastMapAutoInserterForType##TYPE = []() { \ @@ -182,11 +194,11 @@ namespace RTE { LuaEntityCastFunctionsDefinitionsForType(PieSlice); LuaEntityCastFunctionsDefinitionsForType(PieMenu); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define LuaPropertyOwnershipSafetyFakerFunctionDefinition(OBJECTTYPE, PROPERTYTYPE, SETTERFUNCTION) \ - void LuaAdaptersPropertyOwnershipSafetyFaker::OBJECTTYPE##SETTERFUNCTION(OBJECTTYPE *luaSelfObject, PROPERTYTYPE *objectToSet) { \ - luaSelfObject->SETTERFUNCTION(objectToSet ? dynamic_cast(objectToSet->Clone()) : nullptr); \ + void LuaAdaptersPropertyOwnershipSafetyFaker::OBJECTTYPE##SETTERFUNCTION(OBJECTTYPE* luaSelfObject, PROPERTYTYPE* objectToSet) { \ + luaSelfObject->SETTERFUNCTION(objectToSet ? dynamic_cast(objectToSet->Clone()) : nullptr); \ } LuaPropertyOwnershipSafetyFakerFunctionDefinition(MOSRotating, SoundContainer, SetGibSound); @@ -253,18 +265,18 @@ namespace RTE { LuaPropertyOwnershipSafetyFakerFunctionDefinition(HDFirearm, SoundContainer, SetReloadStartSound); LuaPropertyOwnershipSafetyFakerFunctionDefinition(HDFirearm, SoundContainer, SetReloadEndSound); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersEntity::SetPresetName(Entity *luaSelfObject, const std::string &presetName) { + void LuaAdaptersEntity::SetPresetName(Entity* luaSelfObject, const std::string& presetName) { luaSelfObject->SetPresetName(presetName, true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector * LuaAdaptersActor::GetSceneWaypoints(Actor *luaSelfObject) { - std::vector *sceneWaypoints = new std::vector(); + std::vector* LuaAdaptersActor::GetSceneWaypoints(Actor* luaSelfObject) { + std::vector* sceneWaypoints = new std::vector(); sceneWaypoints->reserve(luaSelfObject->GetWaypointsSize()); - for (auto &[sceneWaypoint, movableObjectWaypoint] : luaSelfObject->GetWaypointList()) { + for (auto& [sceneWaypoint, movableObjectWaypoint]: luaSelfObject->GetWaypointList()) { if (movableObjectWaypoint == nullptr) { sceneWaypoints->emplace_back(sceneWaypoint); } @@ -272,15 +284,15 @@ namespace RTE { return sceneWaypoints; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaAdaptersScene::CalculatePath2(Scene *luaSelfObject, const Vector &start, const Vector &end, bool movePathToGround, float digStrength, Activity::Teams team) { + int LuaAdaptersScene::CalculatePath2(Scene* luaSelfObject, const Vector& start, const Vector& end, bool movePathToGround, float digStrength, Activity::Teams team) { std::list& threadScenePath = luaSelfObject->GetScenePath(); team = std::clamp(team, Activity::Teams::NoTeam, Activity::Teams::TeamFour); luaSelfObject->CalculatePath(start, end, threadScenePath, digStrength, team); if (!threadScenePath.empty()) { if (movePathToGround) { - for (Vector &scenePathPoint : threadScenePath) { + for (Vector& scenePathPoint: threadScenePath) { scenePathPoint = g_SceneMan.MovePointToGround(scenePathPoint, 20, 15); } } @@ -290,11 +302,11 @@ namespace RTE { return -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersScene::CalculatePathAsync2(Scene *luaSelfObject, const luabind::object &callbackParam, const Vector &start, const Vector &end, bool movePathToGround, float digStrength, Activity::Teams team) { + void LuaAdaptersScene::CalculatePathAsync2(Scene* luaSelfObject, const luabind::object& callbackParam, const Vector& start, const Vector& end, bool movePathToGround, float digStrength, Activity::Teams team) { team = std::clamp(team, Activity::Teams::NoTeam, Activity::Teams::TeamFour); - + // So, luabind::object is a weak reference, holding just a stack and a position in the stack // This means it's unsafe to store on the C++ side if we do basically anything with the lua state before using it // As such, we need to store this function somewhere safely within our Lua state for us to access later when we need it @@ -312,13 +324,13 @@ namespace RTE { auto callLuaCallback = [luaState, thisCallbackId, movePathToGround](std::shared_ptr pathRequestVol) { // This callback is called from the async pathing thread, so we need to further delay this logic into the main thread (via AddLuaScriptCallback) g_LuaMan.AddLuaScriptCallback([luaState, thisCallbackId, movePathToGround, pathRequestVol]() { - PathRequest pathRequest = const_cast(*pathRequestVol); // erh, to work with luabind etc + PathRequest pathRequest = const_cast(*pathRequestVol); // erh, to work with luabind etc if (movePathToGround) { - for (Vector &scenePathPoint : pathRequest.path) { + for (Vector& scenePathPoint: pathRequest.path) { scenePathPoint = g_SceneMan.MovePointToGround(scenePathPoint, 20, 15); } } - + luabind::call_function(luaState->GetLuaState(), "_TriggerAsyncPathCallback", thisCallbackId, pathRequest); }); }; @@ -326,50 +338,50 @@ namespace RTE { luaSelfObject->CalculatePathAsync(start, end, digStrength, team, callLuaCallback); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersAHuman::ReloadFirearms(AHuman *luaSelfObject) { + void LuaAdaptersAHuman::ReloadFirearms(AHuman* luaSelfObject) { luaSelfObject->ReloadFirearms(false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - float LuaAdaptersSceneObject::GetTotalValue(const SceneObject *luaSelfObject, int nativeModule, float foreignMult) { + float LuaAdaptersSceneObject::GetTotalValue(const SceneObject* luaSelfObject, int nativeModule, float foreignMult) { return luaSelfObject->GetTotalValue(nativeModule, foreignMult, 1.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaAdaptersSceneObject::GetBuyableMode(const SceneObject *luaSelfObject) { + int LuaAdaptersSceneObject::GetBuyableMode(const SceneObject* luaSelfObject) { return static_cast(luaSelfObject->GetBuyableMode()); } - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersActivity::SendMessage1(Activity *luaSelfObject, const std::string &message) { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void LuaAdaptersActivity::SendMessage1(Activity* luaSelfObject, const std::string& message) { luabind::object context; SendMessage2(luaSelfObject, message, context); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersActivity::SendMessage2(Activity *luaSelfObject, const std::string &message, luabind::object context) { + void LuaAdaptersActivity::SendMessage2(Activity* luaSelfObject, const std::string& message, luabind::object context) { GAScripted* scriptedActivity = dynamic_cast(luaSelfObject); if (scriptedActivity) { LuabindObjectWrapper wrapper(&context, "", false); - scriptedActivity->RunLuaFunction("OnMessage", {}, { message }, { &wrapper }); + scriptedActivity->RunLuaFunction("OnMessage", {}, {message}, {&wrapper}); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersMovableObject::HasScript(MovableObject *luaSelfObject, const std::string &scriptPath) { + bool LuaAdaptersMovableObject::HasScript(MovableObject* luaSelfObject, const std::string& scriptPath) { return luaSelfObject->HasScript(g_PresetMan.GetFullModulePath(scriptPath)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersMovableObject::AddScript(MovableObject *luaSelfObject, const std::string &scriptPath) { + bool LuaAdaptersMovableObject::AddScript(MovableObject* luaSelfObject, const std::string& scriptPath) { switch (std::string correctedScriptPath = g_PresetMan.GetFullModulePath(scriptPath); luaSelfObject->LoadScript(correctedScriptPath)) { case 0: return true; @@ -395,66 +407,65 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersMovableObject::EnableScript(MovableObject *luaSelfObject, const std::string &scriptPath) { + bool LuaAdaptersMovableObject::EnableScript(MovableObject* luaSelfObject, const std::string& scriptPath) { return luaSelfObject->EnableOrDisableScript(g_PresetMan.GetFullModulePath(scriptPath), true); } - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaAdaptersMovableObject::DisableScript1(MovableObject* luaSelfObject) { std::string currentScriptFilePath(g_LuaMan.GetThreadCurrentLuaState()->GetCurrentlyRunningScriptFilePath()); return luaSelfObject->EnableOrDisableScript(currentScriptFilePath, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersMovableObject::DisableScript2(MovableObject *luaSelfObject, const std::string &scriptPath) { + bool LuaAdaptersMovableObject::DisableScript2(MovableObject* luaSelfObject, const std::string& scriptPath) { return luaSelfObject->EnableOrDisableScript(g_PresetMan.GetFullModulePath(scriptPath), false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableObject::SendMessage1(MovableObject *luaSelfObject, const std::string &message) { - luaSelfObject->RunScriptedFunctionInAppropriateScripts("OnMessage", false, false, {}, { message }); + void LuaAdaptersMovableObject::SendMessage1(MovableObject* luaSelfObject, const std::string& message) { + luaSelfObject->RunScriptedFunctionInAppropriateScripts("OnMessage", false, false, {}, {message}); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableObject::SendMessage2(MovableObject *luaSelfObject, const std::string &message, luabind::object context) { + void LuaAdaptersMovableObject::SendMessage2(MovableObject* luaSelfObject, const std::string& message, luabind::object context) { LuabindObjectWrapper wrapper(&context, "", false); - luaSelfObject->RunScriptedFunctionInAppropriateScripts("OnMessage", false, false, {}, { message }, { &wrapper }); + luaSelfObject->RunScriptedFunctionInAppropriateScripts("OnMessage", false, false, {}, {message}, {&wrapper}); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMOSRotating::GibThis(MOSRotating *luaSelfObject) { + void LuaAdaptersMOSRotating::GibThis(MOSRotating* luaSelfObject) { luaSelfObject->GibThis(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector * LuaAdaptersMOSRotating::GetWounds1(const MOSRotating *luaSelfObject) { + std::vector* LuaAdaptersMOSRotating::GetWounds1(const MOSRotating* luaSelfObject) { return GetWounds2(luaSelfObject, true, false, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector * LuaAdaptersMOSRotating::GetWounds2(const MOSRotating *luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) { - auto *wounds = new std::vector(); + std::vector* LuaAdaptersMOSRotating::GetWounds2(const MOSRotating* luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables) { + auto* wounds = new std::vector(); GetWoundsImpl(luaSelfObject, includePositiveDamageAttachables, includeNegativeDamageAttachables, includeNoDamageAttachables, *wounds); return wounds; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMOSRotating::GetWoundsImpl(const MOSRotating *luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables, std::vector &wounds) { + void LuaAdaptersMOSRotating::GetWoundsImpl(const MOSRotating* luaSelfObject, bool includePositiveDamageAttachables, bool includeNegativeDamageAttachables, bool includeNoDamageAttachables, std::vector& wounds) { wounds.insert(wounds.end(), luaSelfObject->GetWoundList().begin(), luaSelfObject->GetWoundList().end()); if (includePositiveDamageAttachables || includeNegativeDamageAttachables || includeNoDamageAttachables) { - for (const Attachable *attachable : luaSelfObject->GetAttachables()) { + for (const Attachable* attachable: luaSelfObject->GetAttachables()) { bool attachableSatisfiesConditions = (includePositiveDamageAttachables && attachable->GetDamageMultiplier() > 0) || (includeNegativeDamageAttachables && attachable->GetDamageMultiplier() < 0) || (includeNoDamageAttachables && attachable->GetDamageMultiplier() == 0); @@ -466,74 +477,74 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::list * LuaAdaptersBuyMenuGUI::GetOrderList(const BuyMenuGUI *luaSelfObject) { - std::list constOrderList; + std::list* LuaAdaptersBuyMenuGUI::GetOrderList(const BuyMenuGUI* luaSelfObject) { + std::list constOrderList; luaSelfObject->GetOrderList(constOrderList); // Previously I tried to push back a cloned object for const-correctness (and giving unique ptr so luabind would clean it up after) // This is needed cause lua doesn't really enjoy being given a const SceneObject* // But it didn't like that. So eh auto* orderList = new std::list(); - for (const SceneObject *constObjectInOrderList : constOrderList) { - orderList->push_back( const_cast(constObjectInOrderList) ); + for (const SceneObject* constObjectInOrderList: constOrderList) { + orderList->push_back(const_cast(constObjectInOrderList)); } return orderList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Attachable * LuaAdaptersAttachable::RemoveFromParent1(Attachable *luaSelfObject) { + Attachable* LuaAdaptersAttachable::RemoveFromParent1(Attachable* luaSelfObject) { if (luaSelfObject->IsAttached()) { return luaSelfObject->GetParent()->RemoveAttachable(luaSelfObject); } return luaSelfObject; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Attachable * LuaAdaptersAttachable::RemoveFromParent2(Attachable *luaSelfObject, bool addToMovableMan, bool addBreakWounds) { + Attachable* LuaAdaptersAttachable::RemoveFromParent2(Attachable* luaSelfObject, bool addToMovableMan, bool addBreakWounds) { if (luaSelfObject->IsAttached()) { return luaSelfObject->GetParent()->RemoveAttachable(luaSelfObject, addToMovableMan, addBreakWounds); } return luaSelfObject; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersTurret::AddMountedFirearm(Turret *luaSelfObject, HDFirearm *newMountedDevice) { + void LuaAdaptersTurret::AddMountedFirearm(Turret* luaSelfObject, HDFirearm* newMountedDevice) { luaSelfObject->AddMountedDevice(newMountedDevice); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersGlobalScript::Deactivate(GlobalScript *luaSelfObject) { + void LuaAdaptersGlobalScript::Deactivate(GlobalScript* luaSelfObject) { luaSelfObject->SetActive(false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersPieMenu::AddPieSlice(PieMenu *luaSelfObject, PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource) { + bool LuaAdaptersPieMenu::AddPieSlice(PieMenu* luaSelfObject, PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource) { return luaSelfObject->AddPieSlice(pieSliceToAdd, pieSliceOriginalSource, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique1(PieMenu *luaSelfObject, PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource) { + bool LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique1(PieMenu* luaSelfObject, PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource) { return luaSelfObject->AddPieSliceIfPresetNameIsUnique(pieSliceToAdd, pieSliceOriginalSource, false, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique2(PieMenu *luaSelfObject, PieSlice *pieSliceToAdd, const Entity *pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource) { + bool LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique2(PieMenu* luaSelfObject, PieSlice* pieSliceToAdd, const Entity* pieSliceOriginalSource, bool onlyCheckPieSlicesWithSameOriginalSource) { return luaSelfObject->AddPieSliceIfPresetNameIsUnique(pieSliceToAdd, pieSliceOriginalSource, onlyCheckPieSlicesWithSameOriginalSource, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableMan::AddMO(MovableMan &movableMan, MovableObject *movableObject) { + void LuaAdaptersMovableMan::AddMO(MovableMan& movableMan, MovableObject* movableObject) { if (movableMan.ValidMO(movableObject)) { g_ConsoleMan.PrintString("ERROR: Tried to add a MovableObject that already exists in the simulation! " + movableObject->GetPresetName()); } else { @@ -541,9 +552,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableMan::AddActor(MovableMan &movableMan, Actor *actor) { + void LuaAdaptersMovableMan::AddActor(MovableMan& movableMan, Actor* actor) { if (movableMan.IsActor(actor)) { g_ConsoleMan.PrintString("ERROR: Tried to add an Actor that already exists in the simulation!" + actor->GetPresetName()); } else { @@ -551,19 +562,19 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableMan::AddItem(MovableMan &movableMan, HeldDevice *item) { - if (movableMan.ValidMO(dynamic_cast(item))) { + void LuaAdaptersMovableMan::AddItem(MovableMan& movableMan, HeldDevice* item) { + if (movableMan.ValidMO(dynamic_cast(item))) { g_ConsoleMan.PrintString("ERROR: Tried to add an Item that already exists in the simulation!" + item->GetPresetName()); } else { movableMan.AddItem(item); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableMan::AddParticle(MovableMan &movableMan, MovableObject *particle) { + void LuaAdaptersMovableMan::AddParticle(MovableMan& movableMan, MovableObject* particle) { if (movableMan.ValidMO(particle)) { g_ConsoleMan.PrintString("ERROR: Tried to add a Particle that already exists in the simulation!" + particle->GetPresetName()); } else { @@ -571,165 +582,165 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableMan::SendGlobalMessage1(MovableMan &movableMan, const std::string &message) { + void LuaAdaptersMovableMan::SendGlobalMessage1(MovableMan& movableMan, const std::string& message) { GAScripted* scriptedActivity = dynamic_cast(g_ActivityMan.GetActivity()); if (scriptedActivity) { - scriptedActivity->RunLuaFunction("OnGlobalMessage", {}, { message }); + scriptedActivity->RunLuaFunction("OnGlobalMessage", {}, {message}); } - movableMan.RunLuaFunctionOnAllMOs("OnGlobalMessage", true, {}, { message }); + movableMan.RunLuaFunctionOnAllMOs("OnGlobalMessage", true, {}, {message}); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersMovableMan::SendGlobalMessage2(MovableMan &movableMan, const std::string &message, luabind::object context) { + void LuaAdaptersMovableMan::SendGlobalMessage2(MovableMan& movableMan, const std::string& message, luabind::object context) { LuabindObjectWrapper wrapper(&context, "", false); GAScripted* scriptedActivity = dynamic_cast(g_ActivityMan.GetActivity()); if (scriptedActivity) { - scriptedActivity->RunLuaFunction("OnGlobalMessage", {}, { message }, { &wrapper }); + scriptedActivity->RunLuaFunction("OnGlobalMessage", {}, {message}, {&wrapper}); } - movableMan.RunLuaFunctionOnAllMOs("OnGlobalMessage", true, {}, { message }, { &wrapper }); + movableMan.RunLuaFunctionOnAllMOs("OnGlobalMessage", true, {}, {message}, {&wrapper}); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - double LuaAdaptersTimerMan::GetDeltaTimeTicks(const TimerMan &timerMan) { + double LuaAdaptersTimerMan::GetDeltaTimeTicks(const TimerMan& timerMan) { return static_cast(timerMan.GetDeltaTimeTicks()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - double LuaAdaptersTimerMan::GetTicksPerSecond(const TimerMan &timerMan) { + double LuaAdaptersTimerMan::GetTicksPerSecond(const TimerMan& timerMan) { return static_cast(timerMan.GetTicksPerSecond()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersUInputMan::MouseButtonHeld(const UInputMan &uinputMan, int whichButton) { + bool LuaAdaptersUInputMan::MouseButtonHeld(const UInputMan& uinputMan, int whichButton) { return uinputMan.MouseButtonHeld(whichButton, Players::PlayerOne); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersUInputMan::MouseButtonPressed(const UInputMan &uinputMan, int whichButton) { + bool LuaAdaptersUInputMan::MouseButtonPressed(const UInputMan& uinputMan, int whichButton) { return uinputMan.MouseButtonPressed(whichButton, Players::PlayerOne); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersUInputMan::MouseButtonReleased(const UInputMan &uinputMan, int whichButton) { + bool LuaAdaptersUInputMan::MouseButtonReleased(const UInputMan& uinputMan, int whichButton) { return uinputMan.MouseButtonReleased(whichButton, Players::PlayerOne); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersPresetMan::ReloadEntityPreset1(PresetMan &presetMan, const std::string &presetName, const std::string &className, const std::string &moduleName) { + bool LuaAdaptersPresetMan::ReloadEntityPreset1(PresetMan& presetMan, const std::string& presetName, const std::string& className, const std::string& moduleName) { return presetMan.ReloadEntityPreset(presetName, className, moduleName); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaAdaptersPresetMan::ReloadEntityPreset2(PresetMan &presetMan, const std::string &presetName, const std::string &className) { + bool LuaAdaptersPresetMan::ReloadEntityPreset2(PresetMan& presetMan, const std::string& presetName, const std::string& className) { return ReloadEntityPreset1(presetMan, presetName, className, ""); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::list * LuaAdaptersPresetMan::GetAllEntitiesOfGroup(PresetMan &presetMan, const std::string &group, const std::string &type, int whichModule) { - std::list *entityList = new std::list(); + std::list* LuaAdaptersPresetMan::GetAllEntitiesOfGroup(PresetMan& presetMan, const std::string& group, const std::string& type, int whichModule) { + std::list* entityList = new std::list(); presetMan.GetAllOfGroup(*entityList, group, type, whichModule); return entityList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::list * LuaAdaptersSceneMan::WrapBoxes(SceneMan &sceneMan, const Box &boxToWrap) { - std::list *wrappedBoxes = new std::list(); + const std::list* LuaAdaptersSceneMan::WrapBoxes(SceneMan& sceneMan, const Box& boxToWrap) { + std::list* wrappedBoxes = new std::list(); sceneMan.WrapBox(boxToWrap, *wrappedBoxes); return wrappedBoxes; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersPrimitiveMan::DrawPolygonPrimitive(PrimitiveMan &primitiveMan, const Vector ¢erPos, int color, const luabind::object &verticesTable) { - primitiveMan.DrawPolygonOrPolygonFillPrimitive(-1, centerPos, color, ConvertLuaTableToVectorOfType(verticesTable), false); + void LuaAdaptersPrimitiveMan::DrawPolygonPrimitive(PrimitiveMan& primitiveMan, const Vector& centerPos, int color, const luabind::object& verticesTable) { + primitiveMan.DrawPolygonOrPolygonFillPrimitive(-1, centerPos, color, ConvertLuaTableToVectorOfType(verticesTable), false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersPrimitiveMan::DrawPolygonPrimitiveForPlayer(PrimitiveMan &primitiveMan, int player, const Vector ¢erPos, int color, const luabind::object &verticesTable) { - primitiveMan.DrawPolygonOrPolygonFillPrimitive(player, centerPos, color, ConvertLuaTableToVectorOfType(verticesTable), false); + void LuaAdaptersPrimitiveMan::DrawPolygonPrimitiveForPlayer(PrimitiveMan& primitiveMan, int player, const Vector& centerPos, int color, const luabind::object& verticesTable) { + primitiveMan.DrawPolygonOrPolygonFillPrimitive(player, centerPos, color, ConvertLuaTableToVectorOfType(verticesTable), false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitive(PrimitiveMan &primitiveMan, const Vector &startPos, int color, const luabind::object &verticesTable) { - primitiveMan.DrawPolygonOrPolygonFillPrimitive(-1, startPos, color, ConvertLuaTableToVectorOfType(verticesTable), true); + void LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitive(PrimitiveMan& primitiveMan, const Vector& startPos, int color, const luabind::object& verticesTable) { + primitiveMan.DrawPolygonOrPolygonFillPrimitive(-1, startPos, color, ConvertLuaTableToVectorOfType(verticesTable), true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitiveForPlayer(PrimitiveMan &primitiveMan, int player, const Vector &startPos, int color, const luabind::object &verticesTable) { - primitiveMan.DrawPolygonOrPolygonFillPrimitive(player, startPos, color, ConvertLuaTableToVectorOfType(verticesTable), true); + void LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitiveForPlayer(PrimitiveMan& primitiveMan, int player, const Vector& startPos, int color, const luabind::object& verticesTable) { + primitiveMan.DrawPolygonOrPolygonFillPrimitive(player, startPos, color, ConvertLuaTableToVectorOfType(verticesTable), true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersPrimitiveMan::DrawPrimitivesWithTransparency(PrimitiveMan &primitiveMan, int transValue, const luabind::object &primitivesTable) { - primitiveMan.SchedulePrimitivesForBlendedDrawing(DrawBlendMode::BlendTransparency, transValue, transValue, transValue, BlendAmountLimits::MinBlend, ConvertLuaTableToVectorOfType(primitivesTable)); + void LuaAdaptersPrimitiveMan::DrawPrimitivesWithTransparency(PrimitiveMan& primitiveMan, int transValue, const luabind::object& primitivesTable) { + primitiveMan.SchedulePrimitivesForBlendedDrawing(DrawBlendMode::BlendTransparency, transValue, transValue, transValue, BlendAmountLimits::MinBlend, ConvertLuaTableToVectorOfType(primitivesTable)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlending(PrimitiveMan &primitiveMan, int blendMode, int blendAmount, const luabind::object &primitivesTable) { - primitiveMan.SchedulePrimitivesForBlendedDrawing(static_cast(blendMode), blendAmount, blendAmount, blendAmount, blendAmount, ConvertLuaTableToVectorOfType(primitivesTable)); + void LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlending(PrimitiveMan& primitiveMan, int blendMode, int blendAmount, const luabind::object& primitivesTable) { + primitiveMan.SchedulePrimitivesForBlendedDrawing(static_cast(blendMode), blendAmount, blendAmount, blendAmount, blendAmount, ConvertLuaTableToVectorOfType(primitivesTable)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlendingPerChannel(PrimitiveMan &primitiveMan, int blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const luabind::object &primitivesTable) { - primitiveMan.SchedulePrimitivesForBlendedDrawing(static_cast(blendMode), blendAmountR, blendAmountG, blendAmountB, blendAmountA, ConvertLuaTableToVectorOfType(primitivesTable)); + void LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlendingPerChannel(PrimitiveMan& primitiveMan, int blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const luabind::object& primitivesTable) { + primitiveMan.SchedulePrimitivesForBlendedDrawing(static_cast(blendMode), blendAmountR, blendAmountG, blendAmountB, blendAmountA, ConvertLuaTableToVectorOfType(primitivesTable)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float LuaAdaptersUtility::GetMPP() { return c_MPP; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float LuaAdaptersUtility::GetPPM() { return c_PPM; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float LuaAdaptersUtility::GetLPP() { return c_LPP; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float LuaAdaptersUtility::GetPPL() { return c_PPL; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float LuaAdaptersUtility::GetPathFindingDefaultDigStrength() { return c_PathFindingDefaultDigStrength; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaAdaptersUtility::DeleteEntity(Entity *entityToDelete) { + void LuaAdaptersUtility::DeleteEntity(Entity* entityToDelete) { delete entityToDelete; entityToDelete = nullptr; } #pragma endregion -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuaBindingRegisterDefinitions.h b/Source/Lua/LuaBindingRegisterDefinitions.h index 3459f7c69..b1006a52b 100644 --- a/Source/Lua/LuaBindingRegisterDefinitions.h +++ b/Source/Lua/LuaBindingRegisterDefinitions.h @@ -7,185 +7,185 @@ namespace RTE { // Should be ordered with most-derived classes first -#define LIST_OF_LUABOUND_OBJECTS \ - /* SystemLuaBindings */ \ - PER_LUA_BINDING(Box) \ - PER_LUA_BINDING(Controller) \ - PER_LUA_BINDING(DataModule) \ - PER_LUA_BINDING(Timer) \ - PER_LUA_BINDING(Vector) \ - PER_LUA_BINDING(PathRequest) \ - /* ManagerLuaBindings */ \ - PER_LUA_BINDING(ActivityMan) \ - PER_LUA_BINDING(AudioMan) \ - PER_LUA_BINDING(CameraMan) \ - PER_LUA_BINDING(ConsoleMan) \ - PER_LUA_BINDING(FrameMan) \ - PER_LUA_BINDING(MetaMan) \ - PER_LUA_BINDING(MovableMan) \ - PER_LUA_BINDING(PerformanceMan) \ - PER_LUA_BINDING(PostProcessMan) \ - PER_LUA_BINDING(PresetMan) \ - PER_LUA_BINDING(PrimitiveMan) \ - PER_LUA_BINDING(SceneMan) \ - PER_LUA_BINDING(SettingsMan) \ - PER_LUA_BINDING(TimerMan) \ - PER_LUA_BINDING(UInputMan) \ - /* EntityLuaBindings */ \ - /* ThrownDevice-Derived */ \ - PER_LUA_BINDING(TDExplosive) \ - /* HeldDevice-Derived */ \ - PER_LUA_BINDING(HDFirearm) \ - PER_LUA_BINDING(ThrownDevice) \ - /* AEmitter-Derived */ \ - PER_LUA_BINDING(AEJetpack) \ - /* ACraft-Derived */ \ - PER_LUA_BINDING(ACDropShip) \ - PER_LUA_BINDING(ACRocket) \ - /* Attachable-Derived */ \ - PER_LUA_BINDING(Arm) \ - PER_LUA_BINDING(Leg) \ - PER_LUA_BINDING(AEmitter) \ - PER_LUA_BINDING(HeldDevice) \ - PER_LUA_BINDING(Magazine) \ - PER_LUA_BINDING(Turret) \ - /* Actor-Derived */ \ - PER_LUA_BINDING(ACrab) \ - PER_LUA_BINDING(ACraft) \ - PER_LUA_BINDING(AHuman) \ - PER_LUA_BINDING(ADoor) \ - /* MOSRotating-Derived */ \ - PER_LUA_BINDING(Actor) \ - PER_LUA_BINDING(Attachable) \ - /* MOSParticle-Derived */ \ - PER_LUA_BINDING(PEmitter) \ - /* MOSprite-Derived */ \ - PER_LUA_BINDING(MOSRotating) \ - PER_LUA_BINDING(MOSParticle) \ - /* MovableObject-Derived */ \ - PER_LUA_BINDING(MOPixel) \ - PER_LUA_BINDING(MOSprite) \ - /* SceneObject-Derived */ \ - PER_LUA_BINDING(TerrainObject) \ - PER_LUA_BINDING(Deployment) \ - PER_LUA_BINDING(MovableObject) \ - /* Entity-Derived */ \ - PER_LUA_BINDING(SoundContainer) \ - PER_LUA_BINDING(PieSlice) \ - PER_LUA_BINDING(GlobalScript) \ - PER_LUA_BINDING(Emission) \ - PER_LUA_BINDING(LimbPath) \ - PER_LUA_BINDING(PieMenu) \ - PER_LUA_BINDING(Round) \ - PER_LUA_BINDING(Scene) \ - PER_LUA_BINDING(Scene::Area) \ - PER_LUA_BINDING(Material) \ - PER_LUA_BINDING(MetaPlayer) \ - PER_LUA_BINDING(SceneObject) \ - /* SceneLayer-Derived */ \ - PER_LUA_BINDING(SLBackground) \ - /* Base Classes */ \ - PER_LUA_BINDING(SoundSet) \ - PER_LUA_BINDING(Gib) \ - PER_LUA_BINDING(SceneLayer) \ - PER_LUA_BINDING(Entity) \ - /* ActivityLuaBindings */ \ - PER_LUA_BINDING(GameActivity) \ - PER_LUA_BINDING(Activity) \ - /* GUILuaBindings */ \ - PER_LUA_BINDING(BuyMenuGUI) \ - PER_LUA_BINDING(SceneEditorGUI) \ - PER_LUA_BINDING(GUIBanner) \ - /* PrimitiveLuaBindings */ \ - /* GraphicalPrimitive-Derived */ \ - PER_LUA_BINDING(LinePrimitive) \ - PER_LUA_BINDING(ArcPrimitive) \ - PER_LUA_BINDING(SplinePrimitive) \ - PER_LUA_BINDING(BoxPrimitive) \ - PER_LUA_BINDING(BoxFillPrimitive) \ - PER_LUA_BINDING(RoundedBoxPrimitive) \ - PER_LUA_BINDING(RoundedBoxFillPrimitive) \ - PER_LUA_BINDING(CirclePrimitive) \ - PER_LUA_BINDING(CircleFillPrimitive) \ - PER_LUA_BINDING(EllipsePrimitive) \ - PER_LUA_BINDING(EllipseFillPrimitive) \ - PER_LUA_BINDING(TrianglePrimitive) \ - PER_LUA_BINDING(TriangleFillPrimitive) \ - PER_LUA_BINDING(TextPrimitive) \ - PER_LUA_BINDING(BitmapPrimitive) \ - /* Base Classes */ \ - PER_LUA_BINDING(GraphicalPrimitive) \ - /* InputLuaBindings */ \ - PER_LUA_BINDING(InputDevice) \ - PER_LUA_BINDING(InputElements) \ - PER_LUA_BINDING(MouseButtons) \ - PER_LUA_BINDING(JoyButtons) \ - PER_LUA_BINDING(JoyDirections) \ - PER_LUA_BINDING(SDL_Scancode) \ - PER_LUA_BINDING(SDL_Keycode) \ - PER_LUA_BINDING(SDL_GameControllerButton) \ - PER_LUA_BINDING(SDL_GameControllerAxis) \ - /* MiscLuaBindings */ \ - PER_LUA_BINDING(AlarmEvent) \ - PER_LUA_BINDING(Directions) \ - PER_LUA_BINDING(DrawBlendMode) - +#define LIST_OF_LUABOUND_OBJECTS \ + /* SystemLuaBindings */ \ + PER_LUA_BINDING(Box) \ + PER_LUA_BINDING(Controller) \ + PER_LUA_BINDING(DataModule) \ + PER_LUA_BINDING(Timer) \ + PER_LUA_BINDING(Vector) \ + PER_LUA_BINDING(PathRequest) \ + /* ManagerLuaBindings */ \ + PER_LUA_BINDING(ActivityMan) \ + PER_LUA_BINDING(AudioMan) \ + PER_LUA_BINDING(CameraMan) \ + PER_LUA_BINDING(ConsoleMan) \ + PER_LUA_BINDING(FrameMan) \ + PER_LUA_BINDING(MetaMan) \ + PER_LUA_BINDING(MovableMan) \ + PER_LUA_BINDING(PerformanceMan) \ + PER_LUA_BINDING(PostProcessMan) \ + PER_LUA_BINDING(PresetMan) \ + PER_LUA_BINDING(PrimitiveMan) \ + PER_LUA_BINDING(SceneMan) \ + PER_LUA_BINDING(SettingsMan) \ + PER_LUA_BINDING(TimerMan) \ + PER_LUA_BINDING(UInputMan) \ + /* EntityLuaBindings */ \ + /* ThrownDevice-Derived */ \ + PER_LUA_BINDING(TDExplosive) \ + /* HeldDevice-Derived */ \ + PER_LUA_BINDING(HDFirearm) \ + PER_LUA_BINDING(ThrownDevice) \ + /* AEmitter-Derived */ \ + PER_LUA_BINDING(AEJetpack) \ + /* ACraft-Derived */ \ + PER_LUA_BINDING(ACDropShip) \ + PER_LUA_BINDING(ACRocket) \ + /* Attachable-Derived */ \ + PER_LUA_BINDING(Arm) \ + PER_LUA_BINDING(Leg) \ + PER_LUA_BINDING(AEmitter) \ + PER_LUA_BINDING(HeldDevice) \ + PER_LUA_BINDING(Magazine) \ + PER_LUA_BINDING(Turret) \ + /* Actor-Derived */ \ + PER_LUA_BINDING(ACrab) \ + PER_LUA_BINDING(ACraft) \ + PER_LUA_BINDING(AHuman) \ + PER_LUA_BINDING(ADoor) \ + /* MOSRotating-Derived */ \ + PER_LUA_BINDING(Actor) \ + PER_LUA_BINDING(Attachable) \ + /* MOSParticle-Derived */ \ + PER_LUA_BINDING(PEmitter) \ + /* MOSprite-Derived */ \ + PER_LUA_BINDING(MOSRotating) \ + PER_LUA_BINDING(MOSParticle) \ + /* MovableObject-Derived */ \ + PER_LUA_BINDING(MOPixel) \ + PER_LUA_BINDING(MOSprite) \ + /* SceneObject-Derived */ \ + PER_LUA_BINDING(TerrainObject) \ + PER_LUA_BINDING(Deployment) \ + PER_LUA_BINDING(MovableObject) \ + /* Entity-Derived */ \ + PER_LUA_BINDING(SoundContainer) \ + PER_LUA_BINDING(PieSlice) \ + PER_LUA_BINDING(GlobalScript) \ + PER_LUA_BINDING(Emission) \ + PER_LUA_BINDING(LimbPath) \ + PER_LUA_BINDING(PieMenu) \ + PER_LUA_BINDING(Round) \ + PER_LUA_BINDING(Scene) \ + PER_LUA_BINDING(Scene::Area) \ + PER_LUA_BINDING(Material) \ + PER_LUA_BINDING(MetaPlayer) \ + PER_LUA_BINDING(SceneObject) \ + /* SceneLayer-Derived */ \ + PER_LUA_BINDING(SLBackground) \ + /* Base Classes */ \ + PER_LUA_BINDING(SoundSet) \ + PER_LUA_BINDING(Gib) \ + PER_LUA_BINDING(SceneLayer) \ + PER_LUA_BINDING(Entity) \ + /* ActivityLuaBindings */ \ + PER_LUA_BINDING(GameActivity) \ + PER_LUA_BINDING(Activity) \ + /* GUILuaBindings */ \ + PER_LUA_BINDING(BuyMenuGUI) \ + PER_LUA_BINDING(SceneEditorGUI) \ + PER_LUA_BINDING(GUIBanner) \ + /* PrimitiveLuaBindings */ \ + /* GraphicalPrimitive-Derived */ \ + PER_LUA_BINDING(LinePrimitive) \ + PER_LUA_BINDING(ArcPrimitive) \ + PER_LUA_BINDING(SplinePrimitive) \ + PER_LUA_BINDING(BoxPrimitive) \ + PER_LUA_BINDING(BoxFillPrimitive) \ + PER_LUA_BINDING(RoundedBoxPrimitive) \ + PER_LUA_BINDING(RoundedBoxFillPrimitive) \ + PER_LUA_BINDING(CirclePrimitive) \ + PER_LUA_BINDING(CircleFillPrimitive) \ + PER_LUA_BINDING(EllipsePrimitive) \ + PER_LUA_BINDING(EllipseFillPrimitive) \ + PER_LUA_BINDING(TrianglePrimitive) \ + PER_LUA_BINDING(TriangleFillPrimitive) \ + PER_LUA_BINDING(TextPrimitive) \ + PER_LUA_BINDING(BitmapPrimitive) \ + /* Base Classes */ \ + PER_LUA_BINDING(GraphicalPrimitive) \ + /* InputLuaBindings */ \ + PER_LUA_BINDING(InputDevice) \ + PER_LUA_BINDING(InputElements) \ + PER_LUA_BINDING(MouseButtons) \ + PER_LUA_BINDING(JoyButtons) \ + PER_LUA_BINDING(JoyDirections) \ + PER_LUA_BINDING(SDL_Scancode) \ + PER_LUA_BINDING(SDL_Keycode) \ + PER_LUA_BINDING(SDL_GameControllerButton) \ + PER_LUA_BINDING(SDL_GameControllerAxis) \ + /* MiscLuaBindings */ \ + PER_LUA_BINDING(AlarmEvent) \ + PER_LUA_BINDING(Directions) \ + PER_LUA_BINDING(DrawBlendMode) + #pragma region Lua Binding Registration Macros - /// - /// Convenience macro for declaring a binding register function. - /// - #define LuaBindingRegisterFunctionDeclarationForType(TYPE) \ - static luabind::scope Register##TYPE##LuaBindings() +/// +/// Convenience macro for declaring a binding register function. +/// +#define LuaBindingRegisterFunctionDeclarationForType(TYPE) \ + static luabind::scope Register##TYPE##LuaBindings() - /// - /// Convenience macro for defining a binding register function. - /// - #define LuaBindingRegisterFunctionDefinitionForType(OWNINGSCOPE, TYPE) \ - luabind::scope OWNINGSCOPE::Register##TYPE##LuaBindings() +/// +/// Convenience macro for defining a binding register function. +/// +#define LuaBindingRegisterFunctionDefinitionForType(OWNINGSCOPE, TYPE) \ + luabind::scope OWNINGSCOPE::Register##TYPE##LuaBindings() - /// - /// Convenience macro for a LuaBind scope definition of an abstract type. - /// - #define AbstractTypeLuaClassDefinition(TYPE, PARENTTYPE) \ - luabind::class_(#TYPE) \ - .property("ClassName", &TYPE::GetClassName) +/// +/// Convenience macro for a LuaBind scope definition of an abstract type. +/// +#define AbstractTypeLuaClassDefinition(TYPE, PARENTTYPE) \ + luabind::class_(#TYPE) \ + .property("ClassName", &TYPE::GetClassName) - /// - /// Convenience macro for a LuaBind scope definition of a concrete type. - /// - #define ConcreteTypeLuaClassDefinition(TYPE, PARENTTYPE) \ - luabind::class_(#TYPE) \ - .def("Clone", &LuaAdaptersEntityClone::Clone##TYPE, luabind::adopt(luabind::result)) \ - .property("ClassName", &TYPE::GetClassName) +/// +/// Convenience macro for a LuaBind scope definition of a concrete type. +/// +#define ConcreteTypeLuaClassDefinition(TYPE, PARENTTYPE) \ + luabind::class_(#TYPE) \ + .def("Clone", &LuaAdaptersEntityClone::Clone##TYPE, luabind::adopt(luabind::result)) \ + .property("ClassName", &TYPE::GetClassName) - /// - /// Convenience macro for calling a register function of a type. - /// - #define RegisterLuaBindingsOfType(OWNINGSCOPE, TYPE) \ - OWNINGSCOPE::Register##TYPE##LuaBindings() +/// +/// Convenience macro for calling a register function of a type. +/// +#define RegisterLuaBindingsOfType(OWNINGSCOPE, TYPE) \ + OWNINGSCOPE::Register##TYPE##LuaBindings() - /// - /// Convenience macro for calling a register function of an abstract type, along with registering global bindings for adapters relevant to the type. - /// - #define RegisterLuaBindingsOfAbstractType(OWNINGSCOPE, TYPE) \ - luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (TYPE *(*)(Entity *))&LuaAdaptersEntityCast::To##TYPE), \ - luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (const TYPE *(*)(const Entity *))&LuaAdaptersEntityCast::ToConst##TYPE), \ - luabind::def((std::string("Is") + std::string(#TYPE)).c_str(), (bool(*)(const Entity *))&LuaAdaptersEntityCast::Is##TYPE), \ - OWNINGSCOPE::Register##TYPE##LuaBindings() +/// +/// Convenience macro for calling a register function of an abstract type, along with registering global bindings for adapters relevant to the type. +/// +#define RegisterLuaBindingsOfAbstractType(OWNINGSCOPE, TYPE) \ + luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (TYPE * (*)(Entity*)) & LuaAdaptersEntityCast::To##TYPE), \ + luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (const TYPE* (*)(const Entity*)) & LuaAdaptersEntityCast::ToConst##TYPE), \ + luabind::def((std::string("Is") + std::string(#TYPE)).c_str(), (bool (*)(const Entity*)) & LuaAdaptersEntityCast::Is##TYPE), \ + OWNINGSCOPE::Register##TYPE##LuaBindings() - /// - /// Convenience macro for calling a register function of a concrete type, along with registering global bindings for adapters relevant to the type. - /// - #define RegisterLuaBindingsOfConcreteType(OWNINGSCOPE, TYPE) \ - luabind::def((std::string("Create") + std::string(#TYPE)).c_str(), (TYPE *(*)(std::string, std::string))&LuaAdaptersEntityCreate::Create##TYPE, luabind::adopt(luabind::result)), \ - luabind::def((std::string("Create") + std::string(#TYPE)).c_str(), (TYPE *(*)(std::string))&LuaAdaptersEntityCreate::Create##TYPE, luabind::adopt(luabind::result)), \ - luabind::def((std::string("Random") + std::string(#TYPE)).c_str(), (TYPE *(*)(std::string, int))&LuaAdaptersEntityCreate::Random##TYPE, luabind::adopt(luabind::result)), \ - luabind::def((std::string("Random") + std::string(#TYPE)).c_str(), (TYPE *(*)(std::string, std::string))&LuaAdaptersEntityCreate::Random##TYPE, luabind::adopt(luabind::result)), \ - luabind::def((std::string("Random") + std::string(#TYPE)).c_str(), (TYPE *(*)(std::string))&LuaAdaptersEntityCreate::Random##TYPE, luabind::adopt(luabind::result)), \ - luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (TYPE *(*)(Entity *))&LuaAdaptersEntityCast::To##TYPE), \ - luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (const TYPE *(*)(const Entity *))&LuaAdaptersEntityCast::ToConst##TYPE), \ - luabind::def((std::string("Is") + std::string(#TYPE)).c_str(), (bool(*)(const Entity *))&LuaAdaptersEntityCast::Is##TYPE), \ - OWNINGSCOPE::Register##TYPE##LuaBindings() +/// +/// Convenience macro for calling a register function of a concrete type, along with registering global bindings for adapters relevant to the type. +/// +#define RegisterLuaBindingsOfConcreteType(OWNINGSCOPE, TYPE) \ + luabind::def((std::string("Create") + std::string(#TYPE)).c_str(), (TYPE * (*)(std::string, std::string)) & LuaAdaptersEntityCreate::Create##TYPE, luabind::adopt(luabind::result)), \ + luabind::def((std::string("Create") + std::string(#TYPE)).c_str(), (TYPE * (*)(std::string)) & LuaAdaptersEntityCreate::Create##TYPE, luabind::adopt(luabind::result)), \ + luabind::def((std::string("Random") + std::string(#TYPE)).c_str(), (TYPE * (*)(std::string, int)) & LuaAdaptersEntityCreate::Random##TYPE, luabind::adopt(luabind::result)), \ + luabind::def((std::string("Random") + std::string(#TYPE)).c_str(), (TYPE * (*)(std::string, std::string)) & LuaAdaptersEntityCreate::Random##TYPE, luabind::adopt(luabind::result)), \ + luabind::def((std::string("Random") + std::string(#TYPE)).c_str(), (TYPE * (*)(std::string)) & LuaAdaptersEntityCreate::Random##TYPE, luabind::adopt(luabind::result)), \ + luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (TYPE * (*)(Entity*)) & LuaAdaptersEntityCast::To##TYPE), \ + luabind::def((std::string("To") + std::string(#TYPE)).c_str(), (const TYPE* (*)(const Entity*)) & LuaAdaptersEntityCast::ToConst##TYPE), \ + luabind::def((std::string("Is") + std::string(#TYPE)).c_str(), (bool (*)(const Entity*)) & LuaAdaptersEntityCast::Is##TYPE), \ + OWNINGSCOPE::Register##TYPE##LuaBindings() #pragma endregion /// @@ -332,5 +332,5 @@ namespace RTE { LuaBindingRegisterFunctionDeclarationForType(Directions); LuaBindingRegisterFunctionDeclarationForType(DrawBlendMode); }; -} +} // namespace RTE #endif diff --git a/Source/Lua/LuaBindingsActivities.cpp b/Source/Lua/LuaBindingsActivities.cpp index aef4b0fd9..e6de5cd4b 100644 --- a/Source/Lua/LuaBindingsActivities.cpp +++ b/Source/Lua/LuaBindingsActivities.cpp @@ -4,191 +4,177 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ActivityLuaBindings, Activity) { return AbstractTypeLuaClassDefinition(Activity, Entity) - .def(luabind::constructor<>()) + .def(luabind::constructor<>()) - .property("Description", &Activity::GetDescription) - .property("InCampaignStage", &Activity::GetInCampaignStage, &Activity::SetInCampaignStage) - .property("ActivityState", &Activity::GetActivityState, &Activity::SetActivityState) - .property("AllowsUserSaving", &Activity::GetAllowsUserSaving, &Activity::SetAllowsUserSaving) - .property("SceneName", &Activity::GetSceneName, &Activity::SetSceneName) - .property("PlayerCount", &Activity::GetPlayerCount) - .property("HumanCount", &Activity::GetHumanCount) - .property("TeamCount", &Activity::GetTeamCount) - .property("Difficulty", &Activity::GetDifficulty, &Activity::SetDifficulty) + .property("Description", &Activity::GetDescription) + .property("InCampaignStage", &Activity::GetInCampaignStage, &Activity::SetInCampaignStage) + .property("ActivityState", &Activity::GetActivityState, &Activity::SetActivityState) + .property("AllowsUserSaving", &Activity::GetAllowsUserSaving, &Activity::SetAllowsUserSaving) + .property("SceneName", &Activity::GetSceneName, &Activity::SetSceneName) + .property("PlayerCount", &Activity::GetPlayerCount) + .property("HumanCount", &Activity::GetHumanCount) + .property("TeamCount", &Activity::GetTeamCount) + .property("Difficulty", &Activity::GetDifficulty, &Activity::SetDifficulty) - .def("DeactivatePlayer", &Activity::DeactivatePlayer) - .def("PlayerActive", &Activity::PlayerActive) - .def("PlayerHuman", &Activity::PlayerHuman) - .def("TeamActive", &Activity::TeamActive) - .def("GetTeamOfPlayer", &Activity::GetTeamOfPlayer) - .def("SetTeamOfPlayer", &Activity::SetTeamOfPlayer) - .def("PlayersInTeamCount", &Activity::PlayersInTeamCount) - .def("ScreenOfPlayer", &Activity::ScreenOfPlayer) - .def("GetViewState", &Activity::GetViewState) - .def("SetViewState", &Activity::SetViewState) - .def("GetPlayerBrain", &Activity::GetPlayerBrain) - .def("SetPlayerBrain", &Activity::SetPlayerBrain) - .def("PlayerHadBrain", &Activity::PlayerHadBrain) - .def("SetPlayerHadBrain", &Activity::SetPlayerHadBrain) - .def("SetBrainEvacuated", &Activity::SetBrainEvacuated) - .def("BrainWasEvacuated", &Activity::BrainWasEvacuated) - .def("IsAssignedBrain", &Activity::IsAssignedBrain) - .def("IsBrainOfWhichPlayer", &Activity::IsBrainOfWhichPlayer) - .def("IsOtherPlayerBrain", &Activity::IsOtherPlayerBrain) - .def("HumanBrainCount", &Activity::HumanBrainCount) - .def("AIBrainCount", &Activity::AIBrainCount) - .def("GetControlledActor", &Activity::GetControlledActor) - .def("GetPlayerController", &Activity::GetPlayerController) - .def("SetTeamFunds", &Activity::SetTeamFunds) - .def("GetTeamFunds", &Activity::GetTeamFunds) - .def("SetTeamAISkill", &Activity::SetTeamAISkill) - .def("GetTeamAISkill", &Activity::GetTeamAISkill) - .def("ChangeTeamFunds", &Activity::ChangeTeamFunds) - .def("TeamFundsChanged", &Activity::TeamFundsChanged) - .def("ReportDeath", &Activity::ReportDeath) - .def("GetTeamDeathCount", &Activity::GetTeamDeathCount) - .def("IsRunning", &Activity::IsRunning) - .def("IsPaused", &Activity::IsPaused) - .def("IsOver", &Activity::IsOver) - .def("SwitchToActor", &Activity::SwitchToActor) - .def("SwitchToNextActor", &Activity::SwitchToNextActor) - .def("SwitchToPrevActor", &Activity::SwitchToPrevActor) - .def("IsHumanTeam", &Activity::IsHumanTeam) - .def("ResetMessageTimer", &Activity::ResetMessageTimer) - .def("SaveString", &Activity::SaveString) - .def("LoadString", &Activity::LoadString) - .def("SaveNumber", &Activity::SaveNumber) - .def("LoadNumber", &Activity::LoadNumber) - .def("SendMessage", &LuaAdaptersActivity::SendMessage1) - .def("SendMessage", &LuaAdaptersActivity::SendMessage2) + .def("DeactivatePlayer", &Activity::DeactivatePlayer) + .def("PlayerActive", &Activity::PlayerActive) + .def("PlayerHuman", &Activity::PlayerHuman) + .def("TeamActive", &Activity::TeamActive) + .def("GetTeamOfPlayer", &Activity::GetTeamOfPlayer) + .def("SetTeamOfPlayer", &Activity::SetTeamOfPlayer) + .def("PlayersInTeamCount", &Activity::PlayersInTeamCount) + .def("ScreenOfPlayer", &Activity::ScreenOfPlayer) + .def("GetViewState", &Activity::GetViewState) + .def("SetViewState", &Activity::SetViewState) + .def("GetPlayerBrain", &Activity::GetPlayerBrain) + .def("SetPlayerBrain", &Activity::SetPlayerBrain) + .def("PlayerHadBrain", &Activity::PlayerHadBrain) + .def("SetPlayerHadBrain", &Activity::SetPlayerHadBrain) + .def("SetBrainEvacuated", &Activity::SetBrainEvacuated) + .def("BrainWasEvacuated", &Activity::BrainWasEvacuated) + .def("IsAssignedBrain", &Activity::IsAssignedBrain) + .def("IsBrainOfWhichPlayer", &Activity::IsBrainOfWhichPlayer) + .def("IsOtherPlayerBrain", &Activity::IsOtherPlayerBrain) + .def("HumanBrainCount", &Activity::HumanBrainCount) + .def("AIBrainCount", &Activity::AIBrainCount) + .def("GetControlledActor", &Activity::GetControlledActor) + .def("GetPlayerController", &Activity::GetPlayerController) + .def("SetTeamFunds", &Activity::SetTeamFunds) + .def("GetTeamFunds", &Activity::GetTeamFunds) + .def("SetTeamAISkill", &Activity::SetTeamAISkill) + .def("GetTeamAISkill", &Activity::GetTeamAISkill) + .def("ChangeTeamFunds", &Activity::ChangeTeamFunds) + .def("TeamFundsChanged", &Activity::TeamFundsChanged) + .def("ReportDeath", &Activity::ReportDeath) + .def("GetTeamDeathCount", &Activity::GetTeamDeathCount) + .def("IsRunning", &Activity::IsRunning) + .def("IsPaused", &Activity::IsPaused) + .def("IsOver", &Activity::IsOver) + .def("SwitchToActor", &Activity::SwitchToActor) + .def("SwitchToNextActor", &Activity::SwitchToNextActor) + .def("SwitchToPrevActor", &Activity::SwitchToPrevActor) + .def("IsHumanTeam", &Activity::IsHumanTeam) + .def("ResetMessageTimer", &Activity::ResetMessageTimer) + .def("SaveString", &Activity::SaveString) + .def("LoadString", &Activity::LoadString) + .def("SaveNumber", &Activity::SaveNumber) + .def("LoadNumber", &Activity::LoadNumber) + .def("SendMessage", &LuaAdaptersActivity::SendMessage1) + .def("SendMessage", &LuaAdaptersActivity::SendMessage2) - .enum_("Players")[ - luabind::value("PLAYER_NONE", Players::NoPlayer), - luabind::value("PLAYER_1", Players::PlayerOne), - luabind::value("PLAYER_2", Players::PlayerTwo), - luabind::value("PLAYER_3", Players::PlayerThree), - luabind::value("PLAYER_4", Players::PlayerFour), - luabind::value("MAXPLAYERCOUNT", Players::MaxPlayerCount) - ] - .enum_("ActivityState")[ - luabind::value("NOACTIVITY", Activity::ActivityState::NoActivity), - luabind::value("NOTSTARTED", Activity::ActivityState::NotStarted), - luabind::value("STARTING", Activity::ActivityState::Starting), - luabind::value("EDITING", Activity::ActivityState::Editing), - luabind::value("PREGAME", Activity::ActivityState::PreGame), - luabind::value("RUNNING", Activity::ActivityState::Running), - luabind::value("INERROR", Activity::ActivityState::HasError), - luabind::value("OVER", Activity::ActivityState::Over) - ] - .enum_("Team")[ - luabind::value("NOTEAM", Activity::Teams::NoTeam), - luabind::value("TEAM_1", Activity::Teams::TeamOne), - luabind::value("TEAM_2", Activity::Teams::TeamTwo), - luabind::value("TEAM_3", Activity::Teams::TeamThree), - luabind::value("TEAM_4", Activity::Teams::TeamFour), - luabind::value("MAXTEAMCOUNT", Activity::Teams::MaxTeamCount) - ] - .enum_("ViewState")[ - luabind::value("NORMAL", Activity::ViewState::Normal), - luabind::value("OBSERVE", Activity::ViewState::Observe), - luabind::value("DEATHWATCH", Activity::ViewState::DeathWatch), - luabind::value("ACTORSELECT", Activity::ViewState::ActorSelect), - luabind::value("AISENTRYPOINT", Activity::ViewState::AISentryPoint), - luabind::value("AIPATROLPOINTS", Activity::ViewState::AIPatrolPoints), - luabind::value("AIGOLDDIGPOINT", Activity::ViewState::AIGoldDigPoint), - luabind::value("AIGOTOPOINT", Activity::ViewState::AIGoToPoint), - luabind::value("LZSELECT", Activity::ViewState::LandingZoneSelect) - ] - .enum_("DifficultySetting")[ - luabind::value("MINDIFFICULTY", Activity::DifficultySetting::MinDifficulty), - luabind::value("CAKEDIFFICULTY", Activity::DifficultySetting::CakeDifficulty), - luabind::value("EASYDIFFICULTY", Activity::DifficultySetting::EasyDifficulty), - luabind::value("MEDIUMDIFFICULTY", Activity::DifficultySetting::MediumDifficulty), - luabind::value("HARDDIFFICULTY", Activity::DifficultySetting::HardDifficulty), - luabind::value("NUTSDIFFICULTY", Activity::DifficultySetting::NutsDifficulty), - luabind::value("MAXDIFFICULTY", Activity::DifficultySetting::MaxDifficulty) - ] - .enum_("AISkillSetting")[ - luabind::value("MINSKILL", Activity::AISkillSetting::MinSkill), - luabind::value("INFERIORSKILL", Activity::AISkillSetting::InferiorSkill), - luabind::value("DEFAULTSKILL", Activity::AISkillSetting::DefaultSkill), - luabind::value("AVERAGESKILL", Activity::AISkillSetting::AverageSkill), - luabind::value("GOODSKILL", Activity::AISkillSetting::GoodSkill), - luabind::value("UNFAIRSKILL", Activity::AISkillSetting::UnfairSkill) - ]; + .enum_("Players")[luabind::value("PLAYER_NONE", Players::NoPlayer), + luabind::value("PLAYER_1", Players::PlayerOne), + luabind::value("PLAYER_2", Players::PlayerTwo), + luabind::value("PLAYER_3", Players::PlayerThree), + luabind::value("PLAYER_4", Players::PlayerFour), + luabind::value("MAXPLAYERCOUNT", Players::MaxPlayerCount)] + .enum_("ActivityState")[luabind::value("NOACTIVITY", Activity::ActivityState::NoActivity), + luabind::value("NOTSTARTED", Activity::ActivityState::NotStarted), + luabind::value("STARTING", Activity::ActivityState::Starting), + luabind::value("EDITING", Activity::ActivityState::Editing), + luabind::value("PREGAME", Activity::ActivityState::PreGame), + luabind::value("RUNNING", Activity::ActivityState::Running), + luabind::value("INERROR", Activity::ActivityState::HasError), + luabind::value("OVER", Activity::ActivityState::Over)] + .enum_("Team")[luabind::value("NOTEAM", Activity::Teams::NoTeam), + luabind::value("TEAM_1", Activity::Teams::TeamOne), + luabind::value("TEAM_2", Activity::Teams::TeamTwo), + luabind::value("TEAM_3", Activity::Teams::TeamThree), + luabind::value("TEAM_4", Activity::Teams::TeamFour), + luabind::value("MAXTEAMCOUNT", Activity::Teams::MaxTeamCount)] + .enum_("ViewState")[luabind::value("NORMAL", Activity::ViewState::Normal), + luabind::value("OBSERVE", Activity::ViewState::Observe), + luabind::value("DEATHWATCH", Activity::ViewState::DeathWatch), + luabind::value("ACTORSELECT", Activity::ViewState::ActorSelect), + luabind::value("AISENTRYPOINT", Activity::ViewState::AISentryPoint), + luabind::value("AIPATROLPOINTS", Activity::ViewState::AIPatrolPoints), + luabind::value("AIGOLDDIGPOINT", Activity::ViewState::AIGoldDigPoint), + luabind::value("AIGOTOPOINT", Activity::ViewState::AIGoToPoint), + luabind::value("LZSELECT", Activity::ViewState::LandingZoneSelect)] + .enum_("DifficultySetting")[luabind::value("MINDIFFICULTY", Activity::DifficultySetting::MinDifficulty), + luabind::value("CAKEDIFFICULTY", Activity::DifficultySetting::CakeDifficulty), + luabind::value("EASYDIFFICULTY", Activity::DifficultySetting::EasyDifficulty), + luabind::value("MEDIUMDIFFICULTY", Activity::DifficultySetting::MediumDifficulty), + luabind::value("HARDDIFFICULTY", Activity::DifficultySetting::HardDifficulty), + luabind::value("NUTSDIFFICULTY", Activity::DifficultySetting::NutsDifficulty), + luabind::value("MAXDIFFICULTY", Activity::DifficultySetting::MaxDifficulty)] + .enum_("AISkillSetting")[luabind::value("MINSKILL", Activity::AISkillSetting::MinSkill), + luabind::value("INFERIORSKILL", Activity::AISkillSetting::InferiorSkill), + luabind::value("DEFAULTSKILL", Activity::AISkillSetting::DefaultSkill), + luabind::value("AVERAGESKILL", Activity::AISkillSetting::AverageSkill), + luabind::value("GOODSKILL", Activity::AISkillSetting::GoodSkill), + luabind::value("UNFAIRSKILL", Activity::AISkillSetting::UnfairSkill)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ActivityLuaBindings, GameActivity) { return luabind::class_("GameActivity") - .def(luabind::constructor<>()) + .def(luabind::constructor<>()) - .property("WinnerTeam", &GameActivity::GetWinnerTeam, &GameActivity::SetWinnerTeam) - .property("CPUTeam", &GameActivity::GetCPUTeam, &GameActivity::SetCPUTeam) - .property("DeliveryDelay", &GameActivity::GetDeliveryDelay, &GameActivity::SetDeliveryDelay) - .property("BuyMenuEnabled", &GameActivity::GetBuyMenuEnabled, &GameActivity::SetBuyMenuEnabled) - .property("CraftsOrbitAtTheEdge", &GameActivity::GetCraftOrbitAtTheEdge, &GameActivity::SetCraftOrbitAtTheEdge) + .property("WinnerTeam", &GameActivity::GetWinnerTeam, &GameActivity::SetWinnerTeam) + .property("CPUTeam", &GameActivity::GetCPUTeam, &GameActivity::SetCPUTeam) + .property("DeliveryDelay", &GameActivity::GetDeliveryDelay, &GameActivity::SetDeliveryDelay) + .property("BuyMenuEnabled", &GameActivity::GetBuyMenuEnabled, &GameActivity::SetBuyMenuEnabled) + .property("CraftsOrbitAtTheEdge", &GameActivity::GetCraftOrbitAtTheEdge, &GameActivity::SetCraftOrbitAtTheEdge) - //.def_readwrite("ActorCursor", &GameActivity::m_ActorCursor) - .def_readwrite("CursorTimer", &GameActivity::m_CursorTimer) - .def_readwrite("GameTimer", &GameActivity::m_GameTimer) - .def_readwrite("GameOverTimer", &GameActivity::m_GameOverTimer) - .def_readwrite("GameOverPeriod", &GameActivity::m_GameOverPeriod) + //.def_readwrite("ActorCursor", &GameActivity::m_ActorCursor) + .def_readwrite("CursorTimer", &GameActivity::m_CursorTimer) + .def_readwrite("GameTimer", &GameActivity::m_GameTimer) + .def_readwrite("GameOverTimer", &GameActivity::m_GameOverTimer) + .def_readwrite("GameOverPeriod", &GameActivity::m_GameOverPeriod) - .def("SetObservationTarget", &GameActivity::SetObservationTarget) - .def("SetDeathViewTarget", &GameActivity::SetDeathViewTarget) - .def("SetLandingZone", &GameActivity::SetLandingZone) - .def("GetLandingZone", &GameActivity::GetLandingZone) - .def("SetActorSelectCursor", &GameActivity::SetActorSelectCursor) - .def("GetBuyGUI", &GameActivity::GetBuyGUI) - .def("GetEditorGUI", &GameActivity::GetEditorGUI) - .def("LockControlledActor", &GameActivity::LockControlledActor) - .def("OtherTeam", &GameActivity::OtherTeam) - .def("OneOrNoneTeamsLeft", &GameActivity::OneOrNoneTeamsLeft) - .def("WhichTeamLeft", &GameActivity::WhichTeamLeft) - .def("NoTeamLeft", &GameActivity::NoTeamLeft) - .def("OnlyOneTeamLeft", &GameActivity::OneOrNoneTeamsLeft) // Backwards compat - .def("GetBanner", &GameActivity::GetBanner) - .def("SetLZArea", &GameActivity::SetLZArea) - .def("GetLZArea", &GameActivity::GetLZArea) - .def("SetBrainLZWidth", &GameActivity::SetBrainLZWidth) - .def("GetBrainLZWidth", &GameActivity::GetBrainLZWidth) - .def("GetActiveCPUTeamCount", &GameActivity::GetActiveCPUTeamCount) - .def("GetActiveHumanTeamCount", &GameActivity::GetActiveHumanTeamCount) - .def("AddObjectivePoint", &GameActivity::AddObjectivePoint) - .def("YSortObjectivePoints", &GameActivity::YSortObjectivePoints) - .def("ClearObjectivePoints", &GameActivity::ClearObjectivePoints) - .def("AddOverridePurchase", &GameActivity::AddOverridePurchase) - .def("SetOverridePurchaseList", (int (GameActivity::*)(const Loadout *, int))&GameActivity::SetOverridePurchaseList) - .def("SetOverridePurchaseList", (int (GameActivity::*)(std::string, int))&GameActivity::SetOverridePurchaseList) - .def("ClearOverridePurchase", &GameActivity::ClearOverridePurchase) - .def("CreateDelivery", (bool (GameActivity::*)(int))&GameActivity::CreateDelivery) - .def("CreateDelivery", (bool (GameActivity::*)(int, int))&GameActivity::CreateDelivery) - .def("CreateDelivery", (bool (GameActivity::*)(int, int, Vector&))&GameActivity::CreateDelivery) - .def("CreateDelivery", (bool (GameActivity::*)(int, int, Actor*))&GameActivity::CreateDelivery) - .def("GetDeliveryCount", &GameActivity::GetDeliveryCount) - .def("GetTeamTech", &GameActivity::GetTeamTech) - .def("SetTeamTech", &GameActivity::SetTeamTech) - .def("GetCrabToHumanSpawnRatio", &GameActivity::GetCrabToHumanSpawnRatio) - .def("TeamIsCPU", &GameActivity::TeamIsCPU) - .def("GetStartingGold", &GameActivity::GetStartingGold) - .def("GetFogOfWarEnabled", &GameActivity::GetFogOfWarEnabled) - .def("UpdateEditing", &GameActivity::UpdateEditing) - .def("DisableAIs", &GameActivity::DisableAIs) - .def("InitAIs", &GameActivity::InitAIs) + .def("SetObservationTarget", &GameActivity::SetObservationTarget) + .def("SetDeathViewTarget", &GameActivity::SetDeathViewTarget) + .def("SetLandingZone", &GameActivity::SetLandingZone) + .def("GetLandingZone", &GameActivity::GetLandingZone) + .def("SetActorSelectCursor", &GameActivity::SetActorSelectCursor) + .def("GetBuyGUI", &GameActivity::GetBuyGUI) + .def("GetEditorGUI", &GameActivity::GetEditorGUI) + .def("LockControlledActor", &GameActivity::LockControlledActor) + .def("OtherTeam", &GameActivity::OtherTeam) + .def("OneOrNoneTeamsLeft", &GameActivity::OneOrNoneTeamsLeft) + .def("WhichTeamLeft", &GameActivity::WhichTeamLeft) + .def("NoTeamLeft", &GameActivity::NoTeamLeft) + .def("OnlyOneTeamLeft", &GameActivity::OneOrNoneTeamsLeft) // Backwards compat + .def("GetBanner", &GameActivity::GetBanner) + .def("SetLZArea", &GameActivity::SetLZArea) + .def("GetLZArea", &GameActivity::GetLZArea) + .def("SetBrainLZWidth", &GameActivity::SetBrainLZWidth) + .def("GetBrainLZWidth", &GameActivity::GetBrainLZWidth) + .def("GetActiveCPUTeamCount", &GameActivity::GetActiveCPUTeamCount) + .def("GetActiveHumanTeamCount", &GameActivity::GetActiveHumanTeamCount) + .def("AddObjectivePoint", &GameActivity::AddObjectivePoint) + .def("YSortObjectivePoints", &GameActivity::YSortObjectivePoints) + .def("ClearObjectivePoints", &GameActivity::ClearObjectivePoints) + .def("AddOverridePurchase", &GameActivity::AddOverridePurchase) + .def("SetOverridePurchaseList", (int(GameActivity::*)(const Loadout*, int)) & GameActivity::SetOverridePurchaseList) + .def("SetOverridePurchaseList", (int(GameActivity::*)(std::string, int)) & GameActivity::SetOverridePurchaseList) + .def("ClearOverridePurchase", &GameActivity::ClearOverridePurchase) + .def("CreateDelivery", (bool(GameActivity::*)(int)) & GameActivity::CreateDelivery) + .def("CreateDelivery", (bool(GameActivity::*)(int, int)) & GameActivity::CreateDelivery) + .def("CreateDelivery", (bool(GameActivity::*)(int, int, Vector&)) & GameActivity::CreateDelivery) + .def("CreateDelivery", (bool(GameActivity::*)(int, int, Actor*)) & GameActivity::CreateDelivery) + .def("GetDeliveryCount", &GameActivity::GetDeliveryCount) + .def("GetTeamTech", &GameActivity::GetTeamTech) + .def("SetTeamTech", &GameActivity::SetTeamTech) + .def("GetCrabToHumanSpawnRatio", &GameActivity::GetCrabToHumanSpawnRatio) + .def("TeamIsCPU", &GameActivity::TeamIsCPU) + .def("GetStartingGold", &GameActivity::GetStartingGold) + .def("GetFogOfWarEnabled", &GameActivity::GetFogOfWarEnabled) + .def("UpdateEditing", &GameActivity::UpdateEditing) + .def("DisableAIs", &GameActivity::DisableAIs) + .def("InitAIs", &GameActivity::InitAIs) - .enum_("ObjectiveArrowDir")[ - luabind::value("ARROWDOWN", GameActivity::ObjectiveArrowDir::ARROWDOWN), - luabind::value("ARROWLEFT", GameActivity::ObjectiveArrowDir::ARROWLEFT), - luabind::value("ARROWRIGHT", GameActivity::ObjectiveArrowDir::ARROWRIGHT), - luabind::value("ARROWUP", GameActivity::ObjectiveArrowDir::ARROWUP) - ]; + .enum_("ObjectiveArrowDir")[luabind::value("ARROWDOWN", GameActivity::ObjectiveArrowDir::ARROWDOWN), + luabind::value("ARROWLEFT", GameActivity::ObjectiveArrowDir::ARROWLEFT), + luabind::value("ARROWRIGHT", GameActivity::ObjectiveArrowDir::ARROWRIGHT), + luabind::value("ARROWUP", GameActivity::ObjectiveArrowDir::ARROWUP)]; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuaBindingsEntities.cpp b/Source/Lua/LuaBindingsEntities.cpp index 1c1a04d09..48f9dd7ad 100644 --- a/Source/Lua/LuaBindingsEntities.cpp +++ b/Source/Lua/LuaBindingsEntities.cpp @@ -4,1501 +4,1429 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Entity) { return luabind::class_("Entity") - .def(luabind::tostring(luabind::const_self)) - - .property("ClassName", &Entity::GetClassName) - .property("PresetName", &Entity::GetPresetName, &LuaAdaptersEntity::SetPresetName) - .property("Description", &Entity::GetDescription, &Entity::SetDescription) - .property("IsOriginalPreset", &Entity::IsOriginalPreset) - .property("ModuleID", &Entity::GetModuleID) - .property("ModuleName", &Entity::GetModuleName) - .property("RandomWeight", &Entity::GetRandomWeight) - .property("Groups", &Entity::GetGroups, luabind::return_stl_iterator) - - .def("Clone", &LuaAdaptersEntityClone::CloneEntity) - .def("Reset", &Entity::Reset) - .def("GetModuleAndPresetName", &Entity::GetModuleAndPresetName) - .def("AddToGroup", &Entity::AddToGroup) - .def("RemoveFromGroup", &Entity::RemoveFromGroup) - .def("IsInGroup", &Entity::IsInGroup); + .def(luabind::tostring(luabind::const_self)) + + .property("ClassName", &Entity::GetClassName) + .property("PresetName", &Entity::GetPresetName, &LuaAdaptersEntity::SetPresetName) + .property("Description", &Entity::GetDescription, &Entity::SetDescription) + .property("IsOriginalPreset", &Entity::IsOriginalPreset) + .property("ModuleID", &Entity::GetModuleID) + .property("ModuleName", &Entity::GetModuleName) + .property("RandomWeight", &Entity::GetRandomWeight) + .property("Groups", &Entity::GetGroups, luabind::return_stl_iterator) + + .def("Clone", &LuaAdaptersEntityClone::CloneEntity) + .def("Reset", &Entity::Reset) + .def("GetModuleAndPresetName", &Entity::GetModuleAndPresetName) + .def("AddToGroup", &Entity::AddToGroup) + .def("RemoveFromGroup", &Entity::RemoveFromGroup) + .def("IsInGroup", &Entity::IsInGroup); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, ACDropShip) { return ConcreteTypeLuaClassDefinition(ACDropShip, ACraft) - .property("RightEngine", &ACDropShip::GetRightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetRightThruster) - .property("LeftEngine", &ACDropShip::GetLeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetLeftThruster) - .property("RightThruster", &ACDropShip::GetURightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetURightThruster) - .property("LeftThruster", &ACDropShip::GetULeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetULeftThruster) - .property("RightHatch", &ACDropShip::GetRightHatch, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetRightHatch) - .property("LeftHatch", &ACDropShip::GetLeftHatch, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetLeftHatch) - .property("MaxEngineAngle", &ACDropShip::GetMaxEngineAngle, &ACDropShip::SetMaxEngineAngle) - .property("LateralControlSpeed", &ACDropShip::GetLateralControlSpeed, &ACDropShip::SetLateralControlSpeed) - .property("LateralControl", &ACDropShip::GetLateralControl) - .property("HoverHeightModifier", &ACDropShip::GetHoverHeightModifier, &ACDropShip::SetHoverHeightModifier) - - .def("DetectObstacle", &ACDropShip::DetectObstacle) - .def("GetAltitude", &ACDropShip::GetAltitude); + .property("RightEngine", &ACDropShip::GetRightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetRightThruster) + .property("LeftEngine", &ACDropShip::GetLeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetLeftThruster) + .property("RightThruster", &ACDropShip::GetURightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetURightThruster) + .property("LeftThruster", &ACDropShip::GetULeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetULeftThruster) + .property("RightHatch", &ACDropShip::GetRightHatch, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetRightHatch) + .property("LeftHatch", &ACDropShip::GetLeftHatch, &LuaAdaptersPropertyOwnershipSafetyFaker::ACDropShipSetLeftHatch) + .property("MaxEngineAngle", &ACDropShip::GetMaxEngineAngle, &ACDropShip::SetMaxEngineAngle) + .property("LateralControlSpeed", &ACDropShip::GetLateralControlSpeed, &ACDropShip::SetLateralControlSpeed) + .property("LateralControl", &ACDropShip::GetLateralControl) + .property("HoverHeightModifier", &ACDropShip::GetHoverHeightModifier, &ACDropShip::SetHoverHeightModifier) + + .def("DetectObstacle", &ACDropShip::DetectObstacle) + .def("GetAltitude", &ACDropShip::GetAltitude); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, ACrab) { return ConcreteTypeLuaClassDefinition(ACrab, Actor) - .def(luabind::constructor<>()) - - .property("Turret", &ACrab::GetTurret, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetTurret) - .property("Jetpack", &ACrab::GetJetpack, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetJetpack) - .property("LeftFGLeg", &ACrab::GetLeftFGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetLeftFGLeg) - .property("LeftBGLeg", &ACrab::GetLeftBGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetLeftBGLeg) - .property("RightFGLeg", &ACrab::GetRightFGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetRightFGLeg) - .property("RightBGLeg", &ACrab::GetRightBGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetRightBGLeg) - .property("StrideSound", &ACrab::GetStrideSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetStrideSound) - .property("StrideFrame", &ACrab::StrideFrame) - .property("EquippedItem", &ACrab::GetEquippedItem) - .property("FirearmIsReady", &ACrab::FirearmIsReady) - .property("FirearmIsEmpty", &ACrab::FirearmIsEmpty) - .property("FirearmNeedsReload", &ACrab::FirearmNeedsReload) - .property("FirearmIsSemiAuto", &ACrab::FirearmIsSemiAuto) - .property("FirearmActivationDelay", &ACrab::FirearmActivationDelay) - .property("LimbPathPushForce", &ACrab::GetLimbPathPushForce, &ACrab::SetLimbPathPushForce) - .property("AimRangeUpperLimit", &ACrab::GetAimRangeUpperLimit, &ACrab::SetAimRangeUpperLimit) - .property("AimRangeLowerLimit", &ACrab::GetAimRangeLowerLimit, &ACrab::SetAimRangeLowerLimit) - - .def("ReloadFirearms", &ACrab::ReloadFirearms) - .def("IsWithinRange", &ACrab::IsWithinRange) - .def("Look", &ACrab::Look) - .def("LookForMOs", &ACrab::LookForMOs) - .def("GetLimbPath", &ACrab::GetLimbPath) - .def("GetLimbPathSpeed", &ACrab::GetLimbPathSpeed) - .def("SetLimbPathSpeed", &ACrab::SetLimbPathSpeed) - - .enum_("Side")[ - luabind::value("LEFTSIDE", ACrab::Side::LEFTSIDE), - luabind::value("RIGHTSIDE", ACrab::Side::RIGHTSIDE), - luabind::value("SIDECOUNT", ACrab::Side::SIDECOUNT) - ] - .enum_("Layer")[ - luabind::value("FGROUND", ACrab::Layer::FGROUND), - luabind::value("BGROUND", ACrab::Layer::BGROUND) - ] - .enum_("DeviceHandlingState")[ - luabind::value("STILL", ACrab::DeviceHandlingState::STILL), - luabind::value("POINTING", ACrab::DeviceHandlingState::POINTING), - luabind::value("SCANNING", ACrab::DeviceHandlingState::SCANNING), - luabind::value("AIMING", ACrab::DeviceHandlingState::AIMING), - luabind::value("FIRING", ACrab::DeviceHandlingState::FIRING), - luabind::value("THROWING", ACrab::DeviceHandlingState::THROWING), - luabind::value("DIGGING", ACrab::DeviceHandlingState::DIGGING) - ] - .enum_("SweepState")[ - luabind::value("NOSWEEP", ACrab::SweepState::NOSWEEP), - luabind::value("SWEEPINGUP", ACrab::SweepState::SWEEPINGUP), - luabind::value("SWEEPUPPAUSE", ACrab::SweepState::SWEEPUPPAUSE), - luabind::value("SWEEPINGDOWN", ACrab::SweepState::SWEEPINGDOWN), - luabind::value("SWEEPDOWNPAUSE", ACrab::SweepState::SWEEPDOWNPAUSE) - ] - .enum_("DigState")[ - luabind::value("NOTDIGGING", ACrab::DigState::NOTDIGGING), - luabind::value("PREDIG", ACrab::DigState::PREDIG), - luabind::value("STARTDIG", ACrab::DigState::STARTDIG), - luabind::value("TUNNELING", ACrab::DigState::TUNNELING), - luabind::value("FINISHINGDIG", ACrab::DigState::FINISHINGDIG), - luabind::value("PAUSEDIGGER", ACrab::DigState::PAUSEDIGGER) - ] - .enum_("JumpState")[ - luabind::value("NOTJUMPING", ACrab::JumpState::NOTJUMPING), - luabind::value("FORWARDJUMP", ACrab::JumpState::FORWARDJUMP), - luabind::value("PREJUMP", ACrab::JumpState::PREUPJUMP), - luabind::value("UPJUMP", ACrab::JumpState::UPJUMP), - luabind::value("APEXJUMP", ACrab::JumpState::APEXJUMP), - luabind::value("LANDJUMP", ACrab::JumpState::LANDJUMP) - ]; + .def(luabind::constructor<>()) + + .property("Turret", &ACrab::GetTurret, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetTurret) + .property("Jetpack", &ACrab::GetJetpack, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetJetpack) + .property("LeftFGLeg", &ACrab::GetLeftFGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetLeftFGLeg) + .property("LeftBGLeg", &ACrab::GetLeftBGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetLeftBGLeg) + .property("RightFGLeg", &ACrab::GetRightFGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetRightFGLeg) + .property("RightBGLeg", &ACrab::GetRightBGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetRightBGLeg) + .property("StrideSound", &ACrab::GetStrideSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACrabSetStrideSound) + .property("StrideFrame", &ACrab::StrideFrame) + .property("EquippedItem", &ACrab::GetEquippedItem) + .property("FirearmIsReady", &ACrab::FirearmIsReady) + .property("FirearmIsEmpty", &ACrab::FirearmIsEmpty) + .property("FirearmNeedsReload", &ACrab::FirearmNeedsReload) + .property("FirearmIsSemiAuto", &ACrab::FirearmIsSemiAuto) + .property("FirearmActivationDelay", &ACrab::FirearmActivationDelay) + .property("LimbPathPushForce", &ACrab::GetLimbPathPushForce, &ACrab::SetLimbPathPushForce) + .property("AimRangeUpperLimit", &ACrab::GetAimRangeUpperLimit, &ACrab::SetAimRangeUpperLimit) + .property("AimRangeLowerLimit", &ACrab::GetAimRangeLowerLimit, &ACrab::SetAimRangeLowerLimit) + + .def("ReloadFirearms", &ACrab::ReloadFirearms) + .def("IsWithinRange", &ACrab::IsWithinRange) + .def("Look", &ACrab::Look) + .def("LookForMOs", &ACrab::LookForMOs) + .def("GetLimbPath", &ACrab::GetLimbPath) + .def("GetLimbPathSpeed", &ACrab::GetLimbPathSpeed) + .def("SetLimbPathSpeed", &ACrab::SetLimbPathSpeed) + + .enum_("Side")[luabind::value("LEFTSIDE", ACrab::Side::LEFTSIDE), + luabind::value("RIGHTSIDE", ACrab::Side::RIGHTSIDE), + luabind::value("SIDECOUNT", ACrab::Side::SIDECOUNT)] + .enum_("Layer")[luabind::value("FGROUND", ACrab::Layer::FGROUND), + luabind::value("BGROUND", ACrab::Layer::BGROUND)] + .enum_("DeviceHandlingState")[luabind::value("STILL", ACrab::DeviceHandlingState::STILL), + luabind::value("POINTING", ACrab::DeviceHandlingState::POINTING), + luabind::value("SCANNING", ACrab::DeviceHandlingState::SCANNING), + luabind::value("AIMING", ACrab::DeviceHandlingState::AIMING), + luabind::value("FIRING", ACrab::DeviceHandlingState::FIRING), + luabind::value("THROWING", ACrab::DeviceHandlingState::THROWING), + luabind::value("DIGGING", ACrab::DeviceHandlingState::DIGGING)] + .enum_("SweepState")[luabind::value("NOSWEEP", ACrab::SweepState::NOSWEEP), + luabind::value("SWEEPINGUP", ACrab::SweepState::SWEEPINGUP), + luabind::value("SWEEPUPPAUSE", ACrab::SweepState::SWEEPUPPAUSE), + luabind::value("SWEEPINGDOWN", ACrab::SweepState::SWEEPINGDOWN), + luabind::value("SWEEPDOWNPAUSE", ACrab::SweepState::SWEEPDOWNPAUSE)] + .enum_("DigState")[luabind::value("NOTDIGGING", ACrab::DigState::NOTDIGGING), + luabind::value("PREDIG", ACrab::DigState::PREDIG), + luabind::value("STARTDIG", ACrab::DigState::STARTDIG), + luabind::value("TUNNELING", ACrab::DigState::TUNNELING), + luabind::value("FINISHINGDIG", ACrab::DigState::FINISHINGDIG), + luabind::value("PAUSEDIGGER", ACrab::DigState::PAUSEDIGGER)] + .enum_("JumpState")[luabind::value("NOTJUMPING", ACrab::JumpState::NOTJUMPING), + luabind::value("FORWARDJUMP", ACrab::JumpState::FORWARDJUMP), + luabind::value("PREJUMP", ACrab::JumpState::PREUPJUMP), + luabind::value("UPJUMP", ACrab::JumpState::UPJUMP), + luabind::value("APEXJUMP", ACrab::JumpState::APEXJUMP), + luabind::value("LANDJUMP", ACrab::JumpState::LANDJUMP)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, ACraft) { return AbstractTypeLuaClassDefinition(ACraft, Actor) - .property("HatchState", &ACraft::GetHatchState) - .property("HatchOpenSound", &ACraft::GetHatchOpenSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACraftSetHatchOpenSound) - .property("HatchCloseSound", &ACraft::GetHatchCloseSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACraftSetHatchCloseSound) - .property("CrashSound", &ACraft::GetCrashSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACraftSetCrashSound) - .property("MaxPassengers", &ACraft::GetMaxPassengers) - .property("DeliveryDelayMultiplier", &ACraft::GetDeliveryDelayMultiplier) - .property("ScuttleOnDeath", &ACraft::GetScuttleOnDeath, &ACraft::SetScuttleOnDeath) - .property("HatchDelay", &ACraft::GetHatchDelay, &ACraft::SetHatchDelay) - - .def("OpenHatch", &ACraft::OpenHatch) - .def("CloseHatch", &ACraft::CloseHatch) - - .enum_("HatchState")[ - luabind::value("CLOSED", ACraft::HatchState::CLOSED), - luabind::value("OPENING", ACraft::HatchState::OPENING), - luabind::value("OPEN", ACraft::HatchState::OPEN), - luabind::value("CLOSING", ACraft::HatchState::CLOSING), - luabind::value("HatchStateCount", ACraft::HatchState::HatchStateCount) - ] - .enum_("Side")[ - luabind::value("RIGHT", ACraft::Side::RIGHT), - luabind::value("LEFT", ACraft::Side::LEFT) - ] - - .enum_("CraftDeliverySequence")[ - luabind::value("FALL", ACraft::CraftDeliverySequence::FALL), - luabind::value("LAND", ACraft::CraftDeliverySequence::LAND), - luabind::value("STANDBY", ACraft::CraftDeliverySequence::STANDBY), - luabind::value("UNLOAD", ACraft::CraftDeliverySequence::UNLOAD), - luabind::value("LAUNCH", ACraft::CraftDeliverySequence::LAUNCH), - luabind::value("UNSTICK", ACraft::CraftDeliverySequence::UNSTICK) - ] - .enum_("AltitudeMoveState")[ - luabind::value("HOVER", ACraft::AltitudeMoveState::HOVER), - luabind::value("DESCEND", ACraft::AltitudeMoveState::DESCEND), - luabind::value("ASCEND", ACraft::AltitudeMoveState::ASCEND) - ]; + .property("HatchState", &ACraft::GetHatchState) + .property("HatchOpenSound", &ACraft::GetHatchOpenSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACraftSetHatchOpenSound) + .property("HatchCloseSound", &ACraft::GetHatchCloseSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACraftSetHatchCloseSound) + .property("CrashSound", &ACraft::GetCrashSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ACraftSetCrashSound) + .property("MaxPassengers", &ACraft::GetMaxPassengers) + .property("DeliveryDelayMultiplier", &ACraft::GetDeliveryDelayMultiplier) + .property("ScuttleOnDeath", &ACraft::GetScuttleOnDeath, &ACraft::SetScuttleOnDeath) + .property("HatchDelay", &ACraft::GetHatchDelay, &ACraft::SetHatchDelay) + + .def("OpenHatch", &ACraft::OpenHatch) + .def("CloseHatch", &ACraft::CloseHatch) + + .enum_("HatchState")[luabind::value("CLOSED", ACraft::HatchState::CLOSED), + luabind::value("OPENING", ACraft::HatchState::OPENING), + luabind::value("OPEN", ACraft::HatchState::OPEN), + luabind::value("CLOSING", ACraft::HatchState::CLOSING), + luabind::value("HatchStateCount", ACraft::HatchState::HatchStateCount)] + .enum_("Side")[luabind::value("RIGHT", ACraft::Side::RIGHT), + luabind::value("LEFT", ACraft::Side::LEFT)] + + .enum_("CraftDeliverySequence")[luabind::value("FALL", ACraft::CraftDeliverySequence::FALL), + luabind::value("LAND", ACraft::CraftDeliverySequence::LAND), + luabind::value("STANDBY", ACraft::CraftDeliverySequence::STANDBY), + luabind::value("UNLOAD", ACraft::CraftDeliverySequence::UNLOAD), + luabind::value("LAUNCH", ACraft::CraftDeliverySequence::LAUNCH), + luabind::value("UNSTICK", ACraft::CraftDeliverySequence::UNSTICK)] + .enum_("AltitudeMoveState")[luabind::value("HOVER", ACraft::AltitudeMoveState::HOVER), + luabind::value("DESCEND", ACraft::AltitudeMoveState::DESCEND), + luabind::value("ASCEND", ACraft::AltitudeMoveState::ASCEND)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, ACRocket) { return ConcreteTypeLuaClassDefinition(ACRocket, ACraft) - .property("RightLeg", &ACRocket::GetRightLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetRightLeg) - .property("LeftLeg", &ACRocket::GetLeftLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetLeftLeg) - .property("MainEngine", &ACRocket::GetMainThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetMainThruster) - .property("LeftEngine", &ACRocket::GetLeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetLeftThruster) - .property("RightEngine", &ACRocket::GetRightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetRightThruster) - .property("LeftThruster", &ACRocket::GetULeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetULeftThruster) - .property("RightThruster", &ACRocket::GetURightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetURightThruster) - .property("GearState", &ACRocket::GetGearState) - - .enum_("LandingGearState")[ - luabind::value("RAISED", ACRocket::LandingGearState::RAISED), - luabind::value("LOWERED", ACRocket::LandingGearState::LOWERED), - luabind::value("LOWERING", ACRocket::LandingGearState::LOWERING), - luabind::value("RAISING", ACRocket::LandingGearState::RAISING), - luabind::value("GearStateCount", ACRocket::LandingGearState::GearStateCount) - ]; + .property("RightLeg", &ACRocket::GetRightLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetRightLeg) + .property("LeftLeg", &ACRocket::GetLeftLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetLeftLeg) + .property("MainEngine", &ACRocket::GetMainThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetMainThruster) + .property("LeftEngine", &ACRocket::GetLeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetLeftThruster) + .property("RightEngine", &ACRocket::GetRightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetRightThruster) + .property("LeftThruster", &ACRocket::GetULeftThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetULeftThruster) + .property("RightThruster", &ACRocket::GetURightThruster, &LuaAdaptersPropertyOwnershipSafetyFaker::ACRocketSetURightThruster) + .property("GearState", &ACRocket::GetGearState) + + .enum_("LandingGearState")[luabind::value("RAISED", ACRocket::LandingGearState::RAISED), + luabind::value("LOWERED", ACRocket::LandingGearState::LOWERED), + luabind::value("LOWERING", ACRocket::LandingGearState::LOWERING), + luabind::value("RAISING", ACRocket::LandingGearState::RAISING), + luabind::value("GearStateCount", ACRocket::LandingGearState::GearStateCount)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Actor) { return ConcreteTypeLuaClassDefinition(Actor, MOSRotating) - .def(luabind::constructor<>()) - - .property("PlayerControllable", &Actor::IsPlayerControllable, &Actor::SetPlayerControllable) - .property("BodyHitSound", &Actor::GetBodyHitSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetBodyHitSound) - .property("AlarmSound", &Actor::GetAlarmSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetAlarmSound) - .property("PainSound", &Actor::GetPainSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetPainSound) - .property("DeathSound", &Actor::GetDeathSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetDeathSound) - .property("DeviceSwitchSound", &Actor::GetDeviceSwitchSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetDeviceSwitchSound) - .property("ImpulseDamageThreshold", &Actor::GetTravelImpulseDamage, &Actor::SetTravelImpulseDamage) - .property("StableRecoveryDelay", &Actor::GetStableRecoverDelay, &Actor::SetStableRecoverDelay) - .property("Status", &Actor::GetStatus, &Actor::SetStatus) - .property("Health", &Actor::GetHealth, &Actor::SetHealth) - .property("PrevHealth", &Actor::GetPrevHealth) - .property("MaxHealth", &Actor::GetMaxHealth, &Actor::SetMaxHealth) - .property("InventoryMass", &Actor::GetInventoryMass) - .property("GoldCarried", &Actor::GetGoldCarried, &Actor::SetGoldCarried) - .property("AimRange", &Actor::GetAimRange, &Actor::SetAimRange) - .property("CPUPos", &Actor::GetCPUPos) - .property("EyePos", &Actor::GetEyePos) - .property("HolsterOffset", &Actor::GetHolsterOffset, &Actor::SetHolsterOffset) - .property("ReloadOffset", &Actor::GetReloadOffset, &Actor::SetReloadOffset) - .property("ViewPoint", &Actor::GetViewPoint, &Actor::SetViewPoint) - .property("ItemInReach", &Actor::GetItemInReach, &Actor::SetItemInReach) - .property("SharpAimProgress", &Actor::GetSharpAimProgress) - .property("Height", &Actor::GetHeight) - .property("AIMode", &Actor::GetAIMode, &Actor::SetAIMode) - .property("DeploymentID", &Actor::GetDeploymentID) - .property("PassengerSlots", &Actor::GetPassengerSlots, &Actor::SetPassengerSlots) - .property("Perceptiveness", &Actor::GetPerceptiveness, &Actor::SetPerceptiveness) - .property("PainThreshold", &Actor::GetPainThreshold, &Actor::SetPainThreshold) - .property("CanRevealUnseen", &Actor::GetCanRevealUnseen, &Actor::SetCanRevealUnseen) - .property("InventorySize", &Actor::GetInventorySize) - .property("MaxInventoryMass", &Actor::GetMaxInventoryMass) - .property("MovePathSize", &Actor::GetMovePathSize) - .property("MovePathEnd", &Actor::GetMovePathEnd) - .property("IsWaitingOnNewMovePath", &Actor::IsWaitingOnNewMovePath) - .property("AimDistance", &Actor::GetAimDistance, &Actor::SetAimDistance) - .property("SightDistance", &Actor::GetSightDistance, &Actor::SetSightDistance) - .property("PieMenu", &Actor::GetPieMenu, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetPieMenu) - .property("AIBaseDigStrength", &Actor::GetAIBaseDigStrength, &Actor::SetAIBaseDigStrength) - .property("DigStrength", &Actor::EstimateDigStrength) - .property("SceneWaypoints", &LuaAdaptersActor::GetSceneWaypoints, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .property("LimbPushForcesAndCollisionsDisabled", &Actor::GetLimbPushForcesAndCollisionsDisabled, &Actor::SetLimbPushForcesAndCollisionsDisabled) - .property("MoveProximityLimit", &Actor::GetMoveProximityLimit, &Actor::SetMoveProximityLimit) - - .def_readwrite("MOMoveTarget", &Actor::m_pMOMoveTarget) - .def_readwrite("MovePath", &Actor::m_MovePath, luabind::return_stl_iterator) - .def_readwrite("Inventory", &Actor::m_Inventory, luabind::return_stl_iterator) - - .def("GetController", &Actor::GetController) - .def("IsPlayerControlled", &Actor::IsPlayerControlled) - .def("IsControllable", &Actor::IsControllable) - .def("SetControllerMode", &Actor::SetControllerMode) - .def("SwapControllerModes", &Actor::SwapControllerModes) - .def("GetStableVelocityThreshold", &Actor::GetStableVel) - .def("SetStableVelocityThreshold", (void (Actor::*)(float, float))&Actor::SetStableVel) - .def("SetStableVelocityThreshold", (void (Actor::*)(Vector))&Actor::SetStableVel) - .def("GetAimAngle", &Actor::GetAimAngle) - .def("SetAimAngle", &Actor::SetAimAngle) - .def("HasObject", &Actor::HasObject) - .def("HasObjectInGroup", &Actor::HasObjectInGroup) - .def("IsWithinRange", &Actor::IsWithinRange) - .def("AddGold", &Actor::AddGold) - .def("AddHealth", &Actor::AddHealth) - .def("IsStatus", &Actor::IsStatus) - .def("IsDead", &Actor::IsDead) - .def("AddAISceneWaypoint", &Actor::AddAISceneWaypoint) - .def("AddAIMOWaypoint", &Actor::AddAIMOWaypoint) - .def("ClearAIWaypoints", &Actor::ClearAIWaypoints) - .def("GetLastAIWaypoint", &Actor::GetLastAIWaypoint) - .def("GetAIMOWaypointID", &Actor::GetAIMOWaypointID) - .def("GetWaypointListSize", &Actor::GetWaypointsSize) - .def("ClearMovePath", &Actor::ClearMovePath) - .def("AddToMovePathBeginning", &Actor::AddToMovePathBeginning) - .def("AddToMovePathEnd", &Actor::AddToMovePathEnd) - .def("RemoveMovePathBeginning", &Actor::RemoveMovePathBeginning) - .def("RemoveMovePathEnd", &Actor::RemoveMovePathEnd) - .def("AddInventoryItem", &Actor::AddInventoryItem, luabind::adopt(_2)) - .def("RemoveInventoryItem", (void (Actor::*)(const std::string &))&Actor::RemoveInventoryItem) - .def("RemoveInventoryItem", (void (Actor::*)(const std::string &, const std::string &))&Actor::RemoveInventoryItem) - .def("RemoveInventoryItemAtIndex", &Actor::RemoveInventoryItemAtIndex, luabind::adopt(luabind::return_value)) - .def("SwapNextInventory", &Actor::SwapNextInventory) - .def("SwapPrevInventory", &Actor::SwapPrevInventory) - .def("DropAllInventory", &Actor::DropAllInventory) - .def("DropAllGold", &Actor::DropAllGold) - .def("IsInventoryEmpty", &Actor::IsInventoryEmpty) - .def("DrawWaypoints", &Actor::DrawWaypoints) - .def("SetMovePathToUpdate", &Actor::SetMovePathToUpdate) - .def("UpdateMovePath", &Actor::UpdateMovePath) - .def("SetAlarmPoint", &Actor::AlarmPoint) - .def("GetAlarmPoint", &Actor::GetAlarmPoint) - .def("IsOrganic", &Actor::IsOrganic) - .def("IsMechanical", &Actor::IsMechanical) - - .enum_("Status")[ - luabind::value("STABLE", Actor::Status::STABLE), - luabind::value("UNSTABLE", Actor::Status::UNSTABLE), - luabind::value("INACTIVE", Actor::Status::INACTIVE), - luabind::value("DYING", Actor::Status::DYING), - luabind::value("DEAD", Actor::Status::DEAD) - ] - .enum_("MovementState")[ - luabind::value("NOMOVE", Actor::MovementState::NOMOVE), - luabind::value("STAND", Actor::MovementState::STAND), - luabind::value("WALK", Actor::MovementState::WALK), - luabind::value("JUMP", Actor::MovementState::JUMP), - luabind::value("DISLODGE", Actor::MovementState::DISLODGE), - luabind::value("CROUCH", Actor::MovementState::CROUCH), - luabind::value("CRAWL", Actor::MovementState::CRAWL), - luabind::value("ARMCRAWL", Actor::MovementState::ARMCRAWL), - luabind::value("CLIMB", Actor::MovementState::CLIMB), - luabind::value("MOVEMENTSTATECOUNT", Actor::MovementState::MOVEMENTSTATECOUNT) - ] - .enum_("AIMode")[ - luabind::value("AIMODE_NONE", Actor::AIMode::AIMODE_NONE), - luabind::value("AIMODE_SENTRY", Actor::AIMode::AIMODE_SENTRY), - luabind::value("AIMODE_PATROL", Actor::AIMode::AIMODE_PATROL), - luabind::value("AIMODE_GOTO", Actor::AIMode::AIMODE_GOTO), - luabind::value("AIMODE_BRAINHUNT", Actor::AIMode::AIMODE_BRAINHUNT), - luabind::value("AIMODE_GOLDDIG", Actor::AIMode::AIMODE_GOLDDIG), - luabind::value("AIMODE_RETURN", Actor::AIMode::AIMODE_RETURN), - luabind::value("AIMODE_STAY", Actor::AIMode::AIMODE_STAY), - luabind::value("AIMODE_SCUTTLE", Actor::AIMode::AIMODE_SCUTTLE), - luabind::value("AIMODE_DELIVER", Actor::AIMode::AIMODE_DELIVER), - luabind::value("AIMODE_BOMB", Actor::AIMode::AIMODE_BOMB), - luabind::value("AIMODE_SQUAD", Actor::AIMode::AIMODE_SQUAD), - luabind::value("AIMODE_COUNT", Actor::AIMode::AIMODE_COUNT) - ] - .enum_("ActionState")[ - luabind::value("MOVING", Actor::ActionState::MOVING), - luabind::value("MOVING_FAST", Actor::ActionState::MOVING_FAST), - luabind::value("FIRING", Actor::ActionState::FIRING), - luabind::value("ActionStateCount", Actor::ActionState::ActionStateCount) - ] - .enum_("AimState")[ - luabind::value("AIMSTILL", Actor::AimState::AIMSTILL), - luabind::value("AIMUP", Actor::AimState::AIMUP), - luabind::value("AIMDOWN", Actor::AimState::AIMDOWN), - luabind::value("AimStateCount", Actor::AimState::AimStateCount) - ] - .enum_("LateralMoveState")[ - luabind::value("LAT_STILL", Actor::LateralMoveState::LAT_STILL), - luabind::value("LAT_LEFT", Actor::LateralMoveState::LAT_LEFT), - luabind::value("LAT_RIGHT", Actor::LateralMoveState::LAT_RIGHT) - ] - .enum_("ObstacleState")[ - luabind::value("PROCEEDING", Actor::ObstacleState::PROCEEDING), - luabind::value("BACKSTEPPING", Actor::ObstacleState::BACKSTEPPING), - luabind::value("DIGPAUSING", Actor::ObstacleState::DIGPAUSING), - luabind::value("JUMPING", Actor::ObstacleState::JUMPING), - luabind::value("SOFTLANDING", Actor::ObstacleState::SOFTLANDING) - ] - .enum_("TeamBlockState")[ - luabind::value("NOTBLOCKED", Actor::TeamBlockState::NOTBLOCKED), - luabind::value("BLOCKED", Actor::TeamBlockState::BLOCKED), - luabind::value("IGNORINGBLOCK", Actor::TeamBlockState::IGNORINGBLOCK), - luabind::value("FOLLOWWAIT", Actor::TeamBlockState::FOLLOWWAIT) - ]; + .def(luabind::constructor<>()) + + .property("PlayerControllable", &Actor::IsPlayerControllable, &Actor::SetPlayerControllable) + .property("BodyHitSound", &Actor::GetBodyHitSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetBodyHitSound) + .property("AlarmSound", &Actor::GetAlarmSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetAlarmSound) + .property("PainSound", &Actor::GetPainSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetPainSound) + .property("DeathSound", &Actor::GetDeathSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetDeathSound) + .property("DeviceSwitchSound", &Actor::GetDeviceSwitchSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetDeviceSwitchSound) + .property("ImpulseDamageThreshold", &Actor::GetTravelImpulseDamage, &Actor::SetTravelImpulseDamage) + .property("StableRecoveryDelay", &Actor::GetStableRecoverDelay, &Actor::SetStableRecoverDelay) + .property("Status", &Actor::GetStatus, &Actor::SetStatus) + .property("Health", &Actor::GetHealth, &Actor::SetHealth) + .property("PrevHealth", &Actor::GetPrevHealth) + .property("MaxHealth", &Actor::GetMaxHealth, &Actor::SetMaxHealth) + .property("InventoryMass", &Actor::GetInventoryMass) + .property("GoldCarried", &Actor::GetGoldCarried, &Actor::SetGoldCarried) + .property("AimRange", &Actor::GetAimRange, &Actor::SetAimRange) + .property("CPUPos", &Actor::GetCPUPos) + .property("EyePos", &Actor::GetEyePos) + .property("HolsterOffset", &Actor::GetHolsterOffset, &Actor::SetHolsterOffset) + .property("ReloadOffset", &Actor::GetReloadOffset, &Actor::SetReloadOffset) + .property("ViewPoint", &Actor::GetViewPoint, &Actor::SetViewPoint) + .property("ItemInReach", &Actor::GetItemInReach, &Actor::SetItemInReach) + .property("SharpAimProgress", &Actor::GetSharpAimProgress) + .property("Height", &Actor::GetHeight) + .property("AIMode", &Actor::GetAIMode, &Actor::SetAIMode) + .property("DeploymentID", &Actor::GetDeploymentID) + .property("PassengerSlots", &Actor::GetPassengerSlots, &Actor::SetPassengerSlots) + .property("Perceptiveness", &Actor::GetPerceptiveness, &Actor::SetPerceptiveness) + .property("PainThreshold", &Actor::GetPainThreshold, &Actor::SetPainThreshold) + .property("CanRevealUnseen", &Actor::GetCanRevealUnseen, &Actor::SetCanRevealUnseen) + .property("InventorySize", &Actor::GetInventorySize) + .property("MaxInventoryMass", &Actor::GetMaxInventoryMass) + .property("MovePathSize", &Actor::GetMovePathSize) + .property("MovePathEnd", &Actor::GetMovePathEnd) + .property("IsWaitingOnNewMovePath", &Actor::IsWaitingOnNewMovePath) + .property("AimDistance", &Actor::GetAimDistance, &Actor::SetAimDistance) + .property("SightDistance", &Actor::GetSightDistance, &Actor::SetSightDistance) + .property("PieMenu", &Actor::GetPieMenu, &LuaAdaptersPropertyOwnershipSafetyFaker::ActorSetPieMenu) + .property("AIBaseDigStrength", &Actor::GetAIBaseDigStrength, &Actor::SetAIBaseDigStrength) + .property("DigStrength", &Actor::EstimateDigStrength) + .property("SceneWaypoints", &LuaAdaptersActor::GetSceneWaypoints, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .property("LimbPushForcesAndCollisionsDisabled", &Actor::GetLimbPushForcesAndCollisionsDisabled, &Actor::SetLimbPushForcesAndCollisionsDisabled) + .property("MoveProximityLimit", &Actor::GetMoveProximityLimit, &Actor::SetMoveProximityLimit) + + .def_readwrite("MOMoveTarget", &Actor::m_pMOMoveTarget) + .def_readwrite("MovePath", &Actor::m_MovePath, luabind::return_stl_iterator) + .def_readwrite("Inventory", &Actor::m_Inventory, luabind::return_stl_iterator) + + .def("GetController", &Actor::GetController) + .def("IsPlayerControlled", &Actor::IsPlayerControlled) + .def("IsControllable", &Actor::IsControllable) + .def("SetControllerMode", &Actor::SetControllerMode) + .def("SwapControllerModes", &Actor::SwapControllerModes) + .def("GetStableVelocityThreshold", &Actor::GetStableVel) + .def("SetStableVelocityThreshold", (void(Actor::*)(float, float)) & Actor::SetStableVel) + .def("SetStableVelocityThreshold", (void(Actor::*)(Vector)) & Actor::SetStableVel) + .def("GetAimAngle", &Actor::GetAimAngle) + .def("SetAimAngle", &Actor::SetAimAngle) + .def("HasObject", &Actor::HasObject) + .def("HasObjectInGroup", &Actor::HasObjectInGroup) + .def("IsWithinRange", &Actor::IsWithinRange) + .def("AddGold", &Actor::AddGold) + .def("AddHealth", &Actor::AddHealth) + .def("IsStatus", &Actor::IsStatus) + .def("IsDead", &Actor::IsDead) + .def("AddAISceneWaypoint", &Actor::AddAISceneWaypoint) + .def("AddAIMOWaypoint", &Actor::AddAIMOWaypoint) + .def("ClearAIWaypoints", &Actor::ClearAIWaypoints) + .def("GetLastAIWaypoint", &Actor::GetLastAIWaypoint) + .def("GetAIMOWaypointID", &Actor::GetAIMOWaypointID) + .def("GetWaypointListSize", &Actor::GetWaypointsSize) + .def("ClearMovePath", &Actor::ClearMovePath) + .def("AddToMovePathBeginning", &Actor::AddToMovePathBeginning) + .def("AddToMovePathEnd", &Actor::AddToMovePathEnd) + .def("RemoveMovePathBeginning", &Actor::RemoveMovePathBeginning) + .def("RemoveMovePathEnd", &Actor::RemoveMovePathEnd) + .def("AddInventoryItem", &Actor::AddInventoryItem, luabind::adopt(_2)) + .def("RemoveInventoryItem", (void(Actor::*)(const std::string&)) & Actor::RemoveInventoryItem) + .def("RemoveInventoryItem", (void(Actor::*)(const std::string&, const std::string&)) & Actor::RemoveInventoryItem) + .def("RemoveInventoryItemAtIndex", &Actor::RemoveInventoryItemAtIndex, luabind::adopt(luabind::return_value)) + .def("SwapNextInventory", &Actor::SwapNextInventory) + .def("SwapPrevInventory", &Actor::SwapPrevInventory) + .def("DropAllInventory", &Actor::DropAllInventory) + .def("DropAllGold", &Actor::DropAllGold) + .def("IsInventoryEmpty", &Actor::IsInventoryEmpty) + .def("DrawWaypoints", &Actor::DrawWaypoints) + .def("SetMovePathToUpdate", &Actor::SetMovePathToUpdate) + .def("UpdateMovePath", &Actor::UpdateMovePath) + .def("SetAlarmPoint", &Actor::AlarmPoint) + .def("GetAlarmPoint", &Actor::GetAlarmPoint) + .def("IsOrganic", &Actor::IsOrganic) + .def("IsMechanical", &Actor::IsMechanical) + + .enum_("Status")[luabind::value("STABLE", Actor::Status::STABLE), + luabind::value("UNSTABLE", Actor::Status::UNSTABLE), + luabind::value("INACTIVE", Actor::Status::INACTIVE), + luabind::value("DYING", Actor::Status::DYING), + luabind::value("DEAD", Actor::Status::DEAD)] + .enum_("MovementState")[luabind::value("NOMOVE", Actor::MovementState::NOMOVE), + luabind::value("STAND", Actor::MovementState::STAND), + luabind::value("WALK", Actor::MovementState::WALK), + luabind::value("JUMP", Actor::MovementState::JUMP), + luabind::value("DISLODGE", Actor::MovementState::DISLODGE), + luabind::value("CROUCH", Actor::MovementState::CROUCH), + luabind::value("CRAWL", Actor::MovementState::CRAWL), + luabind::value("ARMCRAWL", Actor::MovementState::ARMCRAWL), + luabind::value("CLIMB", Actor::MovementState::CLIMB), + luabind::value("MOVEMENTSTATECOUNT", Actor::MovementState::MOVEMENTSTATECOUNT)] + .enum_("AIMode")[luabind::value("AIMODE_NONE", Actor::AIMode::AIMODE_NONE), + luabind::value("AIMODE_SENTRY", Actor::AIMode::AIMODE_SENTRY), + luabind::value("AIMODE_PATROL", Actor::AIMode::AIMODE_PATROL), + luabind::value("AIMODE_GOTO", Actor::AIMode::AIMODE_GOTO), + luabind::value("AIMODE_BRAINHUNT", Actor::AIMode::AIMODE_BRAINHUNT), + luabind::value("AIMODE_GOLDDIG", Actor::AIMode::AIMODE_GOLDDIG), + luabind::value("AIMODE_RETURN", Actor::AIMode::AIMODE_RETURN), + luabind::value("AIMODE_STAY", Actor::AIMode::AIMODE_STAY), + luabind::value("AIMODE_SCUTTLE", Actor::AIMode::AIMODE_SCUTTLE), + luabind::value("AIMODE_DELIVER", Actor::AIMode::AIMODE_DELIVER), + luabind::value("AIMODE_BOMB", Actor::AIMode::AIMODE_BOMB), + luabind::value("AIMODE_SQUAD", Actor::AIMode::AIMODE_SQUAD), + luabind::value("AIMODE_COUNT", Actor::AIMode::AIMODE_COUNT)] + .enum_("ActionState")[luabind::value("MOVING", Actor::ActionState::MOVING), + luabind::value("MOVING_FAST", Actor::ActionState::MOVING_FAST), + luabind::value("FIRING", Actor::ActionState::FIRING), + luabind::value("ActionStateCount", Actor::ActionState::ActionStateCount)] + .enum_("AimState")[luabind::value("AIMSTILL", Actor::AimState::AIMSTILL), + luabind::value("AIMUP", Actor::AimState::AIMUP), + luabind::value("AIMDOWN", Actor::AimState::AIMDOWN), + luabind::value("AimStateCount", Actor::AimState::AimStateCount)] + .enum_("LateralMoveState")[luabind::value("LAT_STILL", Actor::LateralMoveState::LAT_STILL), + luabind::value("LAT_LEFT", Actor::LateralMoveState::LAT_LEFT), + luabind::value("LAT_RIGHT", Actor::LateralMoveState::LAT_RIGHT)] + .enum_("ObstacleState")[luabind::value("PROCEEDING", Actor::ObstacleState::PROCEEDING), + luabind::value("BACKSTEPPING", Actor::ObstacleState::BACKSTEPPING), + luabind::value("DIGPAUSING", Actor::ObstacleState::DIGPAUSING), + luabind::value("JUMPING", Actor::ObstacleState::JUMPING), + luabind::value("SOFTLANDING", Actor::ObstacleState::SOFTLANDING)] + .enum_("TeamBlockState")[luabind::value("NOTBLOCKED", Actor::TeamBlockState::NOTBLOCKED), + luabind::value("BLOCKED", Actor::TeamBlockState::BLOCKED), + luabind::value("IGNORINGBLOCK", Actor::TeamBlockState::IGNORINGBLOCK), + luabind::value("FOLLOWWAIT", Actor::TeamBlockState::FOLLOWWAIT)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, ADoor) { return ConcreteTypeLuaClassDefinition(ADoor, Actor) - .property("Door", &ADoor::GetDoor, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoor) - .property("DoorMoveStartSound", &ADoor::GetDoorMoveStartSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorMoveStartSound) - .property("DoorMoveSound", &ADoor::GetDoorMoveSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorMoveSound) - .property("DoorDirectionChangeSound", &ADoor::GetDoorDirectionChangeSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorDirectionChangeSound) - .property("DoorMoveEndSound", &ADoor::GetDoorMoveEndSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorMoveEndSound) - - .def("GetDoorState", &ADoor::GetDoorState) - .def("OpenDoor", &ADoor::OpenDoor) - .def("CloseDoor", &ADoor::CloseDoor) - .def("StopDoor", &ADoor::StopDoor) - .def("ResetSensorTimer", &ADoor::ResetSensorTimer) - .def("SetClosedByDefault", &ADoor::SetClosedByDefault) - - .enum_("DoorState")[ - luabind::value("CLOSED", ADoor::DoorState::CLOSED), - luabind::value("OPENING", ADoor::DoorState::OPENING), - luabind::value("OPEN", ADoor::DoorState::OPEN), - luabind::value("CLOSING", ADoor::DoorState::CLOSING), - luabind::value("STOPPED", ADoor::DoorState::STOPPED) - ]; + .property("Door", &ADoor::GetDoor, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoor) + .property("DoorMoveStartSound", &ADoor::GetDoorMoveStartSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorMoveStartSound) + .property("DoorMoveSound", &ADoor::GetDoorMoveSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorMoveSound) + .property("DoorDirectionChangeSound", &ADoor::GetDoorDirectionChangeSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorDirectionChangeSound) + .property("DoorMoveEndSound", &ADoor::GetDoorMoveEndSound, &LuaAdaptersPropertyOwnershipSafetyFaker::ADoorSetDoorMoveEndSound) + + .def("GetDoorState", &ADoor::GetDoorState) + .def("OpenDoor", &ADoor::OpenDoor) + .def("CloseDoor", &ADoor::CloseDoor) + .def("StopDoor", &ADoor::StopDoor) + .def("ResetSensorTimer", &ADoor::ResetSensorTimer) + .def("SetClosedByDefault", &ADoor::SetClosedByDefault) + + .enum_("DoorState")[luabind::value("CLOSED", ADoor::DoorState::CLOSED), + luabind::value("OPENING", ADoor::DoorState::OPENING), + luabind::value("OPEN", ADoor::DoorState::OPEN), + luabind::value("CLOSING", ADoor::DoorState::CLOSING), + luabind::value("STOPPED", ADoor::DoorState::STOPPED)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, AEmitter) { return ConcreteTypeLuaClassDefinition(AEmitter, Attachable) - .property("EmissionSound", &AEmitter::GetEmissionSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetEmissionSound) - .property("BurstSound", &AEmitter::GetBurstSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetBurstSound) - .property("EndSound", &AEmitter::GetEndSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetEndSound) - .property("BurstScale", &AEmitter::GetBurstScale, &AEmitter::SetBurstScale) - .property("EmitAngle", &AEmitter::GetEmitAngle, &AEmitter::SetEmitAngle) - .property("GetThrottle", &AEmitter::GetThrottle, &AEmitter::SetThrottle) - .property("Throttle", &AEmitter::GetThrottle, &AEmitter::SetThrottle) - .property("ThrottleFactor", &AEmitter::GetThrottleFactor) - .property("NegativeThrottleMultiplier", &AEmitter::GetNegativeThrottleMultiplier, &AEmitter::SetNegativeThrottleMultiplier) - .property("PositiveThrottleMultiplier", &AEmitter::GetPositiveThrottleMultiplier, &AEmitter::SetPositiveThrottleMultiplier) - .property("BurstSpacing", &AEmitter::GetBurstSpacing, &AEmitter::SetBurstSpacing) - .property("BurstDamage", &AEmitter::GetBurstDamage, &AEmitter::SetBurstDamage) - .property("EmitterDamageMultiplier", &AEmitter::GetEmitterDamageMultiplier, &AEmitter::SetEmitterDamageMultiplier) - .property("EmitCount", &AEmitter::GetEmitCount) - .property("EmitCountLimit", &AEmitter::GetEmitCountLimit, &AEmitter::SetEmitCountLimit) - .property("EmitDamage", &AEmitter::GetEmitDamage, &AEmitter::SetEmitDamage) - .property("EmitOffset", &AEmitter::GetEmitOffset, &AEmitter::SetEmitOffset) - .property("Flash", &AEmitter::GetFlash, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetFlash) - .property("FlashScale", &AEmitter::GetFlashScale, &AEmitter::SetFlashScale) - .property("TotalParticlesPerMinute", &AEmitter::GetTotalParticlesPerMinute) - .property("TotalBurstSize", &AEmitter::GetTotalBurstSize) - - .def_readwrite("Emissions", &AEmitter::m_EmissionList, luabind::return_stl_iterator) - - .def("IsEmitting", &AEmitter::IsEmitting) - .def("WasEmitting", &AEmitter::WasEmitting) - .def("EnableEmission", &AEmitter::EnableEmission) - .def("GetEmitVector", &AEmitter::GetEmitVector) - .def("GetRecoilVector", &AEmitter::GetRecoilVector) - .def("EstimateImpulse", &AEmitter::EstimateImpulse) - .def("TriggerBurst", &AEmitter::TriggerBurst) - .def("IsSetToBurst", &AEmitter::IsSetToBurst) - .def("CanTriggerBurst", &AEmitter::CanTriggerBurst) - .def("GetScaledThrottle", &AEmitter::GetScaledThrottle) - .def("JustStartedEmitting", &AEmitter::JustStartedEmitting); + .property("EmissionSound", &AEmitter::GetEmissionSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetEmissionSound) + .property("BurstSound", &AEmitter::GetBurstSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetBurstSound) + .property("EndSound", &AEmitter::GetEndSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetEndSound) + .property("BurstScale", &AEmitter::GetBurstScale, &AEmitter::SetBurstScale) + .property("EmitAngle", &AEmitter::GetEmitAngle, &AEmitter::SetEmitAngle) + .property("GetThrottle", &AEmitter::GetThrottle, &AEmitter::SetThrottle) + .property("Throttle", &AEmitter::GetThrottle, &AEmitter::SetThrottle) + .property("ThrottleFactor", &AEmitter::GetThrottleFactor) + .property("NegativeThrottleMultiplier", &AEmitter::GetNegativeThrottleMultiplier, &AEmitter::SetNegativeThrottleMultiplier) + .property("PositiveThrottleMultiplier", &AEmitter::GetPositiveThrottleMultiplier, &AEmitter::SetPositiveThrottleMultiplier) + .property("BurstSpacing", &AEmitter::GetBurstSpacing, &AEmitter::SetBurstSpacing) + .property("BurstDamage", &AEmitter::GetBurstDamage, &AEmitter::SetBurstDamage) + .property("EmitterDamageMultiplier", &AEmitter::GetEmitterDamageMultiplier, &AEmitter::SetEmitterDamageMultiplier) + .property("EmitCount", &AEmitter::GetEmitCount) + .property("EmitCountLimit", &AEmitter::GetEmitCountLimit, &AEmitter::SetEmitCountLimit) + .property("EmitDamage", &AEmitter::GetEmitDamage, &AEmitter::SetEmitDamage) + .property("EmitOffset", &AEmitter::GetEmitOffset, &AEmitter::SetEmitOffset) + .property("Flash", &AEmitter::GetFlash, &LuaAdaptersPropertyOwnershipSafetyFaker::AEmitterSetFlash) + .property("FlashScale", &AEmitter::GetFlashScale, &AEmitter::SetFlashScale) + .property("TotalParticlesPerMinute", &AEmitter::GetTotalParticlesPerMinute) + .property("TotalBurstSize", &AEmitter::GetTotalBurstSize) + + .def_readwrite("Emissions", &AEmitter::m_EmissionList, luabind::return_stl_iterator) + + .def("IsEmitting", &AEmitter::IsEmitting) + .def("WasEmitting", &AEmitter::WasEmitting) + .def("EnableEmission", &AEmitter::EnableEmission) + .def("GetEmitVector", &AEmitter::GetEmitVector) + .def("GetRecoilVector", &AEmitter::GetRecoilVector) + .def("EstimateImpulse", &AEmitter::EstimateImpulse) + .def("TriggerBurst", &AEmitter::TriggerBurst) + .def("IsSetToBurst", &AEmitter::IsSetToBurst) + .def("CanTriggerBurst", &AEmitter::CanTriggerBurst) + .def("GetScaledThrottle", &AEmitter::GetScaledThrottle) + .def("JustStartedEmitting", &AEmitter::JustStartedEmitting); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, AEJetpack) { return ConcreteTypeLuaClassDefinition(AEJetpack, AEmitter) - .property("JetpackType", &AEJetpack::GetJetpackType, &AEJetpack::SetJetpackType) - .property("JetTimeTotal", &AEJetpack::GetJetTimeTotal, &AEJetpack::SetJetTimeTotal) - .property("JetTimeLeft", &AEJetpack::GetJetTimeLeft) - .property("JetReplenishRate", &AEJetpack::GetJetReplenishRate, &AEJetpack::SetJetReplenishRate) - .property("MinimumFuelRatio", &AEJetpack::GetMinimumFuelRatio, &AEJetpack::SetMinimumFuelRatio) - .property("JetAngleRange", &AEJetpack::GetJetAngleRange, &AEJetpack::SetJetAngleRange) - .property("CanAdjustAngleWhileFiring", &AEJetpack::GetCanAdjustAngleWhileFiring, &AEJetpack::SetCanAdjustAngleWhileFiring) - .property("AdjustsThrottleForWeight", &AEJetpack::GetAdjustsThrottleForWeight, &AEJetpack::SetAdjustsThrottleForWeight) - - .enum_("JetpackType")[ - luabind::value("Standard", AEJetpack::Standard), - luabind::value("JumpPack", AEJetpack::JumpPack) - ]; + .property("JetpackType", &AEJetpack::GetJetpackType, &AEJetpack::SetJetpackType) + .property("JetTimeTotal", &AEJetpack::GetJetTimeTotal, &AEJetpack::SetJetTimeTotal) + .property("JetTimeLeft", &AEJetpack::GetJetTimeLeft) + .property("JetReplenishRate", &AEJetpack::GetJetReplenishRate, &AEJetpack::SetJetReplenishRate) + .property("MinimumFuelRatio", &AEJetpack::GetMinimumFuelRatio, &AEJetpack::SetMinimumFuelRatio) + .property("JetAngleRange", &AEJetpack::GetJetAngleRange, &AEJetpack::SetJetAngleRange) + .property("CanAdjustAngleWhileFiring", &AEJetpack::GetCanAdjustAngleWhileFiring, &AEJetpack::SetCanAdjustAngleWhileFiring) + .property("AdjustsThrottleForWeight", &AEJetpack::GetAdjustsThrottleForWeight, &AEJetpack::SetAdjustsThrottleForWeight) + + .enum_("JetpackType")[luabind::value("Standard", AEJetpack::Standard), + luabind::value("JumpPack", AEJetpack::JumpPack)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, AHuman) { return ConcreteTypeLuaClassDefinition(AHuman, Actor) - .def(luabind::constructor<>()) - - .property("Head", &AHuman::GetHead, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetHead) - .property("Jetpack", &AHuman::GetJetpack, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetJetpack) - .property("FGArm", &AHuman::GetFGArm, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetFGArm) - .property("BGArm", &AHuman::GetBGArm, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetBGArm) - .property("FGLeg", &AHuman::GetFGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetFGLeg) - .property("BGLeg", &AHuman::GetBGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetBGLeg) - .property("FGFoot", &AHuman::GetFGFoot, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetFGFoot) - .property("BGFoot", &AHuman::GetBGFoot, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetBGFoot) - .property("MaxWalkPathCrouchShift", &AHuman::GetMaxWalkPathCrouchShift, &AHuman::SetMaxWalkPathCrouchShift) - .property("MaxCrouchRotation", &AHuman::GetMaxCrouchRotation, &AHuman::SetMaxCrouchRotation) - .property("CrouchAmount", &AHuman::GetCrouchAmount) - .property("CrouchAmountOverride", &AHuman::GetCrouchAmountOverride, &AHuman::SetCrouchAmountOverride) - .property("StrideSound", &AHuman::GetStrideSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetStrideSound) - .property("UpperBodyState", &AHuman::GetUpperBodyState, &AHuman::SetUpperBodyState) - .property("MovementState", &AHuman::GetMovementState, &AHuman::SetMovementState) - .property("ProneState", &AHuman::GetProneState, &AHuman::SetProneState) - .property("ThrowPrepTime", &AHuman::GetThrowPrepTime, &AHuman::SetThrowPrepTime) - .property("ThrowProgress", &AHuman::GetThrowProgress) - .property("EquippedItem", &AHuman::GetEquippedItem) - .property("EquippedBGItem", &AHuman::GetEquippedBGItem) - .property("EquippedMass", &AHuman::GetEquippedMass) - .property("FirearmIsReady", &AHuman::FirearmIsReady) - .property("ThrowableIsReady", &AHuman::ThrowableIsReady) - .property("FirearmIsEmpty", &AHuman::FirearmIsEmpty) - .property("FirearmNeedsReload", &AHuman::FirearmNeedsReload) - .property("FirearmIsSemiAuto", &AHuman::FirearmIsSemiAuto) - .property("FirearmActivationDelay", &AHuman::FirearmActivationDelay) - .property("LimbPathPushForce", &AHuman::GetLimbPathPushForce, &AHuman::SetLimbPathPushForce) - .property("IsClimbing", &AHuman::IsClimbing) - .property("StrideFrame", &AHuman::StrideFrame) - .property("ArmSwingRate", &AHuman::GetArmSwingRate, &AHuman::SetArmSwingRate) - .property("DeviceArmSwayRate", &AHuman::GetDeviceArmSwayRate, &AHuman::SetDeviceArmSwayRate) - - .def("EquipFirearm", &AHuman::EquipFirearm) - .def("EquipThrowable", &AHuman::EquipThrowable) - .def("EquipDiggingTool", &AHuman::EquipDiggingTool) - .def("EquipShield", &AHuman::EquipShield) - .def("EquipShieldInBGArm", &AHuman::EquipShieldInBGArm) - .def("EquipDeviceInGroup", &AHuman::EquipDeviceInGroup) - .def("EquipNamedDevice", (bool (AHuman::*)(const std::string &, bool))&AHuman::EquipNamedDevice) - .def("EquipNamedDevice", (bool (AHuman::*)(const std::string &, const std::string &, bool))&AHuman::EquipNamedDevice) - .def("EquipLoadedFirearmInGroup", &AHuman::EquipLoadedFirearmInGroup) - .def("UnequipFGArm", &AHuman::UnequipFGArm) - .def("UnequipBGArm", &AHuman::UnequipBGArm) - .def("UnequipArms", &AHuman::UnequipArms) - .def("ReloadFirearms", &LuaAdaptersAHuman::ReloadFirearms) - .def("ReloadFirearms", &AHuman::ReloadFirearms) - .def("FirearmsAreReloading", &AHuman::FirearmsAreReloading) - .def("IsWithinRange", &AHuman::IsWithinRange) - .def("Look", &AHuman::Look) - .def("LookForGold", &AHuman::LookForGold) - .def("LookForMOs", &AHuman::LookForMOs) - .def("GetLimbPath", &AHuman::GetLimbPath) - .def("GetLimbPathSpeed", &AHuman::GetLimbPathSpeed) - .def("SetLimbPathSpeed", &AHuman::SetLimbPathSpeed) - .def("GetRotAngleTarget", &AHuman::GetRotAngleTarget) - .def("SetRotAngleTarget", &AHuman::SetRotAngleTarget) - .def("GetWalkAngle", &AHuman::GetWalkAngle) - .def("SetWalkAngle", &AHuman::SetWalkAngle) - - .enum_("UpperBodyState")[ - luabind::value("WEAPON_READY", AHuman::UpperBodyState::WEAPON_READY), - luabind::value("AIMING_SHARP", AHuman::UpperBodyState::AIMING_SHARP), - luabind::value("HOLSTERING_BACK", AHuman::UpperBodyState::HOLSTERING_BACK), - luabind::value("HOLSTERING_BELT", AHuman::UpperBodyState::HOLSTERING_BELT), - luabind::value("DEHOLSTERING_BACK", AHuman::UpperBodyState::DEHOLSTERING_BACK), - luabind::value("DEHOLSTERING_BELT", AHuman::UpperBodyState::DEHOLSTERING_BELT), - luabind::value("THROWING_PREP", AHuman::UpperBodyState::THROWING_PREP), - luabind::value("THROWING_RELEASE",AHuman::UpperBodyState::THROWING_RELEASE) - ] - .enum_("ProneState")[ - luabind::value("NOTPRONE", AHuman::ProneState::NOTPRONE), - luabind::value("GOPRONE", AHuman::ProneState::GOPRONE), - luabind::value("PRONE", AHuman::ProneState::PRONE), - luabind::value("PRONESTATECOUNT", AHuman::ProneState::PRONESTATECOUNT) - ] - .enum_("Layer")[ - luabind::value("FGROUND", AHuman::Layer::FGROUND), - luabind::value("BGROUND", AHuman::Layer::BGROUND) - ] - .enum_("DeviceHandlingState")[ - luabind::value("STILL", AHuman::DeviceHandlingState::STILL), - luabind::value("POINTING", AHuman::DeviceHandlingState::POINTING), - luabind::value("SCANNING", AHuman::DeviceHandlingState::SCANNING), - luabind::value("AIMING", AHuman::DeviceHandlingState::AIMING), - luabind::value("FIRING", AHuman::DeviceHandlingState::FIRING), - luabind::value("THROWING", AHuman::DeviceHandlingState::THROWING), - luabind::value("DIGGING", AHuman::DeviceHandlingState::DIGGING) - ] - .enum_("SweepState")[ - luabind::value("NOSWEEP", AHuman::SweepState::NOSWEEP), - luabind::value("SWEEPINGUP", AHuman::SweepState::SWEEPINGUP), - luabind::value("SWEEPUPPAUSE", AHuman::SweepState::SWEEPUPPAUSE), - luabind::value("SWEEPINGDOWN", AHuman::SweepState::SWEEPINGDOWN), - luabind::value("SWEEPDOWNPAUSE", AHuman::SweepState::SWEEPDOWNPAUSE) - ] - .enum_("DigState")[ - luabind::value("NOTDIGGING", AHuman::DigState::NOTDIGGING), - luabind::value("PREDIG", AHuman::DigState::PREDIG), - luabind::value("STARTDIG", AHuman::DigState::STARTDIG), - luabind::value("TUNNELING", AHuman::DigState::TUNNELING), - luabind::value("FINISHINGDIG", AHuman::DigState::FINISHINGDIG), - luabind::value("PAUSEDIGGER", AHuman::DigState::PAUSEDIGGER) - ] - .enum_("JumpState")[ - luabind::value("NOTJUMPING", AHuman::JumpState::NOTJUMPING), - luabind::value("FORWARDJUMP", AHuman::JumpState::FORWARDJUMP), - luabind::value("PREJUMP", AHuman::JumpState::PREUPJUMP), - luabind::value("UPJUMP", AHuman::JumpState::UPJUMP), - luabind::value("APEXJUMP", AHuman::JumpState::APEXJUMP), - luabind::value("LANDJUMP", AHuman::JumpState::LANDJUMP) - ]; + .def(luabind::constructor<>()) + + .property("Head", &AHuman::GetHead, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetHead) + .property("Jetpack", &AHuman::GetJetpack, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetJetpack) + .property("FGArm", &AHuman::GetFGArm, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetFGArm) + .property("BGArm", &AHuman::GetBGArm, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetBGArm) + .property("FGLeg", &AHuman::GetFGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetFGLeg) + .property("BGLeg", &AHuman::GetBGLeg, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetBGLeg) + .property("FGFoot", &AHuman::GetFGFoot, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetFGFoot) + .property("BGFoot", &AHuman::GetBGFoot, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetBGFoot) + .property("MaxWalkPathCrouchShift", &AHuman::GetMaxWalkPathCrouchShift, &AHuman::SetMaxWalkPathCrouchShift) + .property("MaxCrouchRotation", &AHuman::GetMaxCrouchRotation, &AHuman::SetMaxCrouchRotation) + .property("CrouchAmount", &AHuman::GetCrouchAmount) + .property("CrouchAmountOverride", &AHuman::GetCrouchAmountOverride, &AHuman::SetCrouchAmountOverride) + .property("StrideSound", &AHuman::GetStrideSound, &LuaAdaptersPropertyOwnershipSafetyFaker::AHumanSetStrideSound) + .property("UpperBodyState", &AHuman::GetUpperBodyState, &AHuman::SetUpperBodyState) + .property("MovementState", &AHuman::GetMovementState, &AHuman::SetMovementState) + .property("ProneState", &AHuman::GetProneState, &AHuman::SetProneState) + .property("ThrowPrepTime", &AHuman::GetThrowPrepTime, &AHuman::SetThrowPrepTime) + .property("ThrowProgress", &AHuman::GetThrowProgress) + .property("EquippedItem", &AHuman::GetEquippedItem) + .property("EquippedBGItem", &AHuman::GetEquippedBGItem) + .property("EquippedMass", &AHuman::GetEquippedMass) + .property("FirearmIsReady", &AHuman::FirearmIsReady) + .property("ThrowableIsReady", &AHuman::ThrowableIsReady) + .property("FirearmIsEmpty", &AHuman::FirearmIsEmpty) + .property("FirearmNeedsReload", &AHuman::FirearmNeedsReload) + .property("FirearmIsSemiAuto", &AHuman::FirearmIsSemiAuto) + .property("FirearmActivationDelay", &AHuman::FirearmActivationDelay) + .property("LimbPathPushForce", &AHuman::GetLimbPathPushForce, &AHuman::SetLimbPathPushForce) + .property("IsClimbing", &AHuman::IsClimbing) + .property("StrideFrame", &AHuman::StrideFrame) + .property("ArmSwingRate", &AHuman::GetArmSwingRate, &AHuman::SetArmSwingRate) + .property("DeviceArmSwayRate", &AHuman::GetDeviceArmSwayRate, &AHuman::SetDeviceArmSwayRate) + + .def("EquipFirearm", &AHuman::EquipFirearm) + .def("EquipThrowable", &AHuman::EquipThrowable) + .def("EquipDiggingTool", &AHuman::EquipDiggingTool) + .def("EquipShield", &AHuman::EquipShield) + .def("EquipShieldInBGArm", &AHuman::EquipShieldInBGArm) + .def("EquipDeviceInGroup", &AHuman::EquipDeviceInGroup) + .def("EquipNamedDevice", (bool(AHuman::*)(const std::string&, bool)) & AHuman::EquipNamedDevice) + .def("EquipNamedDevice", (bool(AHuman::*)(const std::string&, const std::string&, bool)) & AHuman::EquipNamedDevice) + .def("EquipLoadedFirearmInGroup", &AHuman::EquipLoadedFirearmInGroup) + .def("UnequipFGArm", &AHuman::UnequipFGArm) + .def("UnequipBGArm", &AHuman::UnequipBGArm) + .def("UnequipArms", &AHuman::UnequipArms) + .def("ReloadFirearms", &LuaAdaptersAHuman::ReloadFirearms) + .def("ReloadFirearms", &AHuman::ReloadFirearms) + .def("FirearmsAreReloading", &AHuman::FirearmsAreReloading) + .def("IsWithinRange", &AHuman::IsWithinRange) + .def("Look", &AHuman::Look) + .def("LookForGold", &AHuman::LookForGold) + .def("LookForMOs", &AHuman::LookForMOs) + .def("GetLimbPath", &AHuman::GetLimbPath) + .def("GetLimbPathSpeed", &AHuman::GetLimbPathSpeed) + .def("SetLimbPathSpeed", &AHuman::SetLimbPathSpeed) + .def("GetRotAngleTarget", &AHuman::GetRotAngleTarget) + .def("SetRotAngleTarget", &AHuman::SetRotAngleTarget) + .def("GetWalkAngle", &AHuman::GetWalkAngle) + .def("SetWalkAngle", &AHuman::SetWalkAngle) + + .enum_("UpperBodyState")[luabind::value("WEAPON_READY", AHuman::UpperBodyState::WEAPON_READY), + luabind::value("AIMING_SHARP", AHuman::UpperBodyState::AIMING_SHARP), + luabind::value("HOLSTERING_BACK", AHuman::UpperBodyState::HOLSTERING_BACK), + luabind::value("HOLSTERING_BELT", AHuman::UpperBodyState::HOLSTERING_BELT), + luabind::value("DEHOLSTERING_BACK", AHuman::UpperBodyState::DEHOLSTERING_BACK), + luabind::value("DEHOLSTERING_BELT", AHuman::UpperBodyState::DEHOLSTERING_BELT), + luabind::value("THROWING_PREP", AHuman::UpperBodyState::THROWING_PREP), + luabind::value("THROWING_RELEASE", AHuman::UpperBodyState::THROWING_RELEASE)] + .enum_("ProneState")[luabind::value("NOTPRONE", AHuman::ProneState::NOTPRONE), + luabind::value("GOPRONE", AHuman::ProneState::GOPRONE), + luabind::value("PRONE", AHuman::ProneState::PRONE), + luabind::value("PRONESTATECOUNT", AHuman::ProneState::PRONESTATECOUNT)] + .enum_("Layer")[luabind::value("FGROUND", AHuman::Layer::FGROUND), + luabind::value("BGROUND", AHuman::Layer::BGROUND)] + .enum_("DeviceHandlingState")[luabind::value("STILL", AHuman::DeviceHandlingState::STILL), + luabind::value("POINTING", AHuman::DeviceHandlingState::POINTING), + luabind::value("SCANNING", AHuman::DeviceHandlingState::SCANNING), + luabind::value("AIMING", AHuman::DeviceHandlingState::AIMING), + luabind::value("FIRING", AHuman::DeviceHandlingState::FIRING), + luabind::value("THROWING", AHuman::DeviceHandlingState::THROWING), + luabind::value("DIGGING", AHuman::DeviceHandlingState::DIGGING)] + .enum_("SweepState")[luabind::value("NOSWEEP", AHuman::SweepState::NOSWEEP), + luabind::value("SWEEPINGUP", AHuman::SweepState::SWEEPINGUP), + luabind::value("SWEEPUPPAUSE", AHuman::SweepState::SWEEPUPPAUSE), + luabind::value("SWEEPINGDOWN", AHuman::SweepState::SWEEPINGDOWN), + luabind::value("SWEEPDOWNPAUSE", AHuman::SweepState::SWEEPDOWNPAUSE)] + .enum_("DigState")[luabind::value("NOTDIGGING", AHuman::DigState::NOTDIGGING), + luabind::value("PREDIG", AHuman::DigState::PREDIG), + luabind::value("STARTDIG", AHuman::DigState::STARTDIG), + luabind::value("TUNNELING", AHuman::DigState::TUNNELING), + luabind::value("FINISHINGDIG", AHuman::DigState::FINISHINGDIG), + luabind::value("PAUSEDIGGER", AHuman::DigState::PAUSEDIGGER)] + .enum_("JumpState")[luabind::value("NOTJUMPING", AHuman::JumpState::NOTJUMPING), + luabind::value("FORWARDJUMP", AHuman::JumpState::FORWARDJUMP), + luabind::value("PREJUMP", AHuman::JumpState::PREUPJUMP), + luabind::value("UPJUMP", AHuman::JumpState::UPJUMP), + luabind::value("APEXJUMP", AHuman::JumpState::APEXJUMP), + luabind::value("LANDJUMP", AHuman::JumpState::LANDJUMP)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Arm) { return ConcreteTypeLuaClassDefinition(Arm, Attachable) - .property("MaxLength", &Arm::GetMaxLength) - .property("MoveSpeed", &Arm::GetMoveSpeed, &Arm::SetMoveSpeed) + .property("MaxLength", &Arm::GetMaxLength) + .property("MoveSpeed", &Arm::GetMoveSpeed, &Arm::SetMoveSpeed) - .property("HandIdleOffset", &Arm::GetHandIdleOffset, &Arm::SetHandIdleOffset) + .property("HandIdleOffset", &Arm::GetHandIdleOffset, &Arm::SetHandIdleOffset) - .property("HandPos", &Arm::GetHandPos, &Arm::SetHandPos) - .property("HasAnyHandTargets", &Arm::HasAnyHandTargets) - .property("NumberOfHandTargets", &Arm::GetNumberOfHandTargets) - .property("NextHandTargetDescription", &Arm::GetNextHandTargetDescription) - .property("NextHandTargetPosition", &Arm::GetNextHandTargetPosition) - .property("HandHasReachedCurrentTarget", &Arm::GetHandHasReachedCurrentTarget) + .property("HandPos", &Arm::GetHandPos, &Arm::SetHandPos) + .property("HasAnyHandTargets", &Arm::HasAnyHandTargets) + .property("NumberOfHandTargets", &Arm::GetNumberOfHandTargets) + .property("NextHandTargetDescription", &Arm::GetNextHandTargetDescription) + .property("NextHandTargetPosition", &Arm::GetNextHandTargetPosition) + .property("HandHasReachedCurrentTarget", &Arm::GetHandHasReachedCurrentTarget) - .property("GripStrength", &Arm::GetGripStrength, &Arm::SetGripStrength) - .property("ThrowStrength", &Arm::GetThrowStrength, &Arm::SetThrowStrength) + .property("GripStrength", &Arm::GetGripStrength, &Arm::SetGripStrength) + .property("ThrowStrength", &Arm::GetThrowStrength, &Arm::SetThrowStrength) - .property("HeldDevice", &Arm::GetHeldDevice, &LuaAdaptersPropertyOwnershipSafetyFaker::ArmSetHeldDevice) - .property("SupportedHeldDevice", &Arm::GetHeldDeviceThisArmIsTryingToSupport) + .property("HeldDevice", &Arm::GetHeldDevice, &LuaAdaptersPropertyOwnershipSafetyFaker::ArmSetHeldDevice) + .property("SupportedHeldDevice", &Arm::GetHeldDeviceThisArmIsTryingToSupport) - .def("AddHandTarget", (void (Arm::*)(const std::string &description, const Vector &handTargetPositionToAdd))&Arm::AddHandTarget) - .def("AddHandTarget", (void (Arm::*)(const std::string &description, const Vector &handTargetPositionToAdd, float delayAtTarget))&Arm::AddHandTarget) - .def("RemoveNextHandTarget", &Arm::RemoveNextHandTarget) - .def("ClearHandTargets", &Arm::ClearHandTargets); + .def("AddHandTarget", (void(Arm::*)(const std::string& description, const Vector& handTargetPositionToAdd)) & Arm::AddHandTarget) + .def("AddHandTarget", (void(Arm::*)(const std::string& description, const Vector& handTargetPositionToAdd, float delayAtTarget)) & Arm::AddHandTarget) + .def("RemoveNextHandTarget", &Arm::RemoveNextHandTarget) + .def("ClearHandTargets", &Arm::ClearHandTargets); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Attachable) { return ConcreteTypeLuaClassDefinition(Attachable, MOSRotating) - .property("ParentOffset", &Attachable::GetParentOffset, &Attachable::SetParentOffset) - .property("JointStrength", &Attachable::GetJointStrength, &Attachable::SetJointStrength) - .property("JointStiffness", &Attachable::GetJointStiffness, &Attachable::SetJointStiffness) - .property("JointOffset", &Attachable::GetJointOffset, &Attachable::SetJointOffset) - .property("JointPos", &Attachable::GetJointPos) - .property("DeleteWhenRemovedFromParent", &Attachable::GetDeleteWhenRemovedFromParent, &Attachable::SetDeleteWhenRemovedFromParent) - .property("GibWhenRemovedFromParent", &Attachable::GetGibWhenRemovedFromParent, &Attachable::SetGibWhenRemovedFromParent) - .property("ApplyTransferredForcesAtOffset", &Attachable::GetApplyTransferredForcesAtOffset, &Attachable::SetApplyTransferredForcesAtOffset) - .property("BreakWound", &Attachable::GetBreakWound, &LuaAdaptersPropertyOwnershipSafetyFaker::AttachableSetBreakWound) - .property("ParentBreakWound", &Attachable::GetParentBreakWound, &LuaAdaptersPropertyOwnershipSafetyFaker::AttachableSetParentBreakWound) - .property("InheritsHFlipped", &Attachable::InheritsHFlipped, &Attachable::SetInheritsHFlipped) - .property("InheritsRotAngle", &Attachable::InheritsRotAngle, &Attachable::SetInheritsRotAngle) - .property("InheritedRotAngleOffset", &Attachable::GetInheritedRotAngleOffset, &Attachable::SetInheritedRotAngleOffset) - .property("AtomSubgroupID", &Attachable::GetAtomSubgroupID) - .property("CollidesWithTerrainWhileAttached", &Attachable::GetCollidesWithTerrainWhileAttached, &Attachable::SetCollidesWithTerrainWhileAttached) - .property("IgnoresParticlesWhileAttached", &Attachable::GetIgnoresParticlesWhileAttached, &Attachable::SetIgnoresParticlesWhileAttached) - .property("CanCollideWithTerrain", &Attachable::CanCollideWithTerrain) - .property("DrawnAfterParent", &Attachable::IsDrawnAfterParent, &Attachable::SetDrawnAfterParent) - .property("InheritsFrame", &Attachable::InheritsFrame, &Attachable::SetInheritsFrame) - - .def("IsAttached", &Attachable::IsAttached) - .def("IsAttachedTo", &Attachable::IsAttachedTo) - - .def("RemoveFromParent", &LuaAdaptersAttachable::RemoveFromParent1, luabind::adopt(luabind::return_value)) - .def("RemoveFromParent", &LuaAdaptersAttachable::RemoveFromParent2, luabind::adopt(luabind::return_value)); + .property("ParentOffset", &Attachable::GetParentOffset, &Attachable::SetParentOffset) + .property("JointStrength", &Attachable::GetJointStrength, &Attachable::SetJointStrength) + .property("JointStiffness", &Attachable::GetJointStiffness, &Attachable::SetJointStiffness) + .property("JointOffset", &Attachable::GetJointOffset, &Attachable::SetJointOffset) + .property("JointPos", &Attachable::GetJointPos) + .property("DeleteWhenRemovedFromParent", &Attachable::GetDeleteWhenRemovedFromParent, &Attachable::SetDeleteWhenRemovedFromParent) + .property("GibWhenRemovedFromParent", &Attachable::GetGibWhenRemovedFromParent, &Attachable::SetGibWhenRemovedFromParent) + .property("ApplyTransferredForcesAtOffset", &Attachable::GetApplyTransferredForcesAtOffset, &Attachable::SetApplyTransferredForcesAtOffset) + .property("BreakWound", &Attachable::GetBreakWound, &LuaAdaptersPropertyOwnershipSafetyFaker::AttachableSetBreakWound) + .property("ParentBreakWound", &Attachable::GetParentBreakWound, &LuaAdaptersPropertyOwnershipSafetyFaker::AttachableSetParentBreakWound) + .property("InheritsHFlipped", &Attachable::InheritsHFlipped, &Attachable::SetInheritsHFlipped) + .property("InheritsRotAngle", &Attachable::InheritsRotAngle, &Attachable::SetInheritsRotAngle) + .property("InheritedRotAngleOffset", &Attachable::GetInheritedRotAngleOffset, &Attachable::SetInheritedRotAngleOffset) + .property("AtomSubgroupID", &Attachable::GetAtomSubgroupID) + .property("CollidesWithTerrainWhileAttached", &Attachable::GetCollidesWithTerrainWhileAttached, &Attachable::SetCollidesWithTerrainWhileAttached) + .property("IgnoresParticlesWhileAttached", &Attachable::GetIgnoresParticlesWhileAttached, &Attachable::SetIgnoresParticlesWhileAttached) + .property("CanCollideWithTerrain", &Attachable::CanCollideWithTerrain) + .property("DrawnAfterParent", &Attachable::IsDrawnAfterParent, &Attachable::SetDrawnAfterParent) + .property("InheritsFrame", &Attachable::InheritsFrame, &Attachable::SetInheritsFrame) + + .def("IsAttached", &Attachable::IsAttached) + .def("IsAttachedTo", &Attachable::IsAttachedTo) + + .def("RemoveFromParent", &LuaAdaptersAttachable::RemoveFromParent1, luabind::adopt(luabind::return_value)) + .def("RemoveFromParent", &LuaAdaptersAttachable::RemoveFromParent2, luabind::adopt(luabind::return_value)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Deployment) { return AbstractTypeLuaClassDefinition(Deployment, SceneObject) - .property("ID", &Deployment::GetID) - .property("HFlipped", &Deployment::IsHFlipped) - .property("SpawnRadius", &Deployment::GetSpawnRadius) + .property("ID", &Deployment::GetID) + .property("HFlipped", &Deployment::IsHFlipped) + .property("SpawnRadius", &Deployment::GetSpawnRadius) - .def("GetLoadoutName", &Deployment::GetLoadoutName) - .def("CreateDeployedActor", (Actor * (Deployment::*)())&Deployment::CreateDeployedActor, luabind::adopt(luabind::result)) - .def("CreateDeployedObject", (SceneObject * (Deployment::*)())&Deployment::CreateDeployedObject, luabind::adopt(luabind::result)); + .def("GetLoadoutName", &Deployment::GetLoadoutName) + .def("CreateDeployedActor", (Actor * (Deployment::*)()) & Deployment::CreateDeployedActor, luabind::adopt(luabind::result)) + .def("CreateDeployedObject", (SceneObject * (Deployment::*)()) & Deployment::CreateDeployedObject, luabind::adopt(luabind::result)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Emission) { return AbstractTypeLuaClassDefinition(Emission, Entity) - .property("ParticlesPerMinute", &Emission::GetRate, &Emission::SetRate) - .property("MinVelocity", &Emission::GetMinVelocity, &Emission::SetMinVelocity) - .property("MaxVelocity", &Emission::GetMaxVelocity, &Emission::SetMaxVelocity) - .property("PushesEmitter", &Emission::PushesEmitter, &Emission::SetPushesEmitter) - .property("LifeVariation", &Emission::GetLifeVariation, &Emission::SetLifeVariation) - .property("BurstSize", &Emission::GetBurstSize, &Emission::SetBurstSize) - .property("Spread", &Emission::GetSpread, &Emission::SetSpread) - .property("Offset", &Emission::GetOffset, &Emission::SetOffset) + .property("ParticlesPerMinute", &Emission::GetRate, &Emission::SetRate) + .property("MinVelocity", &Emission::GetMinVelocity, &Emission::SetMinVelocity) + .property("MaxVelocity", &Emission::GetMaxVelocity, &Emission::SetMaxVelocity) + .property("PushesEmitter", &Emission::PushesEmitter, &Emission::SetPushesEmitter) + .property("LifeVariation", &Emission::GetLifeVariation, &Emission::SetLifeVariation) + .property("BurstSize", &Emission::GetBurstSize, &Emission::SetBurstSize) + .property("Spread", &Emission::GetSpread, &Emission::SetSpread) + .property("Offset", &Emission::GetOffset, &Emission::SetOffset) - .def("ResetEmissionTimers", &Emission::ResetEmissionTimers); + .def("ResetEmissionTimers", &Emission::ResetEmissionTimers); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Gib) { return luabind::class_("Gib") - .property("ParticlePreset", &Gib::GetParticlePreset, &Gib::SetParticlePreset) - .property("MinVelocity", &Gib::GetMinVelocity, &Gib::SetMinVelocity) - .property("MaxVelocity", &Gib::GetMaxVelocity, &Gib::SetMaxVelocity) - .property("SpreadMode", &Gib::GetSpreadMode, &Gib::SetSpreadMode) - - .def_readwrite("Offset", &Gib::m_Offset) - .def_readwrite("Count", &Gib::m_Count) - .def_readwrite("Spread", &Gib::m_Spread) - .def_readwrite("LifeVariation", &Gib::m_LifeVariation) - .def_readwrite("InheritsVel", &Gib::m_InheritsVel) - .def_readwrite("IgnoresTeamHits", &Gib::m_IgnoresTeamHits) - - .enum_("SpreadMode")[ - luabind::value("SpreadRandom", Gib::SpreadMode::SpreadRandom), - luabind::value("SpreadEven", Gib::SpreadMode::SpreadEven), - luabind::value("SpreadSpiral", Gib::SpreadMode::SpreadSpiral) - ]; + .property("ParticlePreset", &Gib::GetParticlePreset, &Gib::SetParticlePreset) + .property("MinVelocity", &Gib::GetMinVelocity, &Gib::SetMinVelocity) + .property("MaxVelocity", &Gib::GetMaxVelocity, &Gib::SetMaxVelocity) + .property("SpreadMode", &Gib::GetSpreadMode, &Gib::SetSpreadMode) + + .def_readwrite("Offset", &Gib::m_Offset) + .def_readwrite("Count", &Gib::m_Count) + .def_readwrite("Spread", &Gib::m_Spread) + .def_readwrite("LifeVariation", &Gib::m_LifeVariation) + .def_readwrite("InheritsVel", &Gib::m_InheritsVel) + .def_readwrite("IgnoresTeamHits", &Gib::m_IgnoresTeamHits) + + .enum_("SpreadMode")[luabind::value("SpreadRandom", Gib::SpreadMode::SpreadRandom), + luabind::value("SpreadEven", Gib::SpreadMode::SpreadEven), + luabind::value("SpreadSpiral", Gib::SpreadMode::SpreadSpiral)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, GlobalScript) { return AbstractTypeLuaClassDefinition(GlobalScript, Entity) - .def("Deactivate", &LuaAdaptersGlobalScript::Deactivate); + .def("Deactivate", &LuaAdaptersGlobalScript::Deactivate); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, HDFirearm) { return ConcreteTypeLuaClassDefinition(HDFirearm, HeldDevice) - .property("ReloadEndOffset", &HDFirearm::GetReloadEndOffset, &HDFirearm::SetReloadEndOffset) - .property("RateOfFire", &HDFirearm::GetRateOfFire, &HDFirearm::SetRateOfFire) - .property("MSPerRound", &HDFirearm::GetMSPerRound) - .property("FullAuto", &HDFirearm::IsFullAuto, &HDFirearm::SetFullAuto) - .property("Reloadable", &HDFirearm::IsReloadable, &HDFirearm::SetReloadable) - .property("DualReloadable", &HDFirearm::IsDualReloadable, &HDFirearm::SetDualReloadable) - .property("OneHandedReloadTimeMultiplier", &HDFirearm::GetOneHandedReloadTimeMultiplier, &HDFirearm::SetOneHandedReloadTimeMultiplier) - .property("ReloadAngle", &HDFirearm::GetReloadAngle, &HDFirearm::SetReloadAngle) - .property("OneHandedReloadAngle", &HDFirearm::GetOneHandedReloadAngle, &HDFirearm::SetOneHandedReloadAngle) - .property("CurrentReloadAngle", &HDFirearm::GetCurrentReloadAngle) - .property("RoundInMagCount", &HDFirearm::GetRoundInMagCount) - .property("RoundInMagCapacity", &HDFirearm::GetRoundInMagCapacity) - .property("Magazine", &HDFirearm::GetMagazine, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetMagazine) - .property("Flash", &HDFirearm::GetFlash, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetFlash) - .property("PreFireSound", &HDFirearm::GetPreFireSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetPreFireSound) - .property("FireSound", &HDFirearm::GetFireSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetFireSound) - .property("FireEchoSound", &HDFirearm::GetFireEchoSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetFireEchoSound) - .property("ActiveSound", &HDFirearm::GetActiveSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetActiveSound) - .property("DeactivationSound", &HDFirearm::GetDeactivationSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetDeactivationSound) - .property("EmptySound", &HDFirearm::GetEmptySound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetEmptySound) - .property("ReloadStartSound", &HDFirearm::GetReloadStartSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetReloadStartSound) - .property("ReloadEndSound", &HDFirearm::GetReloadEndSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetReloadEndSound) - .property("ActivationDelay", &HDFirearm::GetActivationDelay, &HDFirearm::SetActivationDelay) - .property("DeactivationDelay", &HDFirearm::GetDeactivationDelay, &HDFirearm::SetDeactivationDelay) - .property("BaseReloadTime", &HDFirearm::GetBaseReloadTime, &HDFirearm::SetBaseReloadTime) - .property("ReloadTime", &HDFirearm::GetReloadTime) - .property("ReloadProgress", &HDFirearm::GetReloadProgress) - .property("ShakeRange", &HDFirearm::GetShakeRange, &HDFirearm::SetShakeRange) - .property("SharpShakeRange", &HDFirearm::GetSharpShakeRange, &HDFirearm::SetSharpShakeRange) - .property("NoSupportFactor", &HDFirearm::GetNoSupportFactor, &HDFirearm::SetNoSupportFactor) - .property("ParticleSpreadRange", &HDFirearm::GetParticleSpreadRange, &HDFirearm::SetParticleSpreadRange) - .property("ShellVelVariation", &HDFirearm::GetShellVelVariation, &HDFirearm::SetShellVelVariation) - .property("FiredOnce", &HDFirearm::FiredOnce) - .property("FiredFrame", &HDFirearm::FiredFrame) - .property("CanFire", &HDFirearm::CanFire) - .property("RoundsFired", &HDFirearm::RoundsFired) - .property("IsAnimatedManually", &HDFirearm::IsAnimatedManually, &HDFirearm::SetAnimatedManually) - .property("RecoilTransmission", &HDFirearm::GetJointStiffness, &HDFirearm::SetJointStiffness) - - .def("GetAIFireVel", &HDFirearm::GetAIFireVel) - .def("GetAIBulletLifeTime", &HDFirearm::GetAIBulletLifeTime) - .def("GetBulletAccScalar", &HDFirearm::GetBulletAccScalar) - .def("GetAIBlastRadius", &HDFirearm::GetAIBlastRadius) - .def("GetAIPenetration", &HDFirearm::GetAIPenetration) - .def("CompareTrajectories", &HDFirearm::CompareTrajectories) - .def("GetNextMagazineName", &HDFirearm::GetNextMagazineName) - .def("SetNextMagazineName", &HDFirearm::SetNextMagazineName); + .property("ReloadEndOffset", &HDFirearm::GetReloadEndOffset, &HDFirearm::SetReloadEndOffset) + .property("RateOfFire", &HDFirearm::GetRateOfFire, &HDFirearm::SetRateOfFire) + .property("MSPerRound", &HDFirearm::GetMSPerRound) + .property("FullAuto", &HDFirearm::IsFullAuto, &HDFirearm::SetFullAuto) + .property("Reloadable", &HDFirearm::IsReloadable, &HDFirearm::SetReloadable) + .property("DualReloadable", &HDFirearm::IsDualReloadable, &HDFirearm::SetDualReloadable) + .property("OneHandedReloadTimeMultiplier", &HDFirearm::GetOneHandedReloadTimeMultiplier, &HDFirearm::SetOneHandedReloadTimeMultiplier) + .property("ReloadAngle", &HDFirearm::GetReloadAngle, &HDFirearm::SetReloadAngle) + .property("OneHandedReloadAngle", &HDFirearm::GetOneHandedReloadAngle, &HDFirearm::SetOneHandedReloadAngle) + .property("CurrentReloadAngle", &HDFirearm::GetCurrentReloadAngle) + .property("RoundInMagCount", &HDFirearm::GetRoundInMagCount) + .property("RoundInMagCapacity", &HDFirearm::GetRoundInMagCapacity) + .property("Magazine", &HDFirearm::GetMagazine, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetMagazine) + .property("Flash", &HDFirearm::GetFlash, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetFlash) + .property("PreFireSound", &HDFirearm::GetPreFireSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetPreFireSound) + .property("FireSound", &HDFirearm::GetFireSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetFireSound) + .property("FireEchoSound", &HDFirearm::GetFireEchoSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetFireEchoSound) + .property("ActiveSound", &HDFirearm::GetActiveSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetActiveSound) + .property("DeactivationSound", &HDFirearm::GetDeactivationSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetDeactivationSound) + .property("EmptySound", &HDFirearm::GetEmptySound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetEmptySound) + .property("ReloadStartSound", &HDFirearm::GetReloadStartSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetReloadStartSound) + .property("ReloadEndSound", &HDFirearm::GetReloadEndSound, &LuaAdaptersPropertyOwnershipSafetyFaker::HDFirearmSetReloadEndSound) + .property("ActivationDelay", &HDFirearm::GetActivationDelay, &HDFirearm::SetActivationDelay) + .property("DeactivationDelay", &HDFirearm::GetDeactivationDelay, &HDFirearm::SetDeactivationDelay) + .property("BaseReloadTime", &HDFirearm::GetBaseReloadTime, &HDFirearm::SetBaseReloadTime) + .property("ReloadTime", &HDFirearm::GetReloadTime) + .property("ReloadProgress", &HDFirearm::GetReloadProgress) + .property("ShakeRange", &HDFirearm::GetShakeRange, &HDFirearm::SetShakeRange) + .property("SharpShakeRange", &HDFirearm::GetSharpShakeRange, &HDFirearm::SetSharpShakeRange) + .property("NoSupportFactor", &HDFirearm::GetNoSupportFactor, &HDFirearm::SetNoSupportFactor) + .property("ParticleSpreadRange", &HDFirearm::GetParticleSpreadRange, &HDFirearm::SetParticleSpreadRange) + .property("ShellVelVariation", &HDFirearm::GetShellVelVariation, &HDFirearm::SetShellVelVariation) + .property("FiredOnce", &HDFirearm::FiredOnce) + .property("FiredFrame", &HDFirearm::FiredFrame) + .property("CanFire", &HDFirearm::CanFire) + .property("RoundsFired", &HDFirearm::RoundsFired) + .property("IsAnimatedManually", &HDFirearm::IsAnimatedManually, &HDFirearm::SetAnimatedManually) + .property("RecoilTransmission", &HDFirearm::GetJointStiffness, &HDFirearm::SetJointStiffness) + + .def("GetAIFireVel", &HDFirearm::GetAIFireVel) + .def("GetAIBulletLifeTime", &HDFirearm::GetAIBulletLifeTime) + .def("GetBulletAccScalar", &HDFirearm::GetBulletAccScalar) + .def("GetAIBlastRadius", &HDFirearm::GetAIBlastRadius) + .def("GetAIPenetration", &HDFirearm::GetAIPenetration) + .def("CompareTrajectories", &HDFirearm::CompareTrajectories) + .def("GetNextMagazineName", &HDFirearm::GetNextMagazineName) + .def("SetNextMagazineName", &HDFirearm::SetNextMagazineName); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, HeldDevice) { return ConcreteTypeLuaClassDefinition(HeldDevice, Attachable) - .property("SupportPos", &HeldDevice::GetSupportPos) - .property("MagazinePos", &HeldDevice::GetMagazinePos) - .property("MuzzlePos", &HeldDevice::GetMuzzlePos) - .property("MuzzleOffset", &HeldDevice::GetMuzzleOffset, &HeldDevice::SetMuzzleOffset) - .property("StanceOffset", &HeldDevice::GetStanceOffset, &HeldDevice::SetStanceOffset) - .property("SharpStanceOffset", &HeldDevice::GetSharpStanceOffset, &HeldDevice::SetSharpStanceOffset) - .property("SharpLength", &HeldDevice::GetSharpLength, &HeldDevice::SetSharpLength) - .property("SharpLength", &HeldDevice::GetSharpLength, &HeldDevice::SetSharpLength) - .property("Supportable", &HeldDevice::IsSupportable, &HeldDevice::SetSupportable) - .property("SupportOffset", &HeldDevice::GetSupportOffset, &HeldDevice::SetSupportOffset) - .property("UseSupportOffsetWhileReloading", &HeldDevice::GetUseSupportOffsetWhileReloading, &HeldDevice::SetUseSupportOffsetWhileReloading) - .property("HasPickupLimitations", &HeldDevice::HasPickupLimitations) - .property("UnPickupable", &HeldDevice::IsUnPickupable, &HeldDevice::SetUnPickupable) - .property("GripStrengthMultiplier", &HeldDevice::GetGripStrengthMultiplier, &HeldDevice::SetGripStrengthMultiplier) - .property("Supported", &HeldDevice::GetSupported, &HeldDevice::SetSupported) - .property("GetsHitByMOsWhenHeld", &HeldDevice::GetsHitByMOsWhenHeld, &HeldDevice::SetGetsHitByMOsWhenHeld) - .property("VisualRecoilMultiplier", &HeldDevice::GetVisualRecoilMultiplier, &HeldDevice::SetVisualRecoilMultiplier) - - .def("IsBeingHeld", &HeldDevice::IsBeingHeld) - .def("IsWeapon", &HeldDevice::IsWeapon) - .def("IsTool", &HeldDevice::IsTool) - .def("IsShield", &HeldDevice::IsShield) - .def("IsDualWieldable", &HeldDevice::IsDualWieldable) - .def("SetDualWieldable", &HeldDevice::SetDualWieldable) - .def("IsOneHanded", &HeldDevice::IsOneHanded) - .def("SetOneHanded", &HeldDevice::SetOneHanded) - .def("Activate", &HeldDevice::Activate) - .def("Deactivate", &HeldDevice::Deactivate) - .def("Reload", &HeldDevice::Reload) - .def("IsActivated", &HeldDevice::IsActivated) - .def("IsReloading", &HeldDevice::IsReloading) - .def("DoneReloading", &HeldDevice::DoneReloading) - .def("NeedsReloading", &HeldDevice::NeedsReloading) - .def("IsFull", &HeldDevice::IsFull) - .def("IsEmpty", &HeldDevice::IsEmpty) - .def("IsPickupableBy", &HeldDevice::IsPickupableBy) - .def("AddPickupableByPresetName", &HeldDevice::AddPickupableByPresetName) - .def("RemovePickupableByPresetName", &HeldDevice::RemovePickupableByPresetName); + .property("SupportPos", &HeldDevice::GetSupportPos) + .property("MagazinePos", &HeldDevice::GetMagazinePos) + .property("MuzzlePos", &HeldDevice::GetMuzzlePos) + .property("MuzzleOffset", &HeldDevice::GetMuzzleOffset, &HeldDevice::SetMuzzleOffset) + .property("StanceOffset", &HeldDevice::GetStanceOffset, &HeldDevice::SetStanceOffset) + .property("SharpStanceOffset", &HeldDevice::GetSharpStanceOffset, &HeldDevice::SetSharpStanceOffset) + .property("SharpLength", &HeldDevice::GetSharpLength, &HeldDevice::SetSharpLength) + .property("SharpLength", &HeldDevice::GetSharpLength, &HeldDevice::SetSharpLength) + .property("Supportable", &HeldDevice::IsSupportable, &HeldDevice::SetSupportable) + .property("SupportOffset", &HeldDevice::GetSupportOffset, &HeldDevice::SetSupportOffset) + .property("UseSupportOffsetWhileReloading", &HeldDevice::GetUseSupportOffsetWhileReloading, &HeldDevice::SetUseSupportOffsetWhileReloading) + .property("HasPickupLimitations", &HeldDevice::HasPickupLimitations) + .property("UnPickupable", &HeldDevice::IsUnPickupable, &HeldDevice::SetUnPickupable) + .property("GripStrengthMultiplier", &HeldDevice::GetGripStrengthMultiplier, &HeldDevice::SetGripStrengthMultiplier) + .property("Supported", &HeldDevice::GetSupported, &HeldDevice::SetSupported) + .property("GetsHitByMOsWhenHeld", &HeldDevice::GetsHitByMOsWhenHeld, &HeldDevice::SetGetsHitByMOsWhenHeld) + .property("VisualRecoilMultiplier", &HeldDevice::GetVisualRecoilMultiplier, &HeldDevice::SetVisualRecoilMultiplier) + + .def("IsBeingHeld", &HeldDevice::IsBeingHeld) + .def("IsWeapon", &HeldDevice::IsWeapon) + .def("IsTool", &HeldDevice::IsTool) + .def("IsShield", &HeldDevice::IsShield) + .def("IsDualWieldable", &HeldDevice::IsDualWieldable) + .def("SetDualWieldable", &HeldDevice::SetDualWieldable) + .def("IsOneHanded", &HeldDevice::IsOneHanded) + .def("SetOneHanded", &HeldDevice::SetOneHanded) + .def("Activate", &HeldDevice::Activate) + .def("Deactivate", &HeldDevice::Deactivate) + .def("Reload", &HeldDevice::Reload) + .def("IsActivated", &HeldDevice::IsActivated) + .def("IsReloading", &HeldDevice::IsReloading) + .def("DoneReloading", &HeldDevice::DoneReloading) + .def("NeedsReloading", &HeldDevice::NeedsReloading) + .def("IsFull", &HeldDevice::IsFull) + .def("IsEmpty", &HeldDevice::IsEmpty) + .def("IsPickupableBy", &HeldDevice::IsPickupableBy) + .def("AddPickupableByPresetName", &HeldDevice::AddPickupableByPresetName) + .def("RemovePickupableByPresetName", &HeldDevice::RemovePickupableByPresetName); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Leg) { return ConcreteTypeLuaClassDefinition(Leg, Attachable) - .property("Foot", &Leg::GetFoot, &LuaAdaptersPropertyOwnershipSafetyFaker::LegSetFoot) - .property("MoveSpeed", &Leg::GetMoveSpeed, &Leg::SetMoveSpeed); + .property("Foot", &Leg::GetFoot, &LuaAdaptersPropertyOwnershipSafetyFaker::LegSetFoot) + .property("MoveSpeed", &Leg::GetMoveSpeed, &Leg::SetMoveSpeed); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, LimbPath) { return luabind::class_("LimbPath") - .property("StartOffset", &LimbPath::GetStartOffset, &LimbPath::SetStartOffset) - .property("SegmentCount", &LimbPath::GetSegCount) - .property("TravelSpeedMultiplier", &LimbPath::GetTravelSpeedMultiplier, &LimbPath::SetTravelSpeedMultiplier) + .property("StartOffset", &LimbPath::GetStartOffset, &LimbPath::SetStartOffset) + .property("SegmentCount", &LimbPath::GetSegCount) + .property("TravelSpeedMultiplier", &LimbPath::GetTravelSpeedMultiplier, &LimbPath::SetTravelSpeedMultiplier) - .def("GetSegment", &LimbPath::GetSegment); + .def("GetSegment", &LimbPath::GetSegment); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Magazine) { return ConcreteTypeLuaClassDefinition(Magazine, Attachable) - .property("NextRound", &Magazine::GetNextRound) - .property("RoundCount", &Magazine::GetRoundCount, &Magazine::SetRoundCount) - .property("IsEmpty", &Magazine::IsEmpty) - .property("IsFull", &Magazine::IsFull) - .property("IsOverHalfFull", &Magazine::IsOverHalfFull) - .property("Capacity", &Magazine::GetCapacity) - .property("Discardable", &Magazine::IsDiscardable); + .property("NextRound", &Magazine::GetNextRound) + .property("RoundCount", &Magazine::GetRoundCount, &Magazine::SetRoundCount) + .property("IsEmpty", &Magazine::IsEmpty) + .property("IsFull", &Magazine::IsFull) + .property("IsOverHalfFull", &Magazine::IsOverHalfFull) + .property("Capacity", &Magazine::GetCapacity) + .property("Discardable", &Magazine::IsDiscardable); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Material) { return luabind::class_("Material") - .property("ID", &Material::GetIndex) - .property("Restitution", &Material::GetRestitution) - .property("Bounce", &Material::GetRestitution) - .property("Friction", &Material::GetFriction) - .property("Stickiness", &Material::GetStickiness) - .property("Strength", &Material::GetIntegrity) - .property("StructuralIntegrity", &Material::GetIntegrity) - .property("DensityKGPerVolumeL", &Material::GetVolumeDensity) - .property("DensityKGPerPixel", &Material::GetPixelDensity) - .property("SettleMaterial", &Material::GetSettleMaterial) - .property("SpawnMaterial", &Material::GetSpawnMaterial) - .property("TransformsInto", &Material::GetSpawnMaterial) - .property("IsScrap", &Material::IsScrap); + .property("ID", &Material::GetIndex) + .property("Restitution", &Material::GetRestitution) + .property("Bounce", &Material::GetRestitution) + .property("Friction", &Material::GetFriction) + .property("Stickiness", &Material::GetStickiness) + .property("Strength", &Material::GetIntegrity) + .property("StructuralIntegrity", &Material::GetIntegrity) + .property("DensityKGPerVolumeL", &Material::GetVolumeDensity) + .property("DensityKGPerPixel", &Material::GetPixelDensity) + .property("SettleMaterial", &Material::GetSettleMaterial) + .property("SpawnMaterial", &Material::GetSpawnMaterial) + .property("TransformsInto", &Material::GetSpawnMaterial) + .property("IsScrap", &Material::IsScrap); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, MetaPlayer) { return luabind::class_("MetaPlayer") - .def(luabind::constructor<>()) + .def(luabind::constructor<>()) - .property("NativeTechModule", &MetaPlayer::GetNativeTechModule) - .property("ForeignCostMultiplier", &MetaPlayer::GetForeignCostMultiplier) - .property("NativeCostMultiplier", &MetaPlayer::GetNativeCostMultiplier) - .property("InGamePlayer", &MetaPlayer::GetInGamePlayer) - .property("BrainPoolCount", &MetaPlayer::GetBrainPoolCount, &MetaPlayer::SetBrainPoolCount) + .property("NativeTechModule", &MetaPlayer::GetNativeTechModule) + .property("ForeignCostMultiplier", &MetaPlayer::GetForeignCostMultiplier) + .property("NativeCostMultiplier", &MetaPlayer::GetNativeCostMultiplier) + .property("InGamePlayer", &MetaPlayer::GetInGamePlayer) + .property("BrainPoolCount", &MetaPlayer::GetBrainPoolCount, &MetaPlayer::SetBrainPoolCount) - .def("ChangeBrainPoolCount", &MetaPlayer::ChangeBrainPoolCount); + .def("ChangeBrainPoolCount", &MetaPlayer::ChangeBrainPoolCount); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, MOPixel) { return ConcreteTypeLuaClassDefinition(MOPixel, MovableObject) - .property("TrailLength", &MOPixel::GetTrailLength, &MOPixel::SetTrailLength) - .property("Staininess", &MOPixel::GetStaininess, &MOPixel::SetStaininess); + .property("TrailLength", &MOPixel::GetTrailLength, &MOPixel::SetTrailLength) + .property("Staininess", &MOPixel::GetStaininess, &MOPixel::SetStaininess); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, MOSParticle) { return ConcreteTypeLuaClassDefinition(MOSParticle, MOSprite); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, MOSprite) { return AbstractTypeLuaClassDefinition(MOSprite, MovableObject) - .property("Diameter", &MOSprite::GetDiameter) - .property("BoundingBox", &MOSprite::GetBoundingBox) - .property("FrameCount", &MOSprite::GetFrameCount) - .property("SpriteOffset", &MOSprite::GetSpriteOffset, &MOSprite::SetSpriteOffset) - .property("HFlipped", &MOSprite::IsHFlipped, &MOSprite::SetHFlipped) - .property("FlipFactor", &MOSprite::GetFlipFactor) - .property("RotAngle", &MOSprite::GetRotAngle, &MOSprite::SetRotAngle) - .property("PrevRotAngle", &MOSprite::GetPrevRotAngle) - .property("AngularVel", &MOSprite::GetAngularVel, &MOSprite::SetAngularVel) - .property("Frame", &MOSprite::GetFrame, &MOSprite::SetFrame) - .property("SpriteAnimMode", &MOSprite::GetSpriteAnimMode, &MOSprite::SetSpriteAnimMode) - .property("SpriteAnimDuration", &MOSprite::GetSpriteAnimDuration, &MOSprite::SetSpriteAnimDuration) - - .def("SetNextFrame", &MOSprite::SetNextFrame) - .def("IsTooFast", &MOSprite::IsTooFast) - .def("IsOnScenePoint", &MOSprite::IsOnScenePoint) - .def("RotateOffset", &MOSprite::RotateOffset) - .def("UnRotateOffset", &MOSprite::UnRotateOffset) - .def("FacingAngle", &MOSprite::FacingAngle) - .def("GetSpriteWidth", &MOSprite::GetSpriteWidth) - .def("GetSpriteHeight", &MOSprite::GetSpriteHeight) - .def("GetIconWidth", &MOSprite::GetIconWidth) - .def("GetIconHeight", &MOSprite::GetIconHeight) - .def("SetEntryWound", &MOSprite::SetEntryWound) - .def("SetExitWound", &MOSprite::SetExitWound) - .def("GetEntryWoundPresetName", &MOSprite::GetEntryWoundPresetName) - .def("GetExitWoundPresetName", &MOSprite::GetExitWoundPresetName) - - .enum_("SpriteAnimMode")[ - luabind::value("NOANIM", SpriteAnimMode::NOANIM), - luabind::value("ALWAYSLOOP", SpriteAnimMode::ALWAYSLOOP), - luabind::value("ALWAYSRANDOM", SpriteAnimMode::ALWAYSRANDOM), - luabind::value("ALWAYSPINGPONG", SpriteAnimMode::ALWAYSPINGPONG), - luabind::value("LOOPWHENACTIVE", SpriteAnimMode::LOOPWHENACTIVE), - luabind::value("LOOPWHENOPENCLOSE", SpriteAnimMode::LOOPWHENOPENCLOSE), - luabind::value("PINGPONGOPENCLOSE", SpriteAnimMode::PINGPONGOPENCLOSE), - luabind::value("OVERLIFETIME", SpriteAnimMode::OVERLIFETIME), - luabind::value("ONCOLLIDE", SpriteAnimMode::ONCOLLIDE) - ]; + .property("Diameter", &MOSprite::GetDiameter) + .property("BoundingBox", &MOSprite::GetBoundingBox) + .property("FrameCount", &MOSprite::GetFrameCount) + .property("SpriteOffset", &MOSprite::GetSpriteOffset, &MOSprite::SetSpriteOffset) + .property("HFlipped", &MOSprite::IsHFlipped, &MOSprite::SetHFlipped) + .property("FlipFactor", &MOSprite::GetFlipFactor) + .property("RotAngle", &MOSprite::GetRotAngle, &MOSprite::SetRotAngle) + .property("PrevRotAngle", &MOSprite::GetPrevRotAngle) + .property("AngularVel", &MOSprite::GetAngularVel, &MOSprite::SetAngularVel) + .property("Frame", &MOSprite::GetFrame, &MOSprite::SetFrame) + .property("SpriteAnimMode", &MOSprite::GetSpriteAnimMode, &MOSprite::SetSpriteAnimMode) + .property("SpriteAnimDuration", &MOSprite::GetSpriteAnimDuration, &MOSprite::SetSpriteAnimDuration) + + .def("SetNextFrame", &MOSprite::SetNextFrame) + .def("IsTooFast", &MOSprite::IsTooFast) + .def("IsOnScenePoint", &MOSprite::IsOnScenePoint) + .def("RotateOffset", &MOSprite::RotateOffset) + .def("UnRotateOffset", &MOSprite::UnRotateOffset) + .def("FacingAngle", &MOSprite::FacingAngle) + .def("GetSpriteWidth", &MOSprite::GetSpriteWidth) + .def("GetSpriteHeight", &MOSprite::GetSpriteHeight) + .def("GetIconWidth", &MOSprite::GetIconWidth) + .def("GetIconHeight", &MOSprite::GetIconHeight) + .def("SetEntryWound", &MOSprite::SetEntryWound) + .def("SetExitWound", &MOSprite::SetExitWound) + .def("GetEntryWoundPresetName", &MOSprite::GetEntryWoundPresetName) + .def("GetExitWoundPresetName", &MOSprite::GetExitWoundPresetName) + + .enum_("SpriteAnimMode")[luabind::value("NOANIM", SpriteAnimMode::NOANIM), + luabind::value("ALWAYSLOOP", SpriteAnimMode::ALWAYSLOOP), + luabind::value("ALWAYSRANDOM", SpriteAnimMode::ALWAYSRANDOM), + luabind::value("ALWAYSPINGPONG", SpriteAnimMode::ALWAYSPINGPONG), + luabind::value("LOOPWHENACTIVE", SpriteAnimMode::LOOPWHENACTIVE), + luabind::value("LOOPWHENOPENCLOSE", SpriteAnimMode::LOOPWHENOPENCLOSE), + luabind::value("PINGPONGOPENCLOSE", SpriteAnimMode::PINGPONGOPENCLOSE), + luabind::value("OVERLIFETIME", SpriteAnimMode::OVERLIFETIME), + luabind::value("ONCOLLIDE", SpriteAnimMode::ONCOLLIDE)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, MOSRotating) { return ConcreteTypeLuaClassDefinition(MOSRotating, MOSprite) - //.property("Material", &MOSRotating::GetMaterial) - .property("IndividualRadius", &MOSRotating::GetIndividualRadius) - .property("IndividualDiameter", &MOSRotating::GetIndividualDiameter) - .property("IndividualMass", &MOSRotating::GetIndividualMass) - .property("RecoilForce", &MOSRotating::GetRecoilForce) - .property("RecoilOffset", &MOSRotating::GetRecoilOffset) - .property("TravelImpulse", &MOSRotating::GetTravelImpulse, &MOSRotating::SetTravelImpulse) - .property("GibWoundLimit", (int (MOSRotating:: *)() const) &MOSRotating::GetGibWoundLimit, &MOSRotating::SetGibWoundLimit) - .property("GibSound", &MOSRotating::GetGibSound, &LuaAdaptersPropertyOwnershipSafetyFaker::MOSRotatingSetGibSound) - .property("GibImpulseLimit", &MOSRotating::GetGibImpulseLimit, &MOSRotating::SetGibImpulseLimit) - .property("WoundCountAffectsImpulseLimitRatio", &MOSRotating::GetWoundCountAffectsImpulseLimitRatio) - .property("GibAtEndOfLifetime", &MOSRotating::GetGibAtEndOfLifetime, &MOSRotating::SetGibAtEndOfLifetime) - .property("DamageMultiplier", &MOSRotating::GetDamageMultiplier, &MOSRotating::SetDamageMultiplier) - .property("WoundCount", (int (MOSRotating:: *)() const) &MOSRotating::GetWoundCount) - .property("OrientToVel", &MOSRotating::GetOrientToVel, &MOSRotating::SetOrientToVel) - - .def_readonly("Attachables", &MOSRotating::m_Attachables, luabind::return_stl_iterator) - .def_readonly("Wounds", &MOSRotating::m_Wounds, luabind::return_stl_iterator) - .def_readonly("Gibs", &MOSRotating::m_Gibs, luabind::return_stl_iterator) - - .def("AddRecoil", &MOSRotating::AddRecoil) - .def("SetRecoil", &MOSRotating::SetRecoil) - .def("IsRecoiled", &MOSRotating::IsRecoiled) - .def("EnableDeepCheck", &MOSRotating::EnableDeepCheck) - .def("ForceDeepCheck", &MOSRotating::ForceDeepCheck) - .def("GibThis", &MOSRotating::GibThis) - .def("MoveOutOfTerrain", &MOSRotating::MoveOutOfTerrain) - .def("FlashWhite", &MOSRotating::FlashWhite) - .def("GetGibWoundLimit", (int (MOSRotating:: *)() const) &MOSRotating::GetGibWoundLimit) - .def("GetGibWoundLimit", (int (MOSRotating:: *)(bool positiveDamage, bool negativeDamage, bool noDamage) const) &MOSRotating::GetGibWoundLimit) - .def("GetWoundCount", (int (MOSRotating:: *)() const) &MOSRotating::GetWoundCount) - .def("GetWoundCount", (int (MOSRotating:: *)(bool positiveDamage, bool negativeDamage, bool noDamage) const) &MOSRotating::GetWoundCount) - .def("GetWounds", &LuaAdaptersMOSRotating::GetWounds1, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetWounds", &LuaAdaptersMOSRotating::GetWounds2, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("AddWound", &MOSRotating::AddWound, luabind::adopt(_2)) - .def("RemoveWounds", (float (MOSRotating:: *)(int numberOfWoundsToRemove)) &MOSRotating::RemoveWounds) - .def("RemoveWounds", (float (MOSRotating:: *)(int numberOfWoundsToRemove, bool positiveDamage, bool negativeDamage, bool noDamage)) &MOSRotating::RemoveWounds) - .def("IsOnScenePoint", &MOSRotating::IsOnScenePoint) - .def("EraseFromTerrain", &MOSRotating::EraseFromTerrain) - .def("AddAttachable", (void (MOSRotating::*)(Attachable *attachableToAdd))&MOSRotating::AddAttachable, luabind::adopt(_2)) - .def("AddAttachable", (void (MOSRotating::*)(Attachable *attachableToAdd, const Vector &parentOffset))&MOSRotating::AddAttachable, luabind::adopt(_2)) - .def("RemoveAttachable", (Attachable *(MOSRotating:: *)(long uniqueIDOfAttachableToRemove)) &MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) - .def("RemoveAttachable", (Attachable *(MOSRotating:: *)(long uniqueIDOfAttachableToRemove, bool addToMovableMan, bool addBreakWounds)) &MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) - .def("RemoveAttachable", (Attachable *(MOSRotating:: *)(Attachable *attachableToRemove))&MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) - .def("RemoveAttachable", (Attachable *(MOSRotating:: *)(Attachable *attachableToRemove, bool addToMovableMan, bool addBreakWounds)) &MOSRotating::RemoveAttachable) - .def("AddEmitter", (void (MOSRotating::*)(Attachable *attachableToAdd))&MOSRotating::AddAttachable, luabind::adopt(_2)) - .def("AddEmitter", (void (MOSRotating::*)(Attachable *attachableToAdd, const Vector &parentOffset))&MOSRotating::AddAttachable, luabind::adopt(_2)) - .def("RemoveEmitter", (Attachable *(MOSRotating:: *)(long uniqueIDOfAttachableToRemove)) &MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) - .def("RemoveEmitter", (Attachable *(MOSRotating:: *)(long uniqueIDOfAttachableToRemove, bool addToMovableMan, bool addBreakWounds)) &MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) - .def("RemoveEmitter", (Attachable *(MOSRotating:: *)(Attachable *attachableToRemove)) &MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) - .def("RemoveEmitter", (Attachable *(MOSRotating:: *)(Attachable *attachableToRemove, bool addToMovableMan, bool addBreakWounds)) &MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) - - .def("GibThis", &LuaAdaptersMOSRotating::GibThis); + //.property("Material", &MOSRotating::GetMaterial) + .property("IndividualRadius", &MOSRotating::GetIndividualRadius) + .property("IndividualDiameter", &MOSRotating::GetIndividualDiameter) + .property("IndividualMass", &MOSRotating::GetIndividualMass) + .property("RecoilForce", &MOSRotating::GetRecoilForce) + .property("RecoilOffset", &MOSRotating::GetRecoilOffset) + .property("TravelImpulse", &MOSRotating::GetTravelImpulse, &MOSRotating::SetTravelImpulse) + .property("GibWoundLimit", (int(MOSRotating::*)() const) & MOSRotating::GetGibWoundLimit, &MOSRotating::SetGibWoundLimit) + .property("GibSound", &MOSRotating::GetGibSound, &LuaAdaptersPropertyOwnershipSafetyFaker::MOSRotatingSetGibSound) + .property("GibImpulseLimit", &MOSRotating::GetGibImpulseLimit, &MOSRotating::SetGibImpulseLimit) + .property("WoundCountAffectsImpulseLimitRatio", &MOSRotating::GetWoundCountAffectsImpulseLimitRatio) + .property("GibAtEndOfLifetime", &MOSRotating::GetGibAtEndOfLifetime, &MOSRotating::SetGibAtEndOfLifetime) + .property("DamageMultiplier", &MOSRotating::GetDamageMultiplier, &MOSRotating::SetDamageMultiplier) + .property("WoundCount", (int(MOSRotating::*)() const) & MOSRotating::GetWoundCount) + .property("OrientToVel", &MOSRotating::GetOrientToVel, &MOSRotating::SetOrientToVel) + + .def_readonly("Attachables", &MOSRotating::m_Attachables, luabind::return_stl_iterator) + .def_readonly("Wounds", &MOSRotating::m_Wounds, luabind::return_stl_iterator) + .def_readonly("Gibs", &MOSRotating::m_Gibs, luabind::return_stl_iterator) + + .def("AddRecoil", &MOSRotating::AddRecoil) + .def("SetRecoil", &MOSRotating::SetRecoil) + .def("IsRecoiled", &MOSRotating::IsRecoiled) + .def("EnableDeepCheck", &MOSRotating::EnableDeepCheck) + .def("ForceDeepCheck", &MOSRotating::ForceDeepCheck) + .def("GibThis", &MOSRotating::GibThis) + .def("MoveOutOfTerrain", &MOSRotating::MoveOutOfTerrain) + .def("FlashWhite", &MOSRotating::FlashWhite) + .def("GetGibWoundLimit", (int(MOSRotating::*)() const) & MOSRotating::GetGibWoundLimit) + .def("GetGibWoundLimit", (int(MOSRotating::*)(bool positiveDamage, bool negativeDamage, bool noDamage) const) & MOSRotating::GetGibWoundLimit) + .def("GetWoundCount", (int(MOSRotating::*)() const) & MOSRotating::GetWoundCount) + .def("GetWoundCount", (int(MOSRotating::*)(bool positiveDamage, bool negativeDamage, bool noDamage) const) & MOSRotating::GetWoundCount) + .def("GetWounds", &LuaAdaptersMOSRotating::GetWounds1, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetWounds", &LuaAdaptersMOSRotating::GetWounds2, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("AddWound", &MOSRotating::AddWound, luabind::adopt(_2)) + .def("RemoveWounds", (float(MOSRotating::*)(int numberOfWoundsToRemove)) & MOSRotating::RemoveWounds) + .def("RemoveWounds", (float(MOSRotating::*)(int numberOfWoundsToRemove, bool positiveDamage, bool negativeDamage, bool noDamage)) & MOSRotating::RemoveWounds) + .def("IsOnScenePoint", &MOSRotating::IsOnScenePoint) + .def("EraseFromTerrain", &MOSRotating::EraseFromTerrain) + .def("AddAttachable", (void(MOSRotating::*)(Attachable * attachableToAdd)) & MOSRotating::AddAttachable, luabind::adopt(_2)) + .def("AddAttachable", (void(MOSRotating::*)(Attachable * attachableToAdd, const Vector& parentOffset)) & MOSRotating::AddAttachable, luabind::adopt(_2)) + .def("RemoveAttachable", (Attachable * (MOSRotating::*)(long uniqueIDOfAttachableToRemove)) & MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) + .def("RemoveAttachable", (Attachable * (MOSRotating::*)(long uniqueIDOfAttachableToRemove, bool addToMovableMan, bool addBreakWounds)) & MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) + .def("RemoveAttachable", (Attachable * (MOSRotating::*)(Attachable * attachableToRemove)) & MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) + .def("RemoveAttachable", (Attachable * (MOSRotating::*)(Attachable * attachableToRemove, bool addToMovableMan, bool addBreakWounds)) & MOSRotating::RemoveAttachable) + .def("AddEmitter", (void(MOSRotating::*)(Attachable * attachableToAdd)) & MOSRotating::AddAttachable, luabind::adopt(_2)) + .def("AddEmitter", (void(MOSRotating::*)(Attachable * attachableToAdd, const Vector& parentOffset)) & MOSRotating::AddAttachable, luabind::adopt(_2)) + .def("RemoveEmitter", (Attachable * (MOSRotating::*)(long uniqueIDOfAttachableToRemove)) & MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) + .def("RemoveEmitter", (Attachable * (MOSRotating::*)(long uniqueIDOfAttachableToRemove, bool addToMovableMan, bool addBreakWounds)) & MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) + .def("RemoveEmitter", (Attachable * (MOSRotating::*)(Attachable * attachableToRemove)) & MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) + .def("RemoveEmitter", (Attachable * (MOSRotating::*)(Attachable * attachableToRemove, bool addToMovableMan, bool addBreakWounds)) & MOSRotating::RemoveAttachable, luabind::adopt(luabind::return_value)) + + .def("GibThis", &LuaAdaptersMOSRotating::GibThis); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, MovableObject) { return AbstractTypeLuaClassDefinition(MovableObject, SceneObject) - .property("Material", &MovableObject::GetMaterial) - .property("Mass", &MovableObject::GetMass, &MovableObject::SetMass) - .property("Pos", &MovableObject::GetPos, &MovableObject::SetPos) - .property("Vel", &MovableObject::GetVel, &MovableObject::SetVel) - .property("PrevPos", &MovableObject::GetPrevPos) - .property("PrevVel", &MovableObject::GetPrevVel) - .property("DistanceTravelled", &MovableObject::GetDistanceTravelled) - .property("AngularVel", &MovableObject::GetAngularVel, &MovableObject::SetAngularVel) - .property("Radius", &MovableObject::GetRadius) - .property("Diameter", &MovableObject::GetDiameter) - .property("Scale", &MovableObject::GetScale, &MovableObject::SetScale) - .property("EffectRotAngle", &MovableObject::GetEffectRotAngle, &MovableObject::SetEffectRotAngle) - .property("GlobalAccScalar", &MovableObject::GetGlobalAccScalar, &MovableObject::SetGlobalAccScalar) - .property("AirResistance", &MovableObject::GetAirResistance, &MovableObject::SetAirResistance) - .property("AirThreshold", &MovableObject::GetAirThreshold, &MovableObject::SetAirThreshold) - .property("Age", &MovableObject::GetAge, &MovableObject::SetAge) - .property("Lifetime", &MovableObject::GetLifetime, &MovableObject::SetLifetime) - .property("ID", &MovableObject::GetID) - .property("UniqueID", &MovableObject::GetUniqueID) - .property("RootID", &MovableObject::GetRootID) - .property("MOIDFootprint", &MovableObject::GetMOIDFootprint) - .property("Sharpness", &MovableObject::GetSharpness, &MovableObject::SetSharpness) - .property("HasEverBeenAddedToMovableMan", &MovableObject::HasEverBeenAddedToMovableMan) - .property("AboveHUDPos", &MovableObject::GetAboveHUDPos) - .property("HitsMOs", &MovableObject::HitsMOs, &MovableObject::SetToHitMOs) - .property("GetsHitByMOs", &MovableObject::GetsHitByMOs, &MovableObject::SetToGetHitByMOs) - .property("IgnoresTeamHits", &MovableObject::IgnoresTeamHits, &MovableObject::SetIgnoresTeamHits) - .property("IgnoresWhichTeam", &MovableObject::IgnoresWhichTeam) - .property("IgnoreTerrain", &MovableObject::IgnoreTerrain, &MovableObject::SetIgnoreTerrain) - .property("IgnoresActorHits", &MovableObject::GetIgnoresActorHits, &MovableObject::SetIgnoresActorHits) - .property("ToSettle", &MovableObject::ToSettle, &MovableObject::SetToSettle) - .property("ToDelete", &MovableObject::ToDelete, &MovableObject::SetToDelete) - .property("MissionCritical", &MovableObject::IsMissionCritical, &MovableObject::SetMissionCritical) - .property("HUDVisible", &MovableObject::GetHUDVisible, &MovableObject::SetHUDVisible) - .property("PinStrength", &MovableObject::GetPinStrength, &MovableObject::SetPinStrength) - .property("RestThreshold", &MovableObject::GetRestThreshold, &MovableObject::SetRestThreshold) - .property("DamageOnCollision", &MovableObject::DamageOnCollision, &MovableObject::SetDamageOnCollision) - .property("DamageOnPenetration", &MovableObject::DamageOnPenetration, &MovableObject::SetDamageOnPenetration) - .property("WoundDamageMultiplier", &MovableObject::WoundDamageMultiplier, &MovableObject::SetWoundDamageMultiplier) - .property("HitWhatMOID", &MovableObject::HitWhatMOID) - .property("HitWhatTerrMaterial", &MovableObject::HitWhatTerrMaterial) - .property("HitWhatParticleUniqueID", &MovableObject::HitWhatParticleUniqueID) - .property("ApplyWoundDamageOnCollision", &MovableObject::GetApplyWoundDamageOnCollision, &MovableObject::SetApplyWoundDamageOnCollision) - .property("ApplyWoundBurstDamageOnCollision", &MovableObject::GetApplyWoundBurstDamageOnCollision, &MovableObject::SetApplyWoundBurstDamageOnCollision) - .property("SimUpdatesBetweenScriptedUpdates", &MovableObject::GetSimUpdatesBetweenScriptedUpdates, &MovableObject::SetSimUpdatesBetweenScriptedUpdates) - - .def("GetParent", (MOSRotating * (MovableObject::*)())&MovableObject::GetParent) - .def("GetParent", (const MOSRotating * (MovableObject::*)() const)&MovableObject::GetParent) - .def("GetRootParent", (MovableObject * (MovableObject::*)())&MovableObject::GetRootParent) - .def("GetRootParent", (const MovableObject * (MovableObject::*)() const)&MovableObject::GetRootParent) - .def("ReloadScripts", &MovableObject::ReloadScripts) - .def("HasScript", &LuaAdaptersMovableObject::HasScript) - .def("AddScript", &LuaAdaptersMovableObject::AddScript) - .def("ScriptEnabled", &MovableObject::ScriptEnabled) - .def("EnableScript", &LuaAdaptersMovableObject::EnableScript) - .def("DisableScript", &LuaAdaptersMovableObject::DisableScript1) - .def("DisableScript", &LuaAdaptersMovableObject::DisableScript2) - .def("EnableOrDisableAllScripts", &MovableObject::EnableOrDisableAllScripts) - .def("GetStringValue", &MovableObject::GetStringValue) - .def("GetEncodedStringValue", &MovableObject::GetEncodedStringValue) - .def("GetNumberValue", &MovableObject::GetNumberValue) - .def("GetObjectValue", &MovableObject::GetObjectValue) - .def("SetStringValue", &MovableObject::SetStringValue) - .def("SetEncodedStringValue", &MovableObject::SetEncodedStringValue) - .def("SetNumberValue", &MovableObject::SetNumberValue) - .def("SetObjectValue", &MovableObject::SetObjectValue) - .def("RemoveStringValue", &MovableObject::RemoveStringValue) - .def("RemoveNumberValue", &MovableObject::RemoveNumberValue) - .def("RemoveObjectValue", &MovableObject::RemoveObjectValue) - .def("StringValueExists", &MovableObject::StringValueExists) - .def("NumberValueExists", &MovableObject::NumberValueExists) - .def("ObjectValueExists", &MovableObject::ObjectValueExists) - .def("GetAltitude", &MovableObject::GetAltitude) - .def("GetWhichMOToNotHit", &MovableObject::GetWhichMOToNotHit) - .def("SetWhichMOToNotHit", &MovableObject::SetWhichMOToNotHit) - .def("IsSetToDelete", &MovableObject::IsSetToDelete) - .def("IsMissionCritical", &MovableObject::IsMissionCritical) - .def("IsGeneric", &MovableObject::IsGeneric) - .def("IsActor", &MovableObject::IsActor) - .def("IsDevice", &MovableObject::IsDevice) - .def("IsHeldDevice", &MovableObject::IsHeldDevice) - .def("IsThrownDevice", &MovableObject::IsThrownDevice) - .def("IsGold", &MovableObject::IsGold) - .def("IsThrownDevice", &MovableObject::IsThrownDevice) - .def("HasObject", &MovableObject::HasObject) - .def("HasObjectInGroup", &MovableObject::HasObjectInGroup) - .def("AddForce", &MovableObject::AddForce) - .def("AddAbsForce", &MovableObject::AddAbsForce) - .def("AddImpulseForce", &MovableObject::AddImpulseForce) - .def("AddAbsImpulseForce", &MovableObject::AddAbsImpulseForce) - .def("ClearForces", &MovableObject::ClearForces) - .def("ClearImpulseForces", &MovableObject::ClearImpulseForces) - .def("GetForcesCount", &MovableObject::GetForcesCount) - .def("GetForceVector", &MovableObject::GetForceVector) - .def("GetForceOffset", &MovableObject::GetForceOffset) - .def("SetForceVector", &MovableObject::SetForceVector) - .def("SetForceOffset", &MovableObject::SetForceOffset) - .def("GetImpulsesCount", &MovableObject::GetImpulsesCount) - .def("GetImpulseVector", &MovableObject::GetImpulseVector) - .def("GetImpulseOffset", &MovableObject::GetImpulseOffset) - .def("SetImpulseVector", &MovableObject::SetImpulseVector) - .def("SetImpulseOffset", &MovableObject::SetImpulseOffset) - .def("RestDetection", &MovableObject::RestDetection) - .def("NotResting", &MovableObject::NotResting) - .def("IsAtRest", &MovableObject::IsAtRest) - .def("MoveOutOfTerrain", &MovableObject::MoveOutOfTerrain) - .def("RotateOffset", &MovableObject::RotateOffset) - .def("SendMessage", &LuaAdaptersMovableObject::SendMessage1) - .def("SendMessage", &LuaAdaptersMovableObject::SendMessage2) - .def("RequestSyncedUpdate", &MovableObject::RequestSyncedUpdate); + .property("Material", &MovableObject::GetMaterial) + .property("Mass", &MovableObject::GetMass, &MovableObject::SetMass) + .property("Pos", &MovableObject::GetPos, &MovableObject::SetPos) + .property("Vel", &MovableObject::GetVel, &MovableObject::SetVel) + .property("PrevPos", &MovableObject::GetPrevPos) + .property("PrevVel", &MovableObject::GetPrevVel) + .property("DistanceTravelled", &MovableObject::GetDistanceTravelled) + .property("AngularVel", &MovableObject::GetAngularVel, &MovableObject::SetAngularVel) + .property("Radius", &MovableObject::GetRadius) + .property("Diameter", &MovableObject::GetDiameter) + .property("Scale", &MovableObject::GetScale, &MovableObject::SetScale) + .property("EffectRotAngle", &MovableObject::GetEffectRotAngle, &MovableObject::SetEffectRotAngle) + .property("GlobalAccScalar", &MovableObject::GetGlobalAccScalar, &MovableObject::SetGlobalAccScalar) + .property("AirResistance", &MovableObject::GetAirResistance, &MovableObject::SetAirResistance) + .property("AirThreshold", &MovableObject::GetAirThreshold, &MovableObject::SetAirThreshold) + .property("Age", &MovableObject::GetAge, &MovableObject::SetAge) + .property("Lifetime", &MovableObject::GetLifetime, &MovableObject::SetLifetime) + .property("ID", &MovableObject::GetID) + .property("UniqueID", &MovableObject::GetUniqueID) + .property("RootID", &MovableObject::GetRootID) + .property("MOIDFootprint", &MovableObject::GetMOIDFootprint) + .property("Sharpness", &MovableObject::GetSharpness, &MovableObject::SetSharpness) + .property("HasEverBeenAddedToMovableMan", &MovableObject::HasEverBeenAddedToMovableMan) + .property("AboveHUDPos", &MovableObject::GetAboveHUDPos) + .property("HitsMOs", &MovableObject::HitsMOs, &MovableObject::SetToHitMOs) + .property("GetsHitByMOs", &MovableObject::GetsHitByMOs, &MovableObject::SetToGetHitByMOs) + .property("IgnoresTeamHits", &MovableObject::IgnoresTeamHits, &MovableObject::SetIgnoresTeamHits) + .property("IgnoresWhichTeam", &MovableObject::IgnoresWhichTeam) + .property("IgnoreTerrain", &MovableObject::IgnoreTerrain, &MovableObject::SetIgnoreTerrain) + .property("IgnoresActorHits", &MovableObject::GetIgnoresActorHits, &MovableObject::SetIgnoresActorHits) + .property("ToSettle", &MovableObject::ToSettle, &MovableObject::SetToSettle) + .property("ToDelete", &MovableObject::ToDelete, &MovableObject::SetToDelete) + .property("MissionCritical", &MovableObject::IsMissionCritical, &MovableObject::SetMissionCritical) + .property("HUDVisible", &MovableObject::GetHUDVisible, &MovableObject::SetHUDVisible) + .property("PinStrength", &MovableObject::GetPinStrength, &MovableObject::SetPinStrength) + .property("RestThreshold", &MovableObject::GetRestThreshold, &MovableObject::SetRestThreshold) + .property("DamageOnCollision", &MovableObject::DamageOnCollision, &MovableObject::SetDamageOnCollision) + .property("DamageOnPenetration", &MovableObject::DamageOnPenetration, &MovableObject::SetDamageOnPenetration) + .property("WoundDamageMultiplier", &MovableObject::WoundDamageMultiplier, &MovableObject::SetWoundDamageMultiplier) + .property("HitWhatMOID", &MovableObject::HitWhatMOID) + .property("HitWhatTerrMaterial", &MovableObject::HitWhatTerrMaterial) + .property("HitWhatParticleUniqueID", &MovableObject::HitWhatParticleUniqueID) + .property("ApplyWoundDamageOnCollision", &MovableObject::GetApplyWoundDamageOnCollision, &MovableObject::SetApplyWoundDamageOnCollision) + .property("ApplyWoundBurstDamageOnCollision", &MovableObject::GetApplyWoundBurstDamageOnCollision, &MovableObject::SetApplyWoundBurstDamageOnCollision) + .property("SimUpdatesBetweenScriptedUpdates", &MovableObject::GetSimUpdatesBetweenScriptedUpdates, &MovableObject::SetSimUpdatesBetweenScriptedUpdates) + + .def("GetParent", (MOSRotating * (MovableObject::*)()) & MovableObject::GetParent) + .def("GetParent", (const MOSRotating* (MovableObject::*)() const) & MovableObject::GetParent) + .def("GetRootParent", (MovableObject * (MovableObject::*)()) & MovableObject::GetRootParent) + .def("GetRootParent", (const MovableObject* (MovableObject::*)() const) & MovableObject::GetRootParent) + .def("ReloadScripts", &MovableObject::ReloadScripts) + .def("HasScript", &LuaAdaptersMovableObject::HasScript) + .def("AddScript", &LuaAdaptersMovableObject::AddScript) + .def("ScriptEnabled", &MovableObject::ScriptEnabled) + .def("EnableScript", &LuaAdaptersMovableObject::EnableScript) + .def("DisableScript", &LuaAdaptersMovableObject::DisableScript1) + .def("DisableScript", &LuaAdaptersMovableObject::DisableScript2) + .def("EnableOrDisableAllScripts", &MovableObject::EnableOrDisableAllScripts) + .def("GetStringValue", &MovableObject::GetStringValue) + .def("GetEncodedStringValue", &MovableObject::GetEncodedStringValue) + .def("GetNumberValue", &MovableObject::GetNumberValue) + .def("GetObjectValue", &MovableObject::GetObjectValue) + .def("SetStringValue", &MovableObject::SetStringValue) + .def("SetEncodedStringValue", &MovableObject::SetEncodedStringValue) + .def("SetNumberValue", &MovableObject::SetNumberValue) + .def("SetObjectValue", &MovableObject::SetObjectValue) + .def("RemoveStringValue", &MovableObject::RemoveStringValue) + .def("RemoveNumberValue", &MovableObject::RemoveNumberValue) + .def("RemoveObjectValue", &MovableObject::RemoveObjectValue) + .def("StringValueExists", &MovableObject::StringValueExists) + .def("NumberValueExists", &MovableObject::NumberValueExists) + .def("ObjectValueExists", &MovableObject::ObjectValueExists) + .def("GetAltitude", &MovableObject::GetAltitude) + .def("GetWhichMOToNotHit", &MovableObject::GetWhichMOToNotHit) + .def("SetWhichMOToNotHit", &MovableObject::SetWhichMOToNotHit) + .def("IsSetToDelete", &MovableObject::IsSetToDelete) + .def("IsMissionCritical", &MovableObject::IsMissionCritical) + .def("IsGeneric", &MovableObject::IsGeneric) + .def("IsActor", &MovableObject::IsActor) + .def("IsDevice", &MovableObject::IsDevice) + .def("IsHeldDevice", &MovableObject::IsHeldDevice) + .def("IsThrownDevice", &MovableObject::IsThrownDevice) + .def("IsGold", &MovableObject::IsGold) + .def("IsThrownDevice", &MovableObject::IsThrownDevice) + .def("HasObject", &MovableObject::HasObject) + .def("HasObjectInGroup", &MovableObject::HasObjectInGroup) + .def("AddForce", &MovableObject::AddForce) + .def("AddAbsForce", &MovableObject::AddAbsForce) + .def("AddImpulseForce", &MovableObject::AddImpulseForce) + .def("AddAbsImpulseForce", &MovableObject::AddAbsImpulseForce) + .def("ClearForces", &MovableObject::ClearForces) + .def("ClearImpulseForces", &MovableObject::ClearImpulseForces) + .def("GetForcesCount", &MovableObject::GetForcesCount) + .def("GetForceVector", &MovableObject::GetForceVector) + .def("GetForceOffset", &MovableObject::GetForceOffset) + .def("SetForceVector", &MovableObject::SetForceVector) + .def("SetForceOffset", &MovableObject::SetForceOffset) + .def("GetImpulsesCount", &MovableObject::GetImpulsesCount) + .def("GetImpulseVector", &MovableObject::GetImpulseVector) + .def("GetImpulseOffset", &MovableObject::GetImpulseOffset) + .def("SetImpulseVector", &MovableObject::SetImpulseVector) + .def("SetImpulseOffset", &MovableObject::SetImpulseOffset) + .def("RestDetection", &MovableObject::RestDetection) + .def("NotResting", &MovableObject::NotResting) + .def("IsAtRest", &MovableObject::IsAtRest) + .def("MoveOutOfTerrain", &MovableObject::MoveOutOfTerrain) + .def("RotateOffset", &MovableObject::RotateOffset) + .def("SendMessage", &LuaAdaptersMovableObject::SendMessage1) + .def("SendMessage", &LuaAdaptersMovableObject::SendMessage2) + .def("RequestSyncedUpdate", &MovableObject::RequestSyncedUpdate); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, PEmitter) { return ConcreteTypeLuaClassDefinition(PEmitter, MOSParticle) - .property("BurstScale", &PEmitter::GetBurstScale, &PEmitter::SetBurstScale) - .property("EmitAngle", &PEmitter::GetEmitAngle, &PEmitter::SetEmitAngle) - .property("GetThrottle", &PEmitter::GetThrottle, &PEmitter::SetThrottle) - .property("Throttle", &PEmitter::GetThrottle, &PEmitter::SetThrottle) - .property("ThrottleFactor", &PEmitter::GetThrottleFactor) - .property("BurstSpacing", &PEmitter::GetBurstSpacing, &PEmitter::SetBurstSpacing) - .property("EmitCountLimit", &PEmitter::GetEmitCountLimit, &PEmitter::SetEmitCountLimit) - .property("FlashScale", &PEmitter::GetFlashScale, &PEmitter::SetFlashScale) - - .def_readwrite("Emissions", &PEmitter::m_EmissionList, luabind::return_stl_iterator) - - .def("IsEmitting", &PEmitter::IsEmitting) - .def("WasEmitting", &PEmitter::WasEmitting) - .def("EnableEmission", &PEmitter::EnableEmission) - .def("GetEmitVector", &PEmitter::GetEmitVector) - .def("GetRecoilVector", &PEmitter::GetRecoilVector) - .def("EstimateImpulse", &PEmitter::EstimateImpulse) - .def("TriggerBurst", &PEmitter::TriggerBurst) - .def("IsSetToBurst", &PEmitter::IsSetToBurst) - .def("CanTriggerBurst", &PEmitter::CanTriggerBurst) - .def("JustStartedEmitting", &PEmitter::JustStartedEmitting); + .property("BurstScale", &PEmitter::GetBurstScale, &PEmitter::SetBurstScale) + .property("EmitAngle", &PEmitter::GetEmitAngle, &PEmitter::SetEmitAngle) + .property("GetThrottle", &PEmitter::GetThrottle, &PEmitter::SetThrottle) + .property("Throttle", &PEmitter::GetThrottle, &PEmitter::SetThrottle) + .property("ThrottleFactor", &PEmitter::GetThrottleFactor) + .property("BurstSpacing", &PEmitter::GetBurstSpacing, &PEmitter::SetBurstSpacing) + .property("EmitCountLimit", &PEmitter::GetEmitCountLimit, &PEmitter::SetEmitCountLimit) + .property("FlashScale", &PEmitter::GetFlashScale, &PEmitter::SetFlashScale) + + .def_readwrite("Emissions", &PEmitter::m_EmissionList, luabind::return_stl_iterator) + + .def("IsEmitting", &PEmitter::IsEmitting) + .def("WasEmitting", &PEmitter::WasEmitting) + .def("EnableEmission", &PEmitter::EnableEmission) + .def("GetEmitVector", &PEmitter::GetEmitVector) + .def("GetRecoilVector", &PEmitter::GetRecoilVector) + .def("EstimateImpulse", &PEmitter::EstimateImpulse) + .def("TriggerBurst", &PEmitter::TriggerBurst) + .def("IsSetToBurst", &PEmitter::IsSetToBurst) + .def("CanTriggerBurst", &PEmitter::CanTriggerBurst) + .def("JustStartedEmitting", &PEmitter::JustStartedEmitting); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, PieSlice) { return ConcreteTypeLuaClassDefinition(PieSlice, Entity) - .property("Type", &PieSlice::GetType, &PieSlice::SetType) - .property("Direction", &PieSlice::GetDirection, &PieSlice::SetDirection) - .property("CanBeMiddleSlice", &PieSlice::GetCanBeMiddleSlice, &PieSlice::SetCanBeMiddleSlice) - .property("OriginalSource", &PieSlice::GetOriginalSource) - .property("Enabled", &PieSlice::IsEnabled, &PieSlice::SetEnabled) - - .property("ScriptPath", &PieSlice::GetScriptPath, &PieSlice::SetScriptPath) - .property("FunctionName", &PieSlice::GetFunctionName, &PieSlice::SetFunctionName) - .property("SubPieMenu", &PieSlice::GetSubPieMenu, &PieSlice::SetSubPieMenu) - - .property("DrawFlippedToMatchAbsoluteAngle", &PieSlice::GetDrawFlippedToMatchAbsoluteAngle, &PieSlice::SetDrawFlippedToMatchAbsoluteAngle) - - .def("ReloadScripts", &PieSlice::ReloadScripts) - - .enum_("SliceType")[ - luabind::value("NoType", PieSlice::SliceType::NoType), - luabind::value("Pickup", PieSlice::SliceType::Pickup), - luabind::value("Drop", PieSlice::SliceType::Drop), - luabind::value("NextItem", PieSlice::SliceType::NextItem), - luabind::value("PreviousItem", PieSlice::SliceType::PreviousItem), - luabind::value("Reload", PieSlice::SliceType::Reload), - luabind::value("BuyMenu", PieSlice::SliceType::BuyMenu), - luabind::value("Stats", PieSlice::SliceType::Stats), - luabind::value("Map", PieSlice::SliceType::Map), - luabind::value("FormSquad", PieSlice::SliceType::FormSquad), - luabind::value("Ceasefire", PieSlice::SliceType::Ceasefire), - luabind::value("Sentry", PieSlice::SliceType::Sentry), - luabind::value("Patrol", PieSlice::SliceType::Patrol), - luabind::value("BrainHunt", PieSlice::SliceType::BrainHunt), - luabind::value("GoldDig", PieSlice::SliceType::GoldDig), - luabind::value("GoTo", PieSlice::SliceType::GoTo), - luabind::value("Return", PieSlice::SliceType::Return), - luabind::value("Stay", PieSlice::SliceType::Stay), - luabind::value("Deliver", PieSlice::SliceType::Deliver), - luabind::value("Scuttle", PieSlice::SliceType::Scuttle), - luabind::value("Done", PieSlice::SliceType::EditorDone), - luabind::value("Load", PieSlice::SliceType::EditorLoad), - luabind::value("Save", PieSlice::SliceType::EditorSave), - luabind::value("New", PieSlice::SliceType::EditorNew), - luabind::value("Pick", PieSlice::SliceType::EditorPick), - luabind::value("Move", PieSlice::SliceType::EditorMove), - luabind::value("Remove", PieSlice::SliceType::EditorRemove), - luabind::value("InFront", PieSlice::SliceType::EditorInFront), - luabind::value("Behind", PieSlice::SliceType::EditorBehind), - luabind::value("ZoomIn", PieSlice::SliceType::EditorZoomIn), - luabind::value("ZoomOut", PieSlice::SliceType::EditorZoomOut), - luabind::value("Team1", PieSlice::SliceType::EditorTeam1), - luabind::value("Team2", PieSlice::SliceType::EditorTeam2), - luabind::value("Team3", PieSlice::SliceType::EditorTeam3), - luabind::value("Team4", PieSlice::SliceType::EditorTeam4) - ]; + .property("Type", &PieSlice::GetType, &PieSlice::SetType) + .property("Direction", &PieSlice::GetDirection, &PieSlice::SetDirection) + .property("CanBeMiddleSlice", &PieSlice::GetCanBeMiddleSlice, &PieSlice::SetCanBeMiddleSlice) + .property("OriginalSource", &PieSlice::GetOriginalSource) + .property("Enabled", &PieSlice::IsEnabled, &PieSlice::SetEnabled) + + .property("ScriptPath", &PieSlice::GetScriptPath, &PieSlice::SetScriptPath) + .property("FunctionName", &PieSlice::GetFunctionName, &PieSlice::SetFunctionName) + .property("SubPieMenu", &PieSlice::GetSubPieMenu, &PieSlice::SetSubPieMenu) + + .property("DrawFlippedToMatchAbsoluteAngle", &PieSlice::GetDrawFlippedToMatchAbsoluteAngle, &PieSlice::SetDrawFlippedToMatchAbsoluteAngle) + + .def("ReloadScripts", &PieSlice::ReloadScripts) + + .enum_("SliceType")[luabind::value("NoType", PieSlice::SliceType::NoType), + luabind::value("Pickup", PieSlice::SliceType::Pickup), + luabind::value("Drop", PieSlice::SliceType::Drop), + luabind::value("NextItem", PieSlice::SliceType::NextItem), + luabind::value("PreviousItem", PieSlice::SliceType::PreviousItem), + luabind::value("Reload", PieSlice::SliceType::Reload), + luabind::value("BuyMenu", PieSlice::SliceType::BuyMenu), + luabind::value("Stats", PieSlice::SliceType::Stats), + luabind::value("Map", PieSlice::SliceType::Map), + luabind::value("FormSquad", PieSlice::SliceType::FormSquad), + luabind::value("Ceasefire", PieSlice::SliceType::Ceasefire), + luabind::value("Sentry", PieSlice::SliceType::Sentry), + luabind::value("Patrol", PieSlice::SliceType::Patrol), + luabind::value("BrainHunt", PieSlice::SliceType::BrainHunt), + luabind::value("GoldDig", PieSlice::SliceType::GoldDig), + luabind::value("GoTo", PieSlice::SliceType::GoTo), + luabind::value("Return", PieSlice::SliceType::Return), + luabind::value("Stay", PieSlice::SliceType::Stay), + luabind::value("Deliver", PieSlice::SliceType::Deliver), + luabind::value("Scuttle", PieSlice::SliceType::Scuttle), + luabind::value("Done", PieSlice::SliceType::EditorDone), + luabind::value("Load", PieSlice::SliceType::EditorLoad), + luabind::value("Save", PieSlice::SliceType::EditorSave), + luabind::value("New", PieSlice::SliceType::EditorNew), + luabind::value("Pick", PieSlice::SliceType::EditorPick), + luabind::value("Move", PieSlice::SliceType::EditorMove), + luabind::value("Remove", PieSlice::SliceType::EditorRemove), + luabind::value("InFront", PieSlice::SliceType::EditorInFront), + luabind::value("Behind", PieSlice::SliceType::EditorBehind), + luabind::value("ZoomIn", PieSlice::SliceType::EditorZoomIn), + luabind::value("ZoomOut", PieSlice::SliceType::EditorZoomOut), + luabind::value("Team1", PieSlice::SliceType::EditorTeam1), + luabind::value("Team2", PieSlice::SliceType::EditorTeam2), + luabind::value("Team3", PieSlice::SliceType::EditorTeam3), + luabind::value("Team4", PieSlice::SliceType::EditorTeam4)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, PieMenu) { return ConcreteTypeLuaClassDefinition(PieMenu, Entity) - .property("Owner", &PieMenu::GetOwner) - .property("Controller", &PieMenu::GetController) - .property("AffectedObject", &PieMenu::GetAffectedObject) - .property("Pos", &PieMenu::GetPos) - .property("RotAngle", &PieMenu::GetRotAngle, &PieMenu::SetRotAngle) - .property("FullInnerRadius", &PieMenu::GetFullInnerRadius, &PieMenu::SetFullInnerRadius) - - .property("PieSlices", &PieMenu::GetPieSlices, luabind::return_stl_iterator) - - .def("IsSubPieMenu", &PieMenu::IsSubPieMenu) - - .def("IsEnabled", &PieMenu::IsEnabled) - .def("IsEnabling", &PieMenu::IsEnabling) - .def("IsDisabling", &PieMenu::IsDisabling) - .def("IsEnablingOrDisabling", &PieMenu::IsEnablingOrDisabling) - .def("IsVisible", &PieMenu::IsVisible) - .def("HasSubPieMenuOpen", &PieMenu::HasSubPieMenuOpen) - - .def("SetAnimationModeToNormal", &PieMenu::SetAnimationModeToNormal) - .def("DoDisableAnimation", &PieMenu::DoDisableAnimation) - .def("Wobble", &PieMenu::Wobble) - .def("FreezeAtRadius", &PieMenu::FreezeAtRadius) - - .def("GetPieCommand", &PieMenu::GetPieCommand) - .def("GetFirstPieSliceByPresetName", &PieMenu::GetFirstPieSliceByPresetName) - .def("GetFirstPieSliceByType", &PieMenu::GetFirstPieSliceByType) - .def("AddPieSlice", &PieMenu::AddPieSlice, luabind::adopt(_2)) - .def("AddPieSlice", &LuaAdaptersPieMenu::AddPieSlice, luabind::adopt(_2)) - .def("AddPieSliceIfPresetNameIsUnique", &PieMenu::AddPieSliceIfPresetNameIsUnique) - .def("AddPieSliceIfPresetNameIsUnique", &LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique1) - .def("AddPieSliceIfPresetNameIsUnique", &LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique2) - .def("RemovePieSlice", &PieMenu::RemovePieSlice, luabind::adopt(luabind::return_value)) - .def("RemovePieSlicesByPresetName", &PieMenu::RemovePieSlicesByPresetName) - .def("RemovePieSlicesByType", &PieMenu::RemovePieSlicesByType) - .def("RemovePieSlicesByOriginalSource", &PieMenu::RemovePieSlicesByOriginalSource) - .def("ReplacePieSlice", &PieMenu::ReplacePieSlice, luabind::adopt(luabind::result) + luabind::adopt(_3)); + .property("Owner", &PieMenu::GetOwner) + .property("Controller", &PieMenu::GetController) + .property("AffectedObject", &PieMenu::GetAffectedObject) + .property("Pos", &PieMenu::GetPos) + .property("RotAngle", &PieMenu::GetRotAngle, &PieMenu::SetRotAngle) + .property("FullInnerRadius", &PieMenu::GetFullInnerRadius, &PieMenu::SetFullInnerRadius) + + .property("PieSlices", &PieMenu::GetPieSlices, luabind::return_stl_iterator) + + .def("IsSubPieMenu", &PieMenu::IsSubPieMenu) + + .def("IsEnabled", &PieMenu::IsEnabled) + .def("IsEnabling", &PieMenu::IsEnabling) + .def("IsDisabling", &PieMenu::IsDisabling) + .def("IsEnablingOrDisabling", &PieMenu::IsEnablingOrDisabling) + .def("IsVisible", &PieMenu::IsVisible) + .def("HasSubPieMenuOpen", &PieMenu::HasSubPieMenuOpen) + + .def("SetAnimationModeToNormal", &PieMenu::SetAnimationModeToNormal) + .def("DoDisableAnimation", &PieMenu::DoDisableAnimation) + .def("Wobble", &PieMenu::Wobble) + .def("FreezeAtRadius", &PieMenu::FreezeAtRadius) + + .def("GetPieCommand", &PieMenu::GetPieCommand) + .def("GetFirstPieSliceByPresetName", &PieMenu::GetFirstPieSliceByPresetName) + .def("GetFirstPieSliceByType", &PieMenu::GetFirstPieSliceByType) + .def("AddPieSlice", &PieMenu::AddPieSlice, luabind::adopt(_2)) + .def("AddPieSlice", &LuaAdaptersPieMenu::AddPieSlice, luabind::adopt(_2)) + .def("AddPieSliceIfPresetNameIsUnique", &PieMenu::AddPieSliceIfPresetNameIsUnique) + .def("AddPieSliceIfPresetNameIsUnique", &LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique1) + .def("AddPieSliceIfPresetNameIsUnique", &LuaAdaptersPieMenu::AddPieSliceIfPresetNameIsUnique2) + .def("RemovePieSlice", &PieMenu::RemovePieSlice, luabind::adopt(luabind::return_value)) + .def("RemovePieSlicesByPresetName", &PieMenu::RemovePieSlicesByPresetName) + .def("RemovePieSlicesByType", &PieMenu::RemovePieSlicesByType) + .def("RemovePieSlicesByOriginalSource", &PieMenu::RemovePieSlicesByOriginalSource) + .def("ReplacePieSlice", &PieMenu::ReplacePieSlice, luabind::adopt(luabind::result) + luabind::adopt(_3)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Round) { return ConcreteTypeLuaClassDefinition(Round, Entity) - .property("NextParticle", &Round::GetNextParticle) - .property("Shell", &Round::GetShell) - .property("FireVel", &Round::GetFireVel) - .property("InheritsFirerVelocity", &Round::GetInheritsFirerVelocity) - .property("ShellVel", &Round::GetShellVel) - .property("Separation", &Round::GetSeparation) - .property("ParticleCount", &Round::ParticleCount) - .property("AILifeTime", &Round::GetAILifeTime) - .property("AIFireVel", &Round::GetAIFireVel) - .property("IsEmpty", &Round::IsEmpty); + .property("NextParticle", &Round::GetNextParticle) + .property("Shell", &Round::GetShell) + .property("FireVel", &Round::GetFireVel) + .property("InheritsFirerVelocity", &Round::GetInheritsFirerVelocity) + .property("ShellVel", &Round::GetShellVel) + .property("Separation", &Round::GetSeparation) + .property("ParticleCount", &Round::ParticleCount) + .property("AILifeTime", &Round::GetAILifeTime) + .property("AIFireVel", &Round::GetAIFireVel) + .property("IsEmpty", &Round::IsEmpty); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Scene) { return ConcreteTypeLuaClassDefinition(Scene, Entity) - .property("Location", &Scene::GetLocation, &Scene::SetLocation) - //.property("Terrain", &Scene::GetTerrain) - .property("Dimensions", &Scene::GetDimensions) - .property("Width", &Scene::GetWidth) - .property("Height", &Scene::GetHeight) - .property("WrapsX", &Scene::WrapsX) - .property("WrapsY", &Scene::WrapsY) - .property("TeamOwnership", &Scene::GetTeamOwnership, &Scene::SetTeamOwnership) - .property("GlobalAcc", &Scene::GetGlobalAcc, &Scene::SetGlobalAcc) - .property("ScenePathSize", &Scene::GetScenePathSize) - - .def_readwrite("Deployments", &Scene::m_Deployments, luabind::return_stl_iterator) - - .def_readonly("BackgroundLayers", &Scene::m_BackLayerList, luabind::return_stl_iterator) - - .def("GetScenePath", &Scene::GetScenePath, luabind::return_stl_iterator) - .def("GetBuildBudget", &Scene::GetBuildBudget) - .def("SetBuildBudget", &Scene::SetBuildBudget) - .def("IsScanScheduled", &Scene::IsScanScheduled) - .def("SetScheduledScan", &Scene::SetScheduledScan) - .def("ClearPlacedObjectSet", &Scene::ClearPlacedObjectSet) - .def("PlaceResidentBrain", &Scene::PlaceResidentBrain) - .def("PlaceResidentBrains", &Scene::PlaceResidentBrains) - .def("RetrieveResidentBrains", &Scene::RetrieveResidentBrains) - .def("GetResidentBrain", &Scene::GetResidentBrain) - .def("SetResidentBrain", &Scene::SetResidentBrain) - .def_readwrite("Areas", &Scene::m_AreaList, luabind::return_stl_iterator) - .def("SetArea", &Scene::SetArea) - .def("HasArea", &Scene::HasArea) - .def("GetArea", (Scene::Area * (Scene:: *)(const std::string &areaName)) &Scene::GetArea) - .def("GetOptionalArea", &Scene::GetOptionalArea) - .def("WithinArea", &Scene::WithinArea) - .def("AddNavigatableArea", &Scene::AddNavigatableArea) - .def("ClearNavigatableAreas", &Scene::ClearNavigatableAreas) - .def("ResetPathFinding", &Scene::ResetPathFinding) - .def("UpdatePathFinding", &Scene::UpdatePathFinding) - .def("PathFindingUpdated", &Scene::PathFindingUpdated) - .def("CalculatePath", &LuaAdaptersScene::CalculatePath1) - .def("CalculatePath", &LuaAdaptersScene::CalculatePath2) - .def("CalculatePathAsync", &LuaAdaptersScene::CalculatePathAsync1) - .def("CalculatePathAsync", &LuaAdaptersScene::CalculatePathAsync2) - - .enum_("PlacedObjectSets")[ - luabind::value("PLACEONLOAD", Scene::PlacedObjectSets::PLACEONLOAD), - luabind::value("BLUEPRINT", Scene::PlacedObjectSets::BLUEPRINT), - luabind::value("AIPLAN", Scene::PlacedObjectSets::AIPLAN), - luabind::value("PLACEDSETSCOUNT", Scene::PlacedObjectSets::PLACEDSETSCOUNT) - ]; + .property("Location", &Scene::GetLocation, &Scene::SetLocation) + //.property("Terrain", &Scene::GetTerrain) + .property("Dimensions", &Scene::GetDimensions) + .property("Width", &Scene::GetWidth) + .property("Height", &Scene::GetHeight) + .property("WrapsX", &Scene::WrapsX) + .property("WrapsY", &Scene::WrapsY) + .property("TeamOwnership", &Scene::GetTeamOwnership, &Scene::SetTeamOwnership) + .property("GlobalAcc", &Scene::GetGlobalAcc, &Scene::SetGlobalAcc) + .property("ScenePathSize", &Scene::GetScenePathSize) + + .def_readwrite("Deployments", &Scene::m_Deployments, luabind::return_stl_iterator) + + .def_readonly("BackgroundLayers", &Scene::m_BackLayerList, luabind::return_stl_iterator) + + .def("GetScenePath", &Scene::GetScenePath, luabind::return_stl_iterator) + .def("GetBuildBudget", &Scene::GetBuildBudget) + .def("SetBuildBudget", &Scene::SetBuildBudget) + .def("IsScanScheduled", &Scene::IsScanScheduled) + .def("SetScheduledScan", &Scene::SetScheduledScan) + .def("ClearPlacedObjectSet", &Scene::ClearPlacedObjectSet) + .def("PlaceResidentBrain", &Scene::PlaceResidentBrain) + .def("PlaceResidentBrains", &Scene::PlaceResidentBrains) + .def("RetrieveResidentBrains", &Scene::RetrieveResidentBrains) + .def("GetResidentBrain", &Scene::GetResidentBrain) + .def("SetResidentBrain", &Scene::SetResidentBrain) + .def_readwrite("Areas", &Scene::m_AreaList, luabind::return_stl_iterator) + .def("SetArea", &Scene::SetArea) + .def("HasArea", &Scene::HasArea) + .def("GetArea", (Scene::Area * (Scene::*)(const std::string& areaName)) & Scene::GetArea) + .def("GetOptionalArea", &Scene::GetOptionalArea) + .def("WithinArea", &Scene::WithinArea) + .def("AddNavigatableArea", &Scene::AddNavigatableArea) + .def("ClearNavigatableAreas", &Scene::ClearNavigatableAreas) + .def("ResetPathFinding", &Scene::ResetPathFinding) + .def("UpdatePathFinding", &Scene::UpdatePathFinding) + .def("PathFindingUpdated", &Scene::PathFindingUpdated) + .def("CalculatePath", &LuaAdaptersScene::CalculatePath1) + .def("CalculatePath", &LuaAdaptersScene::CalculatePath2) + .def("CalculatePathAsync", &LuaAdaptersScene::CalculatePathAsync1) + .def("CalculatePathAsync", &LuaAdaptersScene::CalculatePathAsync2) + + .enum_("PlacedObjectSets")[luabind::value("PLACEONLOAD", Scene::PlacedObjectSets::PLACEONLOAD), + luabind::value("BLUEPRINT", Scene::PlacedObjectSets::BLUEPRINT), + luabind::value("AIPLAN", Scene::PlacedObjectSets::AIPLAN), + luabind::value("PLACEDSETSCOUNT", Scene::PlacedObjectSets::PLACEDSETSCOUNT)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, SceneArea) { return luabind::class_("Area") - .def(luabind::constructor<>()) - .def(luabind::constructor()) - .def(luabind::constructor()) - - .property("ClassName", &Scene::Area::GetClassName) - .property("Name", &Scene::Area::GetName) - .property("FirstBox", &Scene::Area::GetFirstBox) - .property("Center", &Scene::Area::GetCenterPoint) - .property("RandomPoint", &Scene::Area::GetRandomPoint) - - .def("Reset", &Scene::Area::Reset) - .def_readwrite("Boxes", &Scene::Area::m_BoxList, luabind::return_stl_iterator) - .def("AddBox", &Scene::Area::AddBox) - .def("RemoveBox", &Scene::Area::RemoveBox) - .def("HasNoArea", &Scene::Area::HasNoArea) - .def("IsInside", &Scene::Area::IsInside) - .def("IsInsideX", &Scene::Area::IsInsideX) - .def("IsInsideY", &Scene::Area::IsInsideY) - .def("GetBoxInside", &Scene::Area::GetBoxInside) - .def("RemoveBoxInside", &Scene::Area::RemoveBoxInside) - .def("GetCenterPoint", &Scene::Area::GetCenterPoint) - .def("GetRandomPoint", &Scene::Area::GetRandomPoint); + .def(luabind::constructor<>()) + .def(luabind::constructor()) + .def(luabind::constructor()) + + .property("ClassName", &Scene::Area::GetClassName) + .property("Name", &Scene::Area::GetName) + .property("FirstBox", &Scene::Area::GetFirstBox) + .property("Center", &Scene::Area::GetCenterPoint) + .property("RandomPoint", &Scene::Area::GetRandomPoint) + + .def("Reset", &Scene::Area::Reset) + .def_readwrite("Boxes", &Scene::Area::m_BoxList, luabind::return_stl_iterator) + .def("AddBox", &Scene::Area::AddBox) + .def("RemoveBox", &Scene::Area::RemoveBox) + .def("HasNoArea", &Scene::Area::HasNoArea) + .def("IsInside", &Scene::Area::IsInside) + .def("IsInsideX", &Scene::Area::IsInsideX) + .def("IsInsideY", &Scene::Area::IsInsideY) + .def("GetBoxInside", &Scene::Area::GetBoxInside) + .def("RemoveBoxInside", &Scene::Area::RemoveBoxInside) + .def("GetCenterPoint", &Scene::Area::GetCenterPoint) + .def("GetRandomPoint", &Scene::Area::GetRandomPoint); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, SceneLayer) { return luabind::class_("SceneLayer"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, SceneObject) { return AbstractTypeLuaClassDefinition(SceneObject, Entity) - .property("Pos", &SceneObject::GetPos, &SceneObject::SetPos) - .property("HFlipped", &SceneObject::IsHFlipped, &SceneObject::SetHFlipped) - .property("RotAngle", &SceneObject::GetRotAngle, &SceneObject::SetRotAngle) - .property("Team", &SceneObject::GetTeam, &SceneObject::SetTeam) - .property("PlacedByPlayer", &SceneObject::GetPlacedByPlayer, &SceneObject::SetPlacedByPlayer) - .property("Buyable", &SceneObject::IsBuyable) - - .property("BuyableMode", &LuaAdaptersSceneObject::GetBuyableMode) - - .def("IsOnScenePoint", &SceneObject::IsOnScenePoint) - .def("GetGoldValue", &SceneObject::GetGoldValueOld) - .def("GetGoldValue", &SceneObject::GetGoldValue) - .def("SetGoldValue", &SceneObject::SetGoldValue) - .def("GetGoldValueString", &SceneObject::GetGoldValueString) - - .def("GetTotalValue", &SceneObject::GetTotalValue) - .def("GetTotalValue", &LuaAdaptersSceneObject::GetTotalValue) - - .enum_("BuyableMode")[ - luabind::value("NORESTRICTIONS", static_cast(SceneObject::BuyableMode::NoRestrictions)), - luabind::value("BUYMENUONLY", static_cast(SceneObject::BuyableMode::BuyMenuOnly)), - luabind::value("OBJECTPICKERONLY", static_cast(SceneObject::BuyableMode::ObjectPickerOnly)), - luabind::value("SCRIPTONLY", static_cast(SceneObject::BuyableMode::ScriptOnly))]; - + .property("Pos", &SceneObject::GetPos, &SceneObject::SetPos) + .property("HFlipped", &SceneObject::IsHFlipped, &SceneObject::SetHFlipped) + .property("RotAngle", &SceneObject::GetRotAngle, &SceneObject::SetRotAngle) + .property("Team", &SceneObject::GetTeam, &SceneObject::SetTeam) + .property("PlacedByPlayer", &SceneObject::GetPlacedByPlayer, &SceneObject::SetPlacedByPlayer) + .property("Buyable", &SceneObject::IsBuyable) + + .property("BuyableMode", &LuaAdaptersSceneObject::GetBuyableMode) + + .def("IsOnScenePoint", &SceneObject::IsOnScenePoint) + .def("GetGoldValue", &SceneObject::GetGoldValueOld) + .def("GetGoldValue", &SceneObject::GetGoldValue) + .def("SetGoldValue", &SceneObject::SetGoldValue) + .def("GetGoldValueString", &SceneObject::GetGoldValueString) + + .def("GetTotalValue", &SceneObject::GetTotalValue) + .def("GetTotalValue", &LuaAdaptersSceneObject::GetTotalValue) + + .enum_("BuyableMode")[luabind::value("NORESTRICTIONS", static_cast(SceneObject::BuyableMode::NoRestrictions)), + luabind::value("BUYMENUONLY", static_cast(SceneObject::BuyableMode::BuyMenuOnly)), + luabind::value("OBJECTPICKERONLY", static_cast(SceneObject::BuyableMode::ObjectPickerOnly)), + luabind::value("SCRIPTONLY", static_cast(SceneObject::BuyableMode::ScriptOnly))]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, SLBackground) { return luabind::class_("SLBackground") - .property("Frame", &SLBackground::GetFrame, &SLBackground::SetFrame) - .property("SpriteAnimMode", &SLBackground::GetSpriteAnimMode, &SLBackground::SetSpriteAnimMode) - .property("SpriteAnimDuration", &SLBackground::GetSpriteAnimDuration, &SLBackground::SetSpriteAnimDuration) - .property("IsAnimatedManually", &SLBackground::IsAnimatedManually, &SLBackground::SetAnimatedManually) - .property("AutoScrollX", &SLBackground::GetAutoScrollX, &SLBackground::SetAutoScrollX) - .property("AutoScrollY", &SLBackground::GetAutoScrollY, &SLBackground::SetAutoScrollY) - .property("AutoScrollInterval", &SLBackground::GetAutoScrollStepInterval, &SLBackground::SetAutoScrollStepInterval) - .property("AutoScrollStep", &SLBackground::GetAutoScrollStep, &SLBackground::SetAutoScrollStep) - .property("AutoScrollStepX", &SLBackground::GetAutoScrollStepX, &SLBackground::SetAutoScrollStepX) - .property("AutoScrollStepY", &SLBackground::GetAutoScrollStepY, &SLBackground::SetAutoScrollStepY) - - .def("IsAutoScrolling", &SLBackground::IsAutoScrolling); + .property("Frame", &SLBackground::GetFrame, &SLBackground::SetFrame) + .property("SpriteAnimMode", &SLBackground::GetSpriteAnimMode, &SLBackground::SetSpriteAnimMode) + .property("SpriteAnimDuration", &SLBackground::GetSpriteAnimDuration, &SLBackground::SetSpriteAnimDuration) + .property("IsAnimatedManually", &SLBackground::IsAnimatedManually, &SLBackground::SetAnimatedManually) + .property("AutoScrollX", &SLBackground::GetAutoScrollX, &SLBackground::SetAutoScrollX) + .property("AutoScrollY", &SLBackground::GetAutoScrollY, &SLBackground::SetAutoScrollY) + .property("AutoScrollInterval", &SLBackground::GetAutoScrollStepInterval, &SLBackground::SetAutoScrollStepInterval) + .property("AutoScrollStep", &SLBackground::GetAutoScrollStep, &SLBackground::SetAutoScrollStep) + .property("AutoScrollStepX", &SLBackground::GetAutoScrollStepX, &SLBackground::SetAutoScrollStepX) + .property("AutoScrollStepY", &SLBackground::GetAutoScrollStepY, &SLBackground::SetAutoScrollStepY) + + .def("IsAutoScrolling", &SLBackground::IsAutoScrolling); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, SoundContainer) { return ConcreteTypeLuaClassDefinition(SoundContainer, Entity) - .def(luabind::constructor<>()) - - .property("SoundOverlapMode", &SoundContainer::GetSoundOverlapMode, &SoundContainer::SetSoundOverlapMode) - .property("BusRouting", &SoundContainer::GetBusRouting, &SoundContainer::SetBusRouting) - .property("Immobile", &SoundContainer::IsImmobile, &SoundContainer::SetImmobile) - .property("AttenuationStartDistance", &SoundContainer::GetAttenuationStartDistance, &SoundContainer::SetAttenuationStartDistance) - .property("CustomPanValue", &SoundContainer::GetCustomPanValue, &SoundContainer::SetCustomPanValue) - .property("PanningStrengthMultiplier", &SoundContainer::GetPanningStrengthMultiplier, &SoundContainer::SetPanningStrengthMultiplier) - .property("Loops", &SoundContainer::GetLoopSetting, &SoundContainer::SetLoopSetting) - .property("Priority", &SoundContainer::GetPriority, &SoundContainer::SetPriority) - .property("AffectedByGlobalPitch", &SoundContainer::IsAffectedByGlobalPitch, &SoundContainer::SetAffectedByGlobalPitch) - .property("Pos", &SoundContainer::GetPosition, &SoundContainer::SetPosition) - .property("Volume", &SoundContainer::GetVolume, &SoundContainer::SetVolume) - .property("Pitch", &SoundContainer::GetPitch, &SoundContainer::SetPitch) - .property("PitchVariation", &SoundContainer::GetPitchVariation, &SoundContainer::SetPitchVariation) - - .def("HasAnySounds", &SoundContainer::HasAnySounds) - .def("GetTopLevelSoundSet", &SoundContainer::GetTopLevelSoundSet) - .def("SetTopLevelSoundSet", &SoundContainer::SetTopLevelSoundSet) - .def("IsBeingPlayed", &SoundContainer::IsBeingPlayed) - .def("Play", (bool (SoundContainer:: *)()) &SoundContainer::Play) - .def("Play", (bool (SoundContainer:: *)(const int player)) &SoundContainer::Play) - .def("Play", (bool (SoundContainer:: *)(const Vector &position)) &SoundContainer::Play) - .def("Play", (bool (SoundContainer:: *)(const Vector &position, int player)) &SoundContainer::Play) - .def("Stop", (bool (SoundContainer:: *)()) &SoundContainer::Stop) - .def("Stop", (bool (SoundContainer:: *)(int player)) &SoundContainer::Stop) - .def("Restart", (bool (SoundContainer:: *)()) &SoundContainer::Restart) - .def("Restart", (bool (SoundContainer:: *)(int player)) &SoundContainer::Restart) - .def("FadeOut", &SoundContainer::FadeOut) - - .enum_("BusRouting")[ - luabind::value("SFX", SoundContainer::BusRouting::SFX), - luabind::value("UI", SoundContainer::BusRouting::UI), - luabind::value("MUSIC", SoundContainer::BusRouting::MUSIC) - ] - - .enum_("SoundOverlapMode")[ - luabind::value("OVERLAP", SoundContainer::SoundOverlapMode::OVERLAP), - luabind::value("RESTART", SoundContainer::SoundOverlapMode::RESTART), - luabind::value("IGNORE_PLAY", SoundContainer::SoundOverlapMode::IGNORE_PLAY) - ]; + .def(luabind::constructor<>()) + + .property("SoundOverlapMode", &SoundContainer::GetSoundOverlapMode, &SoundContainer::SetSoundOverlapMode) + .property("BusRouting", &SoundContainer::GetBusRouting, &SoundContainer::SetBusRouting) + .property("Immobile", &SoundContainer::IsImmobile, &SoundContainer::SetImmobile) + .property("AttenuationStartDistance", &SoundContainer::GetAttenuationStartDistance, &SoundContainer::SetAttenuationStartDistance) + .property("CustomPanValue", &SoundContainer::GetCustomPanValue, &SoundContainer::SetCustomPanValue) + .property("PanningStrengthMultiplier", &SoundContainer::GetPanningStrengthMultiplier, &SoundContainer::SetPanningStrengthMultiplier) + .property("Loops", &SoundContainer::GetLoopSetting, &SoundContainer::SetLoopSetting) + .property("Priority", &SoundContainer::GetPriority, &SoundContainer::SetPriority) + .property("AffectedByGlobalPitch", &SoundContainer::IsAffectedByGlobalPitch, &SoundContainer::SetAffectedByGlobalPitch) + .property("Pos", &SoundContainer::GetPosition, &SoundContainer::SetPosition) + .property("Volume", &SoundContainer::GetVolume, &SoundContainer::SetVolume) + .property("Pitch", &SoundContainer::GetPitch, &SoundContainer::SetPitch) + .property("PitchVariation", &SoundContainer::GetPitchVariation, &SoundContainer::SetPitchVariation) + + .def("HasAnySounds", &SoundContainer::HasAnySounds) + .def("GetTopLevelSoundSet", &SoundContainer::GetTopLevelSoundSet) + .def("SetTopLevelSoundSet", &SoundContainer::SetTopLevelSoundSet) + .def("IsBeingPlayed", &SoundContainer::IsBeingPlayed) + .def("Play", (bool(SoundContainer::*)()) & SoundContainer::Play) + .def("Play", (bool(SoundContainer::*)(const int player)) & SoundContainer::Play) + .def("Play", (bool(SoundContainer::*)(const Vector& position)) & SoundContainer::Play) + .def("Play", (bool(SoundContainer::*)(const Vector& position, int player)) & SoundContainer::Play) + .def("Stop", (bool(SoundContainer::*)()) & SoundContainer::Stop) + .def("Stop", (bool(SoundContainer::*)(int player)) & SoundContainer::Stop) + .def("Restart", (bool(SoundContainer::*)()) & SoundContainer::Restart) + .def("Restart", (bool(SoundContainer::*)(int player)) & SoundContainer::Restart) + .def("FadeOut", &SoundContainer::FadeOut) + + .enum_("BusRouting")[luabind::value("SFX", SoundContainer::BusRouting::SFX), + luabind::value("UI", SoundContainer::BusRouting::UI), + luabind::value("MUSIC", SoundContainer::BusRouting::MUSIC)] + + .enum_("SoundOverlapMode")[luabind::value("OVERLAP", SoundContainer::SoundOverlapMode::OVERLAP), + luabind::value("RESTART", SoundContainer::SoundOverlapMode::RESTART), + luabind::value("IGNORE_PLAY", SoundContainer::SoundOverlapMode::IGNORE_PLAY)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, SoundSet) { return luabind::class_("SoundSet") - .def(luabind::constructor<>()) + .def(luabind::constructor<>()) - .property("SoundSelectionCycleMode", &SoundSet::GetSoundSelectionCycleMode, &SoundSet::SetSoundSelectionCycleMode) + .property("SoundSelectionCycleMode", &SoundSet::GetSoundSelectionCycleMode, &SoundSet::SetSoundSelectionCycleMode) - .def_readonly("SubSoundSets", &SoundSet::m_SubSoundSets, luabind::return_stl_iterator) + .def_readonly("SubSoundSets", &SoundSet::m_SubSoundSets, luabind::return_stl_iterator) - .def("HasAnySounds", &SoundSet::HasAnySounds) - .def("SelectNextSounds", &SoundSet::SelectNextSounds) - .def("AddSound", (void (SoundSet:: *)(const std::string &soundFilePath)) &SoundSet::AddSound) - .def("AddSound", (void (SoundSet:: *)(const std::string &soundFilePath, const Vector &offset, float minimumAudibleDistance, float attenuationStartDistance)) &SoundSet::AddSound) - .def("RemoveSound", (bool (SoundSet:: *)(const std::string &soundFilePath)) &SoundSet::RemoveSound) - .def("RemoveSound", (bool (SoundSet:: *)(const std::string &soundFilePath, bool removeFromSubSoundSets)) &SoundSet::RemoveSound) - .def("AddSoundSet", &SoundSet::AddSoundSet) + .def("HasAnySounds", &SoundSet::HasAnySounds) + .def("SelectNextSounds", &SoundSet::SelectNextSounds) + .def("AddSound", (void(SoundSet::*)(const std::string& soundFilePath)) & SoundSet::AddSound) + .def("AddSound", (void(SoundSet::*)(const std::string& soundFilePath, const Vector& offset, float minimumAudibleDistance, float attenuationStartDistance)) & SoundSet::AddSound) + .def("RemoveSound", (bool(SoundSet::*)(const std::string& soundFilePath)) & SoundSet::RemoveSound) + .def("RemoveSound", (bool(SoundSet::*)(const std::string& soundFilePath, bool removeFromSubSoundSets)) & SoundSet::RemoveSound) + .def("AddSoundSet", &SoundSet::AddSoundSet) - .enum_("SoundSelectionCycleMode")[ - luabind::value("RANDOM", SoundSet::SoundSelectionCycleMode::RANDOM), - luabind::value("FORWARDS", SoundSet::SoundSelectionCycleMode::FORWARDS), - luabind::value("ALL", SoundSet::SoundSelectionCycleMode::ALL) - ]; + .enum_("SoundSelectionCycleMode")[luabind::value("RANDOM", SoundSet::SoundSelectionCycleMode::RANDOM), + luabind::value("FORWARDS", SoundSet::SoundSelectionCycleMode::FORWARDS), + luabind::value("ALL", SoundSet::SoundSelectionCycleMode::ALL)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, TDExplosive) { return ConcreteTypeLuaClassDefinition(TDExplosive, ThrownDevice) - .property("IsAnimatedManually", &TDExplosive::IsAnimatedManually, &TDExplosive::SetAnimatedManually); + .property("IsAnimatedManually", &TDExplosive::IsAnimatedManually, &TDExplosive::SetAnimatedManually); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, TerrainObject) { return ConcreteTypeLuaClassDefinition(TerrainObject, SceneObject) - .def("GetBitmapOffset", &TerrainObject::GetBitmapOffset) - .def("GetBitmapWidth", &TerrainObject::GetBitmapWidth) - .def("GetBitmapHeight", &TerrainObject::GetBitmapHeight); + .def("GetBitmapOffset", &TerrainObject::GetBitmapOffset) + .def("GetBitmapWidth", &TerrainObject::GetBitmapWidth) + .def("GetBitmapHeight", &TerrainObject::GetBitmapHeight); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, ThrownDevice) { return ConcreteTypeLuaClassDefinition(ThrownDevice, HeldDevice) - .property("MinThrowVel", &ThrownDevice::GetMinThrowVel, &ThrownDevice::SetMinThrowVel) - .property("MaxThrowVel", &ThrownDevice::GetMaxThrowVel, &ThrownDevice::SetMaxThrowVel) - .property("StartThrowOffset", &ThrownDevice::GetStartThrowOffset, &ThrownDevice::SetStartThrowOffset) - .property("EndThrowOffset", &ThrownDevice::GetEndThrowOffset, &ThrownDevice::SetEndThrowOffset) + .property("MinThrowVel", &ThrownDevice::GetMinThrowVel, &ThrownDevice::SetMinThrowVel) + .property("MaxThrowVel", &ThrownDevice::GetMaxThrowVel, &ThrownDevice::SetMaxThrowVel) + .property("StartThrowOffset", &ThrownDevice::GetStartThrowOffset, &ThrownDevice::SetStartThrowOffset) + .property("EndThrowOffset", &ThrownDevice::GetEndThrowOffset, &ThrownDevice::SetEndThrowOffset) - .def("GetCalculatedMaxThrowVelIncludingArmThrowStrength", &ThrownDevice::GetCalculatedMaxThrowVelIncludingArmThrowStrength); + .def("GetCalculatedMaxThrowVelIncludingArmThrowStrength", &ThrownDevice::GetCalculatedMaxThrowVelIncludingArmThrowStrength); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(EntityLuaBindings, Turret) { return ConcreteTypeLuaClassDefinition(Turret, Attachable) - .property("MountedDevice", &Turret::GetFirstMountedDevice, &LuaAdaptersPropertyOwnershipSafetyFaker::TurretSetFirstMountedDevice) - .property("MountedDeviceRotationOffset", &Turret::GetMountedDeviceRotationOffset, &Turret::SetMountedDeviceRotationOffset) + .property("MountedDevice", &Turret::GetFirstMountedDevice, &LuaAdaptersPropertyOwnershipSafetyFaker::TurretSetFirstMountedDevice) + .property("MountedDeviceRotationOffset", &Turret::GetMountedDeviceRotationOffset, &Turret::SetMountedDeviceRotationOffset) - .def("GetMountedDevices", &Turret::GetMountedDevices, luabind::return_stl_iterator) - .def("AddMountedDevice", &Turret::AddMountedDevice, luabind::adopt(_2)) - .def("AddMountedDevice", &LuaAdaptersTurret::AddMountedFirearm, luabind::adopt(_2)); + .def("GetMountedDevices", &Turret::GetMountedDevices, luabind::return_stl_iterator) + .def("AddMountedDevice", &Turret::AddMountedDevice, luabind::adopt(_2)) + .def("AddMountedDevice", &LuaAdaptersTurret::AddMountedFirearm, luabind::adopt(_2)); } -} +} // namespace RTE diff --git a/Source/Lua/LuaBindingsGUI.cpp b/Source/Lua/LuaBindingsGUI.cpp index 17bcecb05..a80d42593 100644 --- a/Source/Lua/LuaBindingsGUI.cpp +++ b/Source/Lua/LuaBindingsGUI.cpp @@ -4,105 +4,97 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(GUILuaBindings, GUIBanner) { return luabind::class_("GUIBanner") - .property("BannerText", &GUIBanner::GetBannerText) - .property("AnimState", &GUIBanner::GetAnimState) - .property("Kerning", &GUIBanner::GetKerning, &GUIBanner::SetKerning) - - .def("IsVisible", &GUIBanner::IsVisible) - .def("ShowText", &GUIBanner::ShowText) - .def("HideText", &GUIBanner::HideText) - .def("ClearText", &GUIBanner::ClearText) - - .enum_("AnimMode")[ - luabind::value("BLINKING", GUIBanner::AnimMode::BLINKING), - luabind::value("FLYBYLEFTWARD", GUIBanner::AnimMode::FLYBYLEFTWARD), - luabind::value("FLYBYRIGHTWARD", GUIBanner::AnimMode::FLYBYRIGHTWARD), - luabind::value("ANIMMODECOUNT", GUIBanner::AnimMode::ANIMMODECOUNT) - ] - .enum_("AnimState")[ - luabind::value("NOTSTARTED", GUIBanner::AnimState::NOTSTARTED), - luabind::value("SHOWING", GUIBanner::AnimState::SHOWING), - luabind::value("SHOW", GUIBanner::AnimState::SHOW), - luabind::value("HIDING", GUIBanner::AnimState::HIDING), - luabind::value("OVER", GUIBanner::AnimState::OVER), - luabind::value("ANIMSTATECOUNT", GUIBanner::AnimState::ANIMSTATECOUNT) - ] - .enum_("BannerColor")[ - luabind::value("RED", GameActivity::BannerColor::RED), - luabind::value("YELLOW", GameActivity::BannerColor::YELLOW) - ]; + .property("BannerText", &GUIBanner::GetBannerText) + .property("AnimState", &GUIBanner::GetAnimState) + .property("Kerning", &GUIBanner::GetKerning, &GUIBanner::SetKerning) + + .def("IsVisible", &GUIBanner::IsVisible) + .def("ShowText", &GUIBanner::ShowText) + .def("HideText", &GUIBanner::HideText) + .def("ClearText", &GUIBanner::ClearText) + + .enum_("AnimMode")[luabind::value("BLINKING", GUIBanner::AnimMode::BLINKING), + luabind::value("FLYBYLEFTWARD", GUIBanner::AnimMode::FLYBYLEFTWARD), + luabind::value("FLYBYRIGHTWARD", GUIBanner::AnimMode::FLYBYRIGHTWARD), + luabind::value("ANIMMODECOUNT", GUIBanner::AnimMode::ANIMMODECOUNT)] + .enum_("AnimState")[luabind::value("NOTSTARTED", GUIBanner::AnimState::NOTSTARTED), + luabind::value("SHOWING", GUIBanner::AnimState::SHOWING), + luabind::value("SHOW", GUIBanner::AnimState::SHOW), + luabind::value("HIDING", GUIBanner::AnimState::HIDING), + luabind::value("OVER", GUIBanner::AnimState::OVER), + luabind::value("ANIMSTATECOUNT", GUIBanner::AnimState::ANIMSTATECOUNT)] + .enum_("BannerColor")[luabind::value("RED", GameActivity::BannerColor::RED), + luabind::value("YELLOW", GameActivity::BannerColor::YELLOW)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(GUILuaBindings, BuyMenuGUI) { return luabind::class_("BuyMenuGUI") - .property("ShowOnlyOwnedItems", &BuyMenuGUI::GetOnlyShowOwnedItems, &BuyMenuGUI::SetOnlyShowOwnedItems) - .property("EnforceMaxPassengersConstraint", &BuyMenuGUI::EnforceMaxPassengersConstraint, &BuyMenuGUI::SetEnforceMaxPassengersConstraint) - .property("EnforceMaxMassConstraint", &BuyMenuGUI::EnforceMaxMassConstraint, &BuyMenuGUI::SetEnforceMaxMassConstraint) - - .def("SetMetaPlayer", &BuyMenuGUI::SetMetaPlayer) - .def("SetNativeTechModule", &BuyMenuGUI::SetNativeTechModule) - .def("SetForeignCostMultiplier", &BuyMenuGUI::SetForeignCostMultiplier) - .def("SetModuleExpanded", &BuyMenuGUI::SetModuleExpanded) - .def("LoadAllLoadoutsFromFile", &BuyMenuGUI::LoadAllLoadoutsFromFile) - .def("AddAllowedItem", &BuyMenuGUI::AddAllowedItem) - .def("RemoveAllowedItem", &BuyMenuGUI::RemoveAllowedItem) - .def("ClearAllowedItems", &BuyMenuGUI::ClearAllowedItems) - .def("AddAlwaysAllowedItem", &BuyMenuGUI::AddAlwaysAllowedItem) - .def("RemoveAlwaysAllowedItem", &BuyMenuGUI::RemoveAlwaysAllowedItem) - .def("ClearAlwaysAllowedItems", &BuyMenuGUI::ClearAlwaysAllowedItems) - .def("AddProhibitedItem", &BuyMenuGUI::AddProhibitedItem) - .def("RemoveProhibitedItem", &BuyMenuGUI::RemoveProhibitedItem) - .def("ClearProhibitedItems", &BuyMenuGUI::ClearProhibitedItems) - .def("ForceRefresh", &BuyMenuGUI::ForceRefresh) - .def("SetOwnedItemsAmount", &BuyMenuGUI::SetOwnedItemsAmount) - .def("GetOwnedItemsAmount", &BuyMenuGUI::GetOwnedItemsAmount) - .def("SetBannerImage", &BuyMenuGUI::SetBannerImage) - .def("SetLogoImage", &BuyMenuGUI::SetLogoImage) - .def("ClearCartList", &BuyMenuGUI::ClearCartList) - .def("LoadDefaultLoadoutToCart", &BuyMenuGUI::LoadDefaultLoadoutToCart) - .def("GetOrderList", &LuaAdaptersBuyMenuGUI::GetOrderList, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetTotalCartCost", &BuyMenuGUI::GetTotalCartCost) - .def("GetTotalOrderCost", &BuyMenuGUI::GetTotalOrderCost) - .def("GetTotalOrderMass", &BuyMenuGUI::GetTotalOrderMass) - .def("GetTotalOrderPassengers", &BuyMenuGUI::GetTotalOrderPassengers); + .property("ShowOnlyOwnedItems", &BuyMenuGUI::GetOnlyShowOwnedItems, &BuyMenuGUI::SetOnlyShowOwnedItems) + .property("EnforceMaxPassengersConstraint", &BuyMenuGUI::EnforceMaxPassengersConstraint, &BuyMenuGUI::SetEnforceMaxPassengersConstraint) + .property("EnforceMaxMassConstraint", &BuyMenuGUI::EnforceMaxMassConstraint, &BuyMenuGUI::SetEnforceMaxMassConstraint) + + .def("SetMetaPlayer", &BuyMenuGUI::SetMetaPlayer) + .def("SetNativeTechModule", &BuyMenuGUI::SetNativeTechModule) + .def("SetForeignCostMultiplier", &BuyMenuGUI::SetForeignCostMultiplier) + .def("SetModuleExpanded", &BuyMenuGUI::SetModuleExpanded) + .def("LoadAllLoadoutsFromFile", &BuyMenuGUI::LoadAllLoadoutsFromFile) + .def("AddAllowedItem", &BuyMenuGUI::AddAllowedItem) + .def("RemoveAllowedItem", &BuyMenuGUI::RemoveAllowedItem) + .def("ClearAllowedItems", &BuyMenuGUI::ClearAllowedItems) + .def("AddAlwaysAllowedItem", &BuyMenuGUI::AddAlwaysAllowedItem) + .def("RemoveAlwaysAllowedItem", &BuyMenuGUI::RemoveAlwaysAllowedItem) + .def("ClearAlwaysAllowedItems", &BuyMenuGUI::ClearAlwaysAllowedItems) + .def("AddProhibitedItem", &BuyMenuGUI::AddProhibitedItem) + .def("RemoveProhibitedItem", &BuyMenuGUI::RemoveProhibitedItem) + .def("ClearProhibitedItems", &BuyMenuGUI::ClearProhibitedItems) + .def("ForceRefresh", &BuyMenuGUI::ForceRefresh) + .def("SetOwnedItemsAmount", &BuyMenuGUI::SetOwnedItemsAmount) + .def("GetOwnedItemsAmount", &BuyMenuGUI::GetOwnedItemsAmount) + .def("SetBannerImage", &BuyMenuGUI::SetBannerImage) + .def("SetLogoImage", &BuyMenuGUI::SetLogoImage) + .def("ClearCartList", &BuyMenuGUI::ClearCartList) + .def("LoadDefaultLoadoutToCart", &BuyMenuGUI::LoadDefaultLoadoutToCart) + .def("GetOrderList", &LuaAdaptersBuyMenuGUI::GetOrderList, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetTotalCartCost", &BuyMenuGUI::GetTotalCartCost) + .def("GetTotalOrderCost", &BuyMenuGUI::GetTotalOrderCost) + .def("GetTotalOrderMass", &BuyMenuGUI::GetTotalOrderMass) + .def("GetTotalOrderPassengers", &BuyMenuGUI::GetTotalOrderPassengers); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(GUILuaBindings, SceneEditorGUI) { return luabind::class_("SceneEditorGUI") - .property("EditorMode", &SceneEditorGUI::GetEditorGUIMode, &SceneEditorGUI::SetEditorGUIMode) - - .def("SetCursorPos", &SceneEditorGUI::SetCursorPos) - .def("GetCurrentObject", &SceneEditorGUI::GetCurrentObject) - .def("SetCurrentObject", &SceneEditorGUI::SetCurrentObject) - .def("SetModuleSpace", &SceneEditorGUI::SetModuleSpace) - .def("SetNativeTechModule", &SceneEditorGUI::SetNativeTechModule) - .def("SetForeignCostMultiplier", &SceneEditorGUI::SetForeignCostMultiplier) - .def("TestBrainResidence", &SceneEditorGUI::TestBrainResidence) - .def("Update", &SceneEditorGUI::Update) //Gacyr Note: I hate this being here but it's necessary for some metagame bullshit. - - .enum_("EditorGUIMode")[ - luabind::value("INACTIVE", SceneEditorGUI::EditorGUIMode::INACTIVE), - luabind::value("PICKINGOBJECT", SceneEditorGUI::EditorGUIMode::PICKINGOBJECT), - luabind::value("ADDINGOBJECT", SceneEditorGUI::EditorGUIMode::ADDINGOBJECT), - luabind::value("INSTALLINGBRAIN", SceneEditorGUI::EditorGUIMode::INSTALLINGBRAIN), - luabind::value("PLACINGOBJECT", SceneEditorGUI::EditorGUIMode::PLACINGOBJECT), - luabind::value("MOVINGOBJECT", SceneEditorGUI::EditorGUIMode::MOVINGOBJECT), - luabind::value("DELETINGOBJECT", SceneEditorGUI::EditorGUIMode::DELETINGOBJECT), - luabind::value("PLACEINFRONT", SceneEditorGUI::EditorGUIMode::PLACEINFRONT), - luabind::value("PLACEBEHIND", SceneEditorGUI::EditorGUIMode::PLACEBEHIND), - luabind::value("DONEEDITING", SceneEditorGUI::EditorGUIMode::DONEEDITING), - luabind::value("EDITORGUIMODECOUNT", SceneEditorGUI::EditorGUIMode::EDITORGUIMODECOUNT) - ]; + .property("EditorMode", &SceneEditorGUI::GetEditorGUIMode, &SceneEditorGUI::SetEditorGUIMode) + + .def("SetCursorPos", &SceneEditorGUI::SetCursorPos) + .def("GetCurrentObject", &SceneEditorGUI::GetCurrentObject) + .def("SetCurrentObject", &SceneEditorGUI::SetCurrentObject) + .def("SetModuleSpace", &SceneEditorGUI::SetModuleSpace) + .def("SetNativeTechModule", &SceneEditorGUI::SetNativeTechModule) + .def("SetForeignCostMultiplier", &SceneEditorGUI::SetForeignCostMultiplier) + .def("TestBrainResidence", &SceneEditorGUI::TestBrainResidence) + .def("Update", &SceneEditorGUI::Update) // Gacyr Note: I hate this being here but it's necessary for some metagame bullshit. + + .enum_("EditorGUIMode")[luabind::value("INACTIVE", SceneEditorGUI::EditorGUIMode::INACTIVE), + luabind::value("PICKINGOBJECT", SceneEditorGUI::EditorGUIMode::PICKINGOBJECT), + luabind::value("ADDINGOBJECT", SceneEditorGUI::EditorGUIMode::ADDINGOBJECT), + luabind::value("INSTALLINGBRAIN", SceneEditorGUI::EditorGUIMode::INSTALLINGBRAIN), + luabind::value("PLACINGOBJECT", SceneEditorGUI::EditorGUIMode::PLACINGOBJECT), + luabind::value("MOVINGOBJECT", SceneEditorGUI::EditorGUIMode::MOVINGOBJECT), + luabind::value("DELETINGOBJECT", SceneEditorGUI::EditorGUIMode::DELETINGOBJECT), + luabind::value("PLACEINFRONT", SceneEditorGUI::EditorGUIMode::PLACEINFRONT), + luabind::value("PLACEBEHIND", SceneEditorGUI::EditorGUIMode::PLACEBEHIND), + luabind::value("DONEEDITING", SceneEditorGUI::EditorGUIMode::DONEEDITING), + luabind::value("EDITORGUIMODECOUNT", SceneEditorGUI::EditorGUIMode::EDITORGUIMODECOUNT)]; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuaBindingsInput.cpp b/Source/Lua/LuaBindingsInput.cpp index b93c6656e..016dc61cc 100644 --- a/Source/Lua/LuaBindingsInput.cpp +++ b/Source/Lua/LuaBindingsInput.cpp @@ -8,642 +8,624 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, InputDevice) { return luabind::class_("InputDevice") - .enum_("InputDevice")[ - luabind::value("DEVICE_KEYB_ONLY", InputDevice::DEVICE_KEYB_ONLY), - luabind::value("DEVICE_MOUSE_KEYB", InputDevice::DEVICE_MOUSE_KEYB), - luabind::value("DEVICE_GAMEPAD_1", InputDevice::DEVICE_GAMEPAD_1), - luabind::value("DEVICE_GAMEPAD_2", InputDevice::DEVICE_GAMEPAD_2), - luabind::value("DEVICE_GAMEPAD_3", InputDevice::DEVICE_GAMEPAD_3), - luabind::value("DEVICE_GAMEPAD_4", InputDevice::DEVICE_GAMEPAD_4), - luabind::value("DEVICE_COUNT", InputDevice::DEVICE_COUNT) - ]; + .enum_("InputDevice")[luabind::value("DEVICE_KEYB_ONLY", InputDevice::DEVICE_KEYB_ONLY), + luabind::value("DEVICE_MOUSE_KEYB", InputDevice::DEVICE_MOUSE_KEYB), + luabind::value("DEVICE_GAMEPAD_1", InputDevice::DEVICE_GAMEPAD_1), + luabind::value("DEVICE_GAMEPAD_2", InputDevice::DEVICE_GAMEPAD_2), + luabind::value("DEVICE_GAMEPAD_3", InputDevice::DEVICE_GAMEPAD_3), + luabind::value("DEVICE_GAMEPAD_4", InputDevice::DEVICE_GAMEPAD_4), + luabind::value("DEVICE_COUNT", InputDevice::DEVICE_COUNT)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, InputElements) { return luabind::class_("InputElements") - .enum_("InputElements")[ - luabind::value("INPUT_L_UP", InputElements::INPUT_L_UP), - luabind::value("INPUT_L_DOWN", InputElements::INPUT_L_DOWN), - luabind::value("INPUT_L_LEFT", InputElements::INPUT_L_LEFT), - luabind::value("INPUT_L_RIGHT", InputElements::INPUT_L_RIGHT), - luabind::value("INPUT_R_UP", InputElements::INPUT_R_UP), - luabind::value("INPUT_R_DOWN", InputElements::INPUT_R_DOWN), - luabind::value("INPUT_R_LEFT", InputElements::INPUT_R_LEFT), - luabind::value("INPUT_R_RIGHT", InputElements::INPUT_R_RIGHT), - luabind::value("INPUT_FIRE", InputElements::INPUT_FIRE), - luabind::value("INPUT_AIM", InputElements::INPUT_AIM), - luabind::value("INPUT_AIM_UP", InputElements::INPUT_AIM_UP), - luabind::value("INPUT_AIM_DOWN", InputElements::INPUT_AIM_DOWN), - luabind::value("INPUT_AIM_LEFT", InputElements::INPUT_AIM_LEFT), - luabind::value("INPUT_AIM_RIGHT", InputElements::INPUT_AIM_RIGHT), - luabind::value("INPUT_PIEMENU_ANALOG", InputElements::INPUT_PIEMENU_ANALOG), - luabind::value("INPUT_PIEMENU_DIGITAL", InputElements::INPUT_PIEMENU_DIGITAL), - luabind::value("INPUT_JUMP", InputElements::INPUT_JUMP), - luabind::value("INPUT_CROUCH", InputElements::INPUT_CROUCH), - luabind::value("INPUT_NEXT", InputElements::INPUT_NEXT), - luabind::value("INPUT_PREV", InputElements::INPUT_PREV), - luabind::value("INPUT_START", InputElements::INPUT_START), - luabind::value("INPUT_BACK", InputElements::INPUT_BACK), - luabind::value("INPUT_COUNT", InputElements::INPUT_COUNT) - ]; + .enum_("InputElements")[luabind::value("INPUT_L_UP", InputElements::INPUT_L_UP), + luabind::value("INPUT_L_DOWN", InputElements::INPUT_L_DOWN), + luabind::value("INPUT_L_LEFT", InputElements::INPUT_L_LEFT), + luabind::value("INPUT_L_RIGHT", InputElements::INPUT_L_RIGHT), + luabind::value("INPUT_R_UP", InputElements::INPUT_R_UP), + luabind::value("INPUT_R_DOWN", InputElements::INPUT_R_DOWN), + luabind::value("INPUT_R_LEFT", InputElements::INPUT_R_LEFT), + luabind::value("INPUT_R_RIGHT", InputElements::INPUT_R_RIGHT), + luabind::value("INPUT_FIRE", InputElements::INPUT_FIRE), + luabind::value("INPUT_AIM", InputElements::INPUT_AIM), + luabind::value("INPUT_AIM_UP", InputElements::INPUT_AIM_UP), + luabind::value("INPUT_AIM_DOWN", InputElements::INPUT_AIM_DOWN), + luabind::value("INPUT_AIM_LEFT", InputElements::INPUT_AIM_LEFT), + luabind::value("INPUT_AIM_RIGHT", InputElements::INPUT_AIM_RIGHT), + luabind::value("INPUT_PIEMENU_ANALOG", InputElements::INPUT_PIEMENU_ANALOG), + luabind::value("INPUT_PIEMENU_DIGITAL", InputElements::INPUT_PIEMENU_DIGITAL), + luabind::value("INPUT_JUMP", InputElements::INPUT_JUMP), + luabind::value("INPUT_CROUCH", InputElements::INPUT_CROUCH), + luabind::value("INPUT_NEXT", InputElements::INPUT_NEXT), + luabind::value("INPUT_PREV", InputElements::INPUT_PREV), + luabind::value("INPUT_START", InputElements::INPUT_START), + luabind::value("INPUT_BACK", InputElements::INPUT_BACK), + luabind::value("INPUT_COUNT", InputElements::INPUT_COUNT)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, MouseButtons) { return luabind::class_("MouseButtons") - .enum_("MouseButtons")[ - luabind::value("MOUSE_NONE", MouseButtons::MOUSE_NONE), - luabind::value("MOUSE_LEFT", MouseButtons::MOUSE_LEFT), - luabind::value("MOUSE_RIGHT", MouseButtons::MOUSE_RIGHT), - luabind::value("MOUSE_MIDDLE", MouseButtons::MOUSE_MIDDLE), - luabind::value("MAX_MOUSE_BUTTONS", MouseButtons::MAX_MOUSE_BUTTONS) - ]; + .enum_("MouseButtons")[luabind::value("MOUSE_NONE", MouseButtons::MOUSE_NONE), + luabind::value("MOUSE_LEFT", MouseButtons::MOUSE_LEFT), + luabind::value("MOUSE_RIGHT", MouseButtons::MOUSE_RIGHT), + luabind::value("MOUSE_MIDDLE", MouseButtons::MOUSE_MIDDLE), + luabind::value("MAX_MOUSE_BUTTONS", MouseButtons::MAX_MOUSE_BUTTONS)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, JoyButtons) { return luabind::class_("JoyButtons") - .enum_("JoyButtons")[ - luabind::value("JOY_NONE", JoyButtons::JOY_NONE), - luabind::value("JOY_1", JoyButtons::JOY_1), - luabind::value("JOY_2", JoyButtons::JOY_2), - luabind::value("JOY_3", JoyButtons::JOY_3), - luabind::value("JOY_4", JoyButtons::JOY_4), - luabind::value("JOY_5", JoyButtons::JOY_5), - luabind::value("JOY_6", JoyButtons::JOY_6), - luabind::value("JOY_7", JoyButtons::JOY_7), - luabind::value("JOY_8", JoyButtons::JOY_8), - luabind::value("JOY_9", JoyButtons::JOY_9), - luabind::value("JOY_10", JoyButtons::JOY_10), - luabind::value("JOY_11", JoyButtons::JOY_11), - luabind::value("JOY_12", JoyButtons::JOY_12), - luabind::value("MAX_JOY_BUTTONS", JoyButtons::MAX_JOY_BUTTONS) - ]; + .enum_("JoyButtons")[luabind::value("JOY_NONE", JoyButtons::JOY_NONE), + luabind::value("JOY_1", JoyButtons::JOY_1), + luabind::value("JOY_2", JoyButtons::JOY_2), + luabind::value("JOY_3", JoyButtons::JOY_3), + luabind::value("JOY_4", JoyButtons::JOY_4), + luabind::value("JOY_5", JoyButtons::JOY_5), + luabind::value("JOY_6", JoyButtons::JOY_6), + luabind::value("JOY_7", JoyButtons::JOY_7), + luabind::value("JOY_8", JoyButtons::JOY_8), + luabind::value("JOY_9", JoyButtons::JOY_9), + luabind::value("JOY_10", JoyButtons::JOY_10), + luabind::value("JOY_11", JoyButtons::JOY_11), + luabind::value("JOY_12", JoyButtons::JOY_12), + luabind::value("MAX_JOY_BUTTONS", JoyButtons::MAX_JOY_BUTTONS)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, JoyDirections) { return luabind::class_("JoyDirections") - .enum_("JoyDirections")[ - luabind::value("JOYDIR_ONE", JoyDirections::JOYDIR_ONE), - luabind::value("JOYDIR_TWO", JoyDirections::JOYDIR_TWO) - ]; + .enum_("JoyDirections")[luabind::value("JOYDIR_ONE", JoyDirections::JOYDIR_ONE), + luabind::value("JOYDIR_TWO", JoyDirections::JOYDIR_TWO)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, SDL_Keycode) { return luabind::class_("Key") - // Make sure to update https://github.com/cortex-command-community/Cortex-Command-Community-Project-Source/wiki/SDL-Keycode-and-Scancode-enum-values-in-Lua#key-codes if any changes are made. - .enum_("Key")[ - luabind::value("UNKNOWN", SDLK_UNKNOWN), - luabind::value("RETURN", SDLK_RETURN), - luabind::value("ESCAPE", SDLK_ESCAPE), - luabind::value("BACKSPACE", SDLK_BACKSPACE), - luabind::value("TAB", SDLK_TAB), - luabind::value("SPACE", SDLK_SPACE), - luabind::value("EXCLAIM", SDLK_EXCLAIM), - luabind::value("QUOTEDBL", SDLK_QUOTEDBL), - luabind::value("HASH", SDLK_HASH), - luabind::value("PERCENT", SDLK_PERCENT), - luabind::value("DOLLAR", SDLK_DOLLAR), - luabind::value("AMPERSAND", SDLK_AMPERSAND), - luabind::value("QUOTE", SDLK_QUOTE), - luabind::value("LEFTPAREN", SDLK_LEFTPAREN), - luabind::value("RIGHTPAREN", SDLK_RIGHTPAREN), - luabind::value("ASTERISK", SDLK_ASTERISK), - luabind::value("PLUS", SDLK_PLUS), - luabind::value("COMMA", SDLK_COMMA), - luabind::value("MINUS", SDLK_MINUS), - luabind::value("PERIOD", SDLK_PERIOD), - luabind::value("SLASH", SDLK_SLASH), - luabind::value("K_0", SDLK_0), - luabind::value("K_1", SDLK_1), - luabind::value("K_2", SDLK_2), - luabind::value("K_3", SDLK_3), - luabind::value("K_4", SDLK_4), - luabind::value("K_5", SDLK_5), - luabind::value("K_6", SDLK_6), - luabind::value("K_7", SDLK_7), - luabind::value("K_8", SDLK_8), - luabind::value("K_9", SDLK_9), - luabind::value("COLON", SDLK_COLON), - luabind::value("SEMICOLON", SDLK_SEMICOLON), - luabind::value("LESS", SDLK_LESS), - luabind::value("EQUALS", SDLK_EQUALS), - luabind::value("GREATER", SDLK_GREATER), - luabind::value("QUESTION", SDLK_QUESTION), - luabind::value("AT", SDLK_AT), - luabind::value("LEFTBRACKET", SDLK_LEFTBRACKET), - luabind::value("BACKSLASH", SDLK_BACKSLASH), - luabind::value("RIGHTBRACKET", SDLK_RIGHTBRACKET), - luabind::value("CARET", SDLK_CARET), - luabind::value("UNDERSCORE", SDLK_UNDERSCORE), - luabind::value("BACKQUOTE", SDLK_BACKQUOTE), - luabind::value("A", SDLK_a), - luabind::value("B", SDLK_b), - luabind::value("C", SDLK_c), - luabind::value("D", SDLK_d), - luabind::value("E", SDLK_e), - luabind::value("F", SDLK_f), - luabind::value("G", SDLK_g), - luabind::value("H", SDLK_h), - luabind::value("I", SDLK_i), - luabind::value("J", SDLK_j), - luabind::value("K", SDLK_k), - luabind::value("L", SDLK_l), - luabind::value("M", SDLK_m), - luabind::value("N", SDLK_n), - luabind::value("O", SDLK_o), - luabind::value("P", SDLK_p), - luabind::value("Q", SDLK_q), - luabind::value("R", SDLK_r), - luabind::value("S", SDLK_s), - luabind::value("T", SDLK_t), - luabind::value("U", SDLK_u), - luabind::value("V", SDLK_v), - luabind::value("W", SDLK_w), - luabind::value("X", SDLK_x), - luabind::value("Y", SDLK_y), - luabind::value("Z", SDLK_z), - luabind::value("CAPSLOCK", SDLK_CAPSLOCK), - luabind::value("F1", SDLK_F1), - luabind::value("F2", SDLK_F2), - luabind::value("F3", SDLK_F3), - luabind::value("F4", SDLK_F4), - luabind::value("F5", SDLK_F5), - luabind::value("F6", SDLK_F6), - luabind::value("F7", SDLK_F7), - luabind::value("F8", SDLK_F8), - luabind::value("F9", SDLK_F9), - luabind::value("F10", SDLK_F10), - luabind::value("F11", SDLK_F11), - luabind::value("F12", SDLK_F12), - luabind::value("PRINTSCREEN", SDLK_PRINTSCREEN), - luabind::value("SCROLLLOCK", SDLK_SCROLLLOCK), - luabind::value("PAUSE", SDLK_PAUSE), - luabind::value("INSERT", SDLK_INSERT), - luabind::value("HOME", SDLK_HOME), - luabind::value("PAGEUP", SDLK_PAGEUP), - luabind::value("DELETE", SDLK_DELETE), - luabind::value("END", SDLK_END), - luabind::value("PAGEDOWN", SDLK_PAGEDOWN), - luabind::value("RIGHT", SDLK_RIGHT), - luabind::value("LEFT", SDLK_LEFT), - luabind::value("DOWN", SDLK_DOWN), - luabind::value("UP", SDLK_UP), - luabind::value("NUMLOCKCLEAR", SDLK_NUMLOCKCLEAR), - luabind::value("KP_DIVIDE", SDLK_KP_DIVIDE), - luabind::value("KP_MULTIPLY", SDLK_KP_MULTIPLY), - luabind::value("KP_MINUS", SDLK_KP_MINUS), - luabind::value("KP_PLUS", SDLK_KP_PLUS), - luabind::value("KP_ENTER", SDLK_KP_ENTER), - luabind::value("KP_1", SDLK_KP_1), - luabind::value("KP_2", SDLK_KP_2), - luabind::value("KP_3", SDLK_KP_3), - luabind::value("KP_4", SDLK_KP_4), - luabind::value("KP_5", SDLK_KP_5), - luabind::value("KP_6", SDLK_KP_6), - luabind::value("KP_7", SDLK_KP_7), - luabind::value("KP_8", SDLK_KP_8), - luabind::value("KP_9", SDLK_KP_9), - luabind::value("KP_0", SDLK_KP_0), - luabind::value("KP_PERIOD", SDLK_KP_PERIOD), - luabind::value("APPLICATION", SDLK_APPLICATION), - luabind::value("POWER", SDLK_POWER), - luabind::value("KP_EQUALS", SDLK_KP_EQUALS), - luabind::value("F13", SDLK_F13), - luabind::value("F14", SDLK_F14), - luabind::value("F15", SDLK_F15), - luabind::value("F16", SDLK_F16), - luabind::value("F17", SDLK_F17), - luabind::value("F18", SDLK_F18), - luabind::value("F19", SDLK_F19), - luabind::value("F20", SDLK_F20), - luabind::value("F21", SDLK_F21), - luabind::value("F22", SDLK_F22), - luabind::value("F23", SDLK_F23), - luabind::value("F24", SDLK_F24), - luabind::value("EXECUTE", SDLK_EXECUTE), - luabind::value("HELP", SDLK_HELP), - luabind::value("MENU", SDLK_MENU), - luabind::value("SELECT", SDLK_SELECT), - luabind::value("STOP", SDLK_STOP), - luabind::value("AGAIN", SDLK_AGAIN), - luabind::value("UNDO", SDLK_UNDO), - luabind::value("CUT", SDLK_CUT), - luabind::value("COPY", SDLK_COPY), - luabind::value("PASTE", SDLK_PASTE), - luabind::value("FIND", SDLK_FIND), - luabind::value("MUTE", SDLK_MUTE), - luabind::value("VOLUMEUP", SDLK_VOLUMEUP), - luabind::value("VOLUMEDOWN", SDLK_VOLUMEDOWN), - luabind::value("KP_COMMA", SDLK_KP_COMMA), - luabind::value("KP_EQUALSAS400", SDLK_KP_EQUALSAS400), - luabind::value("ALTERASE", SDLK_ALTERASE), - luabind::value("SYSREQ", SDLK_SYSREQ), - luabind::value("CANCEL", SDLK_CANCEL), - luabind::value("CLEAR", SDLK_CLEAR), - luabind::value("PRIOR", SDLK_PRIOR), - luabind::value("RETURN2", SDLK_RETURN2), - luabind::value("SEPARATOR", SDLK_SEPARATOR), - luabind::value("OUT", SDLK_OUT), - luabind::value("OPER", SDLK_OPER), - luabind::value("CLEARAGAIN", SDLK_CLEARAGAIN), - luabind::value("CRSEL", SDLK_CRSEL), - luabind::value("EXSEL", SDLK_EXSEL), - luabind::value("KP_00", SDLK_KP_00), - luabind::value("KP_000", SDLK_KP_000), - luabind::value("THOUSANDSSEPARATOR", SDLK_THOUSANDSSEPARATOR), - luabind::value("DECIMALSEPARATOR", SDLK_DECIMALSEPARATOR), - luabind::value("CURRENCYUNIT", SDLK_CURRENCYUNIT), - luabind::value("CURRENCYSUBUNIT", SDLK_CURRENCYSUBUNIT), - luabind::value("KP_LEFTPAREN", SDLK_KP_LEFTPAREN), - luabind::value("KP_RIGHTPAREN", SDLK_KP_RIGHTPAREN), - luabind::value("KP_LEFTBRACE", SDLK_KP_LEFTBRACE), - luabind::value("KP_RIGHTBRACE", SDLK_KP_RIGHTBRACE), - luabind::value("KP_TAB", SDLK_KP_TAB), - luabind::value("KP_BACKSPACE", SDLK_KP_BACKSPACE), - luabind::value("KP_A", SDLK_KP_A), - luabind::value("KP_B", SDLK_KP_B), - luabind::value("KP_C", SDLK_KP_C), - luabind::value("KP_D", SDLK_KP_D), - luabind::value("KP_E", SDLK_KP_E), - luabind::value("KP_F", SDLK_KP_F), - luabind::value("KP_XOR", SDLK_KP_XOR), - luabind::value("KP_POWER", SDLK_KP_POWER), - luabind::value("KP_PERCENT", SDLK_KP_PERCENT), - luabind::value("KP_LESS", SDLK_KP_LESS), - luabind::value("KP_GREATER", SDLK_KP_GREATER), - luabind::value("KP_AMPERSAND", SDLK_KP_AMPERSAND), - luabind::value("KP_DBLAMPERSAND", SDLK_KP_DBLAMPERSAND), - luabind::value("KP_VERTICALBAR", SDLK_KP_VERTICALBAR), - luabind::value("KP_DBLVERTICALBAR", SDLK_KP_DBLVERTICALBAR), - luabind::value("KP_COLON", SDLK_KP_COLON), - luabind::value("KP_HASH", SDLK_KP_HASH), - luabind::value("KP_SPACE", SDLK_KP_SPACE), - luabind::value("KP_AT", SDLK_KP_AT), - luabind::value("KP_EXCLAM", SDLK_KP_EXCLAM), - luabind::value("KP_MEMSTORE", SDLK_KP_MEMSTORE), - luabind::value("KP_MEMRECALL", SDLK_KP_MEMRECALL), - luabind::value("KP_MEMCLEAR", SDLK_KP_MEMCLEAR), - luabind::value("KP_MEMADD", SDLK_KP_MEMADD), - luabind::value("KP_MEMSUBTRACT", SDLK_KP_MEMSUBTRACT), - luabind::value("KP_MEMMULTIPLY", SDLK_KP_MEMMULTIPLY), - luabind::value("KP_MEMDIVIDE", SDLK_KP_MEMDIVIDE), - luabind::value("KP_PLUSMINUS", SDLK_KP_PLUSMINUS), - luabind::value("KP_CLEAR", SDLK_KP_CLEAR), - luabind::value("KP_CLEARENTRY", SDLK_KP_CLEARENTRY), - luabind::value("KP_BINARY", SDLK_KP_BINARY), - luabind::value("KP_OCTAL", SDLK_KP_OCTAL), - luabind::value("KP_DECIMAL", SDLK_KP_DECIMAL), - luabind::value("KP_HEXADECIMAL", SDLK_KP_HEXADECIMAL), - luabind::value("LCTRL", SDLK_LCTRL), - luabind::value("LSHIFT", SDLK_LSHIFT), - luabind::value("LALT", SDLK_LALT), - luabind::value("LGUI", SDLK_LGUI), - luabind::value("RCTRL", SDLK_RCTRL), - luabind::value("RSHIFT", SDLK_RSHIFT), - luabind::value("RALT", SDLK_RALT), - luabind::value("RGUI", SDLK_RGUI), - luabind::value("MODE", SDLK_MODE), - luabind::value("AUDIONEXT", SDLK_AUDIONEXT), - luabind::value("AUDIOPREV", SDLK_AUDIOPREV), - luabind::value("AUDIOSTOP", SDLK_AUDIOSTOP), - luabind::value("AUDIOPLAY", SDLK_AUDIOPLAY), - luabind::value("AUDIOMUTE", SDLK_AUDIOMUTE), - luabind::value("MEDIASELECT", SDLK_MEDIASELECT), - luabind::value("WWW", SDLK_WWW), - luabind::value("MAIL", SDLK_MAIL), - luabind::value("CALCULATOR", SDLK_CALCULATOR), - luabind::value("COMPUTER", SDLK_COMPUTER), - luabind::value("AC_SEARCH", SDLK_AC_SEARCH), - luabind::value("AC_HOME", SDLK_AC_HOME), - luabind::value("AC_BACK", SDLK_AC_BACK), - luabind::value("AC_FORWARD", SDLK_AC_FORWARD), - luabind::value("AC_STOP", SDLK_AC_STOP), - luabind::value("AC_REFRESH", SDLK_AC_REFRESH), - luabind::value("AC_BOOKMARKS", SDLK_AC_BOOKMARKS), - luabind::value("BRIGHTNESSDOWN", SDLK_BRIGHTNESSDOWN), - luabind::value("BRIGHTNESSUP", SDLK_BRIGHTNESSUP), - luabind::value("DISPLAYSWITCH", SDLK_DISPLAYSWITCH), - luabind::value("KBDILLUMTOGGLE", SDLK_KBDILLUMTOGGLE), - luabind::value("KBDILLUMDOWN", SDLK_KBDILLUMDOWN), - luabind::value("KBDILLUMUP", SDLK_KBDILLUMUP), - luabind::value("EJECT", SDLK_EJECT), - luabind::value("SLEEP", SDLK_SLEEP) - ]; + // Make sure to update https://github.com/cortex-command-community/Cortex-Command-Community-Project-Source/wiki/SDL-Keycode-and-Scancode-enum-values-in-Lua#key-codes if any changes are made. + .enum_("Key")[luabind::value("UNKNOWN", SDLK_UNKNOWN), + luabind::value("RETURN", SDLK_RETURN), + luabind::value("ESCAPE", SDLK_ESCAPE), + luabind::value("BACKSPACE", SDLK_BACKSPACE), + luabind::value("TAB", SDLK_TAB), + luabind::value("SPACE", SDLK_SPACE), + luabind::value("EXCLAIM", SDLK_EXCLAIM), + luabind::value("QUOTEDBL", SDLK_QUOTEDBL), + luabind::value("HASH", SDLK_HASH), + luabind::value("PERCENT", SDLK_PERCENT), + luabind::value("DOLLAR", SDLK_DOLLAR), + luabind::value("AMPERSAND", SDLK_AMPERSAND), + luabind::value("QUOTE", SDLK_QUOTE), + luabind::value("LEFTPAREN", SDLK_LEFTPAREN), + luabind::value("RIGHTPAREN", SDLK_RIGHTPAREN), + luabind::value("ASTERISK", SDLK_ASTERISK), + luabind::value("PLUS", SDLK_PLUS), + luabind::value("COMMA", SDLK_COMMA), + luabind::value("MINUS", SDLK_MINUS), + luabind::value("PERIOD", SDLK_PERIOD), + luabind::value("SLASH", SDLK_SLASH), + luabind::value("K_0", SDLK_0), + luabind::value("K_1", SDLK_1), + luabind::value("K_2", SDLK_2), + luabind::value("K_3", SDLK_3), + luabind::value("K_4", SDLK_4), + luabind::value("K_5", SDLK_5), + luabind::value("K_6", SDLK_6), + luabind::value("K_7", SDLK_7), + luabind::value("K_8", SDLK_8), + luabind::value("K_9", SDLK_9), + luabind::value("COLON", SDLK_COLON), + luabind::value("SEMICOLON", SDLK_SEMICOLON), + luabind::value("LESS", SDLK_LESS), + luabind::value("EQUALS", SDLK_EQUALS), + luabind::value("GREATER", SDLK_GREATER), + luabind::value("QUESTION", SDLK_QUESTION), + luabind::value("AT", SDLK_AT), + luabind::value("LEFTBRACKET", SDLK_LEFTBRACKET), + luabind::value("BACKSLASH", SDLK_BACKSLASH), + luabind::value("RIGHTBRACKET", SDLK_RIGHTBRACKET), + luabind::value("CARET", SDLK_CARET), + luabind::value("UNDERSCORE", SDLK_UNDERSCORE), + luabind::value("BACKQUOTE", SDLK_BACKQUOTE), + luabind::value("A", SDLK_a), + luabind::value("B", SDLK_b), + luabind::value("C", SDLK_c), + luabind::value("D", SDLK_d), + luabind::value("E", SDLK_e), + luabind::value("F", SDLK_f), + luabind::value("G", SDLK_g), + luabind::value("H", SDLK_h), + luabind::value("I", SDLK_i), + luabind::value("J", SDLK_j), + luabind::value("K", SDLK_k), + luabind::value("L", SDLK_l), + luabind::value("M", SDLK_m), + luabind::value("N", SDLK_n), + luabind::value("O", SDLK_o), + luabind::value("P", SDLK_p), + luabind::value("Q", SDLK_q), + luabind::value("R", SDLK_r), + luabind::value("S", SDLK_s), + luabind::value("T", SDLK_t), + luabind::value("U", SDLK_u), + luabind::value("V", SDLK_v), + luabind::value("W", SDLK_w), + luabind::value("X", SDLK_x), + luabind::value("Y", SDLK_y), + luabind::value("Z", SDLK_z), + luabind::value("CAPSLOCK", SDLK_CAPSLOCK), + luabind::value("F1", SDLK_F1), + luabind::value("F2", SDLK_F2), + luabind::value("F3", SDLK_F3), + luabind::value("F4", SDLK_F4), + luabind::value("F5", SDLK_F5), + luabind::value("F6", SDLK_F6), + luabind::value("F7", SDLK_F7), + luabind::value("F8", SDLK_F8), + luabind::value("F9", SDLK_F9), + luabind::value("F10", SDLK_F10), + luabind::value("F11", SDLK_F11), + luabind::value("F12", SDLK_F12), + luabind::value("PRINTSCREEN", SDLK_PRINTSCREEN), + luabind::value("SCROLLLOCK", SDLK_SCROLLLOCK), + luabind::value("PAUSE", SDLK_PAUSE), + luabind::value("INSERT", SDLK_INSERT), + luabind::value("HOME", SDLK_HOME), + luabind::value("PAGEUP", SDLK_PAGEUP), + luabind::value("DELETE", SDLK_DELETE), + luabind::value("END", SDLK_END), + luabind::value("PAGEDOWN", SDLK_PAGEDOWN), + luabind::value("RIGHT", SDLK_RIGHT), + luabind::value("LEFT", SDLK_LEFT), + luabind::value("DOWN", SDLK_DOWN), + luabind::value("UP", SDLK_UP), + luabind::value("NUMLOCKCLEAR", SDLK_NUMLOCKCLEAR), + luabind::value("KP_DIVIDE", SDLK_KP_DIVIDE), + luabind::value("KP_MULTIPLY", SDLK_KP_MULTIPLY), + luabind::value("KP_MINUS", SDLK_KP_MINUS), + luabind::value("KP_PLUS", SDLK_KP_PLUS), + luabind::value("KP_ENTER", SDLK_KP_ENTER), + luabind::value("KP_1", SDLK_KP_1), + luabind::value("KP_2", SDLK_KP_2), + luabind::value("KP_3", SDLK_KP_3), + luabind::value("KP_4", SDLK_KP_4), + luabind::value("KP_5", SDLK_KP_5), + luabind::value("KP_6", SDLK_KP_6), + luabind::value("KP_7", SDLK_KP_7), + luabind::value("KP_8", SDLK_KP_8), + luabind::value("KP_9", SDLK_KP_9), + luabind::value("KP_0", SDLK_KP_0), + luabind::value("KP_PERIOD", SDLK_KP_PERIOD), + luabind::value("APPLICATION", SDLK_APPLICATION), + luabind::value("POWER", SDLK_POWER), + luabind::value("KP_EQUALS", SDLK_KP_EQUALS), + luabind::value("F13", SDLK_F13), + luabind::value("F14", SDLK_F14), + luabind::value("F15", SDLK_F15), + luabind::value("F16", SDLK_F16), + luabind::value("F17", SDLK_F17), + luabind::value("F18", SDLK_F18), + luabind::value("F19", SDLK_F19), + luabind::value("F20", SDLK_F20), + luabind::value("F21", SDLK_F21), + luabind::value("F22", SDLK_F22), + luabind::value("F23", SDLK_F23), + luabind::value("F24", SDLK_F24), + luabind::value("EXECUTE", SDLK_EXECUTE), + luabind::value("HELP", SDLK_HELP), + luabind::value("MENU", SDLK_MENU), + luabind::value("SELECT", SDLK_SELECT), + luabind::value("STOP", SDLK_STOP), + luabind::value("AGAIN", SDLK_AGAIN), + luabind::value("UNDO", SDLK_UNDO), + luabind::value("CUT", SDLK_CUT), + luabind::value("COPY", SDLK_COPY), + luabind::value("PASTE", SDLK_PASTE), + luabind::value("FIND", SDLK_FIND), + luabind::value("MUTE", SDLK_MUTE), + luabind::value("VOLUMEUP", SDLK_VOLUMEUP), + luabind::value("VOLUMEDOWN", SDLK_VOLUMEDOWN), + luabind::value("KP_COMMA", SDLK_KP_COMMA), + luabind::value("KP_EQUALSAS400", SDLK_KP_EQUALSAS400), + luabind::value("ALTERASE", SDLK_ALTERASE), + luabind::value("SYSREQ", SDLK_SYSREQ), + luabind::value("CANCEL", SDLK_CANCEL), + luabind::value("CLEAR", SDLK_CLEAR), + luabind::value("PRIOR", SDLK_PRIOR), + luabind::value("RETURN2", SDLK_RETURN2), + luabind::value("SEPARATOR", SDLK_SEPARATOR), + luabind::value("OUT", SDLK_OUT), + luabind::value("OPER", SDLK_OPER), + luabind::value("CLEARAGAIN", SDLK_CLEARAGAIN), + luabind::value("CRSEL", SDLK_CRSEL), + luabind::value("EXSEL", SDLK_EXSEL), + luabind::value("KP_00", SDLK_KP_00), + luabind::value("KP_000", SDLK_KP_000), + luabind::value("THOUSANDSSEPARATOR", SDLK_THOUSANDSSEPARATOR), + luabind::value("DECIMALSEPARATOR", SDLK_DECIMALSEPARATOR), + luabind::value("CURRENCYUNIT", SDLK_CURRENCYUNIT), + luabind::value("CURRENCYSUBUNIT", SDLK_CURRENCYSUBUNIT), + luabind::value("KP_LEFTPAREN", SDLK_KP_LEFTPAREN), + luabind::value("KP_RIGHTPAREN", SDLK_KP_RIGHTPAREN), + luabind::value("KP_LEFTBRACE", SDLK_KP_LEFTBRACE), + luabind::value("KP_RIGHTBRACE", SDLK_KP_RIGHTBRACE), + luabind::value("KP_TAB", SDLK_KP_TAB), + luabind::value("KP_BACKSPACE", SDLK_KP_BACKSPACE), + luabind::value("KP_A", SDLK_KP_A), + luabind::value("KP_B", SDLK_KP_B), + luabind::value("KP_C", SDLK_KP_C), + luabind::value("KP_D", SDLK_KP_D), + luabind::value("KP_E", SDLK_KP_E), + luabind::value("KP_F", SDLK_KP_F), + luabind::value("KP_XOR", SDLK_KP_XOR), + luabind::value("KP_POWER", SDLK_KP_POWER), + luabind::value("KP_PERCENT", SDLK_KP_PERCENT), + luabind::value("KP_LESS", SDLK_KP_LESS), + luabind::value("KP_GREATER", SDLK_KP_GREATER), + luabind::value("KP_AMPERSAND", SDLK_KP_AMPERSAND), + luabind::value("KP_DBLAMPERSAND", SDLK_KP_DBLAMPERSAND), + luabind::value("KP_VERTICALBAR", SDLK_KP_VERTICALBAR), + luabind::value("KP_DBLVERTICALBAR", SDLK_KP_DBLVERTICALBAR), + luabind::value("KP_COLON", SDLK_KP_COLON), + luabind::value("KP_HASH", SDLK_KP_HASH), + luabind::value("KP_SPACE", SDLK_KP_SPACE), + luabind::value("KP_AT", SDLK_KP_AT), + luabind::value("KP_EXCLAM", SDLK_KP_EXCLAM), + luabind::value("KP_MEMSTORE", SDLK_KP_MEMSTORE), + luabind::value("KP_MEMRECALL", SDLK_KP_MEMRECALL), + luabind::value("KP_MEMCLEAR", SDLK_KP_MEMCLEAR), + luabind::value("KP_MEMADD", SDLK_KP_MEMADD), + luabind::value("KP_MEMSUBTRACT", SDLK_KP_MEMSUBTRACT), + luabind::value("KP_MEMMULTIPLY", SDLK_KP_MEMMULTIPLY), + luabind::value("KP_MEMDIVIDE", SDLK_KP_MEMDIVIDE), + luabind::value("KP_PLUSMINUS", SDLK_KP_PLUSMINUS), + luabind::value("KP_CLEAR", SDLK_KP_CLEAR), + luabind::value("KP_CLEARENTRY", SDLK_KP_CLEARENTRY), + luabind::value("KP_BINARY", SDLK_KP_BINARY), + luabind::value("KP_OCTAL", SDLK_KP_OCTAL), + luabind::value("KP_DECIMAL", SDLK_KP_DECIMAL), + luabind::value("KP_HEXADECIMAL", SDLK_KP_HEXADECIMAL), + luabind::value("LCTRL", SDLK_LCTRL), + luabind::value("LSHIFT", SDLK_LSHIFT), + luabind::value("LALT", SDLK_LALT), + luabind::value("LGUI", SDLK_LGUI), + luabind::value("RCTRL", SDLK_RCTRL), + luabind::value("RSHIFT", SDLK_RSHIFT), + luabind::value("RALT", SDLK_RALT), + luabind::value("RGUI", SDLK_RGUI), + luabind::value("MODE", SDLK_MODE), + luabind::value("AUDIONEXT", SDLK_AUDIONEXT), + luabind::value("AUDIOPREV", SDLK_AUDIOPREV), + luabind::value("AUDIOSTOP", SDLK_AUDIOSTOP), + luabind::value("AUDIOPLAY", SDLK_AUDIOPLAY), + luabind::value("AUDIOMUTE", SDLK_AUDIOMUTE), + luabind::value("MEDIASELECT", SDLK_MEDIASELECT), + luabind::value("WWW", SDLK_WWW), + luabind::value("MAIL", SDLK_MAIL), + luabind::value("CALCULATOR", SDLK_CALCULATOR), + luabind::value("COMPUTER", SDLK_COMPUTER), + luabind::value("AC_SEARCH", SDLK_AC_SEARCH), + luabind::value("AC_HOME", SDLK_AC_HOME), + luabind::value("AC_BACK", SDLK_AC_BACK), + luabind::value("AC_FORWARD", SDLK_AC_FORWARD), + luabind::value("AC_STOP", SDLK_AC_STOP), + luabind::value("AC_REFRESH", SDLK_AC_REFRESH), + luabind::value("AC_BOOKMARKS", SDLK_AC_BOOKMARKS), + luabind::value("BRIGHTNESSDOWN", SDLK_BRIGHTNESSDOWN), + luabind::value("BRIGHTNESSUP", SDLK_BRIGHTNESSUP), + luabind::value("DISPLAYSWITCH", SDLK_DISPLAYSWITCH), + luabind::value("KBDILLUMTOGGLE", SDLK_KBDILLUMTOGGLE), + luabind::value("KBDILLUMDOWN", SDLK_KBDILLUMDOWN), + luabind::value("KBDILLUMUP", SDLK_KBDILLUMUP), + luabind::value("EJECT", SDLK_EJECT), + luabind::value("SLEEP", SDLK_SLEEP)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, SDL_Scancode) { return luabind::class_("Scancode") - // Make sure to update https://github.com/cortex-command-community/Cortex-Command-Community-Project-Source/wiki/SDL-Keycode-and-Scancode-enum-values-in-Lua#scan-codes if any changes are made. - .enum_("Scancode")[ - luabind::value("UNKNOWN", SDL_SCANCODE_UNKNOWN), - luabind::value("A", SDL_SCANCODE_A), - luabind::value("B", SDL_SCANCODE_B), - luabind::value("C", SDL_SCANCODE_C), - luabind::value("D", SDL_SCANCODE_D), - luabind::value("E", SDL_SCANCODE_E), - luabind::value("F", SDL_SCANCODE_F), - luabind::value("G", SDL_SCANCODE_G), - luabind::value("H", SDL_SCANCODE_H), - luabind::value("I", SDL_SCANCODE_I), - luabind::value("J", SDL_SCANCODE_J), - luabind::value("K", SDL_SCANCODE_K), - luabind::value("L", SDL_SCANCODE_L), - luabind::value("M", SDL_SCANCODE_M), - luabind::value("N", SDL_SCANCODE_N), - luabind::value("O", SDL_SCANCODE_O), - luabind::value("P", SDL_SCANCODE_P), - luabind::value("Q", SDL_SCANCODE_Q), - luabind::value("R", SDL_SCANCODE_R), - luabind::value("S", SDL_SCANCODE_S), - luabind::value("T", SDL_SCANCODE_T), - luabind::value("U", SDL_SCANCODE_U), - luabind::value("V", SDL_SCANCODE_V), - luabind::value("W", SDL_SCANCODE_W), - luabind::value("X", SDL_SCANCODE_X), - luabind::value("Y", SDL_SCANCODE_Y), - luabind::value("Z", SDL_SCANCODE_Z), - luabind::value("K_1", SDL_SCANCODE_1), - luabind::value("K_2", SDL_SCANCODE_2), - luabind::value("K_3", SDL_SCANCODE_3), - luabind::value("K_4", SDL_SCANCODE_4), - luabind::value("K_5", SDL_SCANCODE_5), - luabind::value("K_6", SDL_SCANCODE_6), - luabind::value("K_7", SDL_SCANCODE_7), - luabind::value("K_8", SDL_SCANCODE_8), - luabind::value("K_9", SDL_SCANCODE_9), - luabind::value("K_0", SDL_SCANCODE_0), - luabind::value("RETURN", SDL_SCANCODE_RETURN), - luabind::value("ESCAPE", SDL_SCANCODE_ESCAPE), - luabind::value("BACKSPACE", SDL_SCANCODE_BACKSPACE), - luabind::value("TAB", SDL_SCANCODE_TAB), - luabind::value("SPACE", SDL_SCANCODE_SPACE), - luabind::value("MINUS", SDL_SCANCODE_MINUS), - luabind::value("EQUALS", SDL_SCANCODE_EQUALS), - luabind::value("LEFTBRACKET", SDL_SCANCODE_LEFTBRACKET), - luabind::value("RIGHTBRACKET", SDL_SCANCODE_RIGHTBRACKET), - luabind::value("BACKSLASH", SDL_SCANCODE_BACKSLASH), - luabind::value("NONUSHASH", SDL_SCANCODE_NONUSHASH), - luabind::value("SEMICOLON", SDL_SCANCODE_SEMICOLON), - luabind::value("APOSTROPHE", SDL_SCANCODE_APOSTROPHE), - luabind::value("GRAVE", SDL_SCANCODE_GRAVE), - luabind::value("COMMA", SDL_SCANCODE_COMMA), - luabind::value("PERIOD", SDL_SCANCODE_PERIOD), - luabind::value("SLASH", SDL_SCANCODE_SLASH), - luabind::value("CAPSLOCK", SDL_SCANCODE_CAPSLOCK), - luabind::value("F1", SDL_SCANCODE_F1), - luabind::value("F2", SDL_SCANCODE_F2), - luabind::value("F3", SDL_SCANCODE_F3), - luabind::value("F4", SDL_SCANCODE_F4), - luabind::value("F5", SDL_SCANCODE_F5), - luabind::value("F6", SDL_SCANCODE_F6), - luabind::value("F7", SDL_SCANCODE_F7), - luabind::value("F8", SDL_SCANCODE_F8), - luabind::value("F9", SDL_SCANCODE_F9), - luabind::value("F10", SDL_SCANCODE_F10), - luabind::value("F11", SDL_SCANCODE_F11), - luabind::value("F12", SDL_SCANCODE_F12), - luabind::value("PRINTSCREEN", SDL_SCANCODE_PRINTSCREEN), - luabind::value("SCROLLLOCK", SDL_SCANCODE_SCROLLLOCK), - luabind::value("PAUSE", SDL_SCANCODE_PAUSE), - luabind::value("INSERT", SDL_SCANCODE_INSERT), - luabind::value("HOME", SDL_SCANCODE_HOME), - luabind::value("PAGEUP", SDL_SCANCODE_PAGEUP), - luabind::value("DELETE", SDL_SCANCODE_DELETE), - luabind::value("END", SDL_SCANCODE_END), - luabind::value("PAGEDOWN", SDL_SCANCODE_PAGEDOWN), - luabind::value("RIGHT", SDL_SCANCODE_RIGHT), - luabind::value("LEFT", SDL_SCANCODE_LEFT), - luabind::value("DOWN", SDL_SCANCODE_DOWN), - luabind::value("UP", SDL_SCANCODE_UP), - luabind::value("NUMLOCKCLEAR", SDL_SCANCODE_NUMLOCKCLEAR), - luabind::value("KP_DIVIDE", SDL_SCANCODE_KP_DIVIDE), - luabind::value("KP_MULTIPLY", SDL_SCANCODE_KP_MULTIPLY), - luabind::value("KP_MINUS", SDL_SCANCODE_KP_MINUS), - luabind::value("KP_PLUS", SDL_SCANCODE_KP_PLUS), - luabind::value("KP_ENTER", SDL_SCANCODE_KP_ENTER), - luabind::value("KP_1", SDL_SCANCODE_KP_1), - luabind::value("KP_2", SDL_SCANCODE_KP_2), - luabind::value("KP_3", SDL_SCANCODE_KP_3), - luabind::value("KP_4", SDL_SCANCODE_KP_4), - luabind::value("KP_5", SDL_SCANCODE_KP_5), - luabind::value("KP_6", SDL_SCANCODE_KP_6), - luabind::value("KP_7", SDL_SCANCODE_KP_7), - luabind::value("KP_8", SDL_SCANCODE_KP_8), - luabind::value("KP_9", SDL_SCANCODE_KP_9), - luabind::value("KP_0", SDL_SCANCODE_KP_0), - luabind::value("KP_PERIOD", SDL_SCANCODE_KP_PERIOD), - luabind::value("NONUSBACKSLASH", SDL_SCANCODE_NONUSBACKSLASH), - luabind::value("APPLICATION", SDL_SCANCODE_APPLICATION), - luabind::value("POWER", SDL_SCANCODE_POWER), - luabind::value("KP_EQUALS", SDL_SCANCODE_KP_EQUALS), - luabind::value("F13", SDL_SCANCODE_F13), - luabind::value("F14", SDL_SCANCODE_F14), - luabind::value("F15", SDL_SCANCODE_F15), - luabind::value("F16", SDL_SCANCODE_F16), - luabind::value("F17", SDL_SCANCODE_F17), - luabind::value("F18", SDL_SCANCODE_F18), - luabind::value("F19", SDL_SCANCODE_F19), - luabind::value("F20", SDL_SCANCODE_F20), - luabind::value("F21", SDL_SCANCODE_F21), - luabind::value("F22", SDL_SCANCODE_F22), - luabind::value("F23", SDL_SCANCODE_F23), - luabind::value("F24", SDL_SCANCODE_F24), - luabind::value("EXECUTE", SDL_SCANCODE_EXECUTE), - luabind::value("HELP", SDL_SCANCODE_HELP), - luabind::value("MENU", SDL_SCANCODE_MENU), - luabind::value("SELECT", SDL_SCANCODE_SELECT), - luabind::value("STOP", SDL_SCANCODE_STOP), - luabind::value("AGAIN", SDL_SCANCODE_AGAIN), - luabind::value("UNDO", SDL_SCANCODE_UNDO), - luabind::value("CUT", SDL_SCANCODE_CUT), - luabind::value("COPY", SDL_SCANCODE_COPY), - luabind::value("PASTE", SDL_SCANCODE_PASTE), - luabind::value("FIND", SDL_SCANCODE_FIND), - luabind::value("MUTE", SDL_SCANCODE_MUTE), - luabind::value("VOLUMEUP", SDL_SCANCODE_VOLUMEUP), - luabind::value("VOLUMEDOWN", SDL_SCANCODE_VOLUMEDOWN), - luabind::value("KP_COMMA", SDL_SCANCODE_KP_COMMA), - luabind::value("KP_EQUALSAS400", SDL_SCANCODE_KP_EQUALSAS400), - luabind::value("INTERNATIONAL1", SDL_SCANCODE_INTERNATIONAL1), - luabind::value("INTERNATIONAL2", SDL_SCANCODE_INTERNATIONAL2), - luabind::value("INTERNATIONAL3", SDL_SCANCODE_INTERNATIONAL3), - luabind::value("INTERNATIONAL4", SDL_SCANCODE_INTERNATIONAL4), - luabind::value("INTERNATIONAL5", SDL_SCANCODE_INTERNATIONAL5), - luabind::value("INTERNATIONAL6", SDL_SCANCODE_INTERNATIONAL6), - luabind::value("INTERNATIONAL7", SDL_SCANCODE_INTERNATIONAL7), - luabind::value("INTERNATIONAL8", SDL_SCANCODE_INTERNATIONAL8), - luabind::value("INTERNATIONAL9", SDL_SCANCODE_INTERNATIONAL9), - luabind::value("LANG1", SDL_SCANCODE_LANG1), - luabind::value("LANG2", SDL_SCANCODE_LANG2), - luabind::value("LANG3", SDL_SCANCODE_LANG3), - luabind::value("LANG4", SDL_SCANCODE_LANG4), - luabind::value("LANG5", SDL_SCANCODE_LANG5), - luabind::value("LANG6", SDL_SCANCODE_LANG6), - luabind::value("LANG7", SDL_SCANCODE_LANG7), - luabind::value("LANG8", SDL_SCANCODE_LANG8), - luabind::value("LANG9", SDL_SCANCODE_LANG9), - luabind::value("ALTERASE", SDL_SCANCODE_ALTERASE), - luabind::value("SYSREQ", SDL_SCANCODE_SYSREQ), - luabind::value("CANCEL", SDL_SCANCODE_CANCEL), - luabind::value("CLEAR", SDL_SCANCODE_CLEAR), - luabind::value("PRIOR", SDL_SCANCODE_PRIOR), - luabind::value("RETURN2", SDL_SCANCODE_RETURN2), - luabind::value("SEPARATOR", SDL_SCANCODE_SEPARATOR), - luabind::value("OUT", SDL_SCANCODE_OUT), - luabind::value("OPER", SDL_SCANCODE_OPER), - luabind::value("CLEARAGAIN", SDL_SCANCODE_CLEARAGAIN), - luabind::value("CRSEL", SDL_SCANCODE_CRSEL), - luabind::value("EXSEL", SDL_SCANCODE_EXSEL), - luabind::value("KP_00", SDL_SCANCODE_KP_00), - luabind::value("KP_000", SDL_SCANCODE_KP_000), - luabind::value("THOUSANDSSEPARATOR", SDL_SCANCODE_THOUSANDSSEPARATOR), - luabind::value("DECIMALSEPARATOR", SDL_SCANCODE_DECIMALSEPARATOR), - luabind::value("CURRENCYUNIT", SDL_SCANCODE_CURRENCYUNIT), - luabind::value("CURRENCYSUBUNIT", SDL_SCANCODE_CURRENCYSUBUNIT), - luabind::value("KP_LEFTPAREN", SDL_SCANCODE_KP_LEFTPAREN), - luabind::value("KP_RIGHTPAREN", SDL_SCANCODE_KP_RIGHTPAREN), - luabind::value("KP_LEFTBRACE", SDL_SCANCODE_KP_LEFTBRACE), - luabind::value("KP_RIGHTBRACE", SDL_SCANCODE_KP_RIGHTBRACE), - luabind::value("KP_TAB", SDL_SCANCODE_KP_TAB), - luabind::value("KP_BACKSPACE", SDL_SCANCODE_KP_BACKSPACE), - luabind::value("KP_A", SDL_SCANCODE_KP_A), - luabind::value("KP_B", SDL_SCANCODE_KP_B), - luabind::value("KP_C", SDL_SCANCODE_KP_C), - luabind::value("KP_D", SDL_SCANCODE_KP_D), - luabind::value("KP_E", SDL_SCANCODE_KP_E), - luabind::value("KP_F", SDL_SCANCODE_KP_F), - luabind::value("KP_XOR", SDL_SCANCODE_KP_XOR), - luabind::value("KP_POWER", SDL_SCANCODE_KP_POWER), - luabind::value("KP_PERCENT", SDL_SCANCODE_KP_PERCENT), - luabind::value("KP_LESS", SDL_SCANCODE_KP_LESS), - luabind::value("KP_GREATER", SDL_SCANCODE_KP_GREATER), - luabind::value("KP_AMPERSAND", SDL_SCANCODE_KP_AMPERSAND), - luabind::value("KP_DBLAMPERSAND", SDL_SCANCODE_KP_DBLAMPERSAND), - luabind::value("KP_VERTICALBAR", SDL_SCANCODE_KP_VERTICALBAR), - luabind::value("KP_DBLVERTICALBAR", SDL_SCANCODE_KP_DBLVERTICALBAR), - luabind::value("KP_COLON", SDL_SCANCODE_KP_COLON), - luabind::value("KP_HASH", SDL_SCANCODE_KP_HASH), - luabind::value("KP_SPACE", SDL_SCANCODE_KP_SPACE), - luabind::value("KP_AT", SDL_SCANCODE_KP_AT), - luabind::value("KP_EXCLAM", SDL_SCANCODE_KP_EXCLAM), - luabind::value("KP_MEMSTORE", SDL_SCANCODE_KP_MEMSTORE), - luabind::value("KP_MEMRECALL", SDL_SCANCODE_KP_MEMRECALL), - luabind::value("KP_MEMCLEAR", SDL_SCANCODE_KP_MEMCLEAR), - luabind::value("KP_MEMADD", SDL_SCANCODE_KP_MEMADD), - luabind::value("KP_MEMSUBTRACT", SDL_SCANCODE_KP_MEMSUBTRACT), - luabind::value("KP_MEMMULTIPLY", SDL_SCANCODE_KP_MEMMULTIPLY), - luabind::value("KP_MEMDIVIDE", SDL_SCANCODE_KP_MEMDIVIDE), - luabind::value("KP_PLUSMINUS", SDL_SCANCODE_KP_PLUSMINUS), - luabind::value("KP_CLEAR", SDL_SCANCODE_KP_CLEAR), - luabind::value("KP_CLEARENTRY", SDL_SCANCODE_KP_CLEARENTRY), - luabind::value("KP_BINARY", SDL_SCANCODE_KP_BINARY), - luabind::value("KP_OCTAL", SDL_SCANCODE_KP_OCTAL), - luabind::value("KP_DECIMAL", SDL_SCANCODE_KP_DECIMAL), - luabind::value("KP_HEXADECIMAL", SDL_SCANCODE_KP_HEXADECIMAL), - luabind::value("LCTRL", SDL_SCANCODE_LCTRL), - luabind::value("LSHIFT", SDL_SCANCODE_LSHIFT), - luabind::value("LALT", SDL_SCANCODE_LALT), - luabind::value("LGUI", SDL_SCANCODE_LGUI), - luabind::value("RCTRL", SDL_SCANCODE_RCTRL), - luabind::value("RSHIFT", SDL_SCANCODE_RSHIFT), - luabind::value("RALT", SDL_SCANCODE_RALT), - luabind::value("RGUI", SDL_SCANCODE_RGUI), - luabind::value("MODE", SDL_SCANCODE_MODE), - luabind::value("AUDIONEXT", SDL_SCANCODE_AUDIONEXT), - luabind::value("AUDIOPREV", SDL_SCANCODE_AUDIOPREV), - luabind::value("AUDIOSTOP", SDL_SCANCODE_AUDIOSTOP), - luabind::value("AUDIOPLAY", SDL_SCANCODE_AUDIOPLAY), - luabind::value("AUDIOMUTE", SDL_SCANCODE_AUDIOMUTE), - luabind::value("MEDIASELECT", SDL_SCANCODE_MEDIASELECT), - luabind::value("WWW", SDL_SCANCODE_WWW), - luabind::value("MAIL", SDL_SCANCODE_MAIL), - luabind::value("CALCULATOR", SDL_SCANCODE_CALCULATOR), - luabind::value("COMPUTER", SDL_SCANCODE_COMPUTER), - luabind::value("AC_SEARCH", SDL_SCANCODE_AC_SEARCH), - luabind::value("AC_HOME", SDL_SCANCODE_AC_HOME), - luabind::value("AC_BACK", SDL_SCANCODE_AC_BACK), - luabind::value("AC_FORWARD", SDL_SCANCODE_AC_FORWARD), - luabind::value("AC_STOP", SDL_SCANCODE_AC_STOP), - luabind::value("AC_REFRESH", SDL_SCANCODE_AC_REFRESH), - luabind::value("AC_BOOKMARKS", SDL_SCANCODE_AC_BOOKMARKS), - luabind::value("BRIGHTNESSDOWN", SDL_SCANCODE_BRIGHTNESSDOWN), - luabind::value("BRIGHTNESSUP", SDL_SCANCODE_BRIGHTNESSUP), - luabind::value("DISPLAYSWITCH", SDL_SCANCODE_DISPLAYSWITCH), - luabind::value("KBDILLUMTOGGLE", SDL_SCANCODE_KBDILLUMTOGGLE), - luabind::value("KBDILLUMDOWN", SDL_SCANCODE_KBDILLUMDOWN), - luabind::value("KBDILLUMUP", SDL_SCANCODE_KBDILLUMUP), - luabind::value("EJECT", SDL_SCANCODE_EJECT), - luabind::value("SLEEP", SDL_SCANCODE_SLEEP), - luabind::value("APP1", SDL_SCANCODE_APP1), - luabind::value("APP2", SDL_SCANCODE_APP2), - luabind::value("AUDIOREWIND", SDL_SCANCODE_AUDIOREWIND), - luabind::value("AUDIOFASTFORWARD", SDL_SCANCODE_AUDIOFASTFORWARD), - luabind::value("NUM_SCANCODES", SDL_NUM_SCANCODES) - ]; + // Make sure to update https://github.com/cortex-command-community/Cortex-Command-Community-Project-Source/wiki/SDL-Keycode-and-Scancode-enum-values-in-Lua#scan-codes if any changes are made. + .enum_("Scancode")[luabind::value("UNKNOWN", SDL_SCANCODE_UNKNOWN), + luabind::value("A", SDL_SCANCODE_A), + luabind::value("B", SDL_SCANCODE_B), + luabind::value("C", SDL_SCANCODE_C), + luabind::value("D", SDL_SCANCODE_D), + luabind::value("E", SDL_SCANCODE_E), + luabind::value("F", SDL_SCANCODE_F), + luabind::value("G", SDL_SCANCODE_G), + luabind::value("H", SDL_SCANCODE_H), + luabind::value("I", SDL_SCANCODE_I), + luabind::value("J", SDL_SCANCODE_J), + luabind::value("K", SDL_SCANCODE_K), + luabind::value("L", SDL_SCANCODE_L), + luabind::value("M", SDL_SCANCODE_M), + luabind::value("N", SDL_SCANCODE_N), + luabind::value("O", SDL_SCANCODE_O), + luabind::value("P", SDL_SCANCODE_P), + luabind::value("Q", SDL_SCANCODE_Q), + luabind::value("R", SDL_SCANCODE_R), + luabind::value("S", SDL_SCANCODE_S), + luabind::value("T", SDL_SCANCODE_T), + luabind::value("U", SDL_SCANCODE_U), + luabind::value("V", SDL_SCANCODE_V), + luabind::value("W", SDL_SCANCODE_W), + luabind::value("X", SDL_SCANCODE_X), + luabind::value("Y", SDL_SCANCODE_Y), + luabind::value("Z", SDL_SCANCODE_Z), + luabind::value("K_1", SDL_SCANCODE_1), + luabind::value("K_2", SDL_SCANCODE_2), + luabind::value("K_3", SDL_SCANCODE_3), + luabind::value("K_4", SDL_SCANCODE_4), + luabind::value("K_5", SDL_SCANCODE_5), + luabind::value("K_6", SDL_SCANCODE_6), + luabind::value("K_7", SDL_SCANCODE_7), + luabind::value("K_8", SDL_SCANCODE_8), + luabind::value("K_9", SDL_SCANCODE_9), + luabind::value("K_0", SDL_SCANCODE_0), + luabind::value("RETURN", SDL_SCANCODE_RETURN), + luabind::value("ESCAPE", SDL_SCANCODE_ESCAPE), + luabind::value("BACKSPACE", SDL_SCANCODE_BACKSPACE), + luabind::value("TAB", SDL_SCANCODE_TAB), + luabind::value("SPACE", SDL_SCANCODE_SPACE), + luabind::value("MINUS", SDL_SCANCODE_MINUS), + luabind::value("EQUALS", SDL_SCANCODE_EQUALS), + luabind::value("LEFTBRACKET", SDL_SCANCODE_LEFTBRACKET), + luabind::value("RIGHTBRACKET", SDL_SCANCODE_RIGHTBRACKET), + luabind::value("BACKSLASH", SDL_SCANCODE_BACKSLASH), + luabind::value("NONUSHASH", SDL_SCANCODE_NONUSHASH), + luabind::value("SEMICOLON", SDL_SCANCODE_SEMICOLON), + luabind::value("APOSTROPHE", SDL_SCANCODE_APOSTROPHE), + luabind::value("GRAVE", SDL_SCANCODE_GRAVE), + luabind::value("COMMA", SDL_SCANCODE_COMMA), + luabind::value("PERIOD", SDL_SCANCODE_PERIOD), + luabind::value("SLASH", SDL_SCANCODE_SLASH), + luabind::value("CAPSLOCK", SDL_SCANCODE_CAPSLOCK), + luabind::value("F1", SDL_SCANCODE_F1), + luabind::value("F2", SDL_SCANCODE_F2), + luabind::value("F3", SDL_SCANCODE_F3), + luabind::value("F4", SDL_SCANCODE_F4), + luabind::value("F5", SDL_SCANCODE_F5), + luabind::value("F6", SDL_SCANCODE_F6), + luabind::value("F7", SDL_SCANCODE_F7), + luabind::value("F8", SDL_SCANCODE_F8), + luabind::value("F9", SDL_SCANCODE_F9), + luabind::value("F10", SDL_SCANCODE_F10), + luabind::value("F11", SDL_SCANCODE_F11), + luabind::value("F12", SDL_SCANCODE_F12), + luabind::value("PRINTSCREEN", SDL_SCANCODE_PRINTSCREEN), + luabind::value("SCROLLLOCK", SDL_SCANCODE_SCROLLLOCK), + luabind::value("PAUSE", SDL_SCANCODE_PAUSE), + luabind::value("INSERT", SDL_SCANCODE_INSERT), + luabind::value("HOME", SDL_SCANCODE_HOME), + luabind::value("PAGEUP", SDL_SCANCODE_PAGEUP), + luabind::value("DELETE", SDL_SCANCODE_DELETE), + luabind::value("END", SDL_SCANCODE_END), + luabind::value("PAGEDOWN", SDL_SCANCODE_PAGEDOWN), + luabind::value("RIGHT", SDL_SCANCODE_RIGHT), + luabind::value("LEFT", SDL_SCANCODE_LEFT), + luabind::value("DOWN", SDL_SCANCODE_DOWN), + luabind::value("UP", SDL_SCANCODE_UP), + luabind::value("NUMLOCKCLEAR", SDL_SCANCODE_NUMLOCKCLEAR), + luabind::value("KP_DIVIDE", SDL_SCANCODE_KP_DIVIDE), + luabind::value("KP_MULTIPLY", SDL_SCANCODE_KP_MULTIPLY), + luabind::value("KP_MINUS", SDL_SCANCODE_KP_MINUS), + luabind::value("KP_PLUS", SDL_SCANCODE_KP_PLUS), + luabind::value("KP_ENTER", SDL_SCANCODE_KP_ENTER), + luabind::value("KP_1", SDL_SCANCODE_KP_1), + luabind::value("KP_2", SDL_SCANCODE_KP_2), + luabind::value("KP_3", SDL_SCANCODE_KP_3), + luabind::value("KP_4", SDL_SCANCODE_KP_4), + luabind::value("KP_5", SDL_SCANCODE_KP_5), + luabind::value("KP_6", SDL_SCANCODE_KP_6), + luabind::value("KP_7", SDL_SCANCODE_KP_7), + luabind::value("KP_8", SDL_SCANCODE_KP_8), + luabind::value("KP_9", SDL_SCANCODE_KP_9), + luabind::value("KP_0", SDL_SCANCODE_KP_0), + luabind::value("KP_PERIOD", SDL_SCANCODE_KP_PERIOD), + luabind::value("NONUSBACKSLASH", SDL_SCANCODE_NONUSBACKSLASH), + luabind::value("APPLICATION", SDL_SCANCODE_APPLICATION), + luabind::value("POWER", SDL_SCANCODE_POWER), + luabind::value("KP_EQUALS", SDL_SCANCODE_KP_EQUALS), + luabind::value("F13", SDL_SCANCODE_F13), + luabind::value("F14", SDL_SCANCODE_F14), + luabind::value("F15", SDL_SCANCODE_F15), + luabind::value("F16", SDL_SCANCODE_F16), + luabind::value("F17", SDL_SCANCODE_F17), + luabind::value("F18", SDL_SCANCODE_F18), + luabind::value("F19", SDL_SCANCODE_F19), + luabind::value("F20", SDL_SCANCODE_F20), + luabind::value("F21", SDL_SCANCODE_F21), + luabind::value("F22", SDL_SCANCODE_F22), + luabind::value("F23", SDL_SCANCODE_F23), + luabind::value("F24", SDL_SCANCODE_F24), + luabind::value("EXECUTE", SDL_SCANCODE_EXECUTE), + luabind::value("HELP", SDL_SCANCODE_HELP), + luabind::value("MENU", SDL_SCANCODE_MENU), + luabind::value("SELECT", SDL_SCANCODE_SELECT), + luabind::value("STOP", SDL_SCANCODE_STOP), + luabind::value("AGAIN", SDL_SCANCODE_AGAIN), + luabind::value("UNDO", SDL_SCANCODE_UNDO), + luabind::value("CUT", SDL_SCANCODE_CUT), + luabind::value("COPY", SDL_SCANCODE_COPY), + luabind::value("PASTE", SDL_SCANCODE_PASTE), + luabind::value("FIND", SDL_SCANCODE_FIND), + luabind::value("MUTE", SDL_SCANCODE_MUTE), + luabind::value("VOLUMEUP", SDL_SCANCODE_VOLUMEUP), + luabind::value("VOLUMEDOWN", SDL_SCANCODE_VOLUMEDOWN), + luabind::value("KP_COMMA", SDL_SCANCODE_KP_COMMA), + luabind::value("KP_EQUALSAS400", SDL_SCANCODE_KP_EQUALSAS400), + luabind::value("INTERNATIONAL1", SDL_SCANCODE_INTERNATIONAL1), + luabind::value("INTERNATIONAL2", SDL_SCANCODE_INTERNATIONAL2), + luabind::value("INTERNATIONAL3", SDL_SCANCODE_INTERNATIONAL3), + luabind::value("INTERNATIONAL4", SDL_SCANCODE_INTERNATIONAL4), + luabind::value("INTERNATIONAL5", SDL_SCANCODE_INTERNATIONAL5), + luabind::value("INTERNATIONAL6", SDL_SCANCODE_INTERNATIONAL6), + luabind::value("INTERNATIONAL7", SDL_SCANCODE_INTERNATIONAL7), + luabind::value("INTERNATIONAL8", SDL_SCANCODE_INTERNATIONAL8), + luabind::value("INTERNATIONAL9", SDL_SCANCODE_INTERNATIONAL9), + luabind::value("LANG1", SDL_SCANCODE_LANG1), + luabind::value("LANG2", SDL_SCANCODE_LANG2), + luabind::value("LANG3", SDL_SCANCODE_LANG3), + luabind::value("LANG4", SDL_SCANCODE_LANG4), + luabind::value("LANG5", SDL_SCANCODE_LANG5), + luabind::value("LANG6", SDL_SCANCODE_LANG6), + luabind::value("LANG7", SDL_SCANCODE_LANG7), + luabind::value("LANG8", SDL_SCANCODE_LANG8), + luabind::value("LANG9", SDL_SCANCODE_LANG9), + luabind::value("ALTERASE", SDL_SCANCODE_ALTERASE), + luabind::value("SYSREQ", SDL_SCANCODE_SYSREQ), + luabind::value("CANCEL", SDL_SCANCODE_CANCEL), + luabind::value("CLEAR", SDL_SCANCODE_CLEAR), + luabind::value("PRIOR", SDL_SCANCODE_PRIOR), + luabind::value("RETURN2", SDL_SCANCODE_RETURN2), + luabind::value("SEPARATOR", SDL_SCANCODE_SEPARATOR), + luabind::value("OUT", SDL_SCANCODE_OUT), + luabind::value("OPER", SDL_SCANCODE_OPER), + luabind::value("CLEARAGAIN", SDL_SCANCODE_CLEARAGAIN), + luabind::value("CRSEL", SDL_SCANCODE_CRSEL), + luabind::value("EXSEL", SDL_SCANCODE_EXSEL), + luabind::value("KP_00", SDL_SCANCODE_KP_00), + luabind::value("KP_000", SDL_SCANCODE_KP_000), + luabind::value("THOUSANDSSEPARATOR", SDL_SCANCODE_THOUSANDSSEPARATOR), + luabind::value("DECIMALSEPARATOR", SDL_SCANCODE_DECIMALSEPARATOR), + luabind::value("CURRENCYUNIT", SDL_SCANCODE_CURRENCYUNIT), + luabind::value("CURRENCYSUBUNIT", SDL_SCANCODE_CURRENCYSUBUNIT), + luabind::value("KP_LEFTPAREN", SDL_SCANCODE_KP_LEFTPAREN), + luabind::value("KP_RIGHTPAREN", SDL_SCANCODE_KP_RIGHTPAREN), + luabind::value("KP_LEFTBRACE", SDL_SCANCODE_KP_LEFTBRACE), + luabind::value("KP_RIGHTBRACE", SDL_SCANCODE_KP_RIGHTBRACE), + luabind::value("KP_TAB", SDL_SCANCODE_KP_TAB), + luabind::value("KP_BACKSPACE", SDL_SCANCODE_KP_BACKSPACE), + luabind::value("KP_A", SDL_SCANCODE_KP_A), + luabind::value("KP_B", SDL_SCANCODE_KP_B), + luabind::value("KP_C", SDL_SCANCODE_KP_C), + luabind::value("KP_D", SDL_SCANCODE_KP_D), + luabind::value("KP_E", SDL_SCANCODE_KP_E), + luabind::value("KP_F", SDL_SCANCODE_KP_F), + luabind::value("KP_XOR", SDL_SCANCODE_KP_XOR), + luabind::value("KP_POWER", SDL_SCANCODE_KP_POWER), + luabind::value("KP_PERCENT", SDL_SCANCODE_KP_PERCENT), + luabind::value("KP_LESS", SDL_SCANCODE_KP_LESS), + luabind::value("KP_GREATER", SDL_SCANCODE_KP_GREATER), + luabind::value("KP_AMPERSAND", SDL_SCANCODE_KP_AMPERSAND), + luabind::value("KP_DBLAMPERSAND", SDL_SCANCODE_KP_DBLAMPERSAND), + luabind::value("KP_VERTICALBAR", SDL_SCANCODE_KP_VERTICALBAR), + luabind::value("KP_DBLVERTICALBAR", SDL_SCANCODE_KP_DBLVERTICALBAR), + luabind::value("KP_COLON", SDL_SCANCODE_KP_COLON), + luabind::value("KP_HASH", SDL_SCANCODE_KP_HASH), + luabind::value("KP_SPACE", SDL_SCANCODE_KP_SPACE), + luabind::value("KP_AT", SDL_SCANCODE_KP_AT), + luabind::value("KP_EXCLAM", SDL_SCANCODE_KP_EXCLAM), + luabind::value("KP_MEMSTORE", SDL_SCANCODE_KP_MEMSTORE), + luabind::value("KP_MEMRECALL", SDL_SCANCODE_KP_MEMRECALL), + luabind::value("KP_MEMCLEAR", SDL_SCANCODE_KP_MEMCLEAR), + luabind::value("KP_MEMADD", SDL_SCANCODE_KP_MEMADD), + luabind::value("KP_MEMSUBTRACT", SDL_SCANCODE_KP_MEMSUBTRACT), + luabind::value("KP_MEMMULTIPLY", SDL_SCANCODE_KP_MEMMULTIPLY), + luabind::value("KP_MEMDIVIDE", SDL_SCANCODE_KP_MEMDIVIDE), + luabind::value("KP_PLUSMINUS", SDL_SCANCODE_KP_PLUSMINUS), + luabind::value("KP_CLEAR", SDL_SCANCODE_KP_CLEAR), + luabind::value("KP_CLEARENTRY", SDL_SCANCODE_KP_CLEARENTRY), + luabind::value("KP_BINARY", SDL_SCANCODE_KP_BINARY), + luabind::value("KP_OCTAL", SDL_SCANCODE_KP_OCTAL), + luabind::value("KP_DECIMAL", SDL_SCANCODE_KP_DECIMAL), + luabind::value("KP_HEXADECIMAL", SDL_SCANCODE_KP_HEXADECIMAL), + luabind::value("LCTRL", SDL_SCANCODE_LCTRL), + luabind::value("LSHIFT", SDL_SCANCODE_LSHIFT), + luabind::value("LALT", SDL_SCANCODE_LALT), + luabind::value("LGUI", SDL_SCANCODE_LGUI), + luabind::value("RCTRL", SDL_SCANCODE_RCTRL), + luabind::value("RSHIFT", SDL_SCANCODE_RSHIFT), + luabind::value("RALT", SDL_SCANCODE_RALT), + luabind::value("RGUI", SDL_SCANCODE_RGUI), + luabind::value("MODE", SDL_SCANCODE_MODE), + luabind::value("AUDIONEXT", SDL_SCANCODE_AUDIONEXT), + luabind::value("AUDIOPREV", SDL_SCANCODE_AUDIOPREV), + luabind::value("AUDIOSTOP", SDL_SCANCODE_AUDIOSTOP), + luabind::value("AUDIOPLAY", SDL_SCANCODE_AUDIOPLAY), + luabind::value("AUDIOMUTE", SDL_SCANCODE_AUDIOMUTE), + luabind::value("MEDIASELECT", SDL_SCANCODE_MEDIASELECT), + luabind::value("WWW", SDL_SCANCODE_WWW), + luabind::value("MAIL", SDL_SCANCODE_MAIL), + luabind::value("CALCULATOR", SDL_SCANCODE_CALCULATOR), + luabind::value("COMPUTER", SDL_SCANCODE_COMPUTER), + luabind::value("AC_SEARCH", SDL_SCANCODE_AC_SEARCH), + luabind::value("AC_HOME", SDL_SCANCODE_AC_HOME), + luabind::value("AC_BACK", SDL_SCANCODE_AC_BACK), + luabind::value("AC_FORWARD", SDL_SCANCODE_AC_FORWARD), + luabind::value("AC_STOP", SDL_SCANCODE_AC_STOP), + luabind::value("AC_REFRESH", SDL_SCANCODE_AC_REFRESH), + luabind::value("AC_BOOKMARKS", SDL_SCANCODE_AC_BOOKMARKS), + luabind::value("BRIGHTNESSDOWN", SDL_SCANCODE_BRIGHTNESSDOWN), + luabind::value("BRIGHTNESSUP", SDL_SCANCODE_BRIGHTNESSUP), + luabind::value("DISPLAYSWITCH", SDL_SCANCODE_DISPLAYSWITCH), + luabind::value("KBDILLUMTOGGLE", SDL_SCANCODE_KBDILLUMTOGGLE), + luabind::value("KBDILLUMDOWN", SDL_SCANCODE_KBDILLUMDOWN), + luabind::value("KBDILLUMUP", SDL_SCANCODE_KBDILLUMUP), + luabind::value("EJECT", SDL_SCANCODE_EJECT), + luabind::value("SLEEP", SDL_SCANCODE_SLEEP), + luabind::value("APP1", SDL_SCANCODE_APP1), + luabind::value("APP2", SDL_SCANCODE_APP2), + luabind::value("AUDIOREWIND", SDL_SCANCODE_AUDIOREWIND), + luabind::value("AUDIOFASTFORWARD", SDL_SCANCODE_AUDIOFASTFORWARD), + luabind::value("NUM_SCANCODES", SDL_NUM_SCANCODES)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, SDL_GameControllerButton) { return luabind::class_("GamepadButton") - .enum_("GamepadButton")[ - luabind::value("INVALID", SDL_CONTROLLER_BUTTON_INVALID), - luabind::value("A", SDL_CONTROLLER_BUTTON_A), - luabind::value("B", SDL_CONTROLLER_BUTTON_B), - luabind::value("X", SDL_CONTROLLER_BUTTON_X), - luabind::value("Y", SDL_CONTROLLER_BUTTON_Y), - luabind::value("BACK", SDL_CONTROLLER_BUTTON_BACK), - luabind::value("GUIDE", SDL_CONTROLLER_BUTTON_GUIDE), - luabind::value("START", SDL_CONTROLLER_BUTTON_START), - luabind::value("LEFTSTICK", SDL_CONTROLLER_BUTTON_LEFTSTICK), - luabind::value("RIGHTSTICK", SDL_CONTROLLER_BUTTON_RIGHTSTICK), - luabind::value("LEFTSHOULDER", SDL_CONTROLLER_BUTTON_LEFTSHOULDER), - luabind::value("RIGHTSHOULDER", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), - luabind::value("DPAD_UP", SDL_CONTROLLER_BUTTON_DPAD_UP), - luabind::value("DPAD_DOWN", SDL_CONTROLLER_BUTTON_DPAD_DOWN), - luabind::value("DPAD_LEFT", SDL_CONTROLLER_BUTTON_DPAD_LEFT), - luabind::value("DPAD_RIGHT", SDL_CONTROLLER_BUTTON_DPAD_RIGHT), - luabind::value("MAX", SDL_CONTROLLER_BUTTON_MAX) - ]; + .enum_("GamepadButton")[luabind::value("INVALID", SDL_CONTROLLER_BUTTON_INVALID), + luabind::value("A", SDL_CONTROLLER_BUTTON_A), + luabind::value("B", SDL_CONTROLLER_BUTTON_B), + luabind::value("X", SDL_CONTROLLER_BUTTON_X), + luabind::value("Y", SDL_CONTROLLER_BUTTON_Y), + luabind::value("BACK", SDL_CONTROLLER_BUTTON_BACK), + luabind::value("GUIDE", SDL_CONTROLLER_BUTTON_GUIDE), + luabind::value("START", SDL_CONTROLLER_BUTTON_START), + luabind::value("LEFTSTICK", SDL_CONTROLLER_BUTTON_LEFTSTICK), + luabind::value("RIGHTSTICK", SDL_CONTROLLER_BUTTON_RIGHTSTICK), + luabind::value("LEFTSHOULDER", SDL_CONTROLLER_BUTTON_LEFTSHOULDER), + luabind::value("RIGHTSHOULDER", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER), + luabind::value("DPAD_UP", SDL_CONTROLLER_BUTTON_DPAD_UP), + luabind::value("DPAD_DOWN", SDL_CONTROLLER_BUTTON_DPAD_DOWN), + luabind::value("DPAD_LEFT", SDL_CONTROLLER_BUTTON_DPAD_LEFT), + luabind::value("DPAD_RIGHT", SDL_CONTROLLER_BUTTON_DPAD_RIGHT), + luabind::value("MAX", SDL_CONTROLLER_BUTTON_MAX)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(InputLuaBindings, SDL_GameControllerAxis) { return luabind::class_("GamepadAxis") - .enum_("GamepadAxis")[ - luabind::value("INVALID", SDL_CONTROLLER_AXIS_INVALID), - luabind::value("LEFTX", SDL_CONTROLLER_AXIS_LEFTX), - luabind::value("LEFTY", SDL_CONTROLLER_AXIS_LEFTY), - luabind::value("RIGHTX", SDL_CONTROLLER_AXIS_RIGHTX), - luabind::value("RIGHTY", SDL_CONTROLLER_AXIS_RIGHTY), - luabind::value("TRIGGERLEFT", SDL_CONTROLLER_AXIS_TRIGGERLEFT), - luabind::value("TRIGGERRIGHT", SDL_CONTROLLER_AXIS_TRIGGERRIGHT), - luabind::value("MAX", SDL_CONTROLLER_AXIS_MAX) - ]; + .enum_("GamepadAxis")[luabind::value("INVALID", SDL_CONTROLLER_AXIS_INVALID), + luabind::value("LEFTX", SDL_CONTROLLER_AXIS_LEFTX), + luabind::value("LEFTY", SDL_CONTROLLER_AXIS_LEFTY), + luabind::value("RIGHTX", SDL_CONTROLLER_AXIS_RIGHTX), + luabind::value("RIGHTY", SDL_CONTROLLER_AXIS_RIGHTY), + luabind::value("TRIGGERLEFT", SDL_CONTROLLER_AXIS_TRIGGERLEFT), + luabind::value("TRIGGERRIGHT", SDL_CONTROLLER_AXIS_TRIGGERRIGHT), + luabind::value("MAX", SDL_CONTROLLER_AXIS_MAX)]; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuaBindingsManagers.cpp b/Source/Lua/LuaBindingsManagers.cpp index 5ec1706fb..1a9ea3bec 100644 --- a/Source/Lua/LuaBindingsManagers.cpp +++ b/Source/Lua/LuaBindingsManagers.cpp @@ -4,372 +4,372 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, ActivityMan) { return luabind::class_("ActivityManager") - .property("DefaultActivityType", &ActivityMan::GetDefaultActivityType, &ActivityMan::SetDefaultActivityType) - .property("DefaultActivityName", &ActivityMan::GetDefaultActivityName, &ActivityMan::SetDefaultActivityName) - - .def("SetStartActivity", &ActivityMan::SetStartActivity, luabind::adopt(_2)) // Transfers ownership of the Activity to start into the ActivityMan, adopts ownership (_1 is the this ptr) - .def("GetStartActivity", &ActivityMan::GetStartActivity) - .def("GetActivity", &ActivityMan::GetActivity) - .def("StartActivity", (int (ActivityMan::*)(Activity *))&ActivityMan::StartActivity, luabind::adopt(_2)) // Transfers ownership of the Activity to start into the ActivityMan, adopts ownership (_1 is the this ptr) - .def("StartActivity", (int (ActivityMan::*)(const std::string &, const std::string &))&ActivityMan::StartActivity) - .def("RestartActivity", &ActivityMan::RestartActivity) - .def("PauseActivity", &ActivityMan::PauseActivity) - .def("EndActivity", &ActivityMan::EndActivity) - .def("ActivityRunning", &ActivityMan::ActivityRunning) - .def("ActivityPaused", &ActivityMan::ActivityPaused) - .def("SaveGame", &ActivityMan::SaveCurrentGame) - .def("LoadGame", &ActivityMan::LoadAndLaunchGame); + .property("DefaultActivityType", &ActivityMan::GetDefaultActivityType, &ActivityMan::SetDefaultActivityType) + .property("DefaultActivityName", &ActivityMan::GetDefaultActivityName, &ActivityMan::SetDefaultActivityName) + + .def("SetStartActivity", &ActivityMan::SetStartActivity, luabind::adopt(_2)) // Transfers ownership of the Activity to start into the ActivityMan, adopts ownership (_1 is the this ptr) + .def("GetStartActivity", &ActivityMan::GetStartActivity) + .def("GetActivity", &ActivityMan::GetActivity) + .def("StartActivity", (int(ActivityMan::*)(Activity*)) & ActivityMan::StartActivity, luabind::adopt(_2)) // Transfers ownership of the Activity to start into the ActivityMan, adopts ownership (_1 is the this ptr) + .def("StartActivity", (int(ActivityMan::*)(const std::string&, const std::string&)) & ActivityMan::StartActivity) + .def("RestartActivity", &ActivityMan::RestartActivity) + .def("PauseActivity", &ActivityMan::PauseActivity) + .def("EndActivity", &ActivityMan::EndActivity) + .def("ActivityRunning", &ActivityMan::ActivityRunning) + .def("ActivityPaused", &ActivityMan::ActivityPaused) + .def("SaveGame", &ActivityMan::SaveCurrentGame) + .def("LoadGame", &ActivityMan::LoadAndLaunchGame); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, AudioMan) { return luabind::class_("AudioManager") - .property("MusicVolume", &AudioMan::GetMusicVolume, &AudioMan::SetMusicVolume) - .property("SoundsVolume", &AudioMan::GetSoundsVolume, &AudioMan::SetSoundsVolume) - - .def("StopAll", &AudioMan::StopAll) - .def("GetGlobalPitch", &AudioMan::GetGlobalPitch) - .def("IsMusicPlaying", &AudioMan::IsMusicPlaying) - .def("SetTempMusicVolume", &AudioMan::SetTempMusicVolume) - .def("GetMusicPosition", &AudioMan::GetMusicPosition) - .def("SetMusicPosition", &AudioMan::SetMusicPosition) - .def("SetMusicPitch", &AudioMan::SetMusicPitch) - .def("StopMusic", &AudioMan::StopMusic) - .def("PlayMusic", &AudioMan::PlayMusic) - .def("PlayNextStream", &AudioMan::PlayNextStream) - .def("StopMusic", &AudioMan::StopMusic) - .def("QueueMusicStream", &AudioMan::QueueMusicStream) - .def("QueueSilence", &AudioMan::QueueSilence) - .def("ClearMusicQueue", &AudioMan::ClearMusicQueue) - .def("PlaySound", (SoundContainer *(AudioMan:: *)(const std::string &filePath)) &AudioMan::PlaySound, luabind::adopt(luabind::result)) - .def("PlaySound", (SoundContainer *(AudioMan:: *)(const std::string &filePath, const Vector &position)) &AudioMan::PlaySound, luabind::adopt(luabind::result)) - .def("PlaySound", (SoundContainer *(AudioMan:: *)(const std::string &filePath, const Vector &position, int player)) &AudioMan::PlaySound, luabind::adopt(luabind::result)); + .property("MusicVolume", &AudioMan::GetMusicVolume, &AudioMan::SetMusicVolume) + .property("SoundsVolume", &AudioMan::GetSoundsVolume, &AudioMan::SetSoundsVolume) + + .def("StopAll", &AudioMan::StopAll) + .def("GetGlobalPitch", &AudioMan::GetGlobalPitch) + .def("IsMusicPlaying", &AudioMan::IsMusicPlaying) + .def("SetTempMusicVolume", &AudioMan::SetTempMusicVolume) + .def("GetMusicPosition", &AudioMan::GetMusicPosition) + .def("SetMusicPosition", &AudioMan::SetMusicPosition) + .def("SetMusicPitch", &AudioMan::SetMusicPitch) + .def("StopMusic", &AudioMan::StopMusic) + .def("PlayMusic", &AudioMan::PlayMusic) + .def("PlayNextStream", &AudioMan::PlayNextStream) + .def("StopMusic", &AudioMan::StopMusic) + .def("QueueMusicStream", &AudioMan::QueueMusicStream) + .def("QueueSilence", &AudioMan::QueueSilence) + .def("ClearMusicQueue", &AudioMan::ClearMusicQueue) + .def("PlaySound", (SoundContainer * (AudioMan::*)(const std::string& filePath)) & AudioMan::PlaySound, luabind::adopt(luabind::result)) + .def("PlaySound", (SoundContainer * (AudioMan::*)(const std::string& filePath, const Vector& position)) & AudioMan::PlaySound, luabind::adopt(luabind::result)) + .def("PlaySound", (SoundContainer * (AudioMan::*)(const std::string& filePath, const Vector& position, int player)) & AudioMan::PlaySound, luabind::adopt(luabind::result)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, ConsoleMan) { return luabind::class_("ConsoleManager") - .def("PrintString", &ConsoleMan::PrintString) - .def("SaveInputLog", &ConsoleMan::SaveInputLog) - .def("SaveAllText", &ConsoleMan::SaveAllText) - .def("Clear", &ConsoleMan::ClearLog); + .def("PrintString", &ConsoleMan::PrintString) + .def("SaveInputLog", &ConsoleMan::SaveInputLog) + .def("SaveAllText", &ConsoleMan::SaveAllText) + .def("Clear", &ConsoleMan::ClearLog); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, FrameMan) { return luabind::class_("FrameManager") - .property("PlayerScreenWidth", &FrameMan::GetPlayerScreenWidth) - .property("PlayerScreenHeight", &FrameMan::GetPlayerScreenHeight) - .property("ScreenCount", &FrameMan::GetScreenCount) - - .def("IsHudDisabled", &FrameMan::IsHudDisabled) - .def("SetHudDisabled", &FrameMan::SetHudDisabled) - .def("LoadPalette", &FrameMan::LoadPalette) - .def("SetScreenText", &FrameMan::SetScreenText) - .def("ClearScreenText", &FrameMan::ClearScreenText) - .def("FadeInPalette", &FrameMan::FadeInPalette) - .def("FadeOutPalette", &FrameMan::FadeOutPalette) - .def("SaveScreenToPNG", &FrameMan::SaveScreenToPNG) - .def("SaveBitmapToPNG", &FrameMan::SaveBitmapToPNG) - .def("FlashScreen", &FrameMan::FlashScreen) - .def("CalculateTextHeight", &FrameMan::CalculateTextHeight) - .def("CalculateTextWidth", &FrameMan::CalculateTextWidth) - .def("SplitStringToFitWidth", &FrameMan::SplitStringToFitWidth); + .property("PlayerScreenWidth", &FrameMan::GetPlayerScreenWidth) + .property("PlayerScreenHeight", &FrameMan::GetPlayerScreenHeight) + .property("ScreenCount", &FrameMan::GetScreenCount) + + .def("IsHudDisabled", &FrameMan::IsHudDisabled) + .def("SetHudDisabled", &FrameMan::SetHudDisabled) + .def("LoadPalette", &FrameMan::LoadPalette) + .def("SetScreenText", &FrameMan::SetScreenText) + .def("ClearScreenText", &FrameMan::ClearScreenText) + .def("FadeInPalette", &FrameMan::FadeInPalette) + .def("FadeOutPalette", &FrameMan::FadeOutPalette) + .def("SaveScreenToPNG", &FrameMan::SaveScreenToPNG) + .def("SaveBitmapToPNG", &FrameMan::SaveBitmapToPNG) + .def("FlashScreen", &FrameMan::FlashScreen) + .def("CalculateTextHeight", &FrameMan::CalculateTextHeight) + .def("CalculateTextWidth", &FrameMan::CalculateTextWidth) + .def("SplitStringToFitWidth", &FrameMan::SplitStringToFitWidth); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, MetaMan) { return luabind::class_("MetaManager") - .property("GameName", &MetaMan::GetGameName, &MetaMan::SetGameName) - .property("PlayerTurn", &MetaMan::GetPlayerTurn) - .property("PlayerCount", &MetaMan::GetPlayerCount) + .property("GameName", &MetaMan::GetGameName, &MetaMan::SetGameName) + .property("PlayerTurn", &MetaMan::GetPlayerTurn) + .property("PlayerCount", &MetaMan::GetPlayerCount) - .def_readwrite("Players", &MetaMan::m_Players, luabind::return_stl_iterator) + .def_readwrite("Players", &MetaMan::m_Players, luabind::return_stl_iterator) - .def("GetTeamOfPlayer", &MetaMan::GetTeamOfPlayer) - .def("GetPlayer", &MetaMan::GetPlayer) - .def("GetMetaPlayerOfInGamePlayer", &MetaMan::GetMetaPlayerOfInGamePlayer); + .def("GetTeamOfPlayer", &MetaMan::GetTeamOfPlayer) + .def("GetPlayer", &MetaMan::GetPlayer) + .def("GetMetaPlayerOfInGamePlayer", &MetaMan::GetMetaPlayerOfInGamePlayer); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, MovableMan) { return luabind::class_("MovableManager") - .property("MaxDroppedItems", &MovableMan::GetMaxDroppedItems, &MovableMan::SetMaxDroppedItems) - - .def_readwrite("Actors", &MovableMan::m_Actors, luabind::return_stl_iterator) - .def_readwrite("Items", &MovableMan::m_Items, luabind::return_stl_iterator) - .def_readwrite("Particles", &MovableMan::m_Particles, luabind::return_stl_iterator) - .def_readwrite("AddedActors", &MovableMan::m_AddedActors, luabind::return_stl_iterator) - .def_readwrite("AddedItems", &MovableMan::m_AddedItems, luabind::return_stl_iterator) - .def_readwrite("AddedParticles", &MovableMan::m_AddedParticles, luabind::return_stl_iterator) - .def_readwrite("AlarmEvents", &MovableMan::m_AlarmEvents, luabind::return_stl_iterator) - .def_readwrite("AddedAlarmEvents", &MovableMan::m_AddedAlarmEvents, luabind::return_stl_iterator) - - .def("GetMOFromID", &MovableMan::GetMOFromID) - .def("FindObjectByUniqueID", &MovableMan::FindObjectByUniqueID) - .def("GetMOIDCount", &MovableMan::GetMOIDCount) - .def("GetTeamMOIDCount", &MovableMan::GetTeamMOIDCount) - .def("PurgeAllMOs", &MovableMan::PurgeAllMOs) - .def("GetNextActorInGroup", &MovableMan::GetNextActorInGroup) - .def("GetPrevActorInGroup", &MovableMan::GetPrevActorInGroup) - .def("GetNextTeamActor", &MovableMan::GetNextTeamActor) - .def("GetPrevTeamActor", &MovableMan::GetPrevTeamActor) - .def("GetClosestTeamActor", (Actor * (MovableMan::*)(int team, int player, const Vector &scenePoint, int maxRadius, Vector &getDistance, const Actor *excludeThis))&MovableMan::GetClosestTeamActor) - .def("GetClosestTeamActor", (Actor * (MovableMan::*)(int team, int player, const Vector &scenePoint, int maxRadius, Vector &getDistance, bool onlyPlayerControllableActors, const Actor *excludeThis))&MovableMan::GetClosestTeamActor) - .def("GetClosestEnemyActor", &MovableMan::GetClosestEnemyActor) - .def("GetFirstTeamActor", &MovableMan::GetFirstTeamActor) - .def("GetClosestActor", &MovableMan::GetClosestActor) - .def("GetClosestBrainActor", &MovableMan::GetClosestBrainActor) - .def("GetFirstBrainActor", &MovableMan::GetFirstBrainActor) - .def("GetClosestOtherBrainActor", &MovableMan::GetClosestOtherBrainActor) - .def("GetFirstOtherBrainActor", &MovableMan::GetFirstOtherBrainActor) - .def("GetUnassignedBrain", &MovableMan::GetUnassignedBrain) - .def("GetParticleCount", &MovableMan::GetParticleCount) - .def("GetSplashRatio", &MovableMan::GetSplashRatio) - .def("SortTeamRoster", &MovableMan::SortTeamRoster) - .def("ChangeActorTeam", &MovableMan::ChangeActorTeam) - .def("RemoveActor", &MovableMan::RemoveActor, luabind::adopt(luabind::return_value)) - .def("RemoveItem", &MovableMan::RemoveItem, luabind::adopt(luabind::return_value)) - .def("RemoveParticle", &MovableMan::RemoveParticle, luabind::adopt(luabind::return_value)) - .def("ValidMO", &MovableMan::ValidMO) - .def("IsActor", &MovableMan::IsActor) - .def("IsDevice", &MovableMan::IsDevice) - .def("IsParticle", &MovableMan::IsParticle) - .def("IsOfActor", &MovableMan::IsOfActor) - .def("GetRootMOID", &MovableMan::GetRootMOID) - .def("RemoveMO", &MovableMan::RemoveMO) - .def("KillAllTeamActors", &MovableMan::KillAllTeamActors) - .def("KillAllEnemyActors", &MovableMan::KillAllEnemyActors) - .def("OpenAllDoors", &MovableMan::OpenAllDoors) - .def("IsParticleSettlingEnabled", &MovableMan::IsParticleSettlingEnabled) - .def("EnableParticleSettling", &MovableMan::EnableParticleSettling) - .def("IsMOSubtractionEnabled", &MovableMan::IsMOSubtractionEnabled) - .def("GetMOsInBox", (const std::vector * (MovableMan::*)(const Box &box) const)&MovableMan::GetMOsInBox, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetMOsInBox", (const std::vector * (MovableMan::*)(const Box &box, int ignoreTeam) const)&MovableMan::GetMOsInBox, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetMOsInBox", (const std::vector * (MovableMan::*)(const Box &box, int ignoreTeam, bool getsHitByMOsOnly) const)&MovableMan::GetMOsInBox, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetMOsInRadius", (const std::vector * (MovableMan::*)(const Vector ¢re, float radius) const)&MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetMOsInRadius", (const std::vector * (MovableMan::*)(const Vector ¢re, float radius, int ignoreTeam) const)&MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetMOsInRadius", (const std::vector * (MovableMan::*)(const Vector ¢re, float radius, int ignoreTeam, bool getsHitByMOsOnly) const)&MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - - .def("SendGlobalMessage", &LuaAdaptersMovableMan::SendGlobalMessage1) - .def("SendGlobalMessage", &LuaAdaptersMovableMan::SendGlobalMessage2) - .def("AddMO", &LuaAdaptersMovableMan::AddMO, luabind::adopt(_2)) - .def("AddActor", &LuaAdaptersMovableMan::AddActor, luabind::adopt(_2)) - .def("AddItem", &LuaAdaptersMovableMan::AddItem, luabind::adopt(_2)) - .def("AddParticle", &LuaAdaptersMovableMan::AddParticle, luabind::adopt(_2)); + .property("MaxDroppedItems", &MovableMan::GetMaxDroppedItems, &MovableMan::SetMaxDroppedItems) + + .def_readwrite("Actors", &MovableMan::m_Actors, luabind::return_stl_iterator) + .def_readwrite("Items", &MovableMan::m_Items, luabind::return_stl_iterator) + .def_readwrite("Particles", &MovableMan::m_Particles, luabind::return_stl_iterator) + .def_readwrite("AddedActors", &MovableMan::m_AddedActors, luabind::return_stl_iterator) + .def_readwrite("AddedItems", &MovableMan::m_AddedItems, luabind::return_stl_iterator) + .def_readwrite("AddedParticles", &MovableMan::m_AddedParticles, luabind::return_stl_iterator) + .def_readwrite("AlarmEvents", &MovableMan::m_AlarmEvents, luabind::return_stl_iterator) + .def_readwrite("AddedAlarmEvents", &MovableMan::m_AddedAlarmEvents, luabind::return_stl_iterator) + + .def("GetMOFromID", &MovableMan::GetMOFromID) + .def("FindObjectByUniqueID", &MovableMan::FindObjectByUniqueID) + .def("GetMOIDCount", &MovableMan::GetMOIDCount) + .def("GetTeamMOIDCount", &MovableMan::GetTeamMOIDCount) + .def("PurgeAllMOs", &MovableMan::PurgeAllMOs) + .def("GetNextActorInGroup", &MovableMan::GetNextActorInGroup) + .def("GetPrevActorInGroup", &MovableMan::GetPrevActorInGroup) + .def("GetNextTeamActor", &MovableMan::GetNextTeamActor) + .def("GetPrevTeamActor", &MovableMan::GetPrevTeamActor) + .def("GetClosestTeamActor", (Actor * (MovableMan::*)(int team, int player, const Vector& scenePoint, int maxRadius, Vector& getDistance, const Actor* excludeThis)) & MovableMan::GetClosestTeamActor) + .def("GetClosestTeamActor", (Actor * (MovableMan::*)(int team, int player, const Vector& scenePoint, int maxRadius, Vector& getDistance, bool onlyPlayerControllableActors, const Actor* excludeThis)) & MovableMan::GetClosestTeamActor) + .def("GetClosestEnemyActor", &MovableMan::GetClosestEnemyActor) + .def("GetFirstTeamActor", &MovableMan::GetFirstTeamActor) + .def("GetClosestActor", &MovableMan::GetClosestActor) + .def("GetClosestBrainActor", &MovableMan::GetClosestBrainActor) + .def("GetFirstBrainActor", &MovableMan::GetFirstBrainActor) + .def("GetClosestOtherBrainActor", &MovableMan::GetClosestOtherBrainActor) + .def("GetFirstOtherBrainActor", &MovableMan::GetFirstOtherBrainActor) + .def("GetUnassignedBrain", &MovableMan::GetUnassignedBrain) + .def("GetParticleCount", &MovableMan::GetParticleCount) + .def("GetSplashRatio", &MovableMan::GetSplashRatio) + .def("SortTeamRoster", &MovableMan::SortTeamRoster) + .def("ChangeActorTeam", &MovableMan::ChangeActorTeam) + .def("RemoveActor", &MovableMan::RemoveActor, luabind::adopt(luabind::return_value)) + .def("RemoveItem", &MovableMan::RemoveItem, luabind::adopt(luabind::return_value)) + .def("RemoveParticle", &MovableMan::RemoveParticle, luabind::adopt(luabind::return_value)) + .def("ValidMO", &MovableMan::ValidMO) + .def("IsActor", &MovableMan::IsActor) + .def("IsDevice", &MovableMan::IsDevice) + .def("IsParticle", &MovableMan::IsParticle) + .def("IsOfActor", &MovableMan::IsOfActor) + .def("GetRootMOID", &MovableMan::GetRootMOID) + .def("RemoveMO", &MovableMan::RemoveMO) + .def("KillAllTeamActors", &MovableMan::KillAllTeamActors) + .def("KillAllEnemyActors", &MovableMan::KillAllEnemyActors) + .def("OpenAllDoors", &MovableMan::OpenAllDoors) + .def("IsParticleSettlingEnabled", &MovableMan::IsParticleSettlingEnabled) + .def("EnableParticleSettling", &MovableMan::EnableParticleSettling) + .def("IsMOSubtractionEnabled", &MovableMan::IsMOSubtractionEnabled) + .def("GetMOsInBox", (const std::vector* (MovableMan::*)(const Box& box) const) & MovableMan::GetMOsInBox, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsInBox", (const std::vector* (MovableMan::*)(const Box& box, int ignoreTeam) const) & MovableMan::GetMOsInBox, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsInBox", (const std::vector* (MovableMan::*)(const Box& box, int ignoreTeam, bool getsHitByMOsOnly) const) & MovableMan::GetMOsInBox, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsInRadius", (const std::vector* (MovableMan::*)(const Vector& centre, float radius) const) & MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsInRadius", (const std::vector* (MovableMan::*)(const Vector& centre, float radius, int ignoreTeam) const) & MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsInRadius", (const std::vector* (MovableMan::*)(const Vector& centre, float radius, int ignoreTeam, bool getsHitByMOsOnly) const) & MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + + .def("SendGlobalMessage", &LuaAdaptersMovableMan::SendGlobalMessage1) + .def("SendGlobalMessage", &LuaAdaptersMovableMan::SendGlobalMessage2) + .def("AddMO", &LuaAdaptersMovableMan::AddMO, luabind::adopt(_2)) + .def("AddActor", &LuaAdaptersMovableMan::AddActor, luabind::adopt(_2)) + .def("AddItem", &LuaAdaptersMovableMan::AddItem, luabind::adopt(_2)) + .def("AddParticle", &LuaAdaptersMovableMan::AddParticle, luabind::adopt(_2)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, PerformanceMan) { return luabind::class_("PerformanceManager") - .property("ShowPerformanceStats", &PerformanceMan::IsShowingPerformanceStats, &PerformanceMan::ShowPerformanceStats); + .property("ShowPerformanceStats", &PerformanceMan::IsShowingPerformanceStats, &PerformanceMan::ShowPerformanceStats); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, PostProcessMan) { return luabind::class_("PostProcessManager") - .def("RegisterPostEffect", &PostProcessMan::RegisterPostEffect); + .def("RegisterPostEffect", &PostProcessMan::RegisterPostEffect); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, PresetMan) { return luabind::class_("PresetManager") - .def_readwrite("Modules", &PresetMan::m_pDataModules, luabind::return_stl_iterator) - - .def("LoadDataModule", (bool (PresetMan::*)(const std::string &))&PresetMan::LoadDataModule) - .def("GetDataModule", &PresetMan::GetDataModule) - .def("GetModuleID", &PresetMan::GetModuleID) - .def("GetModuleIDFromPath", &PresetMan::GetModuleIDFromPath) - .def("GetTotalModuleCount", &PresetMan::GetTotalModuleCount) - .def("GetOfficialModuleCount", &PresetMan::GetOfficialModuleCount) - .def("AddPreset", &PresetMan::AddEntityPreset) - .def("GetPreset", (const Entity *(PresetMan::*)(std::string, std::string, int))&PresetMan::GetEntityPreset) - .def("GetPreset", (const Entity *(PresetMan::*)(std::string, std::string, std::string))&PresetMan::GetEntityPreset) - .def("GetLoadout", (Actor * (PresetMan::*)(std::string, std::string, bool))&PresetMan::GetLoadout, luabind::adopt(luabind::result)) - .def("GetLoadout", (Actor * (PresetMan::*)(std::string, int, bool))&PresetMan::GetLoadout, luabind::adopt(luabind::result)) - .def("GetRandomOfGroup", &PresetMan::GetRandomOfGroup) - .def("GetRandomOfGroupInModuleSpace", &PresetMan::GetRandomOfGroupInModuleSpace) - .def("GetEntityDataLocation", &PresetMan::GetEntityDataLocation) - .def("ReadReflectedPreset", &PresetMan::ReadReflectedPreset) - .def("ReloadEntityPreset", &LuaAdaptersPresetMan::ReloadEntityPreset1) - .def("ReloadEntityPreset", &LuaAdaptersPresetMan::ReloadEntityPreset2) - .def("GetAllEntities", &LuaAdaptersPresetMan::GetAllEntities, luabind::adopt(luabind::result) + luabind::return_stl_iterator) - .def("GetAllEntitiesOfGroup", &LuaAdaptersPresetMan::GetAllEntitiesOfGroup, luabind::adopt(luabind::result) + luabind::return_stl_iterator) - .def("GetAllEntitiesOfGroup", &LuaAdaptersPresetMan::GetAllEntitiesOfGroup2, luabind::adopt(luabind::result) + luabind::return_stl_iterator) - .def("GetAllEntitiesOfGroup", &LuaAdaptersPresetMan::GetAllEntitiesOfGroup3, luabind::adopt(luabind::result) + luabind::return_stl_iterator) - .def("ReloadAllScripts", &PresetMan::ReloadAllScripts) - .def("IsModuleOfficial", &PresetMan::IsModuleOfficial) - .def("IsModuleUserdata", &PresetMan::IsModuleUserdata) - .def("GetFullModulePath", &PresetMan::GetFullModulePath); + .def_readwrite("Modules", &PresetMan::m_pDataModules, luabind::return_stl_iterator) + + .def("LoadDataModule", (bool(PresetMan::*)(const std::string&)) & PresetMan::LoadDataModule) + .def("GetDataModule", &PresetMan::GetDataModule) + .def("GetModuleID", &PresetMan::GetModuleID) + .def("GetModuleIDFromPath", &PresetMan::GetModuleIDFromPath) + .def("GetTotalModuleCount", &PresetMan::GetTotalModuleCount) + .def("GetOfficialModuleCount", &PresetMan::GetOfficialModuleCount) + .def("AddPreset", &PresetMan::AddEntityPreset) + .def("GetPreset", (const Entity* (PresetMan::*)(std::string, std::string, int)) & PresetMan::GetEntityPreset) + .def("GetPreset", (const Entity* (PresetMan::*)(std::string, std::string, std::string)) & PresetMan::GetEntityPreset) + .def("GetLoadout", (Actor * (PresetMan::*)(std::string, std::string, bool)) & PresetMan::GetLoadout, luabind::adopt(luabind::result)) + .def("GetLoadout", (Actor * (PresetMan::*)(std::string, int, bool)) & PresetMan::GetLoadout, luabind::adopt(luabind::result)) + .def("GetRandomOfGroup", &PresetMan::GetRandomOfGroup) + .def("GetRandomOfGroupInModuleSpace", &PresetMan::GetRandomOfGroupInModuleSpace) + .def("GetEntityDataLocation", &PresetMan::GetEntityDataLocation) + .def("ReadReflectedPreset", &PresetMan::ReadReflectedPreset) + .def("ReloadEntityPreset", &LuaAdaptersPresetMan::ReloadEntityPreset1) + .def("ReloadEntityPreset", &LuaAdaptersPresetMan::ReloadEntityPreset2) + .def("GetAllEntities", &LuaAdaptersPresetMan::GetAllEntities, luabind::adopt(luabind::result) + luabind::return_stl_iterator) + .def("GetAllEntitiesOfGroup", &LuaAdaptersPresetMan::GetAllEntitiesOfGroup, luabind::adopt(luabind::result) + luabind::return_stl_iterator) + .def("GetAllEntitiesOfGroup", &LuaAdaptersPresetMan::GetAllEntitiesOfGroup2, luabind::adopt(luabind::result) + luabind::return_stl_iterator) + .def("GetAllEntitiesOfGroup", &LuaAdaptersPresetMan::GetAllEntitiesOfGroup3, luabind::adopt(luabind::result) + luabind::return_stl_iterator) + .def("ReloadAllScripts", &PresetMan::ReloadAllScripts) + .def("IsModuleOfficial", &PresetMan::IsModuleOfficial) + .def("IsModuleUserdata", &PresetMan::IsModuleUserdata) + .def("GetFullModulePath", &PresetMan::GetFullModulePath); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, PrimitiveMan) { return luabind::class_("PrimitiveManager") - .def("DrawLinePrimitive", (void (PrimitiveMan::*)(const Vector &start, const Vector &end, unsigned char color))&PrimitiveMan::DrawLinePrimitive) - .def("DrawLinePrimitive", (void (PrimitiveMan::*)(const Vector &start, const Vector &end, unsigned char color, int thickness))&PrimitiveMan::DrawLinePrimitive) - .def("DrawLinePrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const Vector &end, unsigned char color))&PrimitiveMan::DrawLinePrimitive) - .def("DrawLinePrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const Vector &end, unsigned char color, int thickness))&PrimitiveMan::DrawLinePrimitive) - .def("DrawArcPrimitive", (void (PrimitiveMan::*)(const Vector &pos, float startAngle, float endAngle, int radius, unsigned char color))&PrimitiveMan::DrawArcPrimitive) - .def("DrawArcPrimitive", (void (PrimitiveMan::*)(const Vector &pos, float startAngle, float endAngle, int radius, unsigned char color, int thickness))&PrimitiveMan::DrawArcPrimitive) - .def("DrawArcPrimitive", (void (PrimitiveMan::*)(int player, const Vector &pos, float startAngle, float endAngle, int radius, unsigned char color))&PrimitiveMan::DrawArcPrimitive) - .def("DrawArcPrimitive", (void (PrimitiveMan::*)(int player, const Vector &pos, float startAngle, float endAngle, int radius, unsigned char color, int thickness))&PrimitiveMan::DrawArcPrimitive) - .def("DrawSplinePrimitive", (void (PrimitiveMan::*)(const Vector &start, const Vector &guideA, const Vector &guideB, const Vector &end, unsigned char color))&PrimitiveMan::DrawSplinePrimitive) - .def("DrawSplinePrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const Vector &guideA, const Vector &guideB, const Vector &end, unsigned char color))&PrimitiveMan::DrawSplinePrimitive) - .def("DrawBoxPrimitive", (void (PrimitiveMan::*)(const Vector &start, const Vector &end, unsigned char color))&PrimitiveMan::DrawBoxPrimitive) - .def("DrawBoxPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const Vector &end, unsigned char color))&PrimitiveMan::DrawBoxPrimitive) - .def("DrawBoxFillPrimitive", (void (PrimitiveMan::*)(const Vector &start, const Vector &end, unsigned char color))&PrimitiveMan::DrawBoxFillPrimitive) - .def("DrawBoxFillPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const Vector &end, unsigned char color))&PrimitiveMan::DrawBoxFillPrimitive) - .def("DrawRoundedBoxPrimitive", (void (PrimitiveMan::*)(const Vector &start, const Vector &end, int cornerRadius, unsigned char color))&PrimitiveMan::DrawRoundedBoxPrimitive) - .def("DrawRoundedBoxPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const Vector &end, int cornerRadius, unsigned char color))&PrimitiveMan::DrawRoundedBoxPrimitive) - .def("DrawRoundedBoxFillPrimitive", (void (PrimitiveMan::*)(const Vector &start, const Vector &end, int cornerRadius, unsigned char color))&PrimitiveMan::DrawRoundedBoxFillPrimitive) - .def("DrawRoundedBoxFillPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const Vector &end, int cornerRadius, unsigned char color))&PrimitiveMan::DrawRoundedBoxFillPrimitive) - .def("DrawCirclePrimitive", (void (PrimitiveMan::*)(const Vector & pos, int radius, unsigned char color))&PrimitiveMan::DrawCirclePrimitive) - .def("DrawCirclePrimitive", (void (PrimitiveMan::*)(int player, const Vector &pos, int radius, unsigned char color))&PrimitiveMan::DrawCirclePrimitive) - .def("DrawCircleFillPrimitive", (void (PrimitiveMan::*)(const Vector &pos, int radius, unsigned char color))&PrimitiveMan::DrawCircleFillPrimitive) - .def("DrawCircleFillPrimitive", (void (PrimitiveMan::*)(int player, const Vector &pos, int radius, unsigned char color))&PrimitiveMan::DrawCircleFillPrimitive) - .def("DrawEllipsePrimitive", (void (PrimitiveMan::*)(const Vector &pos, int horizRadius, int vertRadius, unsigned char color))&PrimitiveMan::DrawEllipsePrimitive) - .def("DrawEllipsePrimitive", (void (PrimitiveMan::*)(int player, const Vector &pos, int horizRadius, int vertRadius, unsigned char color))&PrimitiveMan::DrawEllipsePrimitive) - .def("DrawEllipseFillPrimitive", (void (PrimitiveMan::*)(const Vector &pos, int horizRadius, int vertRadius, unsigned char color))&PrimitiveMan::DrawEllipseFillPrimitive) - .def("DrawEllipseFillPrimitive", (void (PrimitiveMan::*)(int player, const Vector &pos, int horizRadius, int vertRadius, unsigned char color))&PrimitiveMan::DrawEllipseFillPrimitive) - .def("DrawTrianglePrimitive", (void (PrimitiveMan::*)(const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color))&PrimitiveMan::DrawTrianglePrimitive) - .def("DrawTrianglePrimitive", (void (PrimitiveMan::*)(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color))&PrimitiveMan::DrawTrianglePrimitive) - .def("DrawTriangleFillPrimitive", (void (PrimitiveMan::*)(const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color))&PrimitiveMan::DrawTriangleFillPrimitive) - .def("DrawTriangleFillPrimitive", (void (PrimitiveMan::*)(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color))&PrimitiveMan::DrawTriangleFillPrimitive) - .def("DrawTextPrimitive", (void (PrimitiveMan::*)(const Vector &start, const std::string &text, bool isSmall, int alignment))&PrimitiveMan::DrawTextPrimitive) - .def("DrawTextPrimitive", (void (PrimitiveMan::*)(const Vector &start, const std::string &text, bool isSmall, int alignment, float rotAngle))&PrimitiveMan::DrawTextPrimitive) - .def("DrawTextPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const std::string &text, bool isSmall, int alignment))&PrimitiveMan::DrawTextPrimitive) - .def("DrawTextPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const std::string &text, bool isSmall, int alignment, float rotAngle))&PrimitiveMan::DrawTextPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(const Vector &start, const MOSprite *moSprite, float rotAngle, int frame))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(const Vector &start, const MOSprite *moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const MOSprite *moSprite, float rotAngle, int frame))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const MOSprite *moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(const Vector &start, const std::string &filePath, float rotAngle))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(const Vector &start, const std::string &filePath, float rotAngle, bool hFlipped, bool vFlipped))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const std::string &filePath, float rotAngle))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawBitmapPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, const std::string &filePath, float rotAngle, bool hFlipped, bool vFlipped))&PrimitiveMan::DrawBitmapPrimitive) - .def("DrawIconPrimitive", (void (PrimitiveMan::*)(const Vector &start, Entity *entity))&PrimitiveMan::DrawIconPrimitive) - .def("DrawIconPrimitive", (void (PrimitiveMan::*)(int player, const Vector &start, Entity *entity))&PrimitiveMan::DrawIconPrimitive) - - .def("DrawPolygonPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonPrimitive) - .def("DrawPolygonPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonPrimitiveForPlayer) - .def("DrawPolygonFillPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitive) - .def("DrawPolygonFillPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitiveForPlayer) - .def("DrawPrimitives", &LuaAdaptersPrimitiveMan::DrawPrimitivesWithTransparency) - .def("DrawPrimitives", &LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlending) - .def("DrawPrimitives", &LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlendingPerChannel); + .def("DrawLinePrimitive", (void(PrimitiveMan::*)(const Vector& start, const Vector& end, unsigned char color)) & PrimitiveMan::DrawLinePrimitive) + .def("DrawLinePrimitive", (void(PrimitiveMan::*)(const Vector& start, const Vector& end, unsigned char color, int thickness)) & PrimitiveMan::DrawLinePrimitive) + .def("DrawLinePrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const Vector& end, unsigned char color)) & PrimitiveMan::DrawLinePrimitive) + .def("DrawLinePrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const Vector& end, unsigned char color, int thickness)) & PrimitiveMan::DrawLinePrimitive) + .def("DrawArcPrimitive", (void(PrimitiveMan::*)(const Vector& pos, float startAngle, float endAngle, int radius, unsigned char color)) & PrimitiveMan::DrawArcPrimitive) + .def("DrawArcPrimitive", (void(PrimitiveMan::*)(const Vector& pos, float startAngle, float endAngle, int radius, unsigned char color, int thickness)) & PrimitiveMan::DrawArcPrimitive) + .def("DrawArcPrimitive", (void(PrimitiveMan::*)(int player, const Vector& pos, float startAngle, float endAngle, int radius, unsigned char color)) & PrimitiveMan::DrawArcPrimitive) + .def("DrawArcPrimitive", (void(PrimitiveMan::*)(int player, const Vector& pos, float startAngle, float endAngle, int radius, unsigned char color, int thickness)) & PrimitiveMan::DrawArcPrimitive) + .def("DrawSplinePrimitive", (void(PrimitiveMan::*)(const Vector& start, const Vector& guideA, const Vector& guideB, const Vector& end, unsigned char color)) & PrimitiveMan::DrawSplinePrimitive) + .def("DrawSplinePrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const Vector& guideA, const Vector& guideB, const Vector& end, unsigned char color)) & PrimitiveMan::DrawSplinePrimitive) + .def("DrawBoxPrimitive", (void(PrimitiveMan::*)(const Vector& start, const Vector& end, unsigned char color)) & PrimitiveMan::DrawBoxPrimitive) + .def("DrawBoxPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const Vector& end, unsigned char color)) & PrimitiveMan::DrawBoxPrimitive) + .def("DrawBoxFillPrimitive", (void(PrimitiveMan::*)(const Vector& start, const Vector& end, unsigned char color)) & PrimitiveMan::DrawBoxFillPrimitive) + .def("DrawBoxFillPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const Vector& end, unsigned char color)) & PrimitiveMan::DrawBoxFillPrimitive) + .def("DrawRoundedBoxPrimitive", (void(PrimitiveMan::*)(const Vector& start, const Vector& end, int cornerRadius, unsigned char color)) & PrimitiveMan::DrawRoundedBoxPrimitive) + .def("DrawRoundedBoxPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const Vector& end, int cornerRadius, unsigned char color)) & PrimitiveMan::DrawRoundedBoxPrimitive) + .def("DrawRoundedBoxFillPrimitive", (void(PrimitiveMan::*)(const Vector& start, const Vector& end, int cornerRadius, unsigned char color)) & PrimitiveMan::DrawRoundedBoxFillPrimitive) + .def("DrawRoundedBoxFillPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const Vector& end, int cornerRadius, unsigned char color)) & PrimitiveMan::DrawRoundedBoxFillPrimitive) + .def("DrawCirclePrimitive", (void(PrimitiveMan::*)(const Vector& pos, int radius, unsigned char color)) & PrimitiveMan::DrawCirclePrimitive) + .def("DrawCirclePrimitive", (void(PrimitiveMan::*)(int player, const Vector& pos, int radius, unsigned char color)) & PrimitiveMan::DrawCirclePrimitive) + .def("DrawCircleFillPrimitive", (void(PrimitiveMan::*)(const Vector& pos, int radius, unsigned char color)) & PrimitiveMan::DrawCircleFillPrimitive) + .def("DrawCircleFillPrimitive", (void(PrimitiveMan::*)(int player, const Vector& pos, int radius, unsigned char color)) & PrimitiveMan::DrawCircleFillPrimitive) + .def("DrawEllipsePrimitive", (void(PrimitiveMan::*)(const Vector& pos, int horizRadius, int vertRadius, unsigned char color)) & PrimitiveMan::DrawEllipsePrimitive) + .def("DrawEllipsePrimitive", (void(PrimitiveMan::*)(int player, const Vector& pos, int horizRadius, int vertRadius, unsigned char color)) & PrimitiveMan::DrawEllipsePrimitive) + .def("DrawEllipseFillPrimitive", (void(PrimitiveMan::*)(const Vector& pos, int horizRadius, int vertRadius, unsigned char color)) & PrimitiveMan::DrawEllipseFillPrimitive) + .def("DrawEllipseFillPrimitive", (void(PrimitiveMan::*)(int player, const Vector& pos, int horizRadius, int vertRadius, unsigned char color)) & PrimitiveMan::DrawEllipseFillPrimitive) + .def("DrawTrianglePrimitive", (void(PrimitiveMan::*)(const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color)) & PrimitiveMan::DrawTrianglePrimitive) + .def("DrawTrianglePrimitive", (void(PrimitiveMan::*)(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color)) & PrimitiveMan::DrawTrianglePrimitive) + .def("DrawTriangleFillPrimitive", (void(PrimitiveMan::*)(const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color)) & PrimitiveMan::DrawTriangleFillPrimitive) + .def("DrawTriangleFillPrimitive", (void(PrimitiveMan::*)(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color)) & PrimitiveMan::DrawTriangleFillPrimitive) + .def("DrawTextPrimitive", (void(PrimitiveMan::*)(const Vector& start, const std::string& text, bool isSmall, int alignment)) & PrimitiveMan::DrawTextPrimitive) + .def("DrawTextPrimitive", (void(PrimitiveMan::*)(const Vector& start, const std::string& text, bool isSmall, int alignment, float rotAngle)) & PrimitiveMan::DrawTextPrimitive) + .def("DrawTextPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const std::string& text, bool isSmall, int alignment)) & PrimitiveMan::DrawTextPrimitive) + .def("DrawTextPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const std::string& text, bool isSmall, int alignment, float rotAngle)) & PrimitiveMan::DrawTextPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(const Vector& start, const MOSprite* moSprite, float rotAngle, int frame)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(const Vector& start, const MOSprite* moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const MOSprite* moSprite, float rotAngle, int frame)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const MOSprite* moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(const Vector& start, const std::string& filePath, float rotAngle)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(const Vector& start, const std::string& filePath, float rotAngle, bool hFlipped, bool vFlipped)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const std::string& filePath, float rotAngle)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawBitmapPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, const std::string& filePath, float rotAngle, bool hFlipped, bool vFlipped)) & PrimitiveMan::DrawBitmapPrimitive) + .def("DrawIconPrimitive", (void(PrimitiveMan::*)(const Vector& start, Entity* entity)) & PrimitiveMan::DrawIconPrimitive) + .def("DrawIconPrimitive", (void(PrimitiveMan::*)(int player, const Vector& start, Entity* entity)) & PrimitiveMan::DrawIconPrimitive) + + .def("DrawPolygonPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonPrimitive) + .def("DrawPolygonPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonPrimitiveForPlayer) + .def("DrawPolygonFillPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitive) + .def("DrawPolygonFillPrimitive", &LuaAdaptersPrimitiveMan::DrawPolygonFillPrimitiveForPlayer) + .def("DrawPrimitives", &LuaAdaptersPrimitiveMan::DrawPrimitivesWithTransparency) + .def("DrawPrimitives", &LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlending) + .def("DrawPrimitives", &LuaAdaptersPrimitiveMan::DrawPrimitivesWithBlendingPerChannel); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SceneMan) { return luabind::class_("SceneManager") - .property("Scene", &SceneMan::GetScene) - .property("SceneDim", &SceneMan::GetSceneDim) - .property("SceneWidth", &SceneMan::GetSceneWidth) - .property("SceneHeight", &SceneMan::GetSceneHeight) - .property("SceneWrapsX", &SceneMan::SceneWrapsX) - .property("SceneWrapsY", &SceneMan::SceneWrapsY) - .property("SceneOrbitDirection", &SceneMan::GetSceneOrbitDirection) - .property("LayerDrawMode", &SceneMan::GetLayerDrawMode, &SceneMan::SetLayerDrawMode) - .property("GlobalAcc", &SceneMan::GetGlobalAcc) - .property("OzPerKg", &SceneMan::GetOzPerKg) - .property("KgPerOz", &SceneMan::GetKgPerOz) - .property("ScrapCompactingHeight", &SceneMan::GetScrapCompactingHeight, &SceneMan::SetScrapCompactingHeight) - - .def("LoadScene", (int (SceneMan::*)(std::string, bool, bool))&SceneMan::LoadScene) - .def("LoadScene", (int (SceneMan::*)(std::string, bool))&SceneMan::LoadScene) - - .def("GetTerrain", &SceneMan::GetTerrain) - .def("GetMaterial", &SceneMan::GetMaterial) - .def("GetMaterialFromID", &SceneMan::GetMaterialFromID) - .def("GetTerrMatter", &SceneMan::GetTerrMatter) - .def("GetMOIDPixel", (MOID (SceneMan::*)(int, int))&SceneMan::GetMOIDPixel) - .def("GetMOIDPixel", (MOID (SceneMan::*)(int, int, int))&SceneMan::GetMOIDPixel) - .def("SetLayerDrawMode", &SceneMan::SetLayerDrawMode) - .def("LoadUnseenLayer", &SceneMan::LoadUnseenLayer) - .def("MakeAllUnseen", &SceneMan::MakeAllUnseen) - .def("AnythingUnseen", &SceneMan::AnythingUnseen) - .def("GetUnseenResolution", &SceneMan::GetUnseenResolution) - .def("IsUnseen", &SceneMan::IsUnseen) - .def("RevealUnseen", &SceneMan::RevealUnseen) - .def("RevealUnseenBox", &SceneMan::RevealUnseenBox) - .def("RestoreUnseen", &SceneMan::RestoreUnseen) - .def("RestoreUnseenBox", &SceneMan::RestoreUnseenBox) - .def("CastSeeRay", &SceneMan::CastSeeRay) - .def("CastUnseeRay", &SceneMan::CastUnseeRay) - .def("CastUnseenRay", &SceneMan::CastUnseenRay) - .def("CastMaterialRay", (bool (SceneMan::*)(const Vector &, const Vector &, unsigned char, Vector &, int, bool))&SceneMan::CastMaterialRay) - .def("CastMaterialRay", (float (SceneMan::*)(const Vector &, const Vector &, unsigned char, int))&SceneMan::CastMaterialRay) - .def("CastNotMaterialRay", (bool (SceneMan::*)(const Vector &, const Vector &, unsigned char, Vector &, int, bool))&SceneMan::CastNotMaterialRay) - .def("CastNotMaterialRay", (float (SceneMan::*)(const Vector &, const Vector &, unsigned char, int, bool))&SceneMan::CastNotMaterialRay) - .def("CastStrengthSumRay", &SceneMan::CastStrengthSumRay) - .def("CastMaxStrengthRay", (float (SceneMan::*) (const Vector &, const Vector &, int, unsigned char))&SceneMan::CastMaxStrengthRay) - .def("CastMaxStrengthRay", (float (SceneMan::*) (const Vector &, const Vector &, int))&SceneMan::CastMaxStrengthRay) - .def("CastStrengthRay", &SceneMan::CastStrengthRay) - .def("CastWeaknessRay", &SceneMan::CastWeaknessRay) - .def("CastMORay", &SceneMan::CastMORay) - .def("CastFindMORay", &SceneMan::CastFindMORay) - .def("CastObstacleRay", &SceneMan::CastObstacleRay) - .def("GetLastRayHitPos", &SceneMan::GetLastRayHitPos) - .def("FindAltitude", (float (SceneMan::*) (const Vector&, int, int)) &SceneMan::FindAltitude) - .def("FindAltitude", (float (SceneMan::*) (const Vector&, int, int, bool)) &SceneMan::FindAltitude) - .def("MovePointToGround", &SceneMan::MovePointToGround) - .def("IsWithinBounds", &SceneMan::IsWithinBounds) - .def("ForceBounds", (bool (SceneMan::*)(int &, int &))&SceneMan::ForceBounds) - .def("ForceBounds", (bool (SceneMan::*)(Vector &))&SceneMan::ForceBounds)//, out_value(_2)) - .def("WrapPosition", (bool (SceneMan::*)(int &, int &))&SceneMan::WrapPosition) - .def("WrapPosition", (bool (SceneMan::*)(Vector &))&SceneMan::WrapPosition)//, out_value(_2)) - .def("SnapPosition", &SceneMan::SnapPosition) - .def("ShortestDistance", &SceneMan::ShortestDistance) - .def("WrapBox", &LuaAdaptersSceneMan::WrapBoxes, luabind::return_stl_iterator) - .def("ObscuredPoint", (bool (SceneMan::*)(Vector &, int))&SceneMan::ObscuredPoint)//, out_value(_2)) - .def("ObscuredPoint", (bool (SceneMan::*)(int, int, int))&SceneMan::ObscuredPoint) - .def("AddSceneObject", &SceneMan::AddSceneObject, luabind::adopt(_2)) - .def("CheckAndRemoveOrphans", (int (SceneMan::*)(int, int, int, int, bool))&SceneMan::RemoveOrphans) - .def("DislodgePixel", &SceneMan::DislodgePixel); + .property("Scene", &SceneMan::GetScene) + .property("SceneDim", &SceneMan::GetSceneDim) + .property("SceneWidth", &SceneMan::GetSceneWidth) + .property("SceneHeight", &SceneMan::GetSceneHeight) + .property("SceneWrapsX", &SceneMan::SceneWrapsX) + .property("SceneWrapsY", &SceneMan::SceneWrapsY) + .property("SceneOrbitDirection", &SceneMan::GetSceneOrbitDirection) + .property("LayerDrawMode", &SceneMan::GetLayerDrawMode, &SceneMan::SetLayerDrawMode) + .property("GlobalAcc", &SceneMan::GetGlobalAcc) + .property("OzPerKg", &SceneMan::GetOzPerKg) + .property("KgPerOz", &SceneMan::GetKgPerOz) + .property("ScrapCompactingHeight", &SceneMan::GetScrapCompactingHeight, &SceneMan::SetScrapCompactingHeight) + + .def("LoadScene", (int(SceneMan::*)(std::string, bool, bool)) & SceneMan::LoadScene) + .def("LoadScene", (int(SceneMan::*)(std::string, bool)) & SceneMan::LoadScene) + + .def("GetTerrain", &SceneMan::GetTerrain) + .def("GetMaterial", &SceneMan::GetMaterial) + .def("GetMaterialFromID", &SceneMan::GetMaterialFromID) + .def("GetTerrMatter", &SceneMan::GetTerrMatter) + .def("GetMOIDPixel", (MOID(SceneMan::*)(int, int)) & SceneMan::GetMOIDPixel) + .def("GetMOIDPixel", (MOID(SceneMan::*)(int, int, int)) & SceneMan::GetMOIDPixel) + .def("SetLayerDrawMode", &SceneMan::SetLayerDrawMode) + .def("LoadUnseenLayer", &SceneMan::LoadUnseenLayer) + .def("MakeAllUnseen", &SceneMan::MakeAllUnseen) + .def("AnythingUnseen", &SceneMan::AnythingUnseen) + .def("GetUnseenResolution", &SceneMan::GetUnseenResolution) + .def("IsUnseen", &SceneMan::IsUnseen) + .def("RevealUnseen", &SceneMan::RevealUnseen) + .def("RevealUnseenBox", &SceneMan::RevealUnseenBox) + .def("RestoreUnseen", &SceneMan::RestoreUnseen) + .def("RestoreUnseenBox", &SceneMan::RestoreUnseenBox) + .def("CastSeeRay", &SceneMan::CastSeeRay) + .def("CastUnseeRay", &SceneMan::CastUnseeRay) + .def("CastUnseenRay", &SceneMan::CastUnseenRay) + .def("CastMaterialRay", (bool(SceneMan::*)(const Vector&, const Vector&, unsigned char, Vector&, int, bool)) & SceneMan::CastMaterialRay) + .def("CastMaterialRay", (float(SceneMan::*)(const Vector&, const Vector&, unsigned char, int)) & SceneMan::CastMaterialRay) + .def("CastNotMaterialRay", (bool(SceneMan::*)(const Vector&, const Vector&, unsigned char, Vector&, int, bool)) & SceneMan::CastNotMaterialRay) + .def("CastNotMaterialRay", (float(SceneMan::*)(const Vector&, const Vector&, unsigned char, int, bool)) & SceneMan::CastNotMaterialRay) + .def("CastStrengthSumRay", &SceneMan::CastStrengthSumRay) + .def("CastMaxStrengthRay", (float(SceneMan::*)(const Vector&, const Vector&, int, unsigned char)) & SceneMan::CastMaxStrengthRay) + .def("CastMaxStrengthRay", (float(SceneMan::*)(const Vector&, const Vector&, int)) & SceneMan::CastMaxStrengthRay) + .def("CastStrengthRay", &SceneMan::CastStrengthRay) + .def("CastWeaknessRay", &SceneMan::CastWeaknessRay) + .def("CastMORay", &SceneMan::CastMORay) + .def("CastFindMORay", &SceneMan::CastFindMORay) + .def("CastObstacleRay", &SceneMan::CastObstacleRay) + .def("GetLastRayHitPos", &SceneMan::GetLastRayHitPos) + .def("FindAltitude", (float(SceneMan::*)(const Vector&, int, int)) & SceneMan::FindAltitude) + .def("FindAltitude", (float(SceneMan::*)(const Vector&, int, int, bool)) & SceneMan::FindAltitude) + .def("MovePointToGround", &SceneMan::MovePointToGround) + .def("IsWithinBounds", &SceneMan::IsWithinBounds) + .def("ForceBounds", (bool(SceneMan::*)(int&, int&)) & SceneMan::ForceBounds) + .def("ForceBounds", (bool(SceneMan::*)(Vector&)) & SceneMan::ForceBounds) //, out_value(_2)) + .def("WrapPosition", (bool(SceneMan::*)(int&, int&)) & SceneMan::WrapPosition) + .def("WrapPosition", (bool(SceneMan::*)(Vector&)) & SceneMan::WrapPosition) //, out_value(_2)) + .def("SnapPosition", &SceneMan::SnapPosition) + .def("ShortestDistance", &SceneMan::ShortestDistance) + .def("WrapBox", &LuaAdaptersSceneMan::WrapBoxes, luabind::return_stl_iterator) + .def("ObscuredPoint", (bool(SceneMan::*)(Vector&, int)) & SceneMan::ObscuredPoint) //, out_value(_2)) + .def("ObscuredPoint", (bool(SceneMan::*)(int, int, int)) & SceneMan::ObscuredPoint) + .def("AddSceneObject", &SceneMan::AddSceneObject, luabind::adopt(_2)) + .def("CheckAndRemoveOrphans", (int(SceneMan::*)(int, int, int, int, bool)) & SceneMan::RemoveOrphans) + .def("DislodgePixel", &SceneMan::DislodgePixel); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, CameraMan) { return luabind::class_("CameraManager") - .def("GetOffset", &CameraMan::GetOffset) - .def("SetOffset", &CameraMan::SetOffset) - .def("GetScreenOcclusion", &CameraMan::GetScreenOcclusion) - .def("SetScreenOcclusion", &CameraMan::SetScreenOcclusion) - .def("GetScrollTarget", &CameraMan::GetScrollTarget) - .def("SetScrollTarget", &CameraMan::SetScrollTarget) - .def("TargetDistanceScalar", &CameraMan::TargetDistanceScalar) - .def("CheckOffset", &CameraMan::CheckOffset) - .def("SetScroll", &CameraMan::SetScroll) - .def("AddScreenShake", (void (CameraMan::*)(float, int))&CameraMan::AddScreenShake) - .def("AddScreenShake", (void (CameraMan::*)(float, const Vector &))&CameraMan::AddScreenShake); + .def("GetOffset", &CameraMan::GetOffset) + .def("SetOffset", &CameraMan::SetOffset) + .def("GetScreenOcclusion", &CameraMan::GetScreenOcclusion) + .def("SetScreenOcclusion", &CameraMan::SetScreenOcclusion) + .def("GetScrollTarget", &CameraMan::GetScrollTarget) + .def("SetScrollTarget", &CameraMan::SetScrollTarget) + .def("TargetDistanceScalar", &CameraMan::TargetDistanceScalar) + .def("CheckOffset", &CameraMan::CheckOffset) + .def("SetScroll", &CameraMan::SetScroll) + .def("AddScreenShake", (void(CameraMan::*)(float, int)) & CameraMan::AddScreenShake) + .def("AddScreenShake", (void(CameraMan::*)(float, const Vector&)) & CameraMan::AddScreenShake); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -377,85 +377,85 @@ namespace RTE { LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SettingsMan) { return luabind::class_("SettingsManager") - .property("PrintDebugInfo", &SettingsMan::PrintDebugInfo, &SettingsMan::SetPrintDebugInfo) - .property("RecommendedMOIDCount", &SettingsMan::RecommendedMOIDCount) - .property("AIUpdateInterval", &SettingsMan::GetAIUpdateInterval, &SettingsMan::SetAIUpdateInterval) - .property("ShowEnemyHUD", &SettingsMan::ShowEnemyHUD) - .property("AutomaticGoldDeposit", &SettingsMan::GetAutomaticGoldDeposit); + .property("PrintDebugInfo", &SettingsMan::PrintDebugInfo, &SettingsMan::SetPrintDebugInfo) + .property("RecommendedMOIDCount", &SettingsMan::RecommendedMOIDCount) + .property("AIUpdateInterval", &SettingsMan::GetAIUpdateInterval, &SettingsMan::SetAIUpdateInterval) + .property("ShowEnemyHUD", &SettingsMan::ShowEnemyHUD) + .property("AutomaticGoldDeposit", &SettingsMan::GetAutomaticGoldDeposit); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, TimerMan) { return luabind::class_("TimerManager") - .property("TimeScale", &TimerMan::GetTimeScale, &TimerMan::SetTimeScale) - .property("RealToSimCap", &TimerMan::GetRealToSimCap) - .property("DeltaTimeTicks", &LuaAdaptersTimerMan::GetDeltaTimeTicks, &TimerMan::SetDeltaTimeTicks) - .property("DeltaTimeSecs", &TimerMan::GetDeltaTimeSecs, &TimerMan::SetDeltaTimeSecs) - .property("DeltaTimeMS", &TimerMan::GetDeltaTimeMS) - .property("AIDeltaTimeSecs", &TimerMan::GetAIDeltaTimeSecs) - .property("AIDeltaTimeMS", &TimerMan::GetAIDeltaTimeMS) + .property("TimeScale", &TimerMan::GetTimeScale, &TimerMan::SetTimeScale) + .property("RealToSimCap", &TimerMan::GetRealToSimCap) + .property("DeltaTimeTicks", &LuaAdaptersTimerMan::GetDeltaTimeTicks, &TimerMan::SetDeltaTimeTicks) + .property("DeltaTimeSecs", &TimerMan::GetDeltaTimeSecs, &TimerMan::SetDeltaTimeSecs) + .property("DeltaTimeMS", &TimerMan::GetDeltaTimeMS) + .property("AIDeltaTimeSecs", &TimerMan::GetAIDeltaTimeSecs) + .property("AIDeltaTimeMS", &TimerMan::GetAIDeltaTimeMS) - .property("TicksPerSecond", &LuaAdaptersTimerMan::GetTicksPerSecond) + .property("TicksPerSecond", &LuaAdaptersTimerMan::GetTicksPerSecond) - .def("TimeForSimUpdate", &TimerMan::TimeForSimUpdate) - .def("DrawnSimUpdate", &TimerMan::DrawnSimUpdate); + .def("TimeForSimUpdate", &TimerMan::TimeForSimUpdate) + .def("DrawnSimUpdate", &TimerMan::DrawnSimUpdate); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, UInputMan) { return luabind::class_("UInputManager") - .property("FlagAltState", &UInputMan::FlagAltState) - .property("FlagCtrlState", &UInputMan::FlagCtrlState) - .property("FlagShiftState", &UInputMan::FlagShiftState) - - .def("GetInputDevice", &UInputMan::GetInputDevice) - .def("ElementPressed", &UInputMan::ElementPressed) - .def("ElementReleased", &UInputMan::ElementReleased) - .def("ElementHeld", &UInputMan::ElementHeld) - .def("KeyPressed", (bool(UInputMan::*)(SDL_Keycode) const) &UInputMan::KeyPressed) - .def("KeyReleased", (bool(UInputMan::*)(SDL_Keycode) const) &UInputMan::KeyReleased) - .def("KeyHeld", (bool(UInputMan::*)(SDL_Keycode) const) &UInputMan::KeyHeld) - .def("ScancodePressed", (bool(UInputMan::*)(SDL_Scancode) const) &UInputMan::KeyPressed) - .def("ScancodeReleased", (bool(UInputMan::*)(SDL_Scancode) const) &UInputMan::KeyReleased) - .def("ScancodeHeld", (bool(UInputMan::*)(SDL_Scancode) const) &UInputMan::KeyHeld) - .def("MouseButtonPressed", &UInputMan::MouseButtonPressed) - .def("MouseButtonReleased", &UInputMan::MouseButtonReleased) - .def("MouseButtonHeld", &UInputMan::MouseButtonHeld) - .def("GetMousePos", &UInputMan::GetAbsoluteMousePosition) - .def("MouseWheelMoved", &UInputMan::MouseWheelMoved) - .def("JoyButtonPressed", &UInputMan::JoyButtonPressed) - .def("JoyButtonReleased", &UInputMan::JoyButtonReleased) - .def("JoyButtonHeld", &UInputMan::JoyButtonHeld) - .def("WhichJoyButtonPressed", &UInputMan::WhichJoyButtonPressed) - .def("JoyDirectionPressed", &UInputMan::JoyDirectionPressed) - .def("JoyDirectionReleased", &UInputMan::JoyDirectionReleased) - .def("JoyDirectionHeld", &UInputMan::JoyDirectionHeld) - .def("AnalogMoveValues", &UInputMan::AnalogMoveValues) - .def("AnalogAimValues", &UInputMan::AnalogAimValues) - .def("SetMouseValueMagnitude", &UInputMan::SetMouseValueMagnitude) - .def("AnalogAxisValue", &UInputMan::AnalogAxisValue) - .def("MouseUsedByPlayer", &UInputMan::MouseUsedByPlayer) - .def("AnyMouseButtonPress", &UInputMan::AnyMouseButtonPress) - .def("GetMouseMovement", &UInputMan::GetMouseMovement) - .def("DisableMouseMoving", &UInputMan::DisableMouseMoving) - .def("SetMousePos", &UInputMan::SetMousePos) - .def("ForceMouseWithinBox", &UInputMan::ForceMouseWithinBox) - .def("AnyKeyPress", &UInputMan::AnyKeyPress) - .def("AnyJoyInput", &UInputMan::AnyJoyInput) - .def("AnyJoyPress", &UInputMan::AnyJoyPress) - .def("AnyJoyButtonPress", &UInputMan::AnyJoyButtonPress) - .def("AnyInput", &UInputMan::AnyKeyOrJoyInput) - .def("AnyPress", &UInputMan::AnyPress) - .def("AnyStartPress", &UInputMan::AnyStartPress) - .def("HasTextInput", &UInputMan::HasTextInput) - .def("GetTextInput", (const std::string& (UInputMan::*)() const) &UInputMan::GetTextInput) - - .def("MouseButtonPressed", &LuaAdaptersUInputMan::MouseButtonPressed) - .def("MouseButtonReleased", &LuaAdaptersUInputMan::MouseButtonReleased) - .def("MouseButtonHeld", &LuaAdaptersUInputMan::MouseButtonHeld); + .property("FlagAltState", &UInputMan::FlagAltState) + .property("FlagCtrlState", &UInputMan::FlagCtrlState) + .property("FlagShiftState", &UInputMan::FlagShiftState) + + .def("GetInputDevice", &UInputMan::GetInputDevice) + .def("ElementPressed", &UInputMan::ElementPressed) + .def("ElementReleased", &UInputMan::ElementReleased) + .def("ElementHeld", &UInputMan::ElementHeld) + .def("KeyPressed", (bool(UInputMan::*)(SDL_Keycode) const) & UInputMan::KeyPressed) + .def("KeyReleased", (bool(UInputMan::*)(SDL_Keycode) const) & UInputMan::KeyReleased) + .def("KeyHeld", (bool(UInputMan::*)(SDL_Keycode) const) & UInputMan::KeyHeld) + .def("ScancodePressed", (bool(UInputMan::*)(SDL_Scancode) const) & UInputMan::KeyPressed) + .def("ScancodeReleased", (bool(UInputMan::*)(SDL_Scancode) const) & UInputMan::KeyReleased) + .def("ScancodeHeld", (bool(UInputMan::*)(SDL_Scancode) const) & UInputMan::KeyHeld) + .def("MouseButtonPressed", &UInputMan::MouseButtonPressed) + .def("MouseButtonReleased", &UInputMan::MouseButtonReleased) + .def("MouseButtonHeld", &UInputMan::MouseButtonHeld) + .def("GetMousePos", &UInputMan::GetAbsoluteMousePosition) + .def("MouseWheelMoved", &UInputMan::MouseWheelMoved) + .def("JoyButtonPressed", &UInputMan::JoyButtonPressed) + .def("JoyButtonReleased", &UInputMan::JoyButtonReleased) + .def("JoyButtonHeld", &UInputMan::JoyButtonHeld) + .def("WhichJoyButtonPressed", &UInputMan::WhichJoyButtonPressed) + .def("JoyDirectionPressed", &UInputMan::JoyDirectionPressed) + .def("JoyDirectionReleased", &UInputMan::JoyDirectionReleased) + .def("JoyDirectionHeld", &UInputMan::JoyDirectionHeld) + .def("AnalogMoveValues", &UInputMan::AnalogMoveValues) + .def("AnalogAimValues", &UInputMan::AnalogAimValues) + .def("SetMouseValueMagnitude", &UInputMan::SetMouseValueMagnitude) + .def("AnalogAxisValue", &UInputMan::AnalogAxisValue) + .def("MouseUsedByPlayer", &UInputMan::MouseUsedByPlayer) + .def("AnyMouseButtonPress", &UInputMan::AnyMouseButtonPress) + .def("GetMouseMovement", &UInputMan::GetMouseMovement) + .def("DisableMouseMoving", &UInputMan::DisableMouseMoving) + .def("SetMousePos", &UInputMan::SetMousePos) + .def("ForceMouseWithinBox", &UInputMan::ForceMouseWithinBox) + .def("AnyKeyPress", &UInputMan::AnyKeyPress) + .def("AnyJoyInput", &UInputMan::AnyJoyInput) + .def("AnyJoyPress", &UInputMan::AnyJoyPress) + .def("AnyJoyButtonPress", &UInputMan::AnyJoyButtonPress) + .def("AnyInput", &UInputMan::AnyKeyOrJoyInput) + .def("AnyPress", &UInputMan::AnyPress) + .def("AnyStartPress", &UInputMan::AnyStartPress) + .def("HasTextInput", &UInputMan::HasTextInput) + .def("GetTextInput", (const std::string& (UInputMan::*)() const) & UInputMan::GetTextInput) + + .def("MouseButtonPressed", &LuaAdaptersUInputMan::MouseButtonPressed) + .def("MouseButtonReleased", &LuaAdaptersUInputMan::MouseButtonReleased) + .def("MouseButtonHeld", &LuaAdaptersUInputMan::MouseButtonHeld); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuaBindingsMisc.cpp b/Source/Lua/LuaBindingsMisc.cpp index 55bbaa64e..361e9c9d4 100644 --- a/Source/Lua/LuaBindingsMisc.cpp +++ b/Source/Lua/LuaBindingsMisc.cpp @@ -4,53 +4,49 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(MiscLuaBindings, AlarmEvent) { return luabind::class_("AlarmEvent") - .def(luabind::constructor<>()) - .def(luabind::constructor()) + .def(luabind::constructor<>()) + .def(luabind::constructor()) - .def_readwrite("ScenePos", &AlarmEvent::m_ScenePos) - .def_readwrite("Team", &AlarmEvent::m_Team) - .def_readwrite("Range", &AlarmEvent::m_Range); + .def_readwrite("ScenePos", &AlarmEvent::m_ScenePos) + .def_readwrite("Team", &AlarmEvent::m_Team) + .def_readwrite("Range", &AlarmEvent::m_Range); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(MiscLuaBindings, Directions) { return luabind::class_("Directions") - .enum_("Directions")[ - luabind::value("None", Directions::None), - luabind::value("Up", Directions::Up), - luabind::value("Down", Directions::Down), - luabind::value("Left", Directions::Left), - luabind::value("Right", Directions::Right), - luabind::value("Any", Directions::Any) - ]; + .enum_("Directions")[luabind::value("None", Directions::None), + luabind::value("Up", Directions::Up), + luabind::value("Down", Directions::Down), + luabind::value("Left", Directions::Left), + luabind::value("Right", Directions::Right), + luabind::value("Any", Directions::Any)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(MiscLuaBindings, DrawBlendMode) { return luabind::class_("DrawBlendMode") - .enum_("DrawBlendMode")[ - luabind::value("NoBlend", DrawBlendMode::NoBlend), - luabind::value("Burn", DrawBlendMode::BlendBurn), - luabind::value("Color", DrawBlendMode::BlendColor), - luabind::value("Difference", DrawBlendMode::BlendDifference), - luabind::value("Dissolve", DrawBlendMode::BlendDissolve), - luabind::value("Dodge", DrawBlendMode::BlendDodge), - luabind::value("Invert", DrawBlendMode::BlendInvert), - luabind::value("Luminance", DrawBlendMode::BlendLuminance), - luabind::value("Multiply", DrawBlendMode::BlendMultiply), - luabind::value("Saturation", DrawBlendMode::BlendSaturation), - luabind::value("Screen", DrawBlendMode::BlendScreen), - luabind::value("Transparency", DrawBlendMode::BlendTransparency), - luabind::value("BlendModeCount", DrawBlendMode::BlendModeCount) - ]; + .enum_("DrawBlendMode")[luabind::value("NoBlend", DrawBlendMode::NoBlend), + luabind::value("Burn", DrawBlendMode::BlendBurn), + luabind::value("Color", DrawBlendMode::BlendColor), + luabind::value("Difference", DrawBlendMode::BlendDifference), + luabind::value("Dissolve", DrawBlendMode::BlendDissolve), + luabind::value("Dodge", DrawBlendMode::BlendDodge), + luabind::value("Invert", DrawBlendMode::BlendInvert), + luabind::value("Luminance", DrawBlendMode::BlendLuminance), + luabind::value("Multiply", DrawBlendMode::BlendMultiply), + luabind::value("Saturation", DrawBlendMode::BlendSaturation), + luabind::value("Screen", DrawBlendMode::BlendScreen), + luabind::value("Transparency", DrawBlendMode::BlendTransparency), + luabind::value("BlendModeCount", DrawBlendMode::BlendModeCount)]; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuaBindingsPrimitives.cpp b/Source/Lua/LuaBindingsPrimitives.cpp index ae3ac4726..57fc5171c 100644 --- a/Source/Lua/LuaBindingsPrimitives.cpp +++ b/Source/Lua/LuaBindingsPrimitives.cpp @@ -4,130 +4,130 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, GraphicalPrimitive) { return luabind::class_("GraphicalPrimitive"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, LinePrimitive) { return luabind::class_("LinePrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, ArcPrimitive) { return luabind::class_("ArcPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, SplinePrimitive) { return luabind::class_("SplinePrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, BoxPrimitive) { return luabind::class_("BoxPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, BoxFillPrimitive) { return luabind::class_("BoxFillPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, RoundedBoxPrimitive) { return luabind::class_("RoundedBoxPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, RoundedBoxFillPrimitive) { return luabind::class_("RoundedBoxFillPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, CirclePrimitive) { return luabind::class_("CirclePrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, CircleFillPrimitive) { return luabind::class_("CircleFillPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, EllipsePrimitive) { return luabind::class_("EllipsePrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, EllipseFillPrimitive) { return luabind::class_("EllipseFillPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, TrianglePrimitive) { return luabind::class_("TrianglePrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, TriangleFillPrimitive) { return luabind::class_("TriangleFillPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, TextPrimitive) { return luabind::class_("TextPrimitive") - .def(luabind::constructor()); + .def(luabind::constructor()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(PrimitiveLuaBindings, BitmapPrimitive) { return luabind::class_("BitmapPrimitive") - .def(luabind::constructor()) - .def(luabind::constructor()); + .def(luabind::constructor()) + .def(luabind::constructor()); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuaBindingsSystem.cpp b/Source/Lua/LuaBindingsSystem.cpp index 03a9eb55f..2e964d799 100644 --- a/Source/Lua/LuaBindingsSystem.cpp +++ b/Source/Lua/LuaBindingsSystem.cpp @@ -4,252 +4,246 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(SystemLuaBindings, Box) { return luabind::class_("Box") - .def(luabind::constructor<>()) - .def(luabind::constructor()) - .def(luabind::constructor()) - .def(luabind::constructor()) - .def(luabind::constructor()) - .def(luabind::self == luabind::other()) - - .property("ClassName", &Box::GetClassName) - .property("Corner", &Box::GetCorner, &Box::SetCorner) - .property("Width", &Box::GetWidth, &Box::SetWidth) - .property("Height", &Box::GetHeight, &Box::SetHeight) - .property("Center", &Box::GetCenter, &Box::SetCenter) - .property("Area", &Box::GetArea) - - .def("GetRandomPoint", &Box::GetRandomPoint) - .def("Unflip", &Box::Unflip) - .def("IsWithinBox", &Box::IsWithinBox) - .def("IsWithinBoxX", &Box::IsWithinBoxX) - .def("IsWithinBoxY", &Box::IsWithinBoxY) - .def("GetWithinBoxX", &Box::GetWithinBoxX) - .def("GetWithinBoxY", &Box::GetWithinBoxY) - .def("GetWithinBox", &Box::GetWithinBox) - .def("IntersectsBox", &Box::IntersectsBox); + .def(luabind::constructor<>()) + .def(luabind::constructor()) + .def(luabind::constructor()) + .def(luabind::constructor()) + .def(luabind::constructor()) + .def(luabind::self == luabind::other()) + + .property("ClassName", &Box::GetClassName) + .property("Corner", &Box::GetCorner, &Box::SetCorner) + .property("Width", &Box::GetWidth, &Box::SetWidth) + .property("Height", &Box::GetHeight, &Box::SetHeight) + .property("Center", &Box::GetCenter, &Box::SetCenter) + .property("Area", &Box::GetArea) + + .def("GetRandomPoint", &Box::GetRandomPoint) + .def("Unflip", &Box::Unflip) + .def("IsWithinBox", &Box::IsWithinBox) + .def("IsWithinBoxX", &Box::IsWithinBoxX) + .def("IsWithinBoxY", &Box::IsWithinBoxY) + .def("GetWithinBoxX", &Box::GetWithinBoxX) + .def("GetWithinBoxY", &Box::GetWithinBoxY) + .def("GetWithinBox", &Box::GetWithinBox) + .def("IntersectsBox", &Box::IntersectsBox); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(SystemLuaBindings, Controller) { return luabind::class_("Controller") - .def(luabind::constructor<>()) - - .property("InputMode", &Controller::GetInputMode, &Controller::SetInputMode) - .property("ControlledActor", &Controller::GetControlledActor, &Controller::SetControlledActor) - .property("Team", &Controller::GetTeam, &Controller::SetTeam) - .property("AnalogMove", &Controller::GetAnalogMove, &Controller::SetAnalogMove) - .property("AnalogAim", &Controller::GetAnalogAim, &Controller::SetAnalogAim) - .property("AnalogCursor", &Controller::GetAnalogCursor, &Controller::SetAnalogCursor) - .property("Player", &Controller::GetPlayer, &Controller::SetPlayer) - .property("MouseMovement", &Controller::GetMouseMovement) - .property("Disabled", &Controller::IsDisabled, &Controller::SetDisabled) - - .def("IsPlayerControlled", &Controller::IsPlayerControlled) - .def("RelativeCursorMovement", &Controller::RelativeCursorMovement) - .def("IsMouseControlled", &Controller::IsMouseControlled) - .def("IsKeyboardOnlyControlled", &Controller::IsKeyboardOnlyControlled) - .def("IsGamepadControlled", &Controller::IsGamepadControlled) - .def("SetState", &Controller::SetState) - .def("IsState", &Controller::IsState) - .def("Override", &Controller::Override) - - .enum_("ControlState")[ - luabind::value("PRIMARY_ACTION", ControlState::PRIMARY_ACTION), - luabind::value("SECONDARY_ACTION", ControlState::SECONDARY_ACTION), - luabind::value("MOVE_IDLE", ControlState::MOVE_IDLE), - luabind::value("MOVE_RIGHT", ControlState::MOVE_RIGHT), - luabind::value("MOVE_LEFT", ControlState::MOVE_LEFT), - luabind::value("MOVE_UP", ControlState::MOVE_UP), - luabind::value("MOVE_DOWN", ControlState::MOVE_DOWN), - luabind::value("MOVE_FAST", ControlState::MOVE_FAST), - luabind::value("BODY_JUMPSTART", ControlState::BODY_JUMPSTART), - luabind::value("BODY_JUMP", ControlState::BODY_JUMP), - luabind::value("BODY_CROUCH", ControlState::BODY_CROUCH), - luabind::value("AIM_UP", ControlState::AIM_UP), - luabind::value("AIM_DOWN", ControlState::AIM_DOWN), - luabind::value("AIM_SHARP", ControlState::AIM_SHARP), - luabind::value("WEAPON_FIRE", ControlState::WEAPON_FIRE), - luabind::value("WEAPON_RELOAD", ControlState::WEAPON_RELOAD), - luabind::value("PIE_MENU_OPENED", ControlState::PIE_MENU_OPENED), - luabind::value("PIE_MENU_ACTIVE", ControlState::PIE_MENU_ACTIVE), - luabind::value("WEAPON_CHANGE_NEXT", ControlState::WEAPON_CHANGE_NEXT), - luabind::value("WEAPON_CHANGE_PREV", ControlState::WEAPON_CHANGE_PREV), - luabind::value("WEAPON_PICKUP", ControlState::WEAPON_PICKUP), - luabind::value("WEAPON_DROP", ControlState::WEAPON_DROP), - luabind::value("ACTOR_NEXT", ControlState::ACTOR_NEXT), - luabind::value("ACTOR_PREV", ControlState::ACTOR_PREV), - luabind::value("ACTOR_BRAIN", ControlState::ACTOR_BRAIN), - luabind::value("ACTOR_NEXT_PREP", ControlState::ACTOR_NEXT_PREP), - luabind::value("ACTOR_PREV_PREP", ControlState::ACTOR_PREV_PREP), - luabind::value("HOLD_RIGHT", ControlState::HOLD_RIGHT), - luabind::value("HOLD_LEFT", ControlState::HOLD_LEFT), - luabind::value("HOLD_UP", ControlState::HOLD_UP), - luabind::value("HOLD_DOWN", ControlState::HOLD_DOWN), - luabind::value("PRESS_PRIMARY", ControlState::PRESS_PRIMARY), - luabind::value("PRESS_SECONDARY", ControlState::PRESS_SECONDARY), - luabind::value("PRESS_RIGHT", ControlState::PRESS_RIGHT), - luabind::value("PRESS_LEFT", ControlState::PRESS_LEFT), - luabind::value("PRESS_UP", ControlState::PRESS_UP), - luabind::value("PRESS_DOWN", ControlState::PRESS_DOWN), - luabind::value("RELEASE_PRIMARY", ControlState::RELEASE_PRIMARY), - luabind::value("RELEASE_SECONDARY", ControlState::RELEASE_SECONDARY), - luabind::value("PRESS_FACEBUTTON", ControlState::PRESS_FACEBUTTON), - luabind::value("RELEASE_FACEBUTTON", ControlState::RELEASE_FACEBUTTON), - luabind::value("SCROLL_UP", ControlState::SCROLL_UP), - luabind::value("SCROLL_DOWN", ControlState::SCROLL_DOWN), - luabind::value("DEBUG_ONE", ControlState::DEBUG_ONE), - luabind::value("CONTROLSTATECOUNT", ControlState::CONTROLSTATECOUNT) - ] - .enum_("InputMode")[ - luabind::value("CIM_DISABLED", Controller::InputMode::CIM_DISABLED), - luabind::value("CIM_PLAYER", Controller::InputMode::CIM_PLAYER), - luabind::value("CIM_AI", Controller::InputMode::CIM_AI), - luabind::value("CIM_NETWORK", Controller::InputMode::CIM_NETWORK), - luabind::value("CIM_INPUTMODECOUNT", Controller::InputMode::CIM_INPUTMODECOUNT) - ]; + .def(luabind::constructor<>()) + + .property("InputMode", &Controller::GetInputMode, &Controller::SetInputMode) + .property("ControlledActor", &Controller::GetControlledActor, &Controller::SetControlledActor) + .property("Team", &Controller::GetTeam, &Controller::SetTeam) + .property("AnalogMove", &Controller::GetAnalogMove, &Controller::SetAnalogMove) + .property("AnalogAim", &Controller::GetAnalogAim, &Controller::SetAnalogAim) + .property("AnalogCursor", &Controller::GetAnalogCursor, &Controller::SetAnalogCursor) + .property("Player", &Controller::GetPlayer, &Controller::SetPlayer) + .property("MouseMovement", &Controller::GetMouseMovement) + .property("Disabled", &Controller::IsDisabled, &Controller::SetDisabled) + + .def("IsPlayerControlled", &Controller::IsPlayerControlled) + .def("RelativeCursorMovement", &Controller::RelativeCursorMovement) + .def("IsMouseControlled", &Controller::IsMouseControlled) + .def("IsKeyboardOnlyControlled", &Controller::IsKeyboardOnlyControlled) + .def("IsGamepadControlled", &Controller::IsGamepadControlled) + .def("SetState", &Controller::SetState) + .def("IsState", &Controller::IsState) + .def("Override", &Controller::Override) + + .enum_("ControlState")[luabind::value("PRIMARY_ACTION", ControlState::PRIMARY_ACTION), + luabind::value("SECONDARY_ACTION", ControlState::SECONDARY_ACTION), + luabind::value("MOVE_IDLE", ControlState::MOVE_IDLE), + luabind::value("MOVE_RIGHT", ControlState::MOVE_RIGHT), + luabind::value("MOVE_LEFT", ControlState::MOVE_LEFT), + luabind::value("MOVE_UP", ControlState::MOVE_UP), + luabind::value("MOVE_DOWN", ControlState::MOVE_DOWN), + luabind::value("MOVE_FAST", ControlState::MOVE_FAST), + luabind::value("BODY_JUMPSTART", ControlState::BODY_JUMPSTART), + luabind::value("BODY_JUMP", ControlState::BODY_JUMP), + luabind::value("BODY_CROUCH", ControlState::BODY_CROUCH), + luabind::value("AIM_UP", ControlState::AIM_UP), + luabind::value("AIM_DOWN", ControlState::AIM_DOWN), + luabind::value("AIM_SHARP", ControlState::AIM_SHARP), + luabind::value("WEAPON_FIRE", ControlState::WEAPON_FIRE), + luabind::value("WEAPON_RELOAD", ControlState::WEAPON_RELOAD), + luabind::value("PIE_MENU_OPENED", ControlState::PIE_MENU_OPENED), + luabind::value("PIE_MENU_ACTIVE", ControlState::PIE_MENU_ACTIVE), + luabind::value("WEAPON_CHANGE_NEXT", ControlState::WEAPON_CHANGE_NEXT), + luabind::value("WEAPON_CHANGE_PREV", ControlState::WEAPON_CHANGE_PREV), + luabind::value("WEAPON_PICKUP", ControlState::WEAPON_PICKUP), + luabind::value("WEAPON_DROP", ControlState::WEAPON_DROP), + luabind::value("ACTOR_NEXT", ControlState::ACTOR_NEXT), + luabind::value("ACTOR_PREV", ControlState::ACTOR_PREV), + luabind::value("ACTOR_BRAIN", ControlState::ACTOR_BRAIN), + luabind::value("ACTOR_NEXT_PREP", ControlState::ACTOR_NEXT_PREP), + luabind::value("ACTOR_PREV_PREP", ControlState::ACTOR_PREV_PREP), + luabind::value("HOLD_RIGHT", ControlState::HOLD_RIGHT), + luabind::value("HOLD_LEFT", ControlState::HOLD_LEFT), + luabind::value("HOLD_UP", ControlState::HOLD_UP), + luabind::value("HOLD_DOWN", ControlState::HOLD_DOWN), + luabind::value("PRESS_PRIMARY", ControlState::PRESS_PRIMARY), + luabind::value("PRESS_SECONDARY", ControlState::PRESS_SECONDARY), + luabind::value("PRESS_RIGHT", ControlState::PRESS_RIGHT), + luabind::value("PRESS_LEFT", ControlState::PRESS_LEFT), + luabind::value("PRESS_UP", ControlState::PRESS_UP), + luabind::value("PRESS_DOWN", ControlState::PRESS_DOWN), + luabind::value("RELEASE_PRIMARY", ControlState::RELEASE_PRIMARY), + luabind::value("RELEASE_SECONDARY", ControlState::RELEASE_SECONDARY), + luabind::value("PRESS_FACEBUTTON", ControlState::PRESS_FACEBUTTON), + luabind::value("RELEASE_FACEBUTTON", ControlState::RELEASE_FACEBUTTON), + luabind::value("SCROLL_UP", ControlState::SCROLL_UP), + luabind::value("SCROLL_DOWN", ControlState::SCROLL_DOWN), + luabind::value("DEBUG_ONE", ControlState::DEBUG_ONE), + luabind::value("CONTROLSTATECOUNT", ControlState::CONTROLSTATECOUNT)] + .enum_("InputMode")[luabind::value("CIM_DISABLED", Controller::InputMode::CIM_DISABLED), + luabind::value("CIM_PLAYER", Controller::InputMode::CIM_PLAYER), + luabind::value("CIM_AI", Controller::InputMode::CIM_AI), + luabind::value("CIM_NETWORK", Controller::InputMode::CIM_NETWORK), + luabind::value("CIM_INPUTMODECOUNT", Controller::InputMode::CIM_INPUTMODECOUNT)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(SystemLuaBindings, DataModule) { return luabind::class_("DataModule") - .property("FileName", &DataModule::GetFileName) - .property("FriendlyName", &DataModule::GetFriendlyName) - .property("Author", &DataModule::GetAuthor) - .property("Description", &DataModule::GetDescription) - .property("Version", &DataModule::GetVersionNumber) - .property("IsFaction", &DataModule::IsFaction) - .property("IsMerchant", &DataModule::IsMerchant) + .property("FileName", &DataModule::GetFileName) + .property("FriendlyName", &DataModule::GetFriendlyName) + .property("Author", &DataModule::GetAuthor) + .property("Description", &DataModule::GetDescription) + .property("Version", &DataModule::GetVersionNumber) + .property("IsFaction", &DataModule::IsFaction) + .property("IsMerchant", &DataModule::IsMerchant) - .def_readwrite("Presets", &DataModule::m_EntityList, luabind::return_stl_iterator); + .def_readwrite("Presets", &DataModule::m_EntityList, luabind::return_stl_iterator); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(SystemLuaBindings, Timer) { return luabind::class_("Timer") - .def(luabind::constructor<>()) - .def(luabind::constructor()) - .def(luabind::constructor()) - - .property("StartRealTimeMS", &Timer::GetStartRealTimeMS, &Timer::SetStartRealTimeMS) - .property("ElapsedRealTimeS", &Timer::GetElapsedRealTimeS, &Timer::SetElapsedRealTimeS) - .property("ElapsedRealTimeMS", &Timer::GetElapsedRealTimeMS, &Timer::SetElapsedRealTimeMS) - .property("StartSimTimeMS", &Timer::GetStartSimTimeMS, &Timer::SetStartSimTimeMS) - .property("ElapsedSimTimeS", &Timer::GetElapsedSimTimeS, &Timer::SetElapsedSimTimeS) - .property("ElapsedSimTimeMS", &Timer::GetElapsedSimTimeMS, &Timer::SetElapsedSimTimeMS) - .property("RealTimeLimitProgress", &Timer::RealTimeLimitProgress) - .property("SimTimeLimitProgress", &Timer::SimTimeLimitProgress) - - .def("Reset", &Timer::Reset) - .def("SetRealTimeLimitMS", &Timer::SetRealTimeLimitMS) - .def("SetRealTimeLimitS", &Timer::SetRealTimeLimitS) - .def("IsPastRealTimeLimit", &Timer::IsPastRealTimeLimit) - .def("LeftTillRealTimeLimitMS", &Timer::LeftTillRealTimeLimitMS) - .def("LeftTillRealTimeLimitS", &Timer::LeftTillRealTimeLimitS) - .def("LeftTillRealMS", &Timer::LeftTillRealMS) - .def("IsPastRealMS", &Timer::IsPastRealMS) - .def("AlternateReal", &Timer::AlternateReal) - .def("GetSimTimeLimitMS", &Timer::GetSimTimeLimitMS) - .def("SetSimTimeLimitMS", &Timer::SetSimTimeLimitMS) - .def("GetSimTimeLimitS", &Timer::GetSimTimeLimitS) - .def("SetSimTimeLimitS", &Timer::SetSimTimeLimitS) - .def("IsPastSimTimeLimit", &Timer::IsPastSimTimeLimit) - .def("LeftTillSimTimeLimitMS", &Timer::LeftTillSimTimeLimitMS) - .def("LeftTillSimTimeLimitS", &Timer::LeftTillSimTimeLimitS) - .def("LeftTillSimMS", &Timer::LeftTillSimMS) - .def("IsPastSimMS", &Timer::IsPastSimMS) - .def("AlternateSim", &Timer::AlternateSim); + .def(luabind::constructor<>()) + .def(luabind::constructor()) + .def(luabind::constructor()) + + .property("StartRealTimeMS", &Timer::GetStartRealTimeMS, &Timer::SetStartRealTimeMS) + .property("ElapsedRealTimeS", &Timer::GetElapsedRealTimeS, &Timer::SetElapsedRealTimeS) + .property("ElapsedRealTimeMS", &Timer::GetElapsedRealTimeMS, &Timer::SetElapsedRealTimeMS) + .property("StartSimTimeMS", &Timer::GetStartSimTimeMS, &Timer::SetStartSimTimeMS) + .property("ElapsedSimTimeS", &Timer::GetElapsedSimTimeS, &Timer::SetElapsedSimTimeS) + .property("ElapsedSimTimeMS", &Timer::GetElapsedSimTimeMS, &Timer::SetElapsedSimTimeMS) + .property("RealTimeLimitProgress", &Timer::RealTimeLimitProgress) + .property("SimTimeLimitProgress", &Timer::SimTimeLimitProgress) + + .def("Reset", &Timer::Reset) + .def("SetRealTimeLimitMS", &Timer::SetRealTimeLimitMS) + .def("SetRealTimeLimitS", &Timer::SetRealTimeLimitS) + .def("IsPastRealTimeLimit", &Timer::IsPastRealTimeLimit) + .def("LeftTillRealTimeLimitMS", &Timer::LeftTillRealTimeLimitMS) + .def("LeftTillRealTimeLimitS", &Timer::LeftTillRealTimeLimitS) + .def("LeftTillRealMS", &Timer::LeftTillRealMS) + .def("IsPastRealMS", &Timer::IsPastRealMS) + .def("AlternateReal", &Timer::AlternateReal) + .def("GetSimTimeLimitMS", &Timer::GetSimTimeLimitMS) + .def("SetSimTimeLimitMS", &Timer::SetSimTimeLimitMS) + .def("GetSimTimeLimitS", &Timer::GetSimTimeLimitS) + .def("SetSimTimeLimitS", &Timer::SetSimTimeLimitS) + .def("IsPastSimTimeLimit", &Timer::IsPastSimTimeLimit) + .def("LeftTillSimTimeLimitMS", &Timer::LeftTillSimTimeLimitMS) + .def("LeftTillSimTimeLimitS", &Timer::LeftTillSimTimeLimitS) + .def("LeftTillSimMS", &Timer::LeftTillSimMS) + .def("IsPastSimMS", &Timer::IsPastSimMS) + .def("AlternateSim", &Timer::AlternateSim); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(SystemLuaBindings, Vector) { return luabind::class_("Vector") - .def(luabind::constructor<>()) - .def(luabind::constructor()) - .def(luabind::self == luabind::other()) - .def(luabind::const_self + luabind::other()) - .def(luabind::const_self - luabind::other()) - .def(luabind::const_self * float()) - .def(luabind::const_self / float()) - .def(luabind::tostring(luabind::const_self)) - - .property("ClassName", &Vector::GetClassName) - .property("RoundedX", &Vector::GetRoundIntX) - .property("RoundedY", &Vector::GetRoundIntY) - .property("Rounded", &Vector::GetRounded) - .property("FlooredX", &Vector::GetFloorIntX) - .property("FlooredY", &Vector::GetFloorIntY) - .property("Floored", &Vector::GetFloored) - .property("CeilingedX", &Vector::GetCeilingIntX) - .property("CeilingedY", &Vector::GetCeilingIntY) - .property("Ceilinged", &Vector::GetCeilinged) - .property("Magnitude", &Vector::GetMagnitude) - .property("SqrMagnitude", &Vector::GetSqrMagnitude) - .property("Largest", &Vector::GetLargest) - .property("Smallest", &Vector::GetSmallest) - .property("Normalized", &Vector::GetNormalized) - .property("Perpendicular", &Vector::GetPerpendicular) - .property("AbsRadAngle", &Vector::GetAbsRadAngle, &Vector::SetAbsRadAngle) - .property("AbsDegAngle", &Vector::GetAbsDegAngle, &Vector::SetAbsDegAngle) - - .def_readwrite("X", &Vector::m_X) - .def_readwrite("Y", &Vector::m_Y) - - .def("MagnitudeIsGreaterThan", &Vector::MagnitudeIsGreaterThan) - .def("MagnitudeIsLessThan", &Vector::MagnitudeIsLessThan) - .def("SetMagnitude", &Vector::SetMagnitude) - .def("GetXFlipped", &Vector::GetXFlipped) - .def("GetYFlipped", &Vector::GetYFlipped) - .def("CapMagnitude", &Vector::CapMagnitude) - .def("ClampMagnitude", &Vector::ClampMagnitude) - .def("FlipX", &Vector::FlipX) - .def("FlipY", &Vector::FlipY) - .def("IsZero", &Vector::IsZero) - .def("IsOpposedTo", &Vector::IsOpposedTo) - .def("Dot", &Vector::Dot) - .def("Cross", &Vector::Cross) - .def("Round", &Vector::Round) - .def("ToHalf", &Vector::ToHalf) - .def("Floor", &Vector::Floor) - .def("Ceiling", &Vector::Ceiling) - .def("Normalize", &Vector::Normalize) - .def("Perpendicularize", &Vector::Perpendicularize) - .def("Reset", &Vector::Reset) - .def("RadRotate", &Vector::RadRotate) - .def("DegRotate", &Vector::DegRotate) - .def("GetRadRotatedCopy", &Vector::GetRadRotatedCopy) - .def("GetDegRotatedCopy", &Vector::GetDegRotatedCopy) - .def("AbsRotateTo", &Vector::AbsRotateTo) - .def("SetXY", &Vector::SetXY); + .def(luabind::constructor<>()) + .def(luabind::constructor()) + .def(luabind::self == luabind::other()) + .def(luabind::const_self + luabind::other()) + .def(luabind::const_self - luabind::other()) + .def(luabind::const_self * float()) + .def(luabind::const_self / float()) + .def(luabind::tostring(luabind::const_self)) + + .property("ClassName", &Vector::GetClassName) + .property("RoundedX", &Vector::GetRoundIntX) + .property("RoundedY", &Vector::GetRoundIntY) + .property("Rounded", &Vector::GetRounded) + .property("FlooredX", &Vector::GetFloorIntX) + .property("FlooredY", &Vector::GetFloorIntY) + .property("Floored", &Vector::GetFloored) + .property("CeilingedX", &Vector::GetCeilingIntX) + .property("CeilingedY", &Vector::GetCeilingIntY) + .property("Ceilinged", &Vector::GetCeilinged) + .property("Magnitude", &Vector::GetMagnitude) + .property("SqrMagnitude", &Vector::GetSqrMagnitude) + .property("Largest", &Vector::GetLargest) + .property("Smallest", &Vector::GetSmallest) + .property("Normalized", &Vector::GetNormalized) + .property("Perpendicular", &Vector::GetPerpendicular) + .property("AbsRadAngle", &Vector::GetAbsRadAngle, &Vector::SetAbsRadAngle) + .property("AbsDegAngle", &Vector::GetAbsDegAngle, &Vector::SetAbsDegAngle) + + .def_readwrite("X", &Vector::m_X) + .def_readwrite("Y", &Vector::m_Y) + + .def("MagnitudeIsGreaterThan", &Vector::MagnitudeIsGreaterThan) + .def("MagnitudeIsLessThan", &Vector::MagnitudeIsLessThan) + .def("SetMagnitude", &Vector::SetMagnitude) + .def("GetXFlipped", &Vector::GetXFlipped) + .def("GetYFlipped", &Vector::GetYFlipped) + .def("CapMagnitude", &Vector::CapMagnitude) + .def("ClampMagnitude", &Vector::ClampMagnitude) + .def("FlipX", &Vector::FlipX) + .def("FlipY", &Vector::FlipY) + .def("IsZero", &Vector::IsZero) + .def("IsOpposedTo", &Vector::IsOpposedTo) + .def("Dot", &Vector::Dot) + .def("Cross", &Vector::Cross) + .def("Round", &Vector::Round) + .def("ToHalf", &Vector::ToHalf) + .def("Floor", &Vector::Floor) + .def("Ceiling", &Vector::Ceiling) + .def("Normalize", &Vector::Normalize) + .def("Perpendicularize", &Vector::Perpendicularize) + .def("Reset", &Vector::Reset) + .def("RadRotate", &Vector::RadRotate) + .def("DegRotate", &Vector::DegRotate) + .def("GetRadRotatedCopy", &Vector::GetRadRotatedCopy) + .def("GetDegRotatedCopy", &Vector::GetDegRotatedCopy) + .def("AbsRotateTo", &Vector::AbsRotateTo) + .def("SetXY", &Vector::SetXY); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LuaBindingRegisterFunctionDefinitionForType(SystemLuaBindings, PathRequest) { using namespace micropather; return luabind::class_("PathRequest") - .def_readonly("Path", &PathRequest::path, luabind::return_stl_iterator) - .def_readonly("PathLength", &PathRequest::pathLength) - .def_readonly("Status", &PathRequest::status) - .def_readonly("TotalCost", &PathRequest::totalCost) + .def_readonly("Path", &PathRequest::path, luabind::return_stl_iterator) + .def_readonly("PathLength", &PathRequest::pathLength) + .def_readonly("Status", &PathRequest::status) + .def_readonly("TotalCost", &PathRequest::totalCost) - .enum_("Status")[ - luabind::value("Solved", micropather::MicroPather::SOLVED), - luabind::value("NoSolution", micropather::MicroPather::NO_SOLUTION), - luabind::value("StartEndSame", micropather::MicroPather::START_END_SAME) - ]; + .enum_("Status")[luabind::value("Solved", micropather::MicroPather::SOLVED), + luabind::value("NoSolution", micropather::MicroPather::NO_SOLUTION), + luabind::value("StartEndSame", micropather::MicroPather::START_END_SAME)]; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuabindDefinitions.h b/Source/Lua/LuabindDefinitions.h index 31507a386..c28be35b2 100644 --- a/Source/Lua/LuabindDefinitions.h +++ b/Source/Lua/LuabindDefinitions.h @@ -22,7 +22,7 @@ namespace luabind { /// /// The smart pointer to get raw pointer for. /// Raw pointer of the passed in smart pointer. - template Type * get_pointer(boost::shared_ptr &ptr) { + template Type* get_pointer(boost::shared_ptr& ptr) { return ptr.get(); } @@ -30,7 +30,7 @@ namespace luabind { /// Can't have global enums in the master state so we use this dummy struct as a class and register the enums under it. /// struct enum_wrapper {}; -} +} // namespace luabind namespace RTE { /// @@ -55,7 +55,7 @@ namespace RTE { /// /// The Lua master state. /// An error signal, 1, so Lua correctly reports that there's been an error. - static int AddFileAndLineToError(lua_State *luaState) { + static int AddFileAndLineToError(lua_State* luaState) { lua_Debug luaDebug; if (lua_getstack(luaState, 2, &luaDebug) > 0) { lua_getinfo(luaState, "Sln", &luaDebug); @@ -79,7 +79,7 @@ namespace RTE { /// The Lua table object to convert to vector. /// A C++ vector containing all the objects from the Lua table. Ownership is transferred! /// In case of type mismatch (by specifying wrong type or a mix of types in the Lua table) object_cast will print an error to the console and throw, so no need to check what it returns before emplacing. - template static std::vector ConvertLuaTableToVectorOfType(const luabind::object &luaObject) { + template static std::vector ConvertLuaTableToVectorOfType(const luabind::object& luaObject) { std::vector outVector = {}; if (luaObject.is_valid() && luabind::type(luaObject) == LUA_TTABLE) { for (luabind::iterator tableItr(luaObject), tableEnd; tableItr != tableEnd; ++tableItr) { @@ -88,5 +88,5 @@ namespace RTE { } return outVector; } -} +} // namespace RTE #endif diff --git a/Source/Lua/LuabindObjectWrapper.cpp b/Source/Lua/LuabindObjectWrapper.cpp index 5ab34c37c..e02a9e9b7 100644 --- a/Source/Lua/LuabindObjectWrapper.cpp +++ b/Source/Lua/LuabindObjectWrapper.cpp @@ -7,77 +7,72 @@ namespace RTE { -// With multithreaded Lua, objects can be destructed from multiple threads at once -// This is okay, but LuaBind wants to do some management on the lua state when one of it's objects is deleted -// This means that potentially an object being deleted by one lua state actually exists in another lua state -// And upon deletion, it's unsafe for LuaBind to poke at the state until we're out the multithreaded context -// As such, we don't actually delete the object until we're in a safe environment outside the multithreaded parts -// Note - this is required even though we force objects in multithreaded environments to be within our Lua state -// This is because we may assign an object to another state in a singlethreaded context, before the GC runs in the multithreaded context -static std::vector s_QueuedDeletions; - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void LuabindObjectWrapper::ApplyQueuedDeletions() { - for (luabind::adl::object *obj : s_QueuedDeletions) { - delete obj; - } - - s_QueuedDeletions.clear(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // With multithreaded Lua, objects can be destructed from multiple threads at once + // This is okay, but LuaBind wants to do some management on the lua state when one of it's objects is deleted + // This means that potentially an object being deleted by one lua state actually exists in another lua state + // And upon deletion, it's unsafe for LuaBind to poke at the state until we're out the multithreaded context + // As such, we don't actually delete the object until we're in a safe environment outside the multithreaded parts + // Note - this is required even though we force objects in multithreaded environments to be within our Lua state + // This is because we may assign an object to another state in a singlethreaded context, before the GC runs in the multithreaded context + static std::vector s_QueuedDeletions; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void LuabindObjectWrapper::ApplyQueuedDeletions() { + for (luabind::adl::object* obj: s_QueuedDeletions) { + delete obj; + } -LuabindObjectWrapper::~LuabindObjectWrapper() { - if (m_OwnsObject) { - static std::mutex mut; - std::lock_guard guard(mut); - s_QueuedDeletions.push_back(m_LuabindObject); + s_QueuedDeletions.clear(); } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -luabind::adl::object GetCopyForStateInternal(const luabind::adl::object& obj, lua_State& targetState) { - if (obj.is_valid()) { - int type = luabind::type(obj); - if (type == LUA_TNUMBER) { - return luabind::adl::object(&targetState, luabind::object_cast(obj)); - } - else if (type == LUA_TBOOLEAN) { - return luabind::adl::object(&targetState, luabind::object_cast(obj)); - } - else if (type == LUA_TSTRING) { - return luabind::adl::object(&targetState, luabind::object_cast(obj)); - } - else if (type == LUA_TTABLE) { - luabind::object table = luabind::newtable(&targetState); - for (luabind::iterator itr(obj), itrEnd; itr != itrEnd; ++itr) { - table[GetCopyForStateInternal(itr.key(), targetState)] = GetCopyForStateInternal(*itr, targetState); - } - return table; + LuabindObjectWrapper::~LuabindObjectWrapper() { + if (m_OwnsObject) { + static std::mutex mut; + std::lock_guard guard(mut); + s_QueuedDeletions.push_back(m_LuabindObject); } - else if (type == LUA_TUSERDATA) { -#define PER_LUA_BINDING(Type) \ - if (boost::optional boundObject = luabind::object_cast_nothrow(obj)) { \ - return luabind::adl::object(&targetState, boundObject.get()); \ - } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + luabind::adl::object GetCopyForStateInternal(const luabind::adl::object& obj, lua_State& targetState) { + if (obj.is_valid()) { + int type = luabind::type(obj); + if (type == LUA_TNUMBER) { + return luabind::adl::object(&targetState, luabind::object_cast(obj)); + } else if (type == LUA_TBOOLEAN) { + return luabind::adl::object(&targetState, luabind::object_cast(obj)); + } else if (type == LUA_TSTRING) { + return luabind::adl::object(&targetState, luabind::object_cast(obj)); + } else if (type == LUA_TTABLE) { + luabind::object table = luabind::newtable(&targetState); + for (luabind::iterator itr(obj), itrEnd; itr != itrEnd; ++itr) { + table[GetCopyForStateInternal(itr.key(), targetState)] = GetCopyForStateInternal(*itr, targetState); + } + return table; + } else if (type == LUA_TUSERDATA) { +#define PER_LUA_BINDING(Type) \ + if (boost::optional boundObject = luabind::object_cast_nothrow(obj)) { \ + return luabind::adl::object(&targetState, boundObject.get()); \ + } - LIST_OF_LUABOUND_OBJECTS + LIST_OF_LUABOUND_OBJECTS #undef PER_LUA_BINDING + } } + // Dear god, I hope this is safe and equivalent to nil, because I can't find another way of doing it. + return luabind::adl::object(); } - // Dear god, I hope this is safe and equivalent to nil, because I can't find another way of doing it. - return luabind::adl::object(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -LuabindObjectWrapper LuabindObjectWrapper::GetCopyForState(lua_State& targetState) const { - luabind::adl::object* copy = new luabind::adl::object(GetCopyForStateInternal(*m_LuabindObject, targetState)); - return LuabindObjectWrapper(copy, m_FilePath, true); -} + LuabindObjectWrapper LuabindObjectWrapper::GetCopyForState(lua_State& targetState) const { + luabind::adl::object* copy = new luabind::adl::object(GetCopyForStateInternal(*m_LuabindObject, targetState)); + return LuabindObjectWrapper(copy, m_FilePath, true); + } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Lua/LuabindObjectWrapper.h b/Source/Lua/LuabindObjectWrapper.h index dc5b56b32..50f4861c4 100644 --- a/Source/Lua/LuabindObjectWrapper.h +++ b/Source/Lua/LuabindObjectWrapper.h @@ -11,14 +11,14 @@ namespace RTE { #pragma region Global Macro Definitions #define ScriptFunctionNames(...) \ - virtual std::vector GetSupportedScriptFunctionNames() const { return {__VA_ARGS__}; } + virtual std::vector GetSupportedScriptFunctionNames() const { return {__VA_ARGS__}; } #define AddScriptFunctionNames(PARENT, ...) \ - std::vector GetSupportedScriptFunctionNames() const override { \ - std::vector functionNames = PARENT::GetSupportedScriptFunctionNames(); \ - functionNames.insert(functionNames.end(), {__VA_ARGS__}); \ - return functionNames; \ - } + std::vector GetSupportedScriptFunctionNames() const override { \ + std::vector functionNames = PARENT::GetSupportedScriptFunctionNames(); \ + functionNames.insert(functionNames.end(), {__VA_ARGS__}); \ + return functionNames; \ + } #pragma endregion /// @@ -27,7 +27,6 @@ namespace RTE { class LuabindObjectWrapper { public: - #pragma region Creation /// /// Constructor method used for LuabindObjectWrapper. @@ -37,7 +36,8 @@ namespace RTE { /// /// Constructor method used to instantiate a LuabindObjectWrapper object in system memory. /// - explicit LuabindObjectWrapper(luabind::adl::object* luabindObject, const std::string_view& filePath, bool ownsObject = true) : m_LuabindObject(luabindObject), m_FilePath(filePath), m_OwnsObject(ownsObject) {} + explicit LuabindObjectWrapper(luabind::adl::object* luabindObject, const std::string_view& filePath, bool ownsObject = true) : + m_LuabindObject(luabindObject), m_FilePath(filePath), m_OwnsObject(ownsObject) {} #pragma endregion #pragma region Destruction @@ -59,24 +59,23 @@ namespace RTE { /// Gets the LuabindObjectWrapper's luabind object. Ownership is NOT transferred! /// /// The LuabindObjectWrapper's luabind object. - luabind::adl::object * GetLuabindObject() const { return m_LuabindObject; } + luabind::adl::object* GetLuabindObject() const { return m_LuabindObject; } /// /// Gets the LuabindObjectWrapper's file path. /// /// The LuabindObjectWrapper's file path. - const std::string & GetFilePath() const { return m_FilePath; } + const std::string& GetFilePath() const { return m_FilePath; } #pragma endregion private: - bool m_OwnsObject; //!< Whether or not we own the luabind object this is wrapping. - luabind::adl::object *m_LuabindObject; //!< The luabind object this is wrapping. + luabind::adl::object* m_LuabindObject; //!< The luabind object this is wrapping. std::string m_FilePath; //!< The filepath the wrapped luabind object represents, if it's a function. // Disallow the use of some implicit methods. - LuabindObjectWrapper(const LuabindObjectWrapper &reference) = delete; - LuabindObjectWrapper &operator=(const LuabindObjectWrapper &rhs) = delete; + LuabindObjectWrapper(const LuabindObjectWrapper& reference) = delete; + LuabindObjectWrapper& operator=(const LuabindObjectWrapper& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Lua/meson.build b/Source/Lua/meson.build index 2e4691f1b..f52ed9f64 100644 --- a/Source/Lua/meson.build +++ b/Source/Lua/meson.build @@ -23,4 +23,4 @@ error('Unsupported compiler') endif lua_bindings = static_library('lua_bindings', lua_sources, dependencies:deps + luabind_dep, include_directories: [source_inc_dirs, external_inc_dirs], cpp_args: luabindings_cpp_args, cpp_pch:pch, override_options: defaults_override) -source_libs += lua_bindings \ No newline at end of file +source_libs += lua_bindings diff --git a/Source/Main.cpp b/Source/Main.cpp index f96bcfa94..27b9ff540 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -2,7 +2,7 @@ /\ ___\ /\ __ \ /\ == \/\__ _\/\ ___\/\_\_\_\ /\ ___\ /\ __ \ /\ "-./ \ /\ "-./ \ /\ __ \ /\ "-.\ \ /\ __-. \ \ \____\ \ \/\ \\ \ __<\/_/\ \/\ \ __\\/_/\_\/_ \ \ \____\ \ \/\ \\ \ \-./\ \\ \ \-./\ \\ \ __ \\ \ \-. \\ \ \/\ \ \ \_____\\ \_____\\ \_\ \_\ \ \_\ \ \_____\/\_\/\_\ \ \_____\\ \_____\\ \_\ \ \_\\ \_\ \ \_\\ \_\ \_\\ \_\\"\_\\ \____- - \/_____/ \/_____/ \/_/ /_/ \/_/ \/_____/\/_/\/_/ \/_____/ \/_____/ \/_/ \/_/ \/_/ \/_/ \/_/\/_/ \/_/ \/_/ \/____/ + \/_____/ \/_____/ \/_/ /_/ \/_/ \/_____/\/_/\/_/ \/_____/ \/_____/ \/_/ \/_/ \/_/ \/_/ \/_/\/_/ \/_/ \/_/ \/____/ ______ ______ __ __ __ __ __ __ __ __ __ ______ __ __ ______ ______ ______ __ ______ ______ ______ /\ ___\ /\ __ \ /\ "-./ \ /\ "-./ \ /\ \/\ \ /\ "-.\ \ /\ \ /\__ _\/\ \_\ \ /\ == \/\ == \ /\ __ \ /\ \ /\ ___\ /\ ___\ /\__ _\ \ \ \____\ \ \/\ \\ \ \-./\ \\ \ \-./\ \\ \ \_\ \\ \ \-. \\ \ \\/_/\ \/\ \____ \ \ \ _-/\ \ __< \ \ \/\ \ _\_\ \\ \ __\ \ \ \____\/_/\ \/ @@ -50,13 +50,15 @@ #include "tracy/Tracy.hpp" -extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; } +extern "C" { +FILE __iob_func[3] = {*stdin, *stdout, *stderr}; +} using namespace RTE; namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// Initializes all the essential managers. @@ -98,7 +100,9 @@ namespace RTE { g_PostProcessMan.Initialize(); g_PerformanceMan.Initialize(); - if (g_AudioMan.Initialize()) { g_GUISound.Initialize(); } + if (g_AudioMan.Initialize()) { + g_GUISound.Initialize(); + } g_UInputMan.Initialize(); g_ConsoleMan.Initialize(); @@ -109,10 +113,12 @@ namespace RTE { // Overwrite Settings.ini after all the managers are created to fully populate the file. Up until this moment Settings.ini is populated only with minimal required properties to run. // If Settings.ini already exists and is fully populated, this will deal with overwriting it to apply any overrides performed by the managers at boot (e.g resolution validation). - if (g_SettingsMan.SettingsNeedOverwrite()) { g_SettingsMan.UpdateSettingsFile(); } + if (g_SettingsMan.SettingsNeedOverwrite()) { + g_SettingsMan.UpdateSettingsFile(); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// Destroys all the managers and frees all loaded data before termination. @@ -142,14 +148,14 @@ namespace RTE { #endif } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// Command-line argument handling. /// /// Argument count. /// Argument values. - void HandleMainArgs(int argCount, char **argValue) { + void HandleMainArgs(int argCount, char** argValue) { // Discard the first argument because it's always the executable path/name argCount--; argValue++; @@ -163,9 +169,13 @@ namespace RTE { std::string currentArg = argValue[i]; bool lastArg = i + 1 == argCount; - if (currentArg == "-cout") { System::EnableLoggingToCLI(); } + if (currentArg == "-cout") { + System::EnableLoggingToCLI(); + } - if (currentArg == "-ext-validate") { System::EnableExternalModuleValidationMode(); } + if (currentArg == "-ext-validate") { + System::EnableExternalModuleValidationMode(); + } if (!lastArg && !singleModuleSet && currentArg == "-module") { std::string moduleToLoad = argValue[++i]; @@ -186,10 +196,12 @@ namespace RTE { } ++i; } - if (launchModeSet) { g_SettingsMan.SetSkipIntro(true); } + if (launchModeSet) { + g_SettingsMan.SetSkipIntro(true); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// Polls the SDL event queue and passes events to be handled by the relevant managers. @@ -231,7 +243,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// Game menus loop. @@ -270,7 +282,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// Game simulation loop. @@ -377,7 +389,9 @@ namespace RTE { // Pause sim while we're waiting for scene transmission or scene will start changing before clients receive them and those changes will be lost. g_TimerMan.PauseSim(!(g_NetworkServer.ReadyForSimulation() && g_ActivityMan.IsInActivity())); - if (!serverUpdated) { g_NetworkServer.Update(); } + if (!serverUpdated) { + g_NetworkServer.Update(); + } if (g_NetworkServer.GetServerSimSleepWhenIdle()) { long long ticksToSleep = g_TimerMan.GetTimeToSleep(); @@ -400,7 +414,7 @@ namespace RTE { g_PerformanceMan.UpdateMSPF(updateTotalTime, drawTotalTime); } } -} +} // namespace RTE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -417,7 +431,7 @@ static const bool RTESetExceptionHandlers = []() { /// /// Implementation of the main function. /// -int main(int argc, char **argv) { +int main(int argc, char** argv) { install_allegro(SYSTEM_NONE, &errno, std::atexit); loadpng_init(); @@ -439,7 +453,7 @@ int main(int argc, char **argv) { // TODO: use a better thread system that'll do what we want ASAP instead of letting the OS schedule all over us // Disabled for now because windows is great and this means when the game lags out it freezes the entire computer. Which we wouldn't expect with anything but REALTIME priority. // Because apparently high priority class is preferred over "processing mouse input"?! - //SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); + // SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); #endif // WIN32 // argv[0] actually unreliable for exe path and name, because of course, why would it be, why would anything be simple and make sense. @@ -468,7 +482,9 @@ int main(int argc, char **argv) { g_ConsoleMan.SetEnabled(true); } else { // Delete an existing log if there are no warnings so there's less junk in the root folder. - if (std::filesystem::exists(System::GetWorkingDirectory() + "LogLoadingWarning.txt")) { std::remove("LogLoadingWarning.txt"); } + if (std::filesystem::exists(System::GetWorkingDirectory() + "LogLoadingWarning.txt")) { + std::remove("LogLoadingWarning.txt"); + } } if (!g_ActivityMan.Initialize()) { @@ -491,4 +507,4 @@ int main(int argc, char **argv) { #ifdef _WIN32 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return main(__argc, __argv); } -#endif \ No newline at end of file +#endif diff --git a/Source/Managers/AchievementMan.cpp b/Source/Managers/AchievementMan.cpp index 0effceef1..922fd9d11 100644 --- a/Source/Managers/AchievementMan.cpp +++ b/Source/Managers/AchievementMan.cpp @@ -1,5 +1,5 @@ /* -//TODO: Remake this into a nice offline achievement system eventually™. +//TODO: Remake this into a nice offline achievement system eventually. // NO STUPID 999 GAMES THING! // Possibly unlock special junk to use ingame. @@ -15,24 +15,24 @@ AchievementMan::AchievementMan(): AchievementMan::AchievementMan() #endif // STEAM_BUILD { - m_Initialized = false; + m_Initialized = false; #ifdef STEAM_BUILD - m_pSteamUserStats = SteamUserStats(); - - if (m_pSteamUserStats) - { - m_pSteamUserStats->RequestCurrentStats(); - } + m_pSteamUserStats = SteamUserStats(); + + if (m_pSteamUserStats) + { + m_pSteamUserStats->RequestCurrentStats(); + } #endif // STEAM_BUILD } int AchievementMan::Create() { #ifdef STEAM_BUILD - if (!m_pSteamUserStats || !m_pSteamUserStats->RequestCurrentStats()) - { - g_ConsoleMan.PrintString("STEAM API: Failed to download stats!"); - } + if (!m_pSteamUserStats || !m_pSteamUserStats->RequestCurrentStats()) + { + g_ConsoleMan.PrintString("STEAM API: Failed to download stats!"); + } #endif // STEAM_BUILD return 0; @@ -40,114 +40,114 @@ int AchievementMan::Create() bool AchievementMan::IsAchievementUnlocked(const char *achievementName) { - bool unlocked = false; + bool unlocked = false; #ifdef STEAM_BUILD - if (m_pSteamUserStats && !m_pSteamUserStats->GetAchievement(achievementName, &unlocked)) - { - g_ConsoleMan.PrintString("STEAM API: Failed to get achievement status!"); - } + if (m_pSteamUserStats && !m_pSteamUserStats->GetAchievement(achievementName, &unlocked)) + { + g_ConsoleMan.PrintString("STEAM API: Failed to get achievement status!"); + } #endif // STEAM_BUILD - return unlocked; + return unlocked; } void AchievementMan::LockAchievement(const char *achievementName) { #ifdef STEAM_BUILD - if (m_pSteamUserStats) - { - m_pSteamUserStats->ClearAchievement(achievementName); - Sync(); - } + if (m_pSteamUserStats) + { + m_pSteamUserStats->ClearAchievement(achievementName); + Sync(); + } #endif // STEAM_BUILD } void AchievementMan::UnlockAchievement(const char *achievementName) { #ifdef STEAM_BUILD - if (m_pSteamUserStats) - { - m_pSteamUserStats->SetAchievement(achievementName); - Sync(); - } + if (m_pSteamUserStats) + { + m_pSteamUserStats->SetAchievement(achievementName); + Sync(); + } #endif // STEAM_BUILD } #ifdef STEAM_BUILD void AchievementMan::OnUserStatsReceived(UserStatsReceived_t *data) { - if (data->m_nGameID && data->m_eResult == k_EResultOK) - { - g_ConsoleMan.PrintString("STEAM API: Achievement status received!"); - m_Initialized = true; - Sync(); - - UnlockAchievement( "CC_BOOTUP" ); - } + if (data->m_nGameID && data->m_eResult == k_EResultOK) + { + g_ConsoleMan.PrintString("STEAM API: Achievement status received!"); + m_Initialized = true; + Sync(); + + UnlockAchievement( "CC_BOOTUP" ); + } } #endif // STEAM_BUILD void AchievementMan::ProgressAchievement(const char *achievementName, int progress, int max) { #ifdef STEAM_BUILD - if (!IsReady() || !m_pSteamUserStats) - { - g_ConsoleMan.PrintString("ACHIEVEMENTS: Tried to increase progress, but AchievementMan isn't ready!"); - return; - } - - std::string name = achievementName + std::string("_PROGRESS"); - const char *statName = name.c_str(); - - int current = 0; - m_pSteamUserStats->GetStat(statName, ¤t); - - int val = progress + current; - if (val >= max) - { - UnlockAchievement(achievementName); - val = max; - } - - m_pSteamUserStats->SetStat(statName, val); + if (!IsReady() || !m_pSteamUserStats) + { + g_ConsoleMan.PrintString("ACHIEVEMENTS: Tried to increase progress, but AchievementMan isn't ready!"); + return; + } + + std::string name = achievementName + std::string("_PROGRESS"); + const char *statName = name.c_str(); + + int current = 0; + m_pSteamUserStats->GetStat(statName, ¤t); + + int val = progress + current; + if (val >= max) + { + UnlockAchievement(achievementName); + val = max; + } + + m_pSteamUserStats->SetStat(statName, val); #endif // STEAM_BUILD } void AchievementMan::SetAchievementBit(const char *achievementName, int bit, int max) { #ifdef STEAM_BUILD - if (!IsReady() || !m_pSteamUserStats) - { - g_ConsoleMan.PrintString("ACHIEVEMENTS: Tried to increase progress, but AchievementMan isn't ready!"); - return; - } + if (!IsReady() || !m_pSteamUserStats) + { + g_ConsoleMan.PrintString("ACHIEVEMENTS: Tried to increase progress, but AchievementMan isn't ready!"); + return; + } - bit--; + bit--; - std::string name = achievementName + std::string("_BITFIELD"); - const char *statName = name.c_str(); + std::string name = achievementName + std::string("_BITFIELD"); + const char *statName = name.c_str(); - int current = 0; - m_pSteamUserStats->GetStat(statName, ¤t); + int current = 0; + m_pSteamUserStats->GetStat(statName, ¤t); - int val = current | 1 << bit; + int val = current | 1 << bit; - if (val == ~((~0) << max)) - { - UnlockAchievement(achievementName); - } + if (val == ~((~0) << max)) + { + UnlockAchievement(achievementName); + } - m_pSteamUserStats->SetStat(statName, val); + m_pSteamUserStats->SetStat(statName, val); #endif // STEAM_BUILD } void AchievementMan::Sync() { #ifdef STEAM_BUILD - if (m_pSteamUserStats) - { - m_pSteamUserStats->StoreStats(); - } + if (m_pSteamUserStats) + { + m_pSteamUserStats->StoreStats(); + } #endif // STEAM_BUILD } diff --git a/Source/Managers/AchievementMan.h b/Source/Managers/AchievementMan.h index cfa82fa75..ac280b42a 100644 --- a/Source/Managers/AchievementMan.h +++ b/Source/Managers/AchievementMan.h @@ -1,5 +1,5 @@ /* -//TODO: Remake this into a nice offline achievement system eventually™. +//TODO: Remake this into a nice offline achievement system eventually. // NO STUPID 999 GAMES THING! // Possibly unlock special junk to use ingame. @@ -26,7 +26,7 @@ class AchievementMan : public Singleton ~AchievementMan() { Sync(); }; - int Create(); + int Create(); ////////////////////////////////////////////////////////////////////////////////////////// // Method: IsAchievementUnlocked @@ -66,7 +66,7 @@ class AchievementMan : public Singleton // The maximum progress of this achievement. // Return value: None. - void ProgressAchievement(const char *achievementName, int progress, int max); + void ProgressAchievement(const char *achievementName, int progress, int max); ////////////////////////////////////////////////////////////////////////////////////////// @@ -79,7 +79,7 @@ class AchievementMan : public Singleton // The amount of bits required to unlock this achievement. // Return value: None. - void SetAchievementBit(const char *achievementName, int bit, int max); + void SetAchievementBit(const char *achievementName, int bit, int max); ////////////////////////////////////////////////////////////////////////////////////////// @@ -89,7 +89,7 @@ class AchievementMan : public Singleton // Arguments: None. // Return value: Whether this manager is ready. - bool IsReady() { return m_Initialized; }; + bool IsReady() { return m_Initialized; }; ////////////////////////////////////////////////////////////////////////////////////////// @@ -101,10 +101,10 @@ class AchievementMan : public Singleton void Sync(); - void Destroy() { Sync(); }; + void Destroy() { Sync(); }; #ifdef STEAM_BUILD - STEAM_CALLBACK(AchievementMan, OnUserStatsReceived, UserStatsReceived_t, m_OnUserStatsReceived); + STEAM_CALLBACK(AchievementMan, OnUserStatsReceived, UserStatsReceived_t, m_OnUserStatsReceived); #endif // STEAM_BUILD private: @@ -112,11 +112,11 @@ class AchievementMan : public Singleton #ifdef STEAM_BUILD ISteamUserStats *m_pSteamUserStats; #endif // STEAM_BUILD - bool m_Initialized; + bool m_Initialized; }; } // namespace RTE #endif // _ACHIEVEMENTMAN_ -*/ \ No newline at end of file +*/ diff --git a/Source/Managers/ActivityMan.cpp b/Source/Managers/ActivityMan.cpp index a361bfda2..5d6f3399c 100644 --- a/Source/Managers/ActivityMan.cpp +++ b/Source/Managers/ActivityMan.cpp @@ -27,10 +27,9 @@ #include "MultiplayerServerLobby.h" #include "MultiplayerGame.h" - namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ActivityMan::Clear() { m_DefaultActivityType = "GATutorial"; @@ -49,7 +48,7 @@ namespace RTE { m_LaunchIntoEditor = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ActivityMan::Initialize() { if (g_NetworkServer.IsServerModeEnabled()) { @@ -64,7 +63,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ActivityMan::ForceAbortSave() { // Just a utility function we can call in the debugger quickwatch window to force an abort save to occur (great for force-saving the game when it crashes) @@ -72,14 +71,14 @@ namespace RTE { return SaveCurrentGame("AbortSave"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool ActivityMan::SaveCurrentGame(const std::string &fileName) { + bool ActivityMan::SaveCurrentGame(const std::string& fileName) { m_SaveGameTask.wait(); m_SaveGameTask = BS::multi_future(); - Scene *scene = g_SceneMan.GetScene(); - GAScripted *activity = dynamic_cast(GetActivity()); + Scene* scene = g_SceneMan.GetScene(); + GAScripted* activity = dynamic_cast(GetActivity()); if (!scene || !activity || (activity && activity->GetActivityState() == Activity::ActivityState::Over)) { g_ConsoleMan.PrintString("ERROR: Cannot save when there's no game running, or the game is finished!"); @@ -117,8 +116,8 @@ namespace RTE { // Pull all stuff from MovableMan into the Scene for saving, so existing Actors/ADoors are saved, without transferring ownership, so the game can continue. // This is done after the activity is saved, in case the activity wants to add anything to the scene while saving. modifiableScene->RetrieveSceneObjects(false); - for (SceneObject *objectToSave : *modifiableScene->GetPlacedObjects(Scene::PlacedObjectSets::PLACEONLOAD)) { - if (MovableObject *objectToSaveAsMovableObject = dynamic_cast(objectToSave)) { + for (SceneObject* objectToSave: *modifiableScene->GetPlacedObjects(Scene::PlacedObjectSets::PLACEONLOAD)) { + if (MovableObject* objectToSaveAsMovableObject = dynamic_cast(objectToSave)) { objectToSaveAsMovableObject->OnSave(); } } @@ -134,7 +133,7 @@ namespace RTE { }; // For some reason I can't std::move a unique ptr in, so just releasing and deleting manually... - m_SaveGameTask.push_back( g_ThreadMan.GetBackgroundThreadPool().submit(saveWriterData, writer.release()) ); + m_SaveGameTask.push_back(g_ThreadMan.GetBackgroundThreadPool().submit(saveWriterData, writer.release())); // We didn't transfer ownership, so we must be very careful that sceneAltered's deletion doesn't touch the stuff we got from MovableMan. modifiableScene->ClearPlacedObjectSet(Scene::PlacedObjectSets::PLACEONLOAD, false); @@ -143,9 +142,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool ActivityMan::LoadAndLaunchGame(const std::string &fileName) { + bool ActivityMan::LoadAndLaunchGame(const std::string& fileName) { m_SaveGameTask.wait(); std::string saveFilePath = g_PresetMan.GetFullModulePath(c_UserScriptedSavesModuleName) + "/" + fileName + "/Save.ini"; @@ -192,24 +191,26 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ActivityMan::SetStartActivity(Activity *newActivity) { + void ActivityMan::SetStartActivity(Activity* newActivity) { RTEAssert(newActivity, "Trying to replace an activity with a null one!"); m_StartActivity.reset(newActivity); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ActivityMan::SetStartTutorialActivity() { - SetStartActivity(dynamic_cast(g_PresetMan.GetEntityPreset("GATutorial", "Tutorial Mission")->Clone())); - if (GameActivity * gameActivity = dynamic_cast(GetStartActivity())) { gameActivity->SetStartingGold(10000); } + SetStartActivity(dynamic_cast(g_PresetMan.GetEntityPreset("GATutorial", "Tutorial Mission")->Clone())); + if (GameActivity* gameActivity = dynamic_cast(GetStartActivity())) { + gameActivity->SetStartingGold(10000); + } g_SceneMan.SetSceneToLoad("Tutorial Bunker"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ActivityMan::SetStartEditorActivity(const std::string_view &editorToLaunch) { + void ActivityMan::SetStartEditorActivity(const std::string_view& editorToLaunch) { std::unique_ptr editorActivityToStart = nullptr; if (editorToLaunch == "ActorEditor") { @@ -224,7 +225,9 @@ namespace RTE { editorActivityToStart = std::make_unique(); } if (editorActivityToStart) { - if (g_MetaMan.GameInProgress()) { g_MetaMan.EndGame(); } + if (g_MetaMan.GameInProgress()) { + g_MetaMan.EndGame(); + } g_SceneMan.SetSceneToLoad("Editor Scene"); editorActivityToStart->Create(); editorActivityToStart->SetEditorMode(EditorActivity::LOADDIALOG); @@ -235,10 +238,10 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ActivityMan::SetStartEditorActivitySetToLaunchInto() { - std::array validEditorNames = { "ActorEditor", "GibEditor", "SceneEditor", "AreaEditor", "AssemblyEditor" }; + std::array validEditorNames = {"ActorEditor", "GibEditor", "SceneEditor", "AreaEditor", "AssemblyEditor"}; if (std::find(validEditorNames.begin(), validEditorNames.end(), m_EditorToLaunch) != validEditorNames.end()) { // Force mouse + keyboard with default mapping so we won't need to change manually if player 1 is set to keyboard only or gamepad. @@ -254,11 +257,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ActivityMan::SetStartMultiplayerActivity() { if (std::unique_ptr multiplayerGame = std::make_unique()) { - if (g_MetaMan.GameInProgress()) { g_MetaMan.EndGame(); } + if (g_MetaMan.GameInProgress()) { + g_MetaMan.EndGame(); + } g_SceneMan.SetSceneToLoad("Multiplayer Scene"); multiplayerGame->Create(); SetStartActivity(multiplayerGame.release()); @@ -268,7 +273,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ActivityMan::SetStartMultiplayerServerOverview() { g_NetworkServer.Start(); @@ -292,9 +297,9 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ActivityMan::StartActivity(Activity *activity) { + int ActivityMan::StartActivity(Activity* activity) { RTEAssert(activity, "Trying to start a null activity!"); g_ThreadMan.GetPriorityThreadPool().wait_for_tasks(); @@ -304,7 +309,7 @@ namespace RTE { g_AudioMan.StopMusic(); m_StartActivity.reset(activity); - m_Activity.reset(dynamic_cast(m_StartActivity->Clone())); + m_Activity.reset(dynamic_cast(m_StartActivity->Clone())); m_Activity->SetupPlayers(); int error = m_Activity->Start(); @@ -338,12 +343,12 @@ namespace RTE { return error; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ActivityMan::StartActivity(const std::string &className, const std::string &presetName) { - if (const Entity *entity = g_PresetMan.GetEntityPreset(className, presetName)) { - Activity *newActivity = dynamic_cast(entity->Clone()); - if (GameActivity *newActivityAsGameActivity = dynamic_cast(newActivity)) { + int ActivityMan::StartActivity(const std::string& className, const std::string& presetName) { + if (const Entity* entity = g_PresetMan.GetEntityPreset(className, presetName)) { + Activity* newActivity = dynamic_cast(entity->Clone()); + if (GameActivity* newActivityAsGameActivity = dynamic_cast(newActivity)) { newActivityAsGameActivity->SetStartingGold(newActivityAsGameActivity->GetDefaultGoldMediumDifficulty()); if (newActivityAsGameActivity->GetStartingGold() <= 0) { newActivityAsGameActivity->SetStartingGold(static_cast(newActivityAsGameActivity->GetTeamFunds(0))); @@ -358,7 +363,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ActivityMan::PauseActivity(bool pause, bool skipPauseMenu) { if (!m_Activity) { @@ -393,7 +398,7 @@ namespace RTE { g_ConsoleMan.PrintString("SYSTEM: Activity \"" + m_Activity->GetPresetName() + "\" was " + (pause ? "paused" : "resumed")); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ActivityMan::ResumeActivity() { if (GetActivity()->GetActivityState() != Activity::NotStarted) { @@ -406,7 +411,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ActivityMan::RestartActivity() { m_ActivityNeedsRestart = false; @@ -422,7 +427,7 @@ namespace RTE { int activityStarted; if (m_StartActivity) { // Need to pass in a clone of the activity because the original will be deleted and re-set during StartActivity. - Activity *startActivityToUse = dynamic_cast(m_StartActivity->Clone()); + Activity* startActivityToUse = dynamic_cast(m_StartActivity->Clone()); startActivityToUse->SetActivityState(Activity::ActivityState::NotStarted); activityStarted = StartActivity(startActivityToUse); } else { @@ -440,7 +445,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ActivityMan::EndActivity() const { // TODO: Set the activity pointer to nullptr so it doesn't return junk after being destructed. Do it here, or wherever works without crashing. @@ -455,20 +460,21 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ActivityMan::LateUpdateGlobalScripts() const { - if (GAScripted *scriptedActivity = dynamic_cast(m_Activity.get())) { scriptedActivity->UpdateGlobalScripts(true); } + if (GAScripted* scriptedActivity = dynamic_cast(m_Activity.get())) { + scriptedActivity->UpdateGlobalScripts(true); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ActivityMan::Update() - { + void ActivityMan::Update() { g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActivityUpdate); - if (m_Activity) { - m_Activity->Update(); + if (m_Activity) { + m_Activity->Update(); } g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActivityUpdate); - } -} + } +} // namespace RTE diff --git a/Source/Managers/ActivityMan.h b/Source/Managers/ActivityMan.h index d8f4da50a..a6aabc3d0 100644 --- a/Source/Managers/ActivityMan.h +++ b/Source/Managers/ActivityMan.h @@ -17,7 +17,6 @@ namespace RTE { friend class SettingsMan; public: - #pragma region Creation /// /// Constructor method used to instantiate an ActivityMan object in system memory. Create() should be called before using the object. @@ -48,7 +47,7 @@ namespace RTE { /// Gets the currently active Activity. Won't be what has been set by SetStartActivity unless RestartActivity has been called since. /// /// The currently active Activity. Will be nullptr if no Activity is going. - Activity * GetActivity() const { return m_Activity.get(); } + Activity* GetActivity() const { return m_Activity.get(); } /// /// Gets the async save game task. @@ -102,7 +101,10 @@ namespace RTE { /// Sets the game simulation to be started back up after the current Activity was unpaused. /// /// Whether the game simulation is being resumed from the pause menu. - void SetResumeActivity(bool resumingFromPauseMenu = false) { m_ActivityNeedsResume = true; m_ResumingActivityFromPauseMenu = resumingFromPauseMenu; } + void SetResumeActivity(bool resumingFromPauseMenu = false) { + m_ActivityNeedsResume = true; + m_ResumingActivityFromPauseMenu = resumingFromPauseMenu; + } /// /// Gets whether the pause menu should be skipped when the game simulation is paused. @@ -122,7 +124,7 @@ namespace RTE { /// Sets the type name of the default Activity to be loaded if nothing else is available. /// /// The default Activity type name. - void SetDefaultActivityType(const std::string_view &defaultActivityType) { m_DefaultActivityType = defaultActivityType; } + void SetDefaultActivityType(const std::string_view& defaultActivityType) { m_DefaultActivityType = defaultActivityType; } /// /// Gets the name of the default Activity to be loaded if nothing else is available. @@ -134,7 +136,7 @@ namespace RTE { /// Sets the preset name of the default Activity to be loaded if nothing else is available. /// /// The default Activity preset name. - void SetDefaultActivityName(const std::string_view &defaultActivityName) { m_DefaultActivityName = defaultActivityName; } + void SetDefaultActivityName(const std::string_view& defaultActivityName) { m_DefaultActivityName = defaultActivityName; } /// /// Gets whether the intro and main menu should be skipped on game start and launch directly into the set default Activity instead. @@ -152,7 +154,12 @@ namespace RTE { /// Sets the name of the editor to launch directly into. /// /// - void SetEditorToLaunch(const std::string_view &editorName) { if (!editorName.empty()) { m_EditorToLaunch = editorName; m_LaunchIntoEditor = true; } } + void SetEditorToLaunch(const std::string_view& editorName) { + if (!editorName.empty()) { + m_EditorToLaunch = editorName; + m_LaunchIntoEditor = true; + } + } #pragma endregion #pragma region Saving and Loading @@ -167,14 +174,14 @@ namespace RTE { /// /// Path to the file. /// Whether the game was successfully saved. - bool SaveCurrentGame(const std::string &fileName); + bool SaveCurrentGame(const std::string& fileName); /// /// Loads a saved game, and launches its Scene and Activity. /// /// Path to the file. /// Whether or not the saved game was successfully loaded. - bool LoadAndLaunchGame(const std::string &fileName); + bool LoadAndLaunchGame(const std::string& fileName); #pragma endregion #pragma region Activity Start Handling @@ -184,13 +191,13 @@ namespace RTE { /// Gets the Activity that will be used in the next restart. Ownership is NOT transferred! /// /// The Activity to put into effect next time ResetActivity is called. - Activity * GetStartActivity() const { return m_StartActivity.get(); } + Activity* GetStartActivity() const { return m_StartActivity.get(); } /// /// Sets a new Activity to copy for next restart. You have to use RestartActivity to get it going. Ownership IS transferred! /// /// The new Activity to put into effect next time ResetActivity is called. - void SetStartActivity(Activity *newActivity); + void SetStartActivity(Activity* newActivity); /// /// Loads the "Tutorial Mission" Scene and starts the Tutorial Activity. @@ -201,7 +208,7 @@ namespace RTE { /// Loads "Editor Scene" and starts the given editor Activity. /// /// The editor name to put into effect next time ResetActivity is called. - void SetStartEditorActivity(const std::string_view &editorToLaunch); + void SetStartEditorActivity(const std::string_view& editorToLaunch); /// /// Launch editor Activity specified in command-line argument. @@ -228,7 +235,7 @@ namespace RTE { /// /// The new activity to start. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int StartActivity(Activity *activity); + int StartActivity(Activity* activity); /// /// Officially gets and starts the Activity described. @@ -236,7 +243,7 @@ namespace RTE { /// The class name of the Activity to start. /// The PresetName of the Activity to start. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int StartActivity(const std::string &className, const std::string &presetName); + int StartActivity(const std::string& className, const std::string& presetName); /// /// Pauses/unpauses the game and saving/resuming in-game music if possible, or queuing default music if not. @@ -273,7 +280,6 @@ namespace RTE { #pragma endregion private: - std::string m_DefaultActivityType; //!< The type name of the default Activity to be loaded if nothing else is available. std::string m_DefaultActivityName; //!< The preset name of the default Activity to be loaded if nothing else is available. @@ -301,8 +307,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - ActivityMan(const ActivityMan &reference) = delete; - ActivityMan & operator=(const ActivityMan &rhs) = delete; + ActivityMan(const ActivityMan& reference) = delete; + ActivityMan& operator=(const ActivityMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/AudioMan.cpp b/Source/Managers/AudioMan.cpp index 5377f7662..28b26cf31 100644 --- a/Source/Managers/AudioMan.cpp +++ b/Source/Managers/AudioMan.cpp @@ -12,7 +12,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::Clear() { m_AudioEnabled = false; @@ -30,7 +30,7 @@ namespace RTE { m_SoundPanningEffectStrength = 0.5F; ////////////////////////////////////////////////// - //TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking by pawnis. + // TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking by pawnis. m_ListenerZOffset = 400; m_MinimumDistanceForPanning = 30.0F; ////////////////////////////////////////////////// @@ -47,7 +47,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AudioMan::Initialize() { FMOD_RESULT audioSystemSetupResult = FMOD::System_Create(&m_AudioSystem); @@ -64,17 +64,16 @@ namespace RTE { audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_AudioSystem->setSoftwareChannels(c_MaxSoftwareChannels) : audioSystemSetupResult; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_AudioSystem->init(c_MaxVirtualChannels, FMOD_INIT_VOL0_BECOMES_VIRTUAL, 0) : audioSystemSetupResult; - audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_AudioSystem->getMasterChannelGroup(&m_MasterChannelGroup) : audioSystemSetupResult; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_AudioSystem->createChannelGroup("SFX", &m_SFXChannelGroup) : audioSystemSetupResult; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_AudioSystem->createChannelGroup("UI", &m_UIChannelGroup) : audioSystemSetupResult; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_AudioSystem->createChannelGroup("Music", &m_MusicChannelGroup) : audioSystemSetupResult; // Add a safety limiter to the master channel group - FMOD::DSP *dsp_limiter; + FMOD::DSP* dsp_limiter; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_AudioSystem->createDSPByType(FMOD_DSP_TYPE_LIMITER, &dsp_limiter) : audioSystemSetupResult; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_MasterChannelGroup->addDSP(0, dsp_limiter) : audioSystemSetupResult; - + // Add a compressor to the SFX channel group // This is pretty heavy-handed, but it sounds great. Might need to be changed once we have sidechaining and fancier things going on. FMOD::DSP* dsp_compressor; @@ -85,7 +84,7 @@ namespace RTE { audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? dsp_compressor->setParameterFloat(3, 250.0f) : audioSystemSetupResult; // Release time audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? dsp_compressor->setParameterFloat(4, 10.0f) : audioSystemSetupResult; // Make-up gain audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_SFXChannelGroup->addDSP(0, dsp_compressor) : audioSystemSetupResult; - + audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_MasterChannelGroup->addGroup(m_SFXChannelGroup) : audioSystemSetupResult; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_MasterChannelGroup->addGroup(m_UIChannelGroup) : audioSystemSetupResult; audioSystemSetupResult = (audioSystemSetupResult == FMOD_OK) ? m_MasterChannelGroup->addGroup(m_MusicChannelGroup) : audioSystemSetupResult; @@ -96,9 +95,15 @@ namespace RTE { return false; } - if (m_MuteSounds) { SetSoundsMuted(); } - if (m_MuteMusic) { SetMusicMuted(); } - if (m_MuteMaster) { SetMasterMuted(); } + if (m_MuteSounds) { + SetSoundsMuted(); + } + if (m_MuteMusic) { + SetMusicMuted(); + } + if (m_MuteMaster) { + SetMasterMuted(); + } SetGlobalPitch(m_GlobalPitch, false, false); SetSoundsVolume(m_SoundsVolume); @@ -108,7 +113,7 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::Destroy() { if (m_AudioEnabled) { @@ -118,7 +123,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::Update() { if (m_AudioEnabled) { @@ -131,27 +136,31 @@ namespace RTE { // Soften the ratio of the pitch adjustment so it's not such an extreme effect on the audio. // TODO: This coefficient should probably move to SettingsMan and be loaded from ini. That way this effect can be lessened or even turned off entirely by users. 0.35 is a good default value though. globalPitch = timeScale + (1.0F - timeScale) * 0.35F; - + SetGlobalPitch(globalPitch); if (!g_ActivityMan.ActivityPaused()) { - const Activity *currentActivity = g_ActivityMan.GetActivity(); + const Activity* currentActivity = g_ActivityMan.GetActivity(); int currentActivityHumanCount = m_IsInMultiplayerMode ? 1 : currentActivity->GetHumanCount(); - if (m_CurrentActivityHumanPlayerPositions.size() != currentActivityHumanCount) { status = status == FMOD_OK ? m_AudioSystem->set3DNumListeners(currentActivityHumanCount) : status; } + if (m_CurrentActivityHumanPlayerPositions.size() != currentActivityHumanCount) { + status = status == FMOD_OK ? m_AudioSystem->set3DNumListeners(currentActivityHumanCount) : status; + } m_CurrentActivityHumanPlayerPositions.clear(); for (int player = Players::PlayerOne; player < Players::MaxPlayerCount && m_CurrentActivityHumanPlayerPositions.size() < currentActivityHumanCount; player++) { if (currentActivity->PlayerActive(player) && currentActivity->PlayerHuman(player)) { int screen = currentActivity->ScreenOfPlayer(player); Vector humanPlayerPosition = g_CameraMan.GetScrollTarget(screen); - if (IsInMultiplayerMode()) { humanPlayerPosition += (Vector(static_cast(g_FrameMan.GetPlayerFrameBufferWidth(screen)), static_cast(g_FrameMan.GetPlayerFrameBufferHeight(screen))) / 2); } + if (IsInMultiplayerMode()) { + humanPlayerPosition += (Vector(static_cast(g_FrameMan.GetPlayerFrameBufferWidth(screen)), static_cast(g_FrameMan.GetPlayerFrameBufferHeight(screen))) / 2); + } m_CurrentActivityHumanPlayerPositions.push_back(std::make_unique(humanPlayerPosition)); } } int listenerNumber = 0; - for (const std::unique_ptr & humanPlayerPosition : m_CurrentActivityHumanPlayerPositions) { + for (const std::unique_ptr& humanPlayerPosition: m_CurrentActivityHumanPlayerPositions) { if (status == FMOD_OK) { FMOD_VECTOR playerPosition = GetAsFMODVector(*(humanPlayerPosition.get()), m_ListenerZOffset); status = m_AudioSystem->set3DListenerAttributes(listenerNumber, &playerPosition, nullptr, &c_FMODForward, &c_FMODUp); @@ -173,79 +182,95 @@ namespace RTE { status = status == FMOD_OK ? m_AudioSystem->update() : status; - if (!IsMusicPlaying() && m_SilenceTimer.IsPastRealTimeLimit()) { PlayNextStream(); } - if (status != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not update AudioMan due to FMOD error: " + std::string(FMOD_ErrorString(status))); } + if (!IsMusicPlaying() && m_SilenceTimer.IsPastRealTimeLimit()) { + PlayNextStream(); + } + if (status != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not update AudioMan due to FMOD error: " + std::string(FMOD_ErrorString(status))); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::SetGlobalPitch(float pitch, bool includeImmobileSounds, bool includeMusic) { if (!m_AudioEnabled) { return; } - if (m_IsInMultiplayerMode) { RegisterSoundEvent(-1, SOUND_SET_GLOBAL_PITCH, nullptr); } + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(-1, SOUND_SET_GLOBAL_PITCH, nullptr); + } m_GlobalPitch = std::clamp(pitch, 0.125F, 8.0F); - if (includeMusic) { m_MusicChannelGroup->setPitch(m_GlobalPitch); } - + if (includeMusic) { + m_MusicChannelGroup->setPitch(m_GlobalPitch); + } + m_SFXChannelGroup->setPitch(m_GlobalPitch); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::SetTempMusicVolume(float volume) { if (m_AudioEnabled && IsMusicPlaying()) { - FMOD::Channel *musicChannel; + FMOD::Channel* musicChannel; FMOD_RESULT result = m_MusicChannelGroup->getChannel(0, &musicChannel); result = (result == FMOD_OK) ? musicChannel->setVolume(std::clamp(volume, 0.0F, 1.0F)) : result; - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not set temporary volume for current music track: " + std::string(FMOD_ErrorString(result))); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not set temporary volume for current music track: " + std::string(FMOD_ErrorString(result))); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AudioMan::SetMusicPitch(float pitch) { if (!m_AudioEnabled) { return false; } - if (m_IsInMultiplayerMode) { RegisterMusicEvent(-1, MUSIC_SET_PITCH, 0, 0, 0.0, pitch); } + if (m_IsInMultiplayerMode) { + RegisterMusicEvent(-1, MUSIC_SET_PITCH, 0, 0, 0.0, pitch); + } - pitch = Limit(pitch, 8, 0.125); //Limit pitch change to 8 octaves up or down + pitch = Limit(pitch, 8, 0.125); // Limit pitch change to 8 octaves up or down FMOD_RESULT result = m_MusicChannelGroup->setPitch(pitch); - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not set music pitch: " + std::string(FMOD_ErrorString(result))); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not set music pitch: " + std::string(FMOD_ErrorString(result))); + } return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AudioMan::GetMusicPosition() const { if (m_AudioEnabled && IsMusicPlaying()) { FMOD_RESULT result; - FMOD::Channel *musicChannel; + FMOD::Channel* musicChannel; unsigned int position; result = m_MusicChannelGroup->getChannel(0, &musicChannel); result = (result == FMOD_OK) ? musicChannel->getPosition(&position, FMOD_TIMEUNIT_MS) : result; - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not get music position: " + std::string(FMOD_ErrorString(result))); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not get music position: " + std::string(FMOD_ErrorString(result))); + } return (result == FMOD_OK) ? (static_cast(position)) / 1000.0F : 0; } return 0.0F; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::SetMusicPosition(float position) { if (m_AudioEnabled && IsMusicPlaying()) { - FMOD::Channel *musicChannel; + FMOD::Channel* musicChannel; FMOD_RESULT result = m_MusicChannelGroup->getChannel(0, &musicChannel); - FMOD::Sound *musicSound; + FMOD::Sound* musicSound; result = (result == FMOD_OK) ? musicChannel->getCurrentSound(&musicSound) : result; unsigned int musicLength = 0; @@ -253,16 +278,18 @@ namespace RTE { result = (result == FMOD_OK) ? musicChannel->setPosition(std::clamp(static_cast(position * 1000.0F), 0U, musicLength), FMOD_TIMEUNIT_MS) : result; - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not set music position: " + std::string(FMOD_ErrorString(result))); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not set music position: " + std::string(FMOD_ErrorString(result))); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::FinishIngameLoopingSounds() { + void AudioMan::FinishIngameLoopingSounds() { if (m_AudioEnabled) { int numberOfPlayingChannels; - FMOD::Channel *soundChannel; + FMOD::Channel* soundChannel; FMOD_RESULT result = m_SFXChannelGroup->getNumChannels(&numberOfPlayingChannels); if (result != FMOD_OK) { @@ -278,13 +305,12 @@ namespace RTE { } soundChannel->setLoopCount(0); } - } - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::PlayMusic(const char *filePath, int loops, float volumeOverrideIfNotMuted) { + void AudioMan::PlayMusic(const char* filePath, int loops, float volumeOverrideIfNotMuted) { if (m_AudioEnabled) { const std::string fullFilePath = g_PresetMan.GetFullModulePath(filePath); if (m_IsInMultiplayerMode) { @@ -304,7 +330,7 @@ namespace RTE { return; } - FMOD::Sound *musicStream; + FMOD::Sound* musicStream; result = m_AudioSystem->createStream(fullFilePath.c_str(), ((loops == 0 || loops == 1) ? FMOD_LOOP_OFF : FMOD_LOOP_NORMAL), nullptr, &musicStream); @@ -318,7 +344,7 @@ namespace RTE { g_ConsoleMan.PrintString("ERROR: Failed to set looping for music file: " + fullFilePath + ". This means it will only play 1 time, instead of " + (loops == 0 ? "looping endlessly." : loops + " times.") + std::string(FMOD_ErrorString(result))); } - FMOD::Channel *musicChannel; + FMOD::Channel* musicChannel; result = musicStream->set3DMinMaxDistance(c_SoundMaxAudibleDistance, c_SoundMaxAudibleDistance); result = (result == FMOD_OK) ? m_AudioSystem->playSound(musicStream, m_MusicChannelGroup, true, &musicChannel) : result; if (result != FMOD_OK) { @@ -326,7 +352,9 @@ namespace RTE { return; } result = musicChannel->setPriority(PRIORITY_HIGH); - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Failed to set music as high priority when playing music file."); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Failed to set music as high priority when playing music file."); + } if (volumeOverrideIfNotMuted >= 0.0F && m_MusicVolume > 0.0F) { volumeOverrideIfNotMuted = std::clamp((volumeOverrideIfNotMuted > 1.0F ? volumeOverrideIfNotMuted / 100.0F : volumeOverrideIfNotMuted), 0.0F, 1.0F); @@ -352,7 +380,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::PlayNextStream() { if (m_AudioEnabled && !m_MusicPlayList.empty()) { @@ -368,11 +396,15 @@ namespace RTE { bool isPlaying; FMOD_RESULT result = m_MusicChannelGroup->isPlaying(&isPlaying); if (result == FMOD_OK && isPlaying) { - if (m_IsInMultiplayerMode) { RegisterMusicEvent(-1, MUSIC_SILENCE, nullptr, seconds); } + if (m_IsInMultiplayerMode) { + RegisterMusicEvent(-1, MUSIC_SILENCE, nullptr, seconds); + } result = m_MusicChannelGroup->stop(); } - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not play silence as specified in music queue, when trying to play next stream: " + std::string(FMOD_ErrorString(result))); } - } catch (const std::invalid_argument &) { + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not play silence as specified in music queue, when trying to play next stream: " + std::string(FMOD_ErrorString(result))); + } + } catch (const std::invalid_argument&) { g_ConsoleMan.PrintString("ERROR: Could invalid silence specification when trying to play next stream."); } } else { @@ -381,21 +413,25 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::StopMusic() { if (m_AudioEnabled) { - if (m_IsInMultiplayerMode) { RegisterMusicEvent(-1, MUSIC_STOP, 0, 0, 0.0, 0.0); } + if (m_IsInMultiplayerMode) { + RegisterMusicEvent(-1, MUSIC_STOP, 0, 0, 0.0, 0.0); + } FMOD_RESULT result = m_MusicChannelGroup->stop(); - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not stop music: " + std::string(FMOD_ErrorString(result))); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not stop music: " + std::string(FMOD_ErrorString(result))); + } m_MusicPlayList.clear(); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::QueueMusicStream(const char *filepath) { + void AudioMan::QueueMusicStream(const char* filepath) { if (m_AudioEnabled) { bool isPlaying; FMOD_RESULT result = m_MusicChannelGroup->isPlaying(&isPlaying); @@ -410,14 +446,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SoundContainer *AudioMan::PlaySound(const std::string &filePath, const Vector &position, int player) { + SoundContainer* AudioMan::PlaySound(const std::string& filePath, const Vector& position, int player) { if (m_IsInMultiplayerMode) { return nullptr; } - SoundContainer *newSoundContainer = new SoundContainer(); + SoundContainer* newSoundContainer = new SoundContainer(); newSoundContainer->SetPosition(position); newSoundContainer->GetTopLevelSoundSet().AddSound(filePath); if (newSoundContainer->HasAnySounds()) { @@ -426,25 +462,29 @@ namespace RTE { return newSoundContainer; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::GetMusicEvents(int player, std::list &list) { + void AudioMan::GetMusicEvents(int player, std::list& list) { if (player < 0 || player >= c_MaxClients) { return; } list.clear(); g_SoundEventsListMutex[player].lock(); - for (const NetworkMusicData &musicEvent : m_MusicEvents[player]) { list.push_back(musicEvent); } + for (const NetworkMusicData& musicEvent: m_MusicEvents[player]) { + list.push_back(musicEvent); + } m_MusicEvents[player].clear(); g_SoundEventsListMutex[player].unlock(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::RegisterMusicEvent(int player, NetworkMusicState state, const char *filepath, int loopsOrSilence, float position, float pitch) { + void AudioMan::RegisterMusicEvent(int player, NetworkMusicState state, const char* filepath, int loopsOrSilence, float position, float pitch) { if (player == -1) { - for (int i = 0; i < c_MaxClients; i++) { RegisterMusicEvent(i, state, filepath, loopsOrSilence, position, pitch); } + for (int i = 0; i < c_MaxClients; i++) { + RegisterMusicEvent(i, state, filepath, loopsOrSilence, position, pitch); + } } else { NetworkMusicData musicData; musicData.State = state; @@ -462,11 +502,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::ClearMusicEvents(int player) { if (player == -1 || player >= c_MaxClients) { - for (int i = 0; i < c_MaxClients; i++) { ClearMusicEvents(i); } + for (int i = 0; i < c_MaxClients; i++) { + ClearMusicEvents(i); + } } else { g_SoundEventsListMutex[player].lock(); m_MusicEvents[player].clear(); @@ -474,34 +516,37 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::GetSoundEvents(int player, std::list &list) { + void AudioMan::GetSoundEvents(int player, std::list& list) { if (player < 0 || player >= c_MaxClients) { return; } list.clear(); g_SoundEventsListMutex[player].lock(); - const NetworkSoundData *lastSetGlobalPitchEvent = nullptr; - for (const NetworkSoundData &soundEvent : m_SoundEvents[player]) { + const NetworkSoundData* lastSetGlobalPitchEvent = nullptr; + for (const NetworkSoundData& soundEvent: m_SoundEvents[player]) { if (soundEvent.State == SOUND_SET_GLOBAL_PITCH) { lastSetGlobalPitchEvent = &soundEvent; } else { list.push_back(soundEvent); } } - if (lastSetGlobalPitchEvent) { list.push_back(*lastSetGlobalPitchEvent); } + if (lastSetGlobalPitchEvent) { + list.push_back(*lastSetGlobalPitchEvent); + } m_SoundEvents[player].clear(); g_SoundEventsListMutex[player].unlock(); - } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::RegisterSoundEvent(int player, NetworkSoundState state, const SoundContainer *soundContainer, int fadeoutTime) { + void AudioMan::RegisterSoundEvent(int player, NetworkSoundState state, const SoundContainer* soundContainer, int fadeoutTime) { if (player == -1) { - for (int i = 0; i < c_MaxClients; i++) { RegisterSoundEvent(i, state, soundContainer, fadeoutTime); } + for (int i = 0; i < c_MaxClients; i++) { + RegisterSoundEvent(i, state, soundContainer, fadeoutTime); + } } else { FMOD_RESULT result = FMOD_OK; std::vector soundDataVector; @@ -512,10 +557,10 @@ namespace RTE { soundData.Pitch = m_GlobalPitch; soundDataVector.push_back(soundData); } else { - for (int playingChannel : *soundContainer->GetPlayingChannels()) { - FMOD::Channel *soundChannel; + for (int playingChannel: *soundContainer->GetPlayingChannels()) { + FMOD::Channel* soundChannel; result = m_AudioSystem->getChannel(playingChannel, &soundChannel); - FMOD::Sound *sound; + FMOD::Sound* sound; result = (result == FMOD_OK) ? soundChannel->getCurrentSound(&sound) : result; if (result != FMOD_OK) { @@ -545,11 +590,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::ClearSoundEvents(int player) { if (player == -1 || player >= c_MaxClients) { - for (int i = 0; i < c_MaxClients; i++) { ClearSoundEvents(i); } + for (int i = 0; i < c_MaxClients; i++) { + ClearSoundEvents(i); + } } else { g_SoundEventsListMutex[player].lock(); m_SoundEvents[player].clear(); @@ -557,9 +604,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AudioMan::PlaySoundContainer(SoundContainer *soundContainer, int player) { + bool AudioMan::PlaySoundContainer(SoundContainer* soundContainer, int player) { if (!m_AudioEnabled || !soundContainer || soundContainer->GetPlayingChannels()->size() >= c_MaxPlayingSoundsPerContainer) { return false; } @@ -574,9 +621,9 @@ namespace RTE { } } - FMOD::ChannelGroup *channelGroupToPlayIn = m_SFXChannelGroup; + FMOD::ChannelGroup* channelGroupToPlayIn = m_SFXChannelGroup; - switch (soundContainer->GetBusRouting()){ + switch (soundContainer->GetBusRouting()) { case SoundContainer::UI: channelGroupToPlayIn = m_UIChannelGroup; break; @@ -588,15 +635,15 @@ namespace RTE { break; } - FMOD::Channel *channel; + FMOD::Channel* channel; int channelIndex; - std::vector selectedSoundData; + std::vector selectedSoundData; soundContainer->GetTopLevelSoundSet().GetFlattenedSoundData(selectedSoundData, true); float pitchVariationFactor = 1.0F + std::abs(soundContainer->GetPitchVariation()); - for (const SoundSet::SoundData *soundData : selectedSoundData) { + for (const SoundSet::SoundData* soundData: selectedSoundData) { result = (result == FMOD_OK) ? m_AudioSystem->playSound(soundData->SoundObject, channelGroupToPlayIn, true, &channel) : result; result = (result == FMOD_OK) ? channel->getIndex(&channelIndex) : result; - + result = (result == FMOD_OK) ? channel->setUserData(soundContainer) : result; result = (result == FMOD_OK) ? channel->setCallback(SoundChannelEndedCallback) : result; result = (result == FMOD_OK) ? channel->setPriority(soundContainer->GetPriority()) : result; @@ -606,19 +653,19 @@ namespace RTE { if (soundContainer->GetCustomPanValue() != 0.0f) { result = (result == FMOD_OK) ? channel->setPan(soundContainer->GetCustomPanValue()) : result; } - + if (soundContainer->IsImmobile()) { result = (result == FMOD_OK) ? channel->setVolume(soundContainer->GetVolume()) : result; } else { - FMOD::DSP *dsp_multibandeq; + FMOD::DSP* dsp_multibandeq; result = (result == FMOD_OK) ? m_AudioSystem->createDSPByType(FMOD_DSP_TYPE_MULTIBAND_EQ, &dsp_multibandeq) : result; result = (result == FMOD_OK) ? dsp_multibandeq->setParameterFloat(1, 22000.0f) : result; // Functionally inactive lowpass filter - result = (result == FMOD_OK) ? channel->addDSP(0, dsp_multibandeq) : result; - + result = (result == FMOD_OK) ? channel->addDSP(0, dsp_multibandeq) : result; + { std::scoped_lock lock(m_SoundChannelMinimumAudibleDistancesMutex); - m_SoundChannelMinimumAudibleDistances.insert({ channelIndex, soundData->MinimumAudibleDistance }); + m_SoundChannelMinimumAudibleDistances.insert({channelIndex, soundData->MinimumAudibleDistance}); } result = (result == FMOD_OK) ? channel->set3DLevel(m_SoundPanningEffectStrength * soundContainer->GetPanningStrengthMultiplier()) : result; @@ -641,8 +688,8 @@ namespace RTE { soundContainer->AddPlayingChannel(channelIndex); } - if (m_IsInMultiplayerMode) { - RegisterSoundEvent(player, SOUND_PLAY, soundContainer); + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(player, SOUND_PLAY, soundContainer); } // Choose the sounds for next time @@ -652,23 +699,25 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AudioMan::ChangeSoundContainerPlayingChannelsPosition(const SoundContainer *soundContainer) { + bool AudioMan::ChangeSoundContainerPlayingChannelsPosition(const SoundContainer* soundContainer) { if (!m_AudioEnabled || !soundContainer) { return false; } - if (m_IsInMultiplayerMode) { RegisterSoundEvent(-1, SOUND_SET_POSITION, soundContainer); } + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(-1, SOUND_SET_POSITION, soundContainer); + } FMOD_RESULT result = FMOD_OK; - FMOD::Channel *soundChannel; - FMOD::Sound *sound; + FMOD::Channel* soundChannel; + FMOD::Sound* sound; - const std::unordered_set *playingChannels = soundContainer->GetPlayingChannels(); - for (int channelIndex : *playingChannels) { + const std::unordered_set* playingChannels = soundContainer->GetPlayingChannels(); + for (int channelIndex: *playingChannels) { result = m_AudioSystem->getChannel(channelIndex, &soundChannel); result = (result == FMOD_OK) ? soundChannel->getCurrentSound(&sound) : result; - const SoundSet::SoundData *soundData = soundContainer->GetSoundDataForSound(sound); + const SoundSet::SoundData* soundData = soundContainer->GetSoundDataForSound(sound); FMOD_VECTOR soundPosition = GetAsFMODVector(soundContainer->GetPosition() + ((soundData == nullptr) ? Vector() : soundData->Offset)); result = (result == FMOD_OK) ? UpdatePositionalEffectsForSoundChannel(soundChannel, &soundPosition) : result; @@ -679,21 +728,23 @@ namespace RTE { return result == FMOD_OK; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AudioMan::ChangeSoundContainerPlayingChannelsVolume(const SoundContainer *soundContainer, float newVolume) { + bool AudioMan::ChangeSoundContainerPlayingChannelsVolume(const SoundContainer* soundContainer, float newVolume) { if (!m_AudioEnabled || !soundContainer || !soundContainer->IsBeingPlayed()) { return false; } - if (m_IsInMultiplayerMode) { RegisterSoundEvent(-1, SOUND_SET_VOLUME, soundContainer); } + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(-1, SOUND_SET_VOLUME, soundContainer); + } FMOD_RESULT result = FMOD_OK; - FMOD::Channel *soundChannel; + FMOD::Channel* soundChannel; float soundContainerOldVolume = soundContainer->GetVolume() == 0 ? 1.0F : soundContainer->GetVolume(); float soundChannelCurrentVolume; - const std::unordered_set *playingChannels = soundContainer->GetPlayingChannels(); - for (int channelIndex : *playingChannels) { + const std::unordered_set* playingChannels = soundContainer->GetPlayingChannels(); + for (int channelIndex: *playingChannels) { result = m_AudioSystem->getChannel(channelIndex, &soundChannel); result = result == FMOD_OK ? soundChannel->getVolume(&soundChannelCurrentVolume) : result; @@ -711,19 +762,21 @@ namespace RTE { return result == FMOD_OK; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AudioMan::ChangeSoundContainerPlayingChannelsPitch(const SoundContainer *soundContainer) { + bool AudioMan::ChangeSoundContainerPlayingChannelsPitch(const SoundContainer* soundContainer) { if (!m_AudioEnabled || !soundContainer || !soundContainer->IsBeingPlayed()) { return false; } - if (m_IsInMultiplayerMode) { RegisterSoundEvent(-1, SOUND_SET_PITCH, soundContainer); } + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(-1, SOUND_SET_PITCH, soundContainer); + } FMOD_RESULT result = FMOD_OK; - FMOD::Channel *soundChannel; + FMOD::Channel* soundChannel; - const std::unordered_set *playingChannels = soundContainer->GetPlayingChannels(); - for (int channelIndex : *playingChannels) { + const std::unordered_set* playingChannels = soundContainer->GetPlayingChannels(); + for (int channelIndex: *playingChannels) { result = m_AudioSystem->getChannel(channelIndex, &soundChannel); result = result == FMOD_OK ? soundChannel->setPitch(soundContainer->GetPitch()) : result; if (result != FMOD_OK) { @@ -735,17 +788,19 @@ namespace RTE { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AudioMan::ChangeSoundContainerPlayingChannelsCustomPanValue(const SoundContainer *soundContainer) { + bool AudioMan::ChangeSoundContainerPlayingChannelsCustomPanValue(const SoundContainer* soundContainer) { if (!m_AudioEnabled || !soundContainer || !soundContainer->IsBeingPlayed()) { return false; } - if (m_IsInMultiplayerMode) { RegisterSoundEvent(-1, SOUND_SET_PITCH, soundContainer); } + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(-1, SOUND_SET_PITCH, soundContainer); + } FMOD_RESULT result = FMOD_OK; - FMOD::Channel *soundChannel; + FMOD::Channel* soundChannel; - const std::unordered_set *playingChannels = soundContainer->GetPlayingChannels(); - for (int channelIndex : *playingChannels) { + const std::unordered_set* playingChannels = soundContainer->GetPlayingChannels(); + for (int channelIndex: *playingChannels) { result = m_AudioSystem->getChannel(channelIndex, &soundChannel); result = result == FMOD_OK ? soundChannel->setPan(soundContainer->GetCustomPanValue()) : result; if (result != FMOD_OK) { @@ -754,62 +809,70 @@ namespace RTE { } return result == FMOD_OK; } - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool AudioMan::StopSoundContainerPlayingChannels(SoundContainer *soundContainer, int player) { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool AudioMan::StopSoundContainerPlayingChannels(SoundContainer* soundContainer, int player) { if (!m_AudioEnabled || !soundContainer || !soundContainer->IsBeingPlayed()) { return false; } - if (m_IsInMultiplayerMode) { RegisterSoundEvent(player, SOUND_STOP, soundContainer); } + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(player, SOUND_STOP, soundContainer); + } FMOD_RESULT result; - FMOD::Channel *soundChannel; + FMOD::Channel* soundChannel; - const std::unordered_set *channels = soundContainer->GetPlayingChannels(); + const std::unordered_set* channels = soundContainer->GetPlayingChannels(); for (std::unordered_set::const_iterator channelIterator = channels->begin(); channelIterator != channels->end();) { result = m_AudioSystem->getChannel((*channelIterator), &soundChannel); ++channelIterator; // NOTE - stopping the sound will remove the channel, screwing things up if we don't move to the next iterator preemptively result = (result == FMOD_OK) ? soundChannel->stop() : result; - if (result != FMOD_OK) { g_ConsoleMan.PrintString("Error: Failed to stop playing channel in SoundContainer " + soundContainer->GetPresetName() + ": " + std::string(FMOD_ErrorString(result))); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("Error: Failed to stop playing channel in SoundContainer " + soundContainer->GetPresetName() + ": " + std::string(FMOD_ErrorString(result))); + } } return result == FMOD_OK; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void AudioMan::FadeOutSoundContainerPlayingChannels(SoundContainer *soundContainer, int fadeOutTime) { + void AudioMan::FadeOutSoundContainerPlayingChannels(SoundContainer* soundContainer, int fadeOutTime) { if (!m_AudioEnabled || !soundContainer || !soundContainer->IsBeingPlayed()) { return; } - if (m_IsInMultiplayerMode) { RegisterSoundEvent(-1, SOUND_FADE_OUT, soundContainer, fadeOutTime); } + if (m_IsInMultiplayerMode) { + RegisterSoundEvent(-1, SOUND_FADE_OUT, soundContainer, fadeOutTime); + } int sampleRate; m_AudioSystem->getSoftwareFormat(&sampleRate, nullptr, nullptr); int fadeOutTimeAsSamples = fadeOutTime * sampleRate / 1000; FMOD_RESULT result; - FMOD::Channel *soundChannel; + FMOD::Channel* soundChannel; unsigned long long parentClock; float currentVolume; const std::unordered_set channels = *soundContainer->GetPlayingChannels(); - for (int channel : channels) { + for (int channel: channels) { result = m_AudioSystem->getChannel(channel, &soundChannel); result = (result == FMOD_OK) ? soundChannel->getDSPClock(nullptr, &parentClock) : result; result = (result == FMOD_OK) ? soundChannel->getVolume(¤tVolume) : result; result = (result == FMOD_OK) ? soundChannel->addFadePoint(parentClock, currentVolume) : result; result = (result == FMOD_OK) ? soundChannel->addFadePoint(parentClock + fadeOutTimeAsSamples, 0) : result; - if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: Could not fade out sounds in SoundContainer " + soundContainer->GetPresetName() + ": " + std::string(FMOD_ErrorString(result))); } + if (result != FMOD_OK) { + g_ConsoleMan.PrintString("ERROR: Could not fade out sounds in SoundContainer " + soundContainer->GetPresetName() + ": " + std::string(FMOD_ErrorString(result))); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AudioMan::Update3DEffectsForSFXChannels() { int numberOfPlayingChannels; - FMOD::Channel *soundChannel; + FMOD::Channel* soundChannel; FMOD_RESULT result = m_SFXChannelGroup->getNumChannels(&numberOfPlayingChannels); if (result != FMOD_OK) { @@ -822,7 +885,7 @@ namespace RTE { FMOD_MODE mode; result = (result == FMOD_OK) ? soundChannel->getMode(&mode) : result; unsigned modeResult = mode & FMOD_2D; - if (modeResult == 0){ + if (modeResult == 0) { FMOD_VECTOR channelPosition; result = result == FMOD_OK ? soundChannel->get3DAttributes(&channelPosition, nullptr) : result; result = result == FMOD_OK ? UpdatePositionalEffectsForSoundChannel(soundChannel, &channelPosition) : result; @@ -831,9 +894,9 @@ namespace RTE { if (result == FMOD_OK && m_CurrentActivityHumanPlayerPositions.size() == 1) { float sqrDistanceToPlayer = (*(m_CurrentActivityHumanPlayerPositions[0].get()) - GetAsVector(channelPosition)).GetSqrMagnitude(); float doubleMinimumDistanceForPanning = m_MinimumDistanceForPanning * 2.0F; - void *userData; + void* userData; result = result == FMOD_OK ? soundChannel->getUserData(&userData) : result; - const SoundContainer *soundContainer = static_cast(userData); + const SoundContainer* soundContainer = static_cast(userData); if (sqrDistanceToPlayer < (m_MinimumDistanceForPanning * m_MinimumDistanceForPanning) || soundContainer->GetCustomPanValue() != 0.0f) { soundChannel->set3DLevel(0); } else if (sqrDistanceToPlayer < (doubleMinimumDistanceForPanning * doubleMinimumDistanceForPanning)) { @@ -843,7 +906,7 @@ namespace RTE { } } } - + if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: An error occurred updating calculated sound effects for playing channel with index " + std::to_string(i) + ": " + std::string(FMOD_ErrorString(result))); continue; @@ -851,22 +914,22 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - FMOD_RESULT AudioMan::UpdatePositionalEffectsForSoundChannel(FMOD::Channel *soundChannel, const FMOD_VECTOR *positionOverride) const { + FMOD_RESULT AudioMan::UpdatePositionalEffectsForSoundChannel(FMOD::Channel* soundChannel, const FMOD_VECTOR* positionOverride) const { FMOD_RESULT result = FMOD_OK; - - void *userData; + + void* userData; result = result == FMOD_OK ? soundChannel->getUserData(&userData) : result; - const SoundContainer *channelSoundContainer = static_cast(userData); - + const SoundContainer* channelSoundContainer = static_cast(userData); + bool sceneWraps = g_SceneMan.SceneWrapsX(); FMOD_VECTOR channelPosition; if (positionOverride) { channelPosition = *positionOverride; } else if (sceneWraps) { - //NOTE If the scene doesn't wrap and the position hasn't changed, this method doesn't set the channel position below, so there's no need to get it here. + // NOTE If the scene doesn't wrap and the position hasn't changed, this method doesn't set the channel position below, so there's no need to get it here. result = soundChannel->get3DAttributes(&channelPosition, nullptr); if (result != FMOD_OK) { return result; @@ -878,21 +941,21 @@ namespace RTE { if (!sceneWraps) { wrappedChannelPositions = {channelPosition}; } else { - wrappedChannelPositions = (channelPosition.x <= halfSceneWidth) ? - wrappedChannelPositions = {channelPosition, {channelPosition.x + g_SceneMan.GetSceneWidth(), channelPosition.y}} : - wrappedChannelPositions = {FMOD_VECTOR({channelPosition.x - g_SceneMan.GetSceneWidth(), channelPosition.y}), channelPosition}; + wrappedChannelPositions = (channelPosition.x <= halfSceneWidth) ? wrappedChannelPositions = {channelPosition, {channelPosition.x + g_SceneMan.GetSceneWidth(), channelPosition.y}} : wrappedChannelPositions = {FMOD_VECTOR({channelPosition.x - g_SceneMan.GetSceneWidth(), channelPosition.y}), channelPosition}; } float sqrShortestDistance = c_SoundMaxAudibleDistance * c_SoundMaxAudibleDistance; float sqrLongestDistance = 0.0F; - for (const std::unique_ptr & humanPlayerPosition : m_CurrentActivityHumanPlayerPositions) { - for (const FMOD_VECTOR &wrappedChannelPosition : wrappedChannelPositions) { + for (const std::unique_ptr& humanPlayerPosition: m_CurrentActivityHumanPlayerPositions) { + for (const FMOD_VECTOR& wrappedChannelPosition: wrappedChannelPositions) { float sqrDistanceToChannelPosition = (*(humanPlayerPosition.get()) - GetAsVector(wrappedChannelPosition)).GetSqrMagnitude(); if (sqrDistanceToChannelPosition < sqrShortestDistance) { sqrShortestDistance = sqrDistanceToChannelPosition; channelPosition = wrappedChannelPosition; } - if (sqrDistanceToChannelPosition > sqrLongestDistance) { sqrLongestDistance = sqrDistanceToChannelPosition; } + if (sqrDistanceToChannelPosition > sqrLongestDistance) { + sqrLongestDistance = sqrDistanceToChannelPosition; + } if (!sceneWraps) { break; } @@ -906,21 +969,21 @@ namespace RTE { float attenuationStartDistance = c_DefaultAttenuationStartDistance; float soundMaxDistance = 0.0F; result = result == FMOD_OK ? soundChannel->get3DMinMaxDistance(&attenuationStartDistance, &soundMaxDistance) : result; - + float attenuatedVolume = (shortestDistance <= attenuationStartDistance) ? 1.0F : attenuationStartDistance / shortestDistance; - + // Lowpass as distance increases - FMOD::DSP *dsp_multibandeq; + FMOD::DSP* dsp_multibandeq; result = (result == FMOD_OK) ? soundChannel->getDSP(0, &dsp_multibandeq) : result; float factor = 1 - pow(1 - attenuatedVolume, 3); float lowpassFrequency = 22000.0f * factor; lowpassFrequency = std::clamp(lowpassFrequency, 350.0f, 22000.0f); result = (result == FMOD_OK) ? dsp_multibandeq->setParameterFloat(1, lowpassFrequency) : result; - + if (channelSoundContainer->GetCustomPanValue() != 0.0f) { result = (result == FMOD_OK) ? soundChannel->setPan(channelSoundContainer->GetCustomPanValue()) : result; } - + float minimumAudibleDistance = m_SoundChannelMinimumAudibleDistances.at(soundChannelIndex); if (shortestDistance >= soundMaxDistance) { attenuatedVolume = 0.0F; @@ -929,7 +992,7 @@ namespace RTE { } else if (sqrLongestDistance < (minimumAudibleDistance * minimumAudibleDistance)) { attenuatedVolume = 0.0F; } - + float panLevel; result = result == FMOD_OK ? soundChannel->get3DLevel(&panLevel) : result; if (result == FMOD_OK && (panLevel < 1.0F || attenuatedVolume == 0.0F)) { @@ -941,34 +1004,40 @@ namespace RTE { return result; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - FMOD_RESULT F_CALLBACK AudioMan::MusicChannelEndedCallback(FMOD_CHANNELCONTROL *channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void *unusedCommandData1, void *unusedCommandData2) { + FMOD_RESULT F_CALLBACK AudioMan::MusicChannelEndedCallback(FMOD_CHANNELCONTROL* channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void* unusedCommandData1, void* unusedCommandData2) { if (channelControlType == FMOD_CHANNELCONTROL_CHANNEL && callbackType == FMOD_CHANNELCONTROL_CALLBACK_END) { - void *userData; + void* userData; FMOD_RESULT result = g_AudioMan.m_MusicChannelGroup->getUserData(&userData); - if (userData == nullptr) { g_AudioMan.PlayNextStream(); } + if (userData == nullptr) { + g_AudioMan.PlayNextStream(); + } } return FMOD_OK; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - FMOD_RESULT F_CALLBACK AudioMan::SoundChannelEndedCallback(FMOD_CHANNELCONTROL *channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void *unusedCommandData1, void *unusedCommandData2) { + FMOD_RESULT F_CALLBACK AudioMan::SoundChannelEndedCallback(FMOD_CHANNELCONTROL* channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void* unusedCommandData1, void* unusedCommandData2) { if (channelControlType == FMOD_CHANNELCONTROL_CHANNEL && callbackType == FMOD_CHANNELCONTROL_CALLBACK_END) { - FMOD::Channel *channel = reinterpret_cast(channelControl); + FMOD::Channel* channel = reinterpret_cast(channelControl); int channelIndex; FMOD_RESULT result = channel->getIndex(&channelIndex); // Remove this playing sound index from the SoundContainer if it has any playing sounds, i.e. it hasn't been reset before this callback happened. - void *userData; + void* userData; result = (result == FMOD_OK) ? channel->getUserData(&userData) : result; if (result == FMOD_OK) { - SoundContainer *channelSoundContainer = static_cast(userData); - if (channelSoundContainer->IsBeingPlayed()) { channelSoundContainer->RemovePlayingChannel(channelIndex); } + SoundContainer* channelSoundContainer = static_cast(userData); + if (channelSoundContainer->IsBeingPlayed()) { + channelSoundContainer->RemovePlayingChannel(channelIndex); + } result = (result == FMOD_OK) ? channel->setUserData(nullptr) : result; - if (g_AudioMan.m_SoundChannelMinimumAudibleDistances.find(channelIndex) != g_AudioMan.m_SoundChannelMinimumAudibleDistances.end()) { g_AudioMan.m_SoundChannelMinimumAudibleDistances.erase(channelIndex); } + if (g_AudioMan.m_SoundChannelMinimumAudibleDistances.find(channelIndex) != g_AudioMan.m_SoundChannelMinimumAudibleDistances.end()) { + g_AudioMan.m_SoundChannelMinimumAudibleDistances.erase(channelIndex); + } if (result != FMOD_OK) { g_ConsoleMan.PrintString("ERROR: An error occurred when Ending a sound in SoundContainer " + channelSoundContainer->GetPresetName() + ": " + std::string(FMOD_ErrorString(result))); @@ -981,17 +1050,17 @@ namespace RTE { return FMOD_OK; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - FMOD_VECTOR AudioMan::GetAsFMODVector(const Vector &vector, float zValue) const { + FMOD_VECTOR AudioMan::GetAsFMODVector(const Vector& vector, float zValue) const { Vector sceneDimensions = g_SceneMan.GetScene() ? g_SceneMan.GetSceneDim() : Vector(); return sceneDimensions.IsZero() ? FMOD_VECTOR{0, 0, zValue} : FMOD_VECTOR{vector.m_X, sceneDimensions.m_Y - vector.m_Y, zValue}; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector AudioMan::GetAsVector(FMOD_VECTOR fmodVector) const { Vector sceneDimensions = g_SceneMan.GetScene() ? g_SceneMan.GetSceneDim() : Vector(); return sceneDimensions.IsZero() ? Vector() : Vector(fmodVector.x, sceneDimensions.m_Y - fmodVector.y); } -} +} // namespace RTE diff --git a/Source/Managers/AudioMan.h b/Source/Managers/AudioMan.h index f606d1e1f..d11231983 100644 --- a/Source/Managers/AudioMan.h +++ b/Source/Managers/AudioMan.h @@ -24,7 +24,6 @@ namespace RTE { friend class SoundContainer; public: - /// /// Hardcoded playback priorities for sounds. Note that sounds don't have to use these specifically; their priority can be anywhere between high and low. /// @@ -128,7 +127,7 @@ namespace RTE { /// Gets the audio management system object used for playing all audio. /// /// The audio management system object used by AudioMan for playing audio. - FMOD::System *GetAudioSystem() const { return m_AudioSystem; } + FMOD::System* GetAudioSystem() const { return m_AudioSystem; } /// /// Reports whether audio is enabled. @@ -142,7 +141,7 @@ namespace RTE { /// The out-parameter that will hold the virtual channel count. /// The out-parameter that will hold the real channel count. /// Whether or not the playing channel count was succesfully gotten. - bool GetPlayingChannelCount(int *outVirtualChannelCount, int *outRealChannelCount) const { return m_AudioSystem->getChannelsPlaying(outVirtualChannelCount, outRealChannelCount) == FMOD_OK; } + bool GetPlayingChannelCount(int* outVirtualChannelCount, int* outRealChannelCount) const { return m_AudioSystem->getChannelsPlaying(outVirtualChannelCount, outRealChannelCount) == FMOD_OK; } /// /// Returns the total number of virtual audio channels available. @@ -154,7 +153,10 @@ namespace RTE { /// Returns the total number of real audio channels available. /// /// The number of real audio channels available. - int GetTotalRealChannelCount() const { int channelCount; return m_AudioSystem->getSoftwareChannels(&channelCount) == FMOD_OK ? channelCount : 0; } + int GetTotalRealChannelCount() const { + int channelCount; + return m_AudioSystem->getSoftwareChannels(&channelCount) == FMOD_OK ? channelCount : 0; + } /// /// Gets whether all audio is muted or not. @@ -166,7 +168,12 @@ namespace RTE { /// Mutes or unmutes all audio. /// /// Whether to mute or unmute all the audio. - void SetMasterMuted(bool muteOrUnmute = true) { m_MuteMaster = muteOrUnmute; if (m_AudioEnabled) { m_MasterChannelGroup->setMute(m_MuteMaster); } } + void SetMasterMuted(bool muteOrUnmute = true) { + m_MuteMaster = muteOrUnmute; + if (m_AudioEnabled) { + m_MasterChannelGroup->setMute(m_MuteMaster); + } + } /// /// Gets the volume of all audio. Does not get music or sounds individual volumes. @@ -178,7 +185,12 @@ namespace RTE { /// Sets all the audio to a specific volume. Does not affect music or sounds individual volumes. /// /// The desired volume scalar. 0.0-1.0. - void SetMasterVolume(float volume = 1.0F) { m_MasterVolume = std::clamp(volume, 0.0F, 1.0F); if (m_AudioEnabled) { m_MasterChannelGroup->setVolume(m_MasterVolume); } } + void SetMasterVolume(float volume = 1.0F) { + m_MasterVolume = std::clamp(volume, 0.0F, 1.0F); + if (m_AudioEnabled) { + m_MasterChannelGroup->setVolume(m_MasterVolume); + } + } /// /// Gets the global pitch scalar value for all sounds and music. @@ -206,7 +218,10 @@ namespace RTE { /// Reports whether any music stream is currently playing. /// /// Whether any music stream is currently playing. - bool IsMusicPlaying() const { bool isPlayingMusic; return m_AudioEnabled && m_MusicChannelGroup->isPlaying(&isPlayingMusic) == FMOD_OK ? isPlayingMusic : false; } + bool IsMusicPlaying() const { + bool isPlayingMusic; + return m_AudioEnabled && m_MusicChannelGroup->isPlaying(&isPlayingMusic) == FMOD_OK ? isPlayingMusic : false; + } /// /// Gets whether the music channel is muted or not. @@ -218,7 +233,12 @@ namespace RTE { /// Mutes or unmutes the music channel. /// /// Whether to mute or unmute the music channel. - void SetMusicMuted(bool muteOrUnmute = true) { m_MuteMusic = muteOrUnmute; if (m_AudioEnabled) { m_MusicChannelGroup->setMute(m_MuteMusic); } } + void SetMusicMuted(bool muteOrUnmute = true) { + m_MuteMusic = muteOrUnmute; + if (m_AudioEnabled) { + m_MusicChannelGroup->setMute(m_MuteMusic); + } + } /// /// Gets the volume of music. Does not get volume of sounds. @@ -230,7 +250,12 @@ namespace RTE { /// Sets the music to a specific volume. Does not affect sounds. /// /// The desired volume scalar. 0.0-1.0. - void SetMusicVolume(float volume = 1.0F) { m_MusicVolume = std::clamp(volume, 0.0F, 1.0F); if (m_AudioEnabled) { m_MusicChannelGroup->setVolume(m_MusicVolume); } } + void SetMusicVolume(float volume = 1.0F) { + m_MusicVolume = std::clamp(volume, 0.0F, 1.0F); + if (m_AudioEnabled) { + m_MusicChannelGroup->setVolume(m_MusicVolume); + } + } /// /// Sets the music to a specific volume, but it will only last until a new song is played. Useful for fading etc. @@ -275,12 +300,14 @@ namespace RTE { /// Mutes or unmutes all the sound effects channels. /// /// Whether to mute or unmute all the sound effects channels. - void SetSoundsMuted(bool muteOrUnmute = true) { m_MuteSounds = muteOrUnmute; if (m_AudioEnabled) - { - // TODO: We may or may not wanna separate this out and add a UI sound slider - m_SFXChannelGroup->setMute(m_MuteSounds); - m_UIChannelGroup->setMute(m_MuteSounds); - } } + void SetSoundsMuted(bool muteOrUnmute = true) { + m_MuteSounds = muteOrUnmute; + if (m_AudioEnabled) { + // TODO: We may or may not wanna separate this out and add a UI sound slider + m_SFXChannelGroup->setMute(m_MuteSounds); + m_UIChannelGroup->setMute(m_MuteSounds); + } + } /// /// Gets the volume of all sounds. Does not get volume of music. @@ -292,18 +319,25 @@ namespace RTE { /// Sets the volume of all sounds to a specific volume. Does not affect music. /// /// The desired volume scalar. 0.0-1.0. - void SetSoundsVolume(float volume = 1.0F) { m_SoundsVolume = volume; if (m_AudioEnabled) - { - m_SFXChannelGroup->setVolume(m_SoundsVolume); - m_UIChannelGroup->setVolume(m_SoundsVolume); - } } + void SetSoundsVolume(float volume = 1.0F) { + m_SoundsVolume = volume; + if (m_AudioEnabled) { + m_SFXChannelGroup->setVolume(m_SoundsVolume); + m_UIChannelGroup->setVolume(m_SoundsVolume); + } + } #pragma endregion #pragma region Global Playback and Handling /// /// Stops all playback and clears the music playlist. /// - void StopAll() { if (m_AudioEnabled) { m_MasterChannelGroup->stop(); } m_MusicPlayList.clear(); } + void StopAll() { + if (m_AudioEnabled) { + m_MasterChannelGroup->stop(); + } + m_MusicPlayList.clear(); + } /// /// Makes all sounds that are looping stop looping, allowing them to play once more then be finished. @@ -314,7 +348,11 @@ namespace RTE { /// Pauses all ingame sounds. /// Whether to pause sounds or resume them. /// - void PauseIngameSounds(bool pause = true) { if (m_AudioEnabled) { m_SFXChannelGroup->setPaused(pause); } } + void PauseIngameSounds(bool pause = true) { + if (m_AudioEnabled) { + m_SFXChannelGroup->setPaused(pause); + } + } #pragma endregion #pragma region Music Playback and Handling @@ -324,7 +362,7 @@ namespace RTE { /// The path to the music file to play. /// The number of times to loop the song. 0 means play once. -1 means play infinitely until stopped. /// The volume override for music for this song only, if volume is not muted. < 0 means no override. - void PlayMusic(const char *filePath, int loops = -1, float volumeOverrideIfNotMuted = -1.0F); + void PlayMusic(const char* filePath, int loops = -1, float volumeOverrideIfNotMuted = -1.0F); /// /// Plays the next music stream in the queue, if any is queued. @@ -337,17 +375,21 @@ namespace RTE { void StopMusic(); /// - /// Queues up another path to a stream that will be played after the current one is done. + /// Queues up another path to a stream that will be played after the current one is done. /// Can be done several times to queue up many tracks. The last track in the queue will be looped infinitely. /// /// The path to the music file to play after the current one. - void QueueMusicStream(const char *filePath); + void QueueMusicStream(const char* filePath); /// /// Queues up a period of silence in the music stream playlist. /// /// The number of secs to wait before going to the next stream. - void QueueSilence(int seconds) { if (m_AudioEnabled && seconds > 0) { m_MusicPlayList.push_back("@" + std::to_string(seconds)); } } + void QueueSilence(int seconds) { + if (m_AudioEnabled && seconds > 0) { + m_MusicPlayList.push_back("@" + std::to_string(seconds)); + } + } /// /// Clears the music queue. @@ -361,14 +403,14 @@ namespace RTE { /// /// The path to the sound file to play. /// The new SoundContainer being played. OWNERSHIP IS TRANSFERRED! - SoundContainer *PlaySound(const std::string &filePath) { return PlaySound(filePath, Vector(), -1); } + SoundContainer* PlaySound(const std::string& filePath) { return PlaySound(filePath, Vector(), -1); } /// /// Starts playing a certain sound file at a certain position for all players. /// /// The path to the sound file to play. /// The new SoundContainer being played. OWNERSHIP IS TRANSFERRED! - SoundContainer *PlaySound(const std::string &filePath, const Vector &position) { return PlaySound(filePath, position, -1); } + SoundContainer* PlaySound(const std::string& filePath, const Vector& position) { return PlaySound(filePath, position, -1); } /// /// Starts playing a certain sound file at a certain position for a certain player. @@ -377,7 +419,7 @@ namespace RTE { /// The position at which to play the SoundContainer's sounds. /// Which player to play the SoundContainer's sounds for, -1 means all players. /// The new SoundContainer being played. OWNERSHIP IS TRANSFERRED! - SoundContainer *PlaySound(const std::string &filePath, const Vector &position, int player); + SoundContainer* PlaySound(const std::string& filePath, const Vector& position, int player); #pragma endregion #pragma region Network Audio Handling @@ -398,7 +440,7 @@ namespace RTE { /// /// Player to get events for. /// List with events for this player. - void GetMusicEvents(int player, std::list &list); + void GetMusicEvents(int player, std::list& list); /// /// Adds the music event to internal list of music events for the specified player. @@ -409,7 +451,7 @@ namespace RTE { /// LoopsOrSilence counter or, if state is silence, the length of the silence. /// Music playback position. /// Pitch value. - void RegisterMusicEvent(int player, NetworkMusicState state, const char *filepath, int loopsOrSilence = 0, float position = 0, float pitch = 1.0F); + void RegisterMusicEvent(int player, NetworkMusicState state, const char* filepath, int loopsOrSilence = 0, float position = 0, float pitch = 1.0F); /// /// Clears the list of current Music events for the target player. @@ -422,7 +464,7 @@ namespace RTE { /// /// Player to get events for. /// List with events for this player. - void GetSoundEvents(int player, std::list &list); + void GetSoundEvents(int player, std::list& list); /// /// Adds the sound event to the internal list of sound events for the specified player. @@ -431,7 +473,7 @@ namespace RTE { /// NetworkSoundState for the event. /// A pointer to the SoundContainer this event is happening to, or a null pointer for global events. /// THe amount of time, in MS, to fade out over. This data isn't contained in SoundContainer, so it needs to be passed in separately. - void RegisterSoundEvent(int player, NetworkSoundState state, const SoundContainer *soundContainer, int fadeOutTime = 0); + void RegisterSoundEvent(int player, NetworkSoundState state, const SoundContainer* soundContainer, int fadeOutTime = 0); /// /// Clears the list of current Sound events for the target player. @@ -441,15 +483,14 @@ namespace RTE { #pragma endregion protected: - const FMOD_VECTOR c_FMODForward = FMOD_VECTOR{0, 0, 1}; //!< An FMOD_VECTOR defining the Forwards direction. Necessary for 3D Sounds. const FMOD_VECTOR c_FMODUp = FMOD_VECTOR{0, 1, 0}; //!< An FMOD_VECTOR defining the Up direction. Necessary for 3D Sounds. - FMOD::System *m_AudioSystem; //!< The FMOD Sound management object. - FMOD::ChannelGroup *m_MasterChannelGroup; //!< The top-level FMOD ChannelGroup that holds everything. - FMOD::ChannelGroup *m_SFXChannelGroup; //!< The FMOD ChannelGroup for diegetic gameplay sounds. - FMOD::ChannelGroup *m_UIChannelGroup; //!< The FMOD ChannelGroup for UI sounds. - FMOD::ChannelGroup *m_MusicChannelGroup; //!< The FMOD ChannelGroup for music. + FMOD::System* m_AudioSystem; //!< The FMOD Sound management object. + FMOD::ChannelGroup* m_MasterChannelGroup; //!< The top-level FMOD ChannelGroup that holds everything. + FMOD::ChannelGroup* m_SFXChannelGroup; //!< The FMOD ChannelGroup for diegetic gameplay sounds. + FMOD::ChannelGroup* m_UIChannelGroup; //!< The FMOD ChannelGroup for UI sounds. + FMOD::ChannelGroup* m_MusicChannelGroup; //!< The FMOD ChannelGroup for music. bool m_AudioEnabled; //!< Bool to tell whether audio is enabled or not. std::vector> m_CurrentActivityHumanPlayerPositions; //!< The stored positions of each human player in the current activity. Only filled when there's an activity running. @@ -466,7 +507,7 @@ namespace RTE { float m_SoundPanningEffectStrength; //!< The strength of the sound panning effect, 0 (no panning) - 1 (full panning). ////////////////////////////////////////////////// - //TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking by pawnis. + // TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking by pawnis. float m_ListenerZOffset; float m_MinimumDistanceForPanning; ////////////////////////////////////////////////// @@ -483,7 +524,6 @@ namespace RTE { std::mutex m_SoundChannelMinimumAudibleDistancesMutex; //!, As above but for m_SoundChannelMinimumAudibleDistances private: - #pragma region Sound Container Actions and Modifications /// /// Starts playing the next SoundSet of the given SoundContainer for the give player. @@ -491,14 +531,14 @@ namespace RTE { /// Pointer to the SoundContainer to start playing. Ownership is NOT transferred! /// Which player to play the SoundContainer's sounds for, -1 means all players. Defaults to -1. /// Whether or not playback of the Sound was successful. - bool PlaySoundContainer(SoundContainer *soundContainer, int player = -1); + bool PlaySoundContainer(SoundContainer* soundContainer, int player = -1); /// /// Sets/updates the position of a SoundContainer's playing sounds. /// /// A pointer to a SoundContainer object. Ownership IS NOT transferred! /// Whether the position was successfully set. - bool ChangeSoundContainerPlayingChannelsPosition(const SoundContainer *soundContainer); + bool ChangeSoundContainerPlayingChannelsPosition(const SoundContainer* soundContainer); /// /// Changes the volume of a SoundContainer's playing sounds. @@ -506,21 +546,21 @@ namespace RTE { /// A pointer to a SoundContainer object. Ownership IS NOT transferred! /// The new volume to play sounds at, between 0 and 1. /// Whether the volume was successfully updated. - bool ChangeSoundContainerPlayingChannelsVolume(const SoundContainer *soundContainer, float newVolume); + bool ChangeSoundContainerPlayingChannelsVolume(const SoundContainer* soundContainer, float newVolume); /// /// Changes the frequency/pitch of a SoundContainer's playing sounds. /// /// A pointer to a SoundContainer object. Ownership IS NOT transferred! /// Whether the pitch was successfully updated. - bool ChangeSoundContainerPlayingChannelsPitch(const SoundContainer *soundContainer); + bool ChangeSoundContainerPlayingChannelsPitch(const SoundContainer* soundContainer); /// /// Updates the custom pan value of a SoundContainer's playing sounds. /// /// A pointer to a SoundContainer object. Ownership IS NOT transferred! /// Whether the custom pan value was successfully updated. - bool ChangeSoundContainerPlayingChannelsCustomPanValue(const SoundContainer *soundContainer); + bool ChangeSoundContainerPlayingChannelsCustomPanValue(const SoundContainer* soundContainer); /// /// Stops playing a SoundContainer's playing sounds for a certain player. @@ -528,14 +568,14 @@ namespace RTE { /// A pointer to a SoundContainer object6. Ownership is NOT transferred! /// Which player to stop playing the SoundContainer for. /// - bool StopSoundContainerPlayingChannels(SoundContainer *soundContainer, int player); + bool StopSoundContainerPlayingChannels(SoundContainer* soundContainer, int player); /// /// Fades out playback a SoundContainer. /// /// A pointer to a SoundContainer object. Ownership is NOT transferred! /// The amount of time, in ms, to fade out over. - void FadeOutSoundContainerPlayingChannels(SoundContainer *soundContainer, int fadeOutTime); + void FadeOutSoundContainerPlayingChannels(SoundContainer* soundContainer, int fadeOutTime); #pragma endregion #pragma region 3D Effect Handling @@ -550,19 +590,19 @@ namespace RTE { /// The channel whose position should be set or updated. /// An optional position to set for this sound channel. Done this way to save setting and resetting data in FMOD. /// Whether the channel's position was succesfully set. - FMOD_RESULT UpdatePositionalEffectsForSoundChannel(FMOD::Channel *soundChannel, const FMOD_VECTOR *positionToUse = nullptr) const; + FMOD_RESULT UpdatePositionalEffectsForSoundChannel(FMOD::Channel* soundChannel, const FMOD_VECTOR* positionToUse = nullptr) const; #pragma endregion #pragma region FMOD Callbacks /// /// A static callback function for FMOD to invoke when the music channel finishes playing. See fmod docs - FMOD_CHANNELCONTROL_CALLBACK for details /// - static FMOD_RESULT F_CALLBACK MusicChannelEndedCallback(FMOD_CHANNELCONTROL *channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void *commandData1, void *commandData2); + static FMOD_RESULT F_CALLBACK MusicChannelEndedCallback(FMOD_CHANNELCONTROL* channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void* commandData1, void* commandData2); /// /// A static callback function for FMOD to invoke when a sound channel finished playing. See fmod docs - FMOD_CHANNELCONTROL_CALLBACK for details /// - static FMOD_RESULT F_CALLBACK SoundChannelEndedCallback(FMOD_CHANNELCONTROL *channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void *commandData1, void *commandData2); + static FMOD_RESULT F_CALLBACK SoundChannelEndedCallback(FMOD_CHANNELCONTROL* channelControl, FMOD_CHANNELCONTROL_TYPE channelControlType, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbackType, void* commandData1, void* commandData2); #pragma endregion #pragma region Utility Methods @@ -571,7 +611,7 @@ namespace RTE { /// /// The RTE Vector to get as an FMOD_VECTOR. /// The FMOD_VECTOR that corresponds to the given RTE Vector. - FMOD_VECTOR GetAsFMODVector(const Vector &vector, float zValue = 0) const; + FMOD_VECTOR GetAsFMODVector(const Vector& vector, float zValue = 0) const; /// /// Gets the corresponding RTE Vector for a given FMOD_VECTOR. @@ -587,8 +627,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - AudioMan(const AudioMan &reference) = delete; - AudioMan & operator=(const AudioMan &rhs) = delete; + AudioMan(const AudioMan& reference) = delete; + AudioMan& operator=(const AudioMan& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Managers/CameraMan.cpp b/Source/Managers/CameraMan.cpp index 2e640be93..20a26865e 100644 --- a/Source/Managers/CameraMan.cpp +++ b/Source/Managers/CameraMan.cpp @@ -10,7 +10,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void CameraMan::Clear() { m_ScreenShakeStrength = 1.0F; @@ -20,7 +20,7 @@ namespace RTE { m_DefaultShakePerUnitOfRecoilEnergy = 0.5F; m_DefaultShakeFromRecoilMaximum = 0.0F; - for (Screen &screen : m_Screens) { + for (Screen& screen: m_Screens) { screen.Offset.Reset(); screen.DeltaOffset.Reset(); screen.ScrollTarget.Reset(); @@ -36,25 +36,25 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void CameraMan::SetOffset(const Vector &offset, int screenId) { + void CameraMan::SetOffset(const Vector& offset, int screenId) { m_Screens[screenId].Offset = offset.GetFloored(); CheckOffset(screenId); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector CameraMan::GetUnwrappedOffset(int screenId) const { - const Screen &screen = m_Screens[screenId]; - const SLTerrain *terrain = g_SceneMan.GetScene()->GetTerrain(); + const Screen& screen = m_Screens[screenId]; + const SLTerrain* terrain = g_SceneMan.GetScene()->GetTerrain(); return Vector(screen.Offset.GetX() + static_cast(terrain->GetBitmap()->w * screen.SeamCrossCount[Axes::X]), screen.Offset.GetY() + static_cast(terrain->GetBitmap()->h * screen.SeamCrossCount[Axes::Y])); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void CameraMan::SetScroll(const Vector ¢er, int screenId) { - Screen &screen = m_Screens[screenId]; + void CameraMan::SetScroll(const Vector& center, int screenId) { + Screen& screen = m_Screens[screenId]; if (g_FrameMan.IsInMultiplayerMode()) { screen.Offset.SetXY(static_cast(center.GetFloorIntX() - (g_FrameMan.GetPlayerFrameBufferWidth(screenId) / 2)), static_cast(center.GetFloorIntY() - (g_FrameMan.GetPlayerFrameBufferHeight(screenId) / 2))); } else { @@ -63,19 +63,19 @@ namespace RTE { CheckOffset(screenId); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector CameraMan::GetScrollTarget(int screenId) const { return g_NetworkClient.IsConnectedAndRegistered() ? g_NetworkClient.GetFrameTarget() : m_Screens[screenId].ScrollTarget; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void CameraMan::SetScrollTarget(const Vector &targetCenter, float speed, int screenId) { - Screen &screen = m_Screens[screenId]; + void CameraMan::SetScrollTarget(const Vector& targetCenter, float speed, int screenId) { + Screen& screen = m_Screens[screenId]; // See if it would make sense to automatically wrap. - const SLTerrain *terrain = g_SceneMan.GetScene()->GetTerrain(); + const SLTerrain* terrain = g_SceneMan.GetScene()->GetTerrain(); float targetXWrapped = terrain->WrapsX() && (std::fabs(targetCenter.GetX() - screen.ScrollTarget.GetX()) > static_cast(terrain->GetBitmap()->w / 2)); float targetYWrapped = terrain->WrapsY() && (std::fabs(targetCenter.GetY() - screen.ScrollTarget.GetY()) > static_cast(terrain->GetBitmap()->h / 2)); @@ -87,9 +87,9 @@ namespace RTE { screen.TargetYWrapped = screen.TargetYWrapped || targetYWrapped; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - float CameraMan::TargetDistanceScalar(const Vector &point) const { + float CameraMan::TargetDistanceScalar(const Vector& point) const { if (!g_SceneMan.GetScene()) { return 0.0F; } @@ -103,7 +103,7 @@ namespace RTE { } float closestScalar = 1.0F; - for (const Screen &screen : m_Screens) { + for (const Screen& screen: m_Screens) { float distance = g_SceneMan.ShortestDistance(point, screen.ScrollTarget).GetMagnitude(); float scalar = 0.0F; @@ -123,15 +123,15 @@ namespace RTE { return closestScalar; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void CameraMan::CheckOffset(int screenId) { RTEAssert(g_SceneMan.GetScene(), "Trying to check offset before there is a scene or terrain!"); - const SLTerrain *terrain = g_SceneMan.GetScene()->GetTerrain(); + const SLTerrain* terrain = g_SceneMan.GetScene()->GetTerrain(); RTEAssert(terrain, "Trying to get terrain matter before there is a scene or terrain!"); - Screen &screen = m_Screens[screenId]; + Screen& screen = m_Screens[screenId]; if (!terrain->WrapsX() && screen.Offset.GetX() < 0) { screen.Offset.SetX(0.0F); @@ -153,7 +153,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector CameraMan::GetFrameSize(int screenId) { int frameWidth = g_WindowMan.GetResX(); @@ -170,21 +170,21 @@ namespace RTE { return Vector(static_cast(frameWidth), static_cast(frameHeight)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void CameraMan::ResetAllScreenShake() { for (int screenId = 0; screenId < g_FrameMan.GetScreenCount(); ++screenId) { - Screen &screen = m_Screens[screenId]; + Screen& screen = m_Screens[screenId]; screen.ScreenShakeMagnitude = 0; screen.ScrollTimer.Reset(); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void CameraMan::AddScreenShake(float magnitude, const Vector &position) { + void CameraMan::AddScreenShake(float magnitude, const Vector& position) { for (int screenId = 0; screenId < g_FrameMan.GetScreenCount(); ++screenId) { - Screen &screen = m_Screens[screenId]; + Screen& screen = m_Screens[screenId]; Vector frameSize = GetFrameSize(screenId); @@ -193,7 +193,7 @@ namespace RTE { g_SceneMan.WrapBox(screenBox, wrappedBoxes); float closestDistanceFromScreen = std::numeric_limits::max(); - for (const Box &box : wrappedBoxes) { + for (const Box& box: wrappedBoxes) { // Determine how far the position is from the box. Vector closestPointOnBox = box.GetWithinBox(position); Vector distanceFromBoxToPosition = closestPointOnBox - position; @@ -209,11 +209,11 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void CameraMan::Update(int screenId) { - Screen &screen = m_Screens[screenId]; - const SLTerrain *terrain = g_SceneMan.GetScene()->GetTerrain(); + Screen& screen = m_Screens[screenId]; + const SLTerrain* terrain = g_SceneMan.GetScene()->GetTerrain(); if (g_TimerMan.DrawnSimUpdate()) { // Adjust for wrapping if the scroll target jumped a seam this frame, as reported by whatever screen set it (the scroll target) this frame. This is to avoid big, scene-wide jumps in scrolling when traversing the seam. @@ -283,4 +283,4 @@ namespace RTE { screen.DeltaOffset = screen.Offset - oldOffset; screen.ScrollTimer.Reset(); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/CameraMan.h b/Source/Managers/CameraMan.h index 2019b5336..adec7208b 100644 --- a/Source/Managers/CameraMan.h +++ b/Source/Managers/CameraMan.h @@ -16,7 +16,6 @@ namespace RTE { friend class SettingsMan; public: - #pragma region Creation /// /// Constructor method used to instantiate a CameraMan object in system memory. Create() should be called before using the object. @@ -60,7 +59,7 @@ namespace RTE { /// /// The new offset value. /// Which screen you want to set the offset of. - void SetOffset(const Vector &offset, int screenId = 0); + void SetOffset(const Vector& offset, int screenId = 0); /// /// Gets the difference in current offset and that of the Update() before. @@ -81,7 +80,7 @@ namespace RTE { /// /// The coordinates to center the terrain scroll on. /// Which screen you want to set the offset of. - void SetScroll(const Vector ¢er, int screenId = 0); + void SetScroll(const Vector& center, int screenId = 0); /// /// Gets the team associated with a specific screen. @@ -103,7 +102,7 @@ namespace RTE { /// /// Which screen you want to get the team of. /// A vector indicating the screen occlusion amount. - Vector & GetScreenOcclusion(int screenId = 0) { return m_Screens[screenId].ScreenOcclusion; } + Vector& GetScreenOcclusion(int screenId = 0) { return m_Screens[screenId].ScreenOcclusion; } /// /// Sets the amount that a specific screen is occluded by a GUI panel or something of the sort. @@ -111,7 +110,7 @@ namespace RTE { /// /// The amount of occlusion of the screen. /// Which screen you want to set the occlusion of. - void SetScreenOcclusion(const Vector &occlusion, int screenId = 0) { m_Screens[screenId].ScreenOcclusion = occlusion; } + void SetScreenOcclusion(const Vector& occlusion, int screenId = 0) { m_Screens[screenId].ScreenOcclusion = occlusion; } /// /// Gets the currently set scroll target, i.e. where the center of the specific screen is trying to line up with. @@ -126,7 +125,7 @@ namespace RTE { /// The new target vector in Scene coordinates. /// The normalized speed at screen the view scrolls. 0 being no movement, and 1.0 being instant movement to the target in one frame. /// Which screen you want to set the scroll offset of. - void SetScrollTarget(const Vector &targetCenter, float speed = 0.1F, int screenId = 0); + void SetScrollTarget(const Vector& targetCenter, float speed = 0.1F, int screenId = 0); /// /// Calculates a scalar of how distant a certain point in the world is from the currently closest scroll target of all active screens. @@ -136,7 +135,7 @@ namespace RTE { /// A normalized scalar representing the distance between the closest scroll target of all active screens, to the passed in point. /// 0 means it's the point is within half a screen's width of the target, and 1.0 means it's on the clear opposite side of the scene. /// - float TargetDistanceScalar(const Vector &point) const; + float TargetDistanceScalar(const Vector& point) const; /// /// Makes sure the current offset won't create a view of outside the scene. @@ -211,7 +210,7 @@ namespace RTE { /// /// The amount of screen shake. /// The spatial location of the screen-shake event. - void AddScreenShake(float magnitude, const Vector &position); + void AddScreenShake(float magnitude, const Vector& position); /// /// Increases the magnitude of screen shake. @@ -243,7 +242,6 @@ namespace RTE { #pragma endregion private: - /// /// A screen. Each player should have one of these. /// @@ -261,7 +259,7 @@ namespace RTE { bool TargetXWrapped = false; //!< Whether the ScrollTarget got x wrapped around the world this frame or not. bool TargetYWrapped = false; //!< Whether the ScrollTarget got y wrapped around the world this frame or not. - std::array SeamCrossCount = { 0, 0 }; //!< Keeps track of how many times and in screen directions the wrapping seam has been crossed. This is used for keeping the background layers' scroll from jumping when wrapping around. X and Y. + std::array SeamCrossCount = {0, 0}; //!< Keeps track of how many times and in screen directions the wrapping seam has been crossed. This is used for keeping the background layers' scroll from jumping when wrapping around. X and Y. Vector ScreenOcclusion; //!< The amount a screen is occluded or covered by GUI, etc. @@ -283,8 +281,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - CameraMan(const CameraMan &reference) = delete; - CameraMan & operator=(const CameraMan &rhs) = delete; + CameraMan(const CameraMan& reference) = delete; + CameraMan& operator=(const CameraMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/ConsoleMan.cpp b/Source/Managers/ConsoleMan.cpp index 0f25bb852..f59812cee 100644 --- a/Source/Managers/ConsoleMan.cpp +++ b/Source/Managers/ConsoleMan.cpp @@ -16,7 +16,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::Clear() { m_ConsoleState = ConsoleState::Disabled; @@ -38,12 +38,18 @@ namespace RTE { m_ConsoleUseMonospaceFont = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int ConsoleMan::Initialize() { - if (!m_GUIScreen) { m_GUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer32()); } - if (!m_GUIInput) { m_GUIInput = new GUIInputWrapper(-1); } - if (!m_GUIControlManager) { m_GUIControlManager = new GUIControlManager(); } + if (!m_GUIScreen) { + m_GUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer32()); + } + if (!m_GUIInput) { + m_GUIInput = new GUIInputWrapper(-1); + } + if (!m_GUIControlManager) { + m_GUIControlManager = new GUIControlManager(); + } if (!m_GUIControlManager->Create(m_GUIScreen, m_GUIInput, "Base.rte/GUIs/Skins/Menus", m_ConsoleUseMonospaceFont ? "ConsoleMonospaceSkin.ini" : "ConsoleSkin.ini")) { RTEAbort("Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/ConsoleSkin.ini"); @@ -53,14 +59,14 @@ namespace RTE { m_GUIControlManager->EnableMouse(false); // Stretch the invisible root box to fill the screen - dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); if (!m_ParentBox) { - m_ParentBox = dynamic_cast(m_GUIControlManager->GetControl("ConsoleGUIBox")); + m_ParentBox = dynamic_cast(m_GUIControlManager->GetControl("ConsoleGUIBox")); m_ParentBox->SetDrawType(GUICollectionBox::Color); } - m_ConsoleText = dynamic_cast(m_GUIControlManager->GetControl("ConsoleLabel")); - m_InputTextBox = dynamic_cast(m_GUIControlManager->GetControl("InputTB")); + m_ConsoleText = dynamic_cast(m_GUIControlManager->GetControl("ConsoleLabel")); + m_InputTextBox = dynamic_cast(m_GUIControlManager->GetControl("InputTB")); SetConsoleScreenSize(m_ConsoleScreenRatio); @@ -68,15 +74,19 @@ namespace RTE { m_ParentBox->SetEnabled(false); m_ParentBox->SetVisible(false); - if (!g_WindowMan.ResolutionChanged()) { m_OutputLog.emplace_back("- RTE Lua Console -\nSee the Data Realms Wiki for commands: http://www.datarealms.com/wiki/\nPress F1 for a list of helpful shortcuts\n-------------------------------------"); } + if (!g_WindowMan.ResolutionChanged()) { + m_OutputLog.emplace_back("- RTE Lua Console -\nSee the Data Realms Wiki for commands: http://www.datarealms.com/wiki/\nPress F1 for a list of helpful shortcuts\n-------------------------------------"); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::Destroy() { - if (!g_WindowMan.ResolutionChanged()) { SaveAllText("LogConsole.txt"); } + if (!g_WindowMan.ResolutionChanged()) { + SaveAllText("LogConsole.txt"); + } delete m_GUIControlManager; delete m_GUIInput; @@ -92,7 +102,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::SetEnabled(bool enable) { if (enable && m_ConsoleState != ConsoleState::Enabled && m_ConsoleState != ConsoleState::Enabling) { @@ -104,7 +114,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::SetReadOnly() { if (!m_ReadOnly) { @@ -116,7 +126,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::SetConsoleScreenSize(float screenRatio) { m_ConsoleScreenRatio = Limit(screenRatio, 1.0F, 0.1F); @@ -132,61 +142,67 @@ namespace RTE { m_InputTextBox->Resize(m_ParentBox->GetWidth() - 3, m_InputTextBox->GetHeight()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::SetConsoleUseMonospaceFont(bool useFont) { m_ConsoleUseMonospaceFont = useFont; - if (m_GUIControlManager) { m_GUIControlManager->ChangeSkin("Base.rte/GUIs/Skins/Menus", m_ConsoleUseMonospaceFont ? "ConsoleMonospaceSkin.ini" : "ConsoleSkin.ini"); } + if (m_GUIControlManager) { + m_GUIControlManager->ChangeSkin("Base.rte/GUIs/Skins/Menus", m_ConsoleUseMonospaceFont ? "ConsoleMonospaceSkin.ini" : "ConsoleSkin.ini"); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ConsoleMan::AddLoadWarningLogExtensionMismatchEntry(const std::string &pathToLog, const std::string &readerPosition, const std::string &altFileExtension) { + void ConsoleMan::AddLoadWarningLogExtensionMismatchEntry(const std::string& pathToLog, const std::string& readerPosition, const std::string& altFileExtension) { const std::string pathAndAccessLocation = "\"" + pathToLog + "\" referenced " + readerPosition + ". "; std::string newEntry = pathAndAccessLocation + (!altFileExtension.empty() ? "Found and loaded a file with \"" + altFileExtension + "\" extension." : "The file was not loaded."); if (g_PresetMan.GetReloadEntityPresetCalledThisUpdate()) { PrintString(newEntry); } else { std::transform(newEntry.begin(), newEntry.end(), newEntry.begin(), ::tolower); - if (m_LoadWarningLog.find(newEntry) == m_LoadWarningLog.end()) { m_LoadWarningLog.emplace(newEntry); } + if (m_LoadWarningLog.find(newEntry) == m_LoadWarningLog.end()) { + m_LoadWarningLog.emplace(newEntry); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ConsoleMan::SaveLoadWarningLog(const std::string &filePath) { + void ConsoleMan::SaveLoadWarningLog(const std::string& filePath) { Writer logWriter(filePath.c_str()); if (logWriter.WriterOK()) { logWriter << "// Warnings produced during loading:"; logWriter.NewLine(false); - for (const std::string &logEntry : m_LoadWarningLog) { + for (const std::string& logEntry: m_LoadWarningLog) { logWriter.NewLineString(logEntry, false); } PrintString("SYSTEM: Loading warning log saved to " + filePath); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ConsoleMan::SaveInputLog(const std::string &filePath) { + void ConsoleMan::SaveInputLog(const std::string& filePath) { Writer logWriter(filePath.c_str()); if (logWriter.WriterOK()) { for (std::deque::reverse_iterator logItr = m_InputLog.rbegin(); logItr != m_InputLog.rend(); ++logItr) { logWriter << *logItr; // Add semicolon so the line input becomes a statement - if (!logItr->empty() && (*logItr)[logItr->length() - 1] != ';') { logWriter << ";"; } + if (!logItr->empty() && (*logItr)[logItr->length() - 1] != ';') { + logWriter << ";"; + } logWriter << "\n"; } PrintString("SYSTEM: Console input log saved to " + filePath); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool ConsoleMan::SaveAllText(const std::string &filePath) { + bool ConsoleMan::SaveAllText(const std::string& filePath) { Writer logWriter(filePath.c_str()); if (logWriter.WriterOK()) { - for (const std::string &loggedString : m_OutputLog) { + for (const std::string& loggedString: m_OutputLog) { logWriter << loggedString; } logWriter.EndWrite(); @@ -196,7 +212,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::ClearLog() { m_InputLog.clear(); @@ -204,51 +220,52 @@ namespace RTE { m_OutputLog.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ConsoleMan::PrintString(const std::string &stringToPrint) { + void ConsoleMan::PrintString(const std::string& stringToPrint) { static std::mutex printStringMutex; std::scoped_lock printStringLock(printStringMutex); m_OutputLog.emplace_back("\n" + stringToPrint); - if (System::IsLoggingToCLI()) { - System::PrintToCLI(stringToPrint); + if (System::IsLoggingToCLI()) { + System::PrintToCLI(stringToPrint); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::ShowShortcuts() { - if (!IsEnabled()) { SetEnabled(); } + if (!IsEnabled()) { + SetEnabled(); + } PrintString( - "\n--- SHORTCUTS ---\n" - "CTRL + ~ - Console in read-only mode without input capture\n" - "CTRL + DOWN / UP - Increase/decrease console size (Only while console is open)\n" - "CTRL + S - Make continuous screenshots while the keys are held\n" - "CTRL + W - Make a screenshot of the entire level\n" - "ALT + W - Make a miniature preview image of the entire level\n" - "CTRL + P - Show performance stats\n" - "ALT + P - Show advanced performance stats (Only while performance stats are visible)\n" - "CTRL + R - Reset activity\n" - "CTRL + M - Switch display mode: Draw -> Material -> MO\n" - "CTRL + O - Toggle one sim update per frame\n" - "SHIFT + ESC - Skip pause menu when pausing activity (straight to scenario/conquest menu)\n" - "----------------\n" - "F2 - Reload all Lua scripts\n" - "ALT + F2 - Reload all sprites\n" - "CTRL + F2 - Quick reload Entity preset previously reloaded with PresetMan:ReloadEntityPreset\n" - "F3 - Save console log\n" - "F4 - Save console user input log\n" - "F5 - Quick save\n" - "F9 - Load latest quick-save\n" - "CTRL + F9 - Load latest auto-save\n" - "F10 - Clear Console log\n" - "F12 - Make a single screenshot" - ); + "\n--- SHORTCUTS ---\n" + "CTRL + ~ - Console in read-only mode without input capture\n" + "CTRL + DOWN / UP - Increase/decrease console size (Only while console is open)\n" + "CTRL + S - Make continuous screenshots while the keys are held\n" + "CTRL + W - Make a screenshot of the entire level\n" + "ALT + W - Make a miniature preview image of the entire level\n" + "CTRL + P - Show performance stats\n" + "ALT + P - Show advanced performance stats (Only while performance stats are visible)\n" + "CTRL + R - Reset activity\n" + "CTRL + M - Switch display mode: Draw -> Material -> MO\n" + "CTRL + O - Toggle one sim update per frame\n" + "SHIFT + ESC - Skip pause menu when pausing activity (straight to scenario/conquest menu)\n" + "----------------\n" + "F2 - Reload all Lua scripts\n" + "ALT + F2 - Reload all sprites\n" + "CTRL + F2 - Quick reload Entity preset previously reloaded with PresetMan:ReloadEntityPreset\n" + "F3 - Save console log\n" + "F4 - Save console user input log\n" + "F5 - Quick save\n" + "F9 - Load latest quick-save\n" + "CTRL + F9 - Load latest auto-save\n" + "F10 - Clear Console log\n" + "F12 - Make a single screenshot"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::Update() { if (g_UInputMan.FlagCtrlState() && g_UInputMan.KeyPressed(SDL_SCANCODE_GRAVE)) { @@ -276,7 +293,9 @@ namespace RTE { } } - if (m_ConsoleState != ConsoleState::Enabled && m_ConsoleState != ConsoleState::Disabled) { ConsoleOpenClose(); } + if (m_ConsoleState != ConsoleState::Enabled && m_ConsoleState != ConsoleState::Disabled) { + ConsoleOpenClose(); + } std::stringstream consoleText; for (std::deque::iterator logIterator = (m_OutputLog.size() < m_ConsoleTextMaxNumLines) ? m_OutputLog.begin() : m_OutputLog.end() - m_ConsoleTextMaxNumLines; logIterator != m_OutputLog.end(); ++logIterator) { @@ -320,7 +339,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::ConsoleOpenClose() { float travelCompletionDistance; @@ -332,7 +351,9 @@ namespace RTE { travelCompletionDistance = std::floor(static_cast(m_ParentBox->GetYPos()) * 0.5F); m_ParentBox->SetPositionAbs(0, m_ParentBox->GetYPos() - static_cast(travelCompletionDistance)); - if (m_ParentBox->GetYPos() >= 0) { m_ConsoleState = ConsoleState::Enabled; } + if (m_ParentBox->GetYPos() >= 0) { + m_ConsoleState = ConsoleState::Enabled; + } } else if (m_ConsoleState == ConsoleState::Disabling) { travelCompletionDistance = std::ceil((static_cast(m_ParentBox->GetHeight()) + static_cast(m_ParentBox->GetYPos())) * 0.5F); m_ParentBox->SetPositionAbs(0, m_ParentBox->GetYPos() - static_cast(travelCompletionDistance)); @@ -354,7 +375,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::FeedString(bool feedEmptyString) { char strLine[1024]; @@ -370,8 +391,12 @@ namespace RTE { m_OutputLog.emplace_back("\n" + line); g_LuaMan.GetMasterScriptState().RunScriptString(line, false); - if (g_LuaMan.GetMasterScriptState().ErrorExists()) { m_OutputLog.emplace_back("\nERROR: " + g_LuaMan.GetMasterScriptState().GetLastError()); } - if (m_InputLog.empty() || m_InputLog.front() != line) { m_InputLog.push_front(line); } + if (g_LuaMan.GetMasterScriptState().ErrorExists()) { + m_OutputLog.emplace_back("\nERROR: " + g_LuaMan.GetMasterScriptState().GetLastError()); + } + if (m_InputLog.empty() || m_InputLog.front() != line) { + m_InputLog.push_front(line); + } m_InputLogPosition = m_InputLog.begin(); m_LastLogMove = 0; @@ -384,12 +409,14 @@ namespace RTE { m_InputTextBox->SetText(""); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::LoadLoggedInput(bool nextEntry) { if (nextEntry) { // See if we should decrement doubly because the last move was in the opposite direction - if (m_LastLogMove > 0 && m_InputLogPosition != m_InputLog.begin()) { --m_InputLogPosition; } + if (m_LastLogMove > 0 && m_InputLogPosition != m_InputLog.begin()) { + --m_InputLogPosition; + } if (m_InputLogPosition == m_InputLog.begin()) { m_InputTextBox->SetText(""); @@ -402,7 +429,9 @@ namespace RTE { } } else { // See if we should increment doubly because the last move was in the opposite direction - if (m_LastLogMove < 0 && m_InputLogPosition != m_InputLog.end() - 1) { ++m_InputLogPosition; } + if (m_LastLogMove < 0 && m_InputLogPosition != m_InputLog.end() - 1) { + ++m_InputLogPosition; + } m_InputTextBox->SetText(*m_InputLogPosition); m_InputTextBox->SetCursorPos(m_InputTextBox->GetText().length()); @@ -417,7 +446,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ConsoleMan::RemoveGraveAccents() const { std::string textBoxString = m_InputTextBox->GetText(); @@ -428,12 +457,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ConsoleMan::Draw(BITMAP *targetBitmap) const { + void ConsoleMan::Draw(BITMAP* targetBitmap) const { if (m_ConsoleState != ConsoleState::Disabled) { AllegroScreen drawScreen(targetBitmap); m_GUIControlManager->Draw(&drawScreen); } } -} +} // namespace RTE diff --git a/Source/Managers/ConsoleMan.h b/Source/Managers/ConsoleMan.h index 4b293db6e..a943c7372 100644 --- a/Source/Managers/ConsoleMan.h +++ b/Source/Managers/ConsoleMan.h @@ -21,7 +21,6 @@ namespace RTE { friend class SettingsMan; public: - #pragma region Creation /// /// Constructor method used to instantiate a ConsoleMan object in system memory. Create() should be called before using the object. @@ -104,26 +103,26 @@ namespace RTE { /// The path that produced the warning. /// The file and line currently being loaded. /// The alternative file extension to the path that produced the warning (e.g. if file is ".bmp", alternative extension is ".png"). - void AddLoadWarningLogExtensionMismatchEntry(const std::string &pathToLog, const std::string &readerPosition = "", const std::string &altFileExtension = "" ); + void AddLoadWarningLogExtensionMismatchEntry(const std::string& pathToLog, const std::string& readerPosition = "", const std::string& altFileExtension = ""); /// /// Writes the entire loading warning log to a file. /// /// The filename of the file to write to. - void SaveLoadWarningLog(const std::string &filePath); + void SaveLoadWarningLog(const std::string& filePath); /// /// Writes all the input strings to a log in the order they were entered. /// /// The filename of the file to write to. - void SaveInputLog(const std::string &filePath); + void SaveInputLog(const std::string& filePath); /// /// Writes the entire console buffer to a file. /// /// The filename of the file to write to. /// Whether writing to the file was successful. - bool SaveAllText(const std::string &filePath); + bool SaveAllText(const std::string& filePath); /// /// Clears all previous input. @@ -136,7 +135,7 @@ namespace RTE { /// Prints a string into the console. /// /// The string to print. - void PrintString(const std::string &stringToPrint); + void PrintString(const std::string& stringToPrint); /// /// Opens the console and prints the shortcut help text. @@ -152,26 +151,30 @@ namespace RTE { /// Draws this ConsoleMan's current graphical representation to a BITMAP of choice. /// /// A pointer to a BITMAP to draw on. - void Draw(BITMAP *targetBitmap) const; + void Draw(BITMAP* targetBitmap) const; #pragma endregion protected: - /// /// Enumeration for console states when enabling/disabling the console. NOTE: This can't be lower down because m_ConsoleState relies on this definition. /// - enum ConsoleState { Enabling = 0, Enabled, Disabling, Disabled }; + enum ConsoleState { + Enabling = 0, + Enabled, + Disabling, + Disabled + }; ConsoleState m_ConsoleState; //!< Current state of the console. bool m_ReadOnly; //!< Read-only mode where console text input is disabled and controller input should be preserved. float m_ConsoleScreenRatio; //!< The ratio of the screen that the console should take up, from 0.1 to 1.0 (whole screen). - GUIScreen *m_GUIScreen; //!< GUI Screen for use by the in-game GUI. - GUIInput *m_GUIInput; //!< GUI Input controller. - GUIControlManager *m_GUIControlManager; //!< Manager of the console GUI elements. - GUICollectionBox *m_ParentBox; //!< Collection box of the console GUI. - GUILabel *m_ConsoleText; //!< The label which presents the console output. - GUITextBox *m_InputTextBox; //!< The TextBox which the user types in the edited line. + GUIScreen* m_GUIScreen; //!< GUI Screen for use by the in-game GUI. + GUIInput* m_GUIInput; //!< GUI Input controller. + GUIControlManager* m_GUIControlManager; //!< Manager of the console GUI elements. + GUICollectionBox* m_ParentBox; //!< Collection box of the console GUI. + GUILabel* m_ConsoleText; //!< The label which presents the console output. + GUITextBox* m_InputTextBox; //!< The TextBox which the user types in the edited line. int m_ConsoleTextMaxNumLines; //!< Maximum number of lines to display in the console text label. @@ -184,7 +187,6 @@ namespace RTE { short m_LastLogMove; //!< The last direction the log marker was moved. Needed so that changing directions won't need double tapping. private: - bool m_ConsoleUseMonospaceFont; //!< Whether the console text is using the monospace font. /// @@ -223,8 +225,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - ConsoleMan(const ConsoleMan &reference) = delete; - ConsoleMan & operator=(const ConsoleMan &rhs) = delete; + ConsoleMan(const ConsoleMan& reference) = delete; + ConsoleMan& operator=(const ConsoleMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/FrameMan.cpp b/Source/Managers/FrameMan.cpp index 63a047dde..bbd65d7ad 100644 --- a/Source/Managers/FrameMan.cpp +++ b/Source/Managers/FrameMan.cpp @@ -26,24 +26,24 @@ namespace RTE { - void BitmapDeleter::operator()(BITMAP *bitmap) const { destroy_bitmap(bitmap); } + void BitmapDeleter::operator()(BITMAP* bitmap) const { destroy_bitmap(bitmap); } const std::array, DrawBlendMode::BlendModeCount> FrameMan::c_BlenderSetterFunctions = { - nullptr, // NoBlend obviously has no blender, but we want to keep the indices matching with the enum. - &set_burn_blender, - &set_color_blender, - &set_difference_blender, - &set_dissolve_blender, - &set_dodge_blender, - &set_invert_blender, - &set_luminance_blender, - &set_multiply_blender, - &set_saturation_blender, - &set_screen_blender, - nullptr // Transparency does not rely on the blender setting, it creates a map with the dedicated function instead of with the generic one. + nullptr, // NoBlend obviously has no blender, but we want to keep the indices matching with the enum. + &set_burn_blender, + &set_color_blender, + &set_difference_blender, + &set_dissolve_blender, + &set_dodge_blender, + &set_invert_blender, + &set_luminance_blender, + &set_multiply_blender, + &set_saturation_blender, + &set_screen_blender, + nullptr // Transparency does not rely on the blender setting, it creates a map with the dedicated function instead of with the generic one. }; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::Clear() { m_HSplit = false; @@ -92,7 +92,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int FrameMan::Initialize() { set_color_depth(c_BPP); @@ -120,7 +120,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int FrameMan::CreateBackBuffers() { int resX = g_WindowMan.GetResX(); @@ -173,7 +173,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::CreatePresetColorTables() { // Create RGB lookup table that supposedly speeds up calculation of other color tables. @@ -184,7 +184,7 @@ namespace RTE { int transparencyPresetCount = BlendAmountLimits::MaxBlend / c_BlendAmountStep; for (int index = 0; index <= transparencyPresetCount; ++index) { int presetBlendAmount = index * c_BlendAmountStep; - std::array colorChannelBlendAmounts = { presetBlendAmount, presetBlendAmount, presetBlendAmount, BlendAmountLimits::MinBlend }; + std::array colorChannelBlendAmounts = {presetBlendAmount, presetBlendAmount, presetBlendAmount, BlendAmountLimits::MinBlend}; int adjustedBlendAmount = 255 - (static_cast(255.0F * (1.0F / static_cast(transparencyPresetCount) * static_cast(index)))); m_ColorTables.at(DrawBlendMode::BlendTransparency).try_emplace(colorChannelBlendAmounts); @@ -193,22 +193,22 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::Destroy() { - for (const GUIScreen *guiScreen : m_GUIScreens) { + for (const GUIScreen* guiScreen: m_GUIScreens) { delete guiScreen; } - for (const GUIFont *guiFont : m_LargeFonts) { + for (const GUIFont* guiFont: m_LargeFonts) { delete guiFont; } - for (const GUIFont *guiFont : m_SmallFonts) { + for (const GUIFont* guiFont: m_SmallFonts) { delete guiFont; } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::Update() { // Remove all scheduled primitives, those will be re-added by updates from other entities. @@ -218,16 +218,18 @@ namespace RTE { // Prune unused color tables every 5 real minutes to prevent ridiculous memory usage over time. if (m_ColorTablePruneTimer.IsPastRealMS(300000)) { long long currentTime = g_TimerMan.GetAbsoluteTime() / 10000; - for (std::unordered_map, std::pair> &colorTableMap : m_ColorTables) { + for (std::unordered_map, std::pair>& colorTableMap: m_ColorTables) { if (colorTableMap.size() >= 100) { std::vector> markedForDelete; markedForDelete.reserve(colorTableMap.size()); - for (const auto &[tableKey, tableData] : colorTableMap) { + for (const auto& [tableKey, tableData]: colorTableMap) { long long lastAccessTime = tableData.second; // Mark tables that haven't been accessed in the last minute for deletion. Avoid marking the transparency table presets, those will have lastAccessTime set to -1. - if (lastAccessTime != -1 && (currentTime - lastAccessTime > 60)) { markedForDelete.emplace_back(tableKey); } + if (lastAccessTime != -1 && (currentTime - lastAccessTime > 60)) { + markedForDelete.emplace_back(tableKey); + } } - for (const std::array &keyToDelete : markedForDelete) { + for (const std::array& keyToDelete: markedForDelete) { colorTableMap.erase(keyToDelete); } } @@ -242,10 +244,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::ResetSplitScreens(bool hSplit, bool vSplit) { - if (m_PlayerScreen) { release_bitmap(m_PlayerScreen.get()); } + if (m_PlayerScreen) { + release_bitmap(m_PlayerScreen.get()); + } // Override screen splitting according to settings if needed if ((hSplit || vSplit) && !(hSplit && vSplit) && m_TwoPlayerVSplit) { @@ -274,7 +278,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector FrameMan::GetMiddleOfPlayerScreen(int whichPlayer) { Vector middleOfPlayerScreen; @@ -295,7 +299,7 @@ namespace RTE { return middleOfPlayerScreen; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int FrameMan::GetPlayerFrameBufferWidth(int whichPlayer) const { if (IsInMultiplayerMode()) { @@ -316,7 +320,7 @@ namespace RTE { return m_PlayerScreenWidth; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int FrameMan::GetPlayerFrameBufferHeight(int whichPlayer) const { if (IsInMultiplayerMode()) { @@ -337,17 +341,17 @@ namespace RTE { return m_PlayerScreenHeight; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int FrameMan::CalculateTextHeight(const std::string &text, int maxWidth, bool isSmall) { + int FrameMan::CalculateTextHeight(const std::string& text, int maxWidth, bool isSmall) { return isSmall ? GetSmallFont()->CalculateHeight(text, maxWidth) : GetLargeFont()->CalculateHeight(text, maxWidth); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string FrameMan::SplitStringToFitWidth(const std::string &stringToSplit, int widthLimit, bool useSmallFont) { - GUIFont *fontToUse = GetFont(useSmallFont, false); - auto SplitSingleLineAsNeeded = [this, &widthLimit, &fontToUse](std::string &lineToSplitAsNeeded) { + std::string FrameMan::SplitStringToFitWidth(const std::string& stringToSplit, int widthLimit, bool useSmallFont) { + GUIFont* fontToUse = GetFont(useSmallFont, false); + auto SplitSingleLineAsNeeded = [this, &widthLimit, &fontToUse](std::string& lineToSplitAsNeeded) { int numberOfScreenWidthsForText = static_cast(std::ceil(static_cast(fontToUse->CalculateWidth(lineToSplitAsNeeded)) / static_cast(widthLimit))); if (numberOfScreenWidthsForText > 1) { int splitInterval = static_cast(std::ceil(static_cast(lineToSplitAsNeeded.size()) / static_cast(numberOfScreenWidthsForText))); @@ -384,15 +388,15 @@ namespace RTE { return splitString; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int FrameMan::CalculateTextWidth(const std::string &text, bool isSmall) { + int FrameMan::CalculateTextWidth(const std::string& text, bool isSmall) { return isSmall ? GetSmallFont()->CalculateWidth(text) : GetLargeFont()->CalculateWidth(text); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void FrameMan::SetScreenText(const std::string &message, int whichScreen, int blinkInterval, int displayDuration, bool centered) { + void FrameMan::SetScreenText(const std::string& message, int whichScreen, int blinkInterval, int displayDuration, bool centered) { // See if we can overwrite the previous message if (whichScreen >= 0 && whichScreen < c_MaxScreenCount && m_TextDurationTimer[whichScreen].IsPastRealMS(m_TextDuration[whichScreen])) { m_ScreenText[whichScreen] = message; @@ -403,7 +407,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::ClearScreenText(int whichScreen) { if (whichScreen >= 0 && whichScreen < c_MaxScreenCount) { @@ -414,12 +418,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::SetColorTable(DrawBlendMode blendMode, std::array colorChannelBlendAmounts) { RTEAssert(blendMode > DrawBlendMode::NoBlend && blendMode < DrawBlendMode::BlendModeCount, "Invalid DrawBlendMode or DrawBlendMode::NoBlend passed into FrameMan::SetColorTable. See DrawBlendMode enumeration for defined values."); - for (int &colorChannelBlendAmount : colorChannelBlendAmounts) { + for (int& colorChannelBlendAmount: colorChannelBlendAmounts) { colorChannelBlendAmount = RoundToNearestMultiple(std::clamp(colorChannelBlendAmount, static_cast(BlendAmountLimits::MinBlend), static_cast(BlendAmountLimits::MaxBlend)), c_BlendAmountStep); } @@ -447,7 +451,7 @@ namespace RTE { if (m_ColorTables[blendMode].find(colorChannelBlendAmounts) == m_ColorTables[blendMode].end()) { m_ColorTables[blendMode].try_emplace(colorChannelBlendAmounts); - std::array adjustedColorChannelBlendAmounts = { BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend }; + std::array adjustedColorChannelBlendAmounts = {BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend}; for (int index = 0; index < adjustedColorChannelBlendAmounts.size(); ++index) { adjustedColorChannelBlendAmounts[index] = 255 - (static_cast(255.0F * 0.01F * static_cast(colorChannelBlendAmounts[index]))); } @@ -466,18 +470,18 @@ namespace RTE { m_ColorTables[blendMode].at(colorChannelBlendAmounts).second = usedPresetTransparencyTable ? -1 : (g_TimerMan.GetAbsoluteTime() / 10000); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::SetTransTableFromPreset(TransparencyPreset transPreset) { RTEAssert(transPreset == TransparencyPreset::LessTrans || transPreset == TransparencyPreset::HalfTrans || transPreset == TransparencyPreset::MoreTrans, "Undefined transparency preset value passed in. See TransparencyPreset enumeration for defined values."); - std::array colorChannelBlendAmounts = { transPreset, transPreset, transPreset, BlendAmountLimits::MinBlend }; + std::array colorChannelBlendAmounts = {transPreset, transPreset, transPreset, BlendAmountLimits::MinBlend}; if (m_ColorTables[DrawBlendMode::BlendTransparency].find(colorChannelBlendAmounts) != m_ColorTables[DrawBlendMode::BlendTransparency].end()) { color_map = &m_ColorTables[DrawBlendMode::BlendTransparency].at(colorChannelBlendAmounts).first; m_ColorTables[DrawBlendMode::BlendTransparency].at(colorChannelBlendAmounts).second = -1; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::CreateNewNetworkPlayerBackBuffer(int player, int width, int height) { for (int f = 0; f < 2; f++) { @@ -490,11 +494,11 @@ namespace RTE { m_PlayerScreenHeight = height; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool FrameMan::LoadPalette(const std::string &palettePath) { + bool FrameMan::LoadPalette(const std::string& palettePath) { const std::string fullPalettePath = g_PresetMan.GetFullModulePath(palettePath); - BITMAP *tempBitmap = load_bitmap(fullPalettePath.c_str(), m_Palette); + BITMAP* tempBitmap = load_bitmap(fullPalettePath.c_str(), m_Palette); RTEAssert(tempBitmap, ("Failed to load palette from bitmap with following path:\n\n" + fullPalettePath).c_str()); set_palette(m_Palette); @@ -508,9 +512,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int FrameMan::SaveBitmap(SaveBitmapMode modeToSave, const std::string &nameBase, BITMAP *bitmapToSave) { + int FrameMan::SaveBitmap(SaveBitmapMode modeToSave, const std::string& nameBase, BITMAP* bitmapToSave) { if ((modeToSave == WorldDump || modeToSave == ScenePreviewDump) && !g_ActivityMan.ActivityRunning()) { return 0; } @@ -522,7 +526,7 @@ namespace RTE { #if defined(__GNUC__) && __GNUC__ < 13 std::chrono::time_point now = std::chrono::system_clock::now(); time_t currentTime = std::chrono::system_clock::to_time_t(now); - tm *localCurrentTime = std::localtime(¤tTime); + tm* localCurrentTime = std::localtime(¤tTime); std::array formattedTimeAndDate = {}; std::strftime(formattedTimeAndDate.data(), sizeof(formattedTimeAndDate), "%F_%H-%M-%S", localCurrentTime); @@ -549,10 +553,10 @@ namespace RTE { SaveScreenToBitmap(); // Make a copy of the buffer because it may be overwritten mid thread and everything will be on fire. - BITMAP *outputBitmap = create_bitmap_ex(bitmap_color_depth(m_ScreenDumpBuffer.get()), m_ScreenDumpBuffer->w, m_ScreenDumpBuffer->h); + BITMAP* outputBitmap = create_bitmap_ex(bitmap_color_depth(m_ScreenDumpBuffer.get()), m_ScreenDumpBuffer->w, m_ScreenDumpBuffer->h); stretch_blit(m_ScreenDumpBuffer.get(), outputBitmap, 0, 0, m_ScreenDumpBuffer->w, m_ScreenDumpBuffer->h, 0, 0, outputBitmap->w, outputBitmap->h); - auto saveScreenDump = [fullFileName](BITMAP *bitmapToSaveCopy) { + auto saveScreenDump = [fullFileName](BITMAP* bitmapToSaveCopy) { // nullptr for the PALETTE parameter here because we're saving a 24bpp file and it's irrelevant. if (save_png(fullFileName.c_str(), bitmapToSaveCopy, nullptr) == 0) { g_ConsoleMan.PrintString("SYSTEM: Screen was dumped to: " + fullFileName); @@ -575,7 +579,7 @@ namespace RTE { if (modeToSave == ScenePreviewDump) { DrawWorldDump(true); - BITMAP *scenePreviewDumpBuffer = create_bitmap_ex(c_BPP, c_ScenePreviewWidth, c_ScenePreviewHeight); + BITMAP* scenePreviewDumpBuffer = create_bitmap_ex(c_BPP, c_ScenePreviewWidth, c_ScenePreviewHeight); blit(m_ScenePreviewDumpGradient.get(), scenePreviewDumpBuffer, 0, 0, 0, 0, scenePreviewDumpBuffer->w, scenePreviewDumpBuffer->h); masked_stretch_blit(m_WorldDumpBuffer.get(), scenePreviewDumpBuffer, 0, 0, m_WorldDumpBuffer->w, m_WorldDumpBuffer->h, 0, 0, scenePreviewDumpBuffer->w, scenePreviewDumpBuffer->h); @@ -587,7 +591,7 @@ namespace RTE { } else { DrawWorldDump(); - BITMAP *depthConvertBitmap = create_bitmap_ex(24, m_WorldDumpBuffer->w, m_WorldDumpBuffer->h); + BITMAP* depthConvertBitmap = create_bitmap_ex(24, m_WorldDumpBuffer->w, m_WorldDumpBuffer->h); blit(m_WorldDumpBuffer.get(), depthConvertBitmap, 0, 0, 0, 0, m_WorldDumpBuffer->w, m_WorldDumpBuffer->h); if (save_png(fullFileName.c_str(), depthConvertBitmap, nullptr) == 0) { @@ -616,22 +620,21 @@ namespace RTE { glBindTexture(GL_TEXTURE_2D, g_WindowMan.GetScreenBufferTexture()); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, m_ScreenDumpBuffer->line[0]); - } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int FrameMan::SaveIndexedPNG(const char *fileName, BITMAP *bitmapToSave) const { + int FrameMan::SaveIndexedPNG(const char* fileName, BITMAP* bitmapToSave) const { // nullptr for the PALETTE parameter here because the bitmap is 32bpp and whatever we index it with will end up wrong anyway. save_png(fileName, bitmapToSave, nullptr); int lastColorConversionMode = get_color_conversion(); set_color_conversion(COLORCONV_REDUCE_TO_256); // nullptr for the PALETTE parameter here because we don't need the bad palette from it and don't want it to overwrite anything. - BITMAP *tempLoadBitmap = load_bitmap(fileName, nullptr); + BITMAP* tempLoadBitmap = load_bitmap(fileName, nullptr); std::remove(fileName); - BITMAP *tempConvertingBitmap = create_bitmap_ex(8, bitmapToSave->w, bitmapToSave->h); + BITMAP* tempConvertingBitmap = create_bitmap_ex(8, bitmapToSave->w, bitmapToSave->h); blit(tempLoadBitmap, tempConvertingBitmap, 0, 0, 0, 0, tempConvertingBitmap->w, tempConvertingBitmap->h); int saveResult = save_png(fileName, tempConvertingBitmap, m_Palette); @@ -643,11 +646,13 @@ namespace RTE { return saveResult; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int FrameMan::SharedDrawLine(BITMAP *bitmap, const Vector &start, const Vector &end, int color, int altColor, int skip, int skipStart, bool shortestWrap, bool drawDot, BITMAP *dot) const { + int FrameMan::SharedDrawLine(BITMAP* bitmap, const Vector& start, const Vector& end, int color, int altColor, int skip, int skipStart, bool shortestWrap, bool drawDot, BITMAP* dot) const { RTEAssert(bitmap, "Trying to draw line to null Bitmap"); - if (drawDot) { RTEAssert(dot, "Trying to draw line of dots without specifying a dot Bitmap"); } + if (drawDot) { + RTEAssert(dot, "Trying to draw line of dots without specifying a dot Bitmap"); + } int error = 0; int dom = 0; @@ -663,10 +668,12 @@ namespace RTE { int dotHeight = drawDot ? dot->h : 0; int dotWidth = drawDot ? dot->w : 0; - //acquire_bitmap(bitmap); + // acquire_bitmap(bitmap); // Just make the alt the same color as the main one if no one was specified - if (altColor == 0) { altColor = color; } + if (altColor == 0) { + altColor = color; + } intPos[X] = start.GetFloorIntX(); intPos[Y] = start.GetFloorIntY(); @@ -736,15 +743,15 @@ namespace RTE { } } - //release_bitmap(bitmap); + // release_bitmap(bitmap); // Return the end phase state of the skipping return skipped; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIFont * FrameMan::GetFont(bool isSmall, bool trueColor) { + GUIFont* FrameMan::GetFont(bool isSmall, bool trueColor) { size_t colorIndex = trueColor ? 1 : 0; if (!m_GUIScreens[colorIndex]) { @@ -779,9 +786,9 @@ namespace RTE { return m_LargeFonts[colorIndex]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void FrameMan::UpdateScreenOffsetForSplitScreen(int playerScreen, Vector &screenOffset) const { + void FrameMan::UpdateScreenOffsetForSplitScreen(int playerScreen, Vector& screenOffset) const { switch (playerScreen) { case Players::PlayerTwo: // If both splits, or just VSplit, then in upper right quadrant @@ -807,7 +814,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::Draw() { ZoneScopedN("Draw"); @@ -822,14 +829,14 @@ namespace RTE { std::list screenRelativeEffects; std::list screenRelativeGlowBoxes; - const Activity *pActivity = g_ActivityMan.GetActivity(); + const Activity* pActivity = g_ActivityMan.GetActivity(); for (int playerScreen = 0; playerScreen < screenCount; ++playerScreen) { screenRelativeEffects.clear(); screenRelativeGlowBoxes.clear(); - BITMAP *drawScreen = (screenCount == 1) ? m_BackBuffer8.get() : m_PlayerScreen.get(); - BITMAP *drawScreenGUI = drawScreen; + BITMAP* drawScreen = (screenCount == 1) ? m_BackBuffer8.get() : m_PlayerScreen.get(); + BITMAP* drawScreenGUI = drawScreen; if (IsInMultiplayerMode()) { drawScreen = m_NetworkBackBufferIntermediate8[m_NetworkFrameCurrent][playerScreen].get(); drawScreenGUI = m_NetworkBackBufferIntermediateGUI8[m_NetworkFrameCurrent][playerScreen].get(); @@ -848,7 +855,7 @@ namespace RTE { if (IsInMultiplayerMode()) { int layerCount = 0; - for (const SceneLayer *sceneLayer : g_SceneMan.GetScene()->GetBackLayers()) { + for (const SceneLayer* sceneLayer: g_SceneMan.GetScene()->GetBackLayers()) { SLOffset[playerScreen][layerCount] = sceneLayer->GetOffset(); layerCount++; @@ -862,8 +869,12 @@ namespace RTE { // Adjust the drawing position on the target screen for if the target screen is larger than the scene in non-wrapping dimension. // Scene needs to be displayed centered on the target bitmap then, and that has to be adjusted for when drawing to the screen - if (!g_SceneMan.SceneWrapsX() && drawScreen->w > g_SceneMan.GetSceneWidth()) { targetPos.m_X += (drawScreen->w - g_SceneMan.GetSceneWidth()) / 2; } - if (!g_SceneMan.SceneWrapsY() && drawScreen->h > g_SceneMan.GetSceneHeight()) { targetPos.m_Y += (drawScreen->h - g_SceneMan.GetSceneHeight()) / 2; } + if (!g_SceneMan.SceneWrapsX() && drawScreen->w > g_SceneMan.GetSceneWidth()) { + targetPos.m_X += (drawScreen->w - g_SceneMan.GetSceneWidth()) / 2; + } + if (!g_SceneMan.SceneWrapsY() && drawScreen->h > g_SceneMan.GetSceneHeight()) { + targetPos.m_Y += (drawScreen->h - g_SceneMan.GetSceneHeight()) / 2; + } // Try to move at the frame buffer copy time to maybe prevent wonkyness m_TargetPos[m_NetworkFrameCurrent][playerScreen] = targetPos; @@ -880,7 +891,9 @@ namespace RTE { g_PostProcessMan.GetPostScreenEffectsWrapped(targetPos, drawScreen->w, drawScreen->h, screenRelativeEffects, pActivity->GetTeamOfPlayer(pActivity->PlayerOfScreen(playerScreen))); g_PostProcessMan.GetGlowAreasWrapped(targetPos, drawScreen->w, drawScreen->h, screenRelativeGlowBoxes); - if (IsInMultiplayerMode()) { g_PostProcessMan.SetNetworkPostEffectsList(playerScreen, screenRelativeEffects); } + if (IsInMultiplayerMode()) { + g_PostProcessMan.SetNetworkPostEffectsList(playerScreen, screenRelativeEffects); + } } // TODO: Find out what keeps disabling the clipping on the draw bitmap @@ -893,7 +906,9 @@ namespace RTE { Vector screenOffset; // If we are dealing with split screens, then deal with the fact that we need to draw the player screens to different locations on the final buffer - if (screenCount > 1) { UpdateScreenOffsetForSplitScreen(playerScreen, screenOffset); } + if (screenCount > 1) { + UpdateScreenOffsetForSplitScreen(playerScreen, screenOffset); + } DrawScreenFlash(playerScreen, drawScreenGUI); @@ -926,15 +941,21 @@ namespace RTE { blit(m_NetworkBackBufferFinal8[m_NetworkFrameReady][0].get(), m_BackBuffer8.get(), 0, 0, 0, 0, m_BackBuffer8->w, m_BackBuffer8->h); masked_blit(m_NetworkBackBufferFinalGUI8[m_NetworkFrameReady][0].get(), m_BackBuffer8.get(), 0, 0, 0, 0, m_BackBuffer8->w, m_BackBuffer8->h); - if (g_UInputMan.FlagAltState() || g_UInputMan.FlagCtrlState() || g_UInputMan.FlagShiftState()) { g_PerformanceMan.DrawCurrentPing(); } + if (g_UInputMan.FlagAltState() || g_UInputMan.FlagCtrlState() || g_UInputMan.FlagShiftState()) { + g_PerformanceMan.DrawCurrentPing(); + } m_NetworkBitmapLock[0].unlock(); } } - if (IsInMultiplayerMode()) { PrepareFrameForNetwork(); } + if (IsInMultiplayerMode()) { + PrepareFrameForNetwork(); + } - if (g_ActivityMan.IsInActivity()) { g_PostProcessMan.PostProcess(); } + if (g_ActivityMan.IsInActivity()) { + g_PostProcessMan.PostProcess(); + } // Draw the performance stats and console on top of everything. g_PerformanceMan.Draw(m_BackBuffer32.get()); @@ -946,7 +967,7 @@ namespace RTE { #endif } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::DrawScreenText(int playerScreen, AllegroBitmap playerGUIBitmap) { int textPosY = 0; @@ -958,11 +979,15 @@ namespace RTE { int bufferOrScreenWidth = IsInMultiplayerMode() ? GetPlayerFrameBufferWidth(playerScreen) : GetPlayerScreenWidth(); int bufferOrScreenHeight = IsInMultiplayerMode() ? GetPlayerFrameBufferHeight(playerScreen) : GetPlayerScreenHeight(); - if (m_TextCentered[playerScreen]) { textPosY = (bufferOrScreenHeight / 2) - 52; } + if (m_TextCentered[playerScreen]) { + textPosY = (bufferOrScreenHeight / 2) - 52; + } int screenOcclusionOffsetX = g_CameraMan.GetScreenOcclusion(playerScreen).GetRoundIntX(); // If there's really no room to offset the text into, then don't - if (GetPlayerScreenWidth() <= g_WindowMan.GetResX() / 2) { screenOcclusionOffsetX = 0; } + if (GetPlayerScreenWidth() <= g_WindowMan.GetResX() / 2) { + screenOcclusionOffsetX = 0; + } std::string screenTextToDraw = m_ScreenText[playerScreen]; if (m_TextBlinking[playerScreen] && m_TextBlinkTimer.AlternateReal(m_TextBlinking[playerScreen])) { @@ -992,9 +1017,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void FrameMan::DrawScreenFlash(int playerScreen, BITMAP *playerGUIBitmap) { + void FrameMan::DrawScreenFlash(int playerScreen, BITMAP* playerGUIBitmap) { if (m_FlashScreenColor[playerScreen] != -1) { // If set to flash for a period of time, first be solid and then start flashing slower double timeTillLimit = m_FlashTimer[playerScreen].LeftTillRealTimeLimitMS(); @@ -1007,11 +1032,13 @@ namespace RTE { m_FlashedLastFrame[playerScreen] = true; } } - if (m_FlashTimer[playerScreen].IsPastRealTimeLimit()) { m_FlashScreenColor[playerScreen] = -1; } + if (m_FlashTimer[playerScreen].IsPastRealTimeLimit()) { + m_FlashScreenColor[playerScreen] = -1; + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::DrawWorldDump(bool drawForScenePreview) const { float worldBitmapWidth = static_cast(m_WorldDumpBuffer->w); @@ -1035,7 +1062,7 @@ namespace RTE { // If we're not dumping a scene preview, draw objects and post-effects. if (!drawForScenePreview) { std::list postEffectsList; - BITMAP *effectBitmap = nullptr; + BITMAP* effectBitmap = nullptr; int effectPosX = 0; int effectPosY = 0; int effectStrength = 0; @@ -1047,7 +1074,7 @@ namespace RTE { // Draw post-effects g_PostProcessMan.GetPostScreenEffectsWrapped(targetPos, worldBitmapWidth, worldBitmapHeight, postEffectsList, -1); - for (const PostEffect &postEffect : postEffectsList) { + for (const PostEffect& postEffect: postEffectsList) { effectBitmap = postEffect.m_Bitmap; effectStrength = postEffect.m_Strength; set_screen_blender(effectStrength, effectStrength, effectStrength, effectStrength); @@ -1057,7 +1084,7 @@ namespace RTE { if (postEffect.m_Angle == 0.0F) { draw_trans_sprite(m_WorldDumpBuffer.get(), effectBitmap, effectPosX, effectPosY); } else { - BITMAP *targetBitmap = g_PostProcessMan.GetTempEffectBitmap(effectBitmap); + BITMAP* targetBitmap = g_PostProcessMan.GetTempEffectBitmap(effectBitmap); clear_to_color(targetBitmap, 0); Matrix newAngle(postEffect.m_Angle); @@ -1068,7 +1095,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void FrameMan::PrepareFrameForNetwork() { int dx = 0; @@ -1112,4 +1139,4 @@ namespace RTE { m_NetworkFrameReady = m_NetworkFrameCurrent; m_NetworkFrameCurrent = (m_NetworkFrameCurrent == 0) ? 1 : 0; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/FrameMan.h b/Source/Managers/FrameMan.h index 55d74eb61..db6c0529d 100644 --- a/Source/Managers/FrameMan.h +++ b/Source/Managers/FrameMan.h @@ -15,7 +15,7 @@ namespace RTE { class ScreenShader; struct BitmapDeleter { - void operator() (BITMAP *bitmap) const; + void operator()(BITMAP* bitmap) const; }; /// @@ -26,7 +26,6 @@ namespace RTE { friend class WindowMan; public: - static constexpr int c_BPP = 32; //!< Color depth (bits per pixel). Vector SLOffset[c_MaxScreenCount][c_MaxLayersStoredForNetwork]; //!< SceneLayer offsets for each screen in online multiplayer. @@ -73,22 +72,22 @@ namespace RTE { /// Gets the 8bpp backbuffer bitmap. /// /// A pointer to the BITMAP 8bpp backbuffer. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetBackBuffer8() const { return m_BackBuffer8.get(); } + BITMAP* GetBackBuffer8() const { return m_BackBuffer8.get(); } /// /// Gets the 32bpp backbuffer bitmap. Make sure you don't do any blending stuff to the 8bpp one! /// /// A pointer to the BITMAP 32bpp backbuffer. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetBackBuffer32() const { return m_BackBuffer32.get(); } + BITMAP* GetBackBuffer32() const { return m_BackBuffer32.get(); } /// /// Gets the 32bpp bitmap that is used for overlaying the screen. /// /// A pointer to the overlay BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetOverlayBitmap32() const { return m_OverlayBitmap32.get(); } + BITMAP* GetOverlayBitmap32() const { return m_OverlayBitmap32.get(); } #pragma endregion -#pragma region Split-Screen Handling +#pragma region Split - Screen Handling /// /// Gets whether the screen is split horizontally across the screen, ie as two splitscreens one above the other. /// @@ -178,14 +177,14 @@ namespace RTE { /// /// Whether to get the 32bpp color version of the font. /// A pointer to the requested font, or 0 if no small font was found. - GUIFont * GetSmallFont(bool trueColor = false) { return GetFont(true, trueColor); } + GUIFont* GetSmallFont(bool trueColor = false) { return GetFont(true, trueColor); } /// /// Gets the large font from the GUI engine's current skin. Ownership is NOT transferred! /// /// Whether to get the 32bpp color version of the font. /// A pointer to the requested font, or 0 if no large font was found. - GUIFont * GetLargeFont(bool trueColor = false) { return GetFont(false, trueColor); } + GUIFont* GetLargeFont(bool trueColor = false) { return GetFont(false, trueColor); } /// /// Calculates the width of a text string using the given font size. @@ -193,7 +192,7 @@ namespace RTE { /// Text string. /// Whether to use small or large font. /// Width of the text string. - int CalculateTextWidth(const std::string &text, bool isSmall); + int CalculateTextWidth(const std::string& text, bool isSmall); /// /// Calculates the height of a text string using the given font size. @@ -202,7 +201,7 @@ namespace RTE { /// Maximum width of the text string. /// Whether to use small or large font. /// Height of the text string. - int CalculateTextHeight(const std::string &text, int maxWidth, bool isSmall); + int CalculateTextHeight(const std::string& text, int maxWidth, bool isSmall); /// /// Gets a copy of the passed in string, split into multiple lines as needed to fit within the specified width limit, based on the font to use. @@ -211,7 +210,7 @@ namespace RTE { /// The maximum width each line of the string can be. /// The font the string will use for calculating the string's width. /// A copy of the passed in string, split into multiple lines as needed. - std::string SplitStringToFitWidth(const std::string &stringToSplit, int widthLimit, bool useSmallFont); + std::string SplitStringToFitWidth(const std::string& stringToSplit, int widthLimit, bool useSmallFont); /// /// Gets the message to be displayed on top of each player's screen. @@ -228,7 +227,7 @@ namespace RTE { /// The interval with which the screen will be blinking, in ms. 0 means no blinking. /// The duration, in MS to force this message to display. No other message can be displayed before this expires. ClearScreenText overrides it though. /// Vertically centered on the screen. - void SetScreenText(const std::string &message, int whichScreen = 0, int blinkInterval = 0, int displayDuration = -1, bool centered = false); + void SetScreenText(const std::string& message, int whichScreen = 0, int blinkInterval = 0, int displayDuration = -1, bool centered = false); /// /// Clears the message to be displayed on top of each player's screen. @@ -267,7 +266,11 @@ namespace RTE { /// Which screen to flash. /// What color to flash it. -1 means no color or flash. /// How long a period to fill the frame with color. If 0, a single-frame flash will happen. - void FlashScreen(int screen, int color, float periodMS = 0) { m_FlashScreenColor[screen] = color; m_FlashTimer[screen].SetRealTimeLimitMS(periodMS); m_FlashTimer[screen].Reset(); } + void FlashScreen(int screen, int color, float periodMS = 0) { + m_FlashScreenColor[screen] = color; + m_FlashTimer[screen].SetRealTimeLimitMS(periodMS); + m_FlashTimer[screen].Reset(); + } /// /// Draws a line that can be dotted or with other effects. @@ -281,7 +284,7 @@ namespace RTE { /// The start of the skipping phase. If skip is 10 and this is 5, the first dot will be drawn after 5 pixels. /// Whether the line should take the shortest possible route across scene wraps. /// The end state of the skipping phase. Eg if 4 is returned here the last dot was placed 4 pixels ago. - int DrawLine(BITMAP *bitmap, const Vector &start, const Vector &end, int color, int altColor = 0, int skip = 0, int skipStart = 0, bool shortestWrap = false) const { + int DrawLine(BITMAP* bitmap, const Vector& start, const Vector& end, int color, int altColor = 0, int skip = 0, int skipStart = 0, bool shortestWrap = false) const { return SharedDrawLine(bitmap, start, end, color, altColor, skip, skipStart, shortestWrap, false, nullptr); } @@ -296,7 +299,7 @@ namespace RTE { /// The start of the skipping phase. If skip is 10 and this is 5, the first dot will be drawn after 5 pixels. /// Whether the line should take the shortest possible route across scene wraps. /// The end state of the skipping phase. Eg if 4 is returned here the last dot was placed 4 pixels ago. - int DrawDotLine(BITMAP *bitmap, const Vector &start, const Vector &end, BITMAP *dot, int skip = 0, int skipStart = 0, bool shortestWrap = false) const { + int DrawDotLine(BITMAP* bitmap, const Vector& start, const Vector& end, BITMAP* dot, int skip = 0, int skipStart = 0, bool shortestWrap = false) const { return SharedDrawLine(bitmap, start, end, 0, 0, skip, skipStart, shortestWrap, true, dot); } #pragma endregion @@ -333,56 +336,56 @@ namespace RTE { /// /// Which player screen to get backbuffer bitmap for. /// A pointer to the 8bpp backbuffer BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBuffer8Ready(int player) const { return m_NetworkBackBufferFinal8[m_NetworkFrameReady][player].get(); } + BITMAP* GetNetworkBackBuffer8Ready(int player) const { return m_NetworkBackBufferFinal8[m_NetworkFrameReady][player].get(); } /// /// Gets the ready 8bpp backbuffer GUI bitmap used to draw network transmitted image on top of everything. /// /// Which player screen to get GUI backbuffer bitmap for. /// A pointer to the 8bpp GUI backbuffer BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBufferGUI8Ready(int player) const { return m_NetworkBackBufferFinalGUI8[m_NetworkFrameReady][player].get(); } + BITMAP* GetNetworkBackBufferGUI8Ready(int player) const { return m_NetworkBackBufferFinalGUI8[m_NetworkFrameReady][player].get(); } /// /// Gets the current 8bpp backbuffer bitmap used to draw network transmitted image on top of everything. /// /// Which player screen to get backbuffer bitmap for. /// A pointer to the 8bpp backbuffer BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBuffer8Current(int player) const { return m_NetworkBackBufferFinal8[m_NetworkFrameCurrent][player].get(); } + BITMAP* GetNetworkBackBuffer8Current(int player) const { return m_NetworkBackBufferFinal8[m_NetworkFrameCurrent][player].get(); } /// /// Gets the current 8bpp backbuffer GUI bitmap used to draw network transmitted image on top of everything. /// /// Which player screen to get backbuffer bitmap for. /// A pointer to the 8bpp GUI backbuffer BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBufferGUI8Current(int player) const { return m_NetworkBackBufferFinalGUI8[m_NetworkFrameCurrent][player].get(); } + BITMAP* GetNetworkBackBufferGUI8Current(int player) const { return m_NetworkBackBufferFinalGUI8[m_NetworkFrameCurrent][player].get(); } /// /// Gets the ready 8bpp intermediate backbuffer bitmap used to copy network transmitted image to before sending. /// /// Which player screen to get intermediate bitmap for. /// A pointer to the 8bpp intermediate BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBufferIntermediate8Ready(int player) const { return m_NetworkBackBufferIntermediate8[m_NetworkFrameReady][player].get(); } + BITMAP* GetNetworkBackBufferIntermediate8Ready(int player) const { return m_NetworkBackBufferIntermediate8[m_NetworkFrameReady][player].get(); } /// /// Gets the ready 8bpp intermediate backbuffer GUI bitmap used to copy network transmitted image to before sending. /// /// Which player screen to get intermediate GUI bitmap for. /// A pointer to the 8bpp intermediate GUI BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBufferIntermediate8Current(int player) const { return m_NetworkBackBufferIntermediate8[m_NetworkFrameCurrent][player].get(); } + BITMAP* GetNetworkBackBufferIntermediate8Current(int player) const { return m_NetworkBackBufferIntermediate8[m_NetworkFrameCurrent][player].get(); } /// /// Gets the current 8bpp intermediate backbuffer bitmap used to copy network transmitted image to before sending. /// /// Which player screen to get intermediate bitmap for. /// A pointer to the 8bpp intermediate BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBufferIntermediateGUI8Ready(int player) const { return m_NetworkBackBufferIntermediateGUI8[m_NetworkFrameReady][player].get(); } + BITMAP* GetNetworkBackBufferIntermediateGUI8Ready(int player) const { return m_NetworkBackBufferIntermediateGUI8[m_NetworkFrameReady][player].get(); } /// /// Gets the current 8bpp intermediate backbuffer GUI bitmap used to copy network transmitted image to before sending. /// /// Which player screen to get intermediate GUI bitmap for. /// A pointer to the 8bpp intermediate GUI BITMAP. OWNERSHIP IS NOT TRANSFERRED! - BITMAP * GetNetworkBackBufferIntermediateGUI8Current(int player) const { return m_NetworkBackBufferIntermediateGUI8[m_NetworkFrameCurrent][player].get(); } + BITMAP* GetNetworkBackBufferIntermediateGUI8Current(int player) const { return m_NetworkBackBufferIntermediateGUI8[m_NetworkFrameCurrent][player].get(); } // TODO: Figure out. /// @@ -425,19 +428,23 @@ namespace RTE { /// /// String with the path to the palette bitmap file. /// Whether palette loaded successfully or not. - bool LoadPalette(const std::string &palettePath); + bool LoadPalette(const std::string& palettePath); /// /// Gets the ContentFile describing the location of the color palette. /// /// An reference to a ContentFile which described the palette location. - const ContentFile & GetPaletteFile() const { return m_PaletteFile; } + const ContentFile& GetPaletteFile() const { return m_PaletteFile; } /// /// Fades the palette in from black at a specified speed. /// /// Speed specified from (slowest) 1 - 64 (fastest). - void FadeInPalette(int fadeSpeed = 1) { PALETTE pal; get_palette(pal); fade_in(pal, Limit(fadeSpeed, 64, 1)); } + void FadeInPalette(int fadeSpeed = 1) { + PALETTE pal; + get_palette(pal); + fade_in(pal, Limit(fadeSpeed, 64, 1)); + } /// /// Fades the palette out to black at a specified speed. @@ -453,36 +460,40 @@ namespace RTE { /// The individual bitmap that will be dumped. /// The filename of the file to save to, WITHOUT EXTENSION. /// 0 for success, anything below 0 is a sign of failure. - int SaveBitmapToPNG(BITMAP *bitmap, const char *nameBase) { return SaveBitmap(SingleBitmap, nameBase, bitmap); } + int SaveBitmapToPNG(BITMAP* bitmap, const char* nameBase) { return SaveBitmap(SingleBitmap, nameBase, bitmap); } /// /// Dumps a bitmap of the screen backbuffer to a 8bpp PNG file. /// /// The filename of the file to save to, WITHOUT EXTENSION. /// 0 for success, anything below 0 is a sign of failure. - int SaveScreenToPNG(const char *nameBase) { return SaveBitmap(ScreenDump, nameBase); } + int SaveScreenToPNG(const char* nameBase) { return SaveBitmap(ScreenDump, nameBase); } /// /// Dumps a bitmap of everything on the scene to a PNG file. /// /// The filename of the file to save to, WITHOUT EXTENSION. /// 0 for success, anything below 0 is a sign of failure. - int SaveWorldToPNG(const char *nameBase) { return SaveBitmap(WorldDump, nameBase); } + int SaveWorldToPNG(const char* nameBase) { return SaveBitmap(WorldDump, nameBase); } /// /// Dumps a miniature screenshot of the whole scene to be used as a preview to a PNG file. /// /// The filename of the file to save to, WITHOUT EXTENSION. /// 0 for success, anything below 0 is a sign of failure. - int SaveWorldPreviewToPNG(const char *nameBase) { return SaveBitmap(ScenePreviewDump, nameBase); } + int SaveWorldPreviewToPNG(const char* nameBase) { return SaveBitmap(ScenePreviewDump, nameBase); } #pragma endregion private: - /// /// Enumeration with different settings for the SaveBitmap() method. /// - enum SaveBitmapMode { SingleBitmap, ScreenDump, WorldDump, ScenePreviewDump }; + enum SaveBitmapMode { + SingleBitmap, + ScreenDump, + WorldDump, + ScenePreviewDump + }; static const std::array, DrawBlendMode::BlendModeCount> c_BlenderSetterFunctions; //!< Array of function references to Allegro blender setters for convenient access when creating new color tables. @@ -509,9 +520,9 @@ namespace RTE { int m_PlayerScreenWidth; //!< Width of the screen of each player. Will be smaller than resolution only if the screen is split. int m_PlayerScreenHeight; //!< Height of the screen of each player. Will be smaller than resolution only if the screen is split. - std::array m_GUIScreens; //!< GUI screen objects kept and owned just for the fonts. - std::array m_SmallFonts; //!< Pointers to the standard small font for quick access. - std::array m_LargeFonts; //!< Pointers to the standard large font for quick access. + std::array m_GUIScreens; //!< GUI screen objects kept and owned just for the fonts. + std::array m_SmallFonts; //!< Pointers to the standard small font for quick access. + std::array m_LargeFonts; //!< Pointers to the standard large font for quick access. std::string m_ScreenText[c_MaxScreenCount]; //!< The text to be displayed on each player's screen. bool m_TextCentered[c_MaxScreenCount]; //!< Whether screen text is centered vertically. @@ -569,7 +580,7 @@ namespace RTE { /// /// The player screen to update offset for. /// Vector representing the screen offset. - void UpdateScreenOffsetForSplitScreen(int playerScreen, Vector &screenOffset) const; + void UpdateScreenOffsetForSplitScreen(int playerScreen, Vector& screenOffset) const; /// /// Draws all the text messages to the specified player screen. This is called during Draw(). @@ -583,7 +594,7 @@ namespace RTE { /// /// The player screen the flash effect will be shown to. /// The bitmap the flash effect will be drawn on. - void DrawScreenFlash(int playerScreen, BITMAP *playerGUIBitmap); + void DrawScreenFlash(int playerScreen, BITMAP* playerGUIBitmap); /// /// Renders current frame and marks it ready for network transmission. This is called during Draw(). @@ -608,7 +619,7 @@ namespace RTE { /// /// The individual bitmap that will be dumped. 0 or nullptr if not in SingleBitmap mode. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int SaveBitmap(SaveBitmapMode modeToSave, const std::string &nameBase, BITMAP *bitmapToSave = nullptr); + int SaveBitmap(SaveBitmapMode modeToSave, const std::string& nameBase, BITMAP* bitmapToSave = nullptr); /// /// Saves the front buffer to the screen dump buffer. @@ -626,7 +637,7 @@ namespace RTE { /// It works by first saving the 32bpp bitmap as is, then loading it back under the REDUCE_TO_256 color conversion mode, blitting it to a fresh bitmap and saving it again with the passed in palette. /// The re-blitted bitmap is properly 8bpp and will be indexed correctly. The old saved file is deleted in the process before the new one is saved. /// - int SaveIndexedPNG(const char *fileName, BITMAP *bitmapToSave) const; + int SaveIndexedPNG(const char* fileName, BITMAP* bitmapToSave) const; #pragma endregion /// @@ -643,7 +654,7 @@ namespace RTE { /// Whether to draw a regular line or a dot line. True for dot line. /// The bitmap to be used for dots (will be centered). /// The end state of the skipping phase. Eg if 4 is returned here the last dot was placed 4 pixels ago. - int SharedDrawLine(BITMAP *bitmap, const Vector &start, const Vector &end, int color, int altColor = 0, int skip = 0, int skipStart = 0, bool shortestWrap = false, bool drawDot = false, BITMAP *dot = nullptr) const; + int SharedDrawLine(BITMAP* bitmap, const Vector& start, const Vector& end, int color, int altColor = 0, int skip = 0, int skipStart = 0, bool shortestWrap = false, bool drawDot = false, BITMAP* dot = nullptr) const; /// /// Gets the requested font from the GUI engine's current skin. Ownership is NOT transferred! @@ -651,7 +662,7 @@ namespace RTE { /// Size of font to get. True for small font, false for large font. /// Whether to get the 32bpp color version of the font. /// A pointer to the requested font, or 0 if no font was found. - GUIFont * GetFont(bool isSmall, bool trueColor); + GUIFont* GetFont(bool isSmall, bool trueColor); /// /// Clears all the member variables of this FrameMan, effectively resetting the members of this abstraction level only. @@ -659,8 +670,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - FrameMan(const FrameMan &reference) = delete; - FrameMan & operator=(const FrameMan &rhs) = delete; + FrameMan(const FrameMan& reference) = delete; + FrameMan& operator=(const FrameMan& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Managers/LuaMan.cpp b/Source/Managers/LuaMan.cpp index 33e68b48a..3a467337a 100644 --- a/Source/Managers/LuaMan.cpp +++ b/Source/Managers/LuaMan.cpp @@ -9,9 +9,9 @@ namespace RTE { - const std::unordered_set LuaMan::c_FileAccessModes = { "r", "r+", "w", "w+", "a", "a+", "rt", "wt"}; + const std::unordered_set LuaMan::c_FileAccessModes = {"r", "r+", "w", "w+", "a", "a+", "rt", "wt"}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaStateWrapper::Clear() { m_State = nullptr; @@ -21,7 +21,7 @@ namespace RTE { m_CurrentlyRunningScriptPath = ""; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaStateWrapper::Initialize() { m_State = luaL_newstate(); @@ -32,17 +32,17 @@ namespace RTE { lua_gc(m_State, LUA_GCSTOP, 0); const luaL_Reg libsToLoad[] = { - { LUA_COLIBNAME, luaopen_base }, - { LUA_LOADLIBNAME, luaopen_package }, - { LUA_TABLIBNAME, luaopen_table }, - { LUA_STRLIBNAME, luaopen_string }, - { LUA_MATHLIBNAME, luaopen_math }, - { LUA_DBLIBNAME, luaopen_debug }, - { LUA_JITLIBNAME, luaopen_jit }, - { NULL, NULL } // End of array + {LUA_COLIBNAME, luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {LUA_JITLIBNAME, luaopen_jit}, + {NULL, NULL} // End of array }; - for (const luaL_Reg *lib = libsToLoad; lib->func; lib++) { + for (const luaL_Reg* lib = libsToLoad; lib->func; lib++) { if (g_SettingsMan.DisableLuaJIT() && strcmp(lib->name, LUA_JITLIBNAME) == 0) { continue; } @@ -52,156 +52,156 @@ namespace RTE { } // LuaJIT should start automatically after we load the library (if we loaded it) but we're making sure it did anyway. - if (!g_SettingsMan.DisableLuaJIT() && !luaJIT_setmode(m_State, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_ON)) { RTEAbort("Failed to initialize LuaJIT!\nIf this error persists, please disable LuaJIT with \"Settings.ini\" property \"DisableLuaJIT\"."); } + if (!g_SettingsMan.DisableLuaJIT() && !luaJIT_setmode(m_State, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_ON)) { + RTEAbort("Failed to initialize LuaJIT!\nIf this error persists, please disable LuaJIT with \"Settings.ini\" property \"DisableLuaJIT\"."); + } // From LuaBind documentation: // As mentioned in the Lua documentation, it is possible to pass an error handler function to lua_pcall(). LuaBind makes use of lua_pcall() internally when calling member functions and free functions. // It is possible to set the error handler function that LuaBind will use globally: - //set_pcall_callback(&AddFileAndLineToError); // NOTE: this seems to do nothing because retrieving the error from the lua stack wasn't done correctly. The current error handling works just fine but might look into doing this properly sometime later. + // set_pcall_callback(&AddFileAndLineToError); // NOTE: this seems to do nothing because retrieving the error from the lua stack wasn't done correctly. The current error handling works just fine but might look into doing this properly sometime later. // Register all relevant bindings to the state. Note that the order of registration is important, as bindings can't derive from an unregistered type (inheritance and all that). - luabind::module(m_State)[ - luabind::class_("LuaManager") - .property("TempEntity", &LuaStateWrapper::GetTempEntity) - .property("TempEntities", &LuaStateWrapper::GetTempEntityVector, luabind::return_stl_iterator) - .def("SelectRand", &LuaStateWrapper::SelectRand) - .def("RangeRand", &LuaStateWrapper::RangeRand) - .def("PosRand", &LuaStateWrapper::PosRand) - .def("NormalRand", &LuaStateWrapper::NormalRand) - .def("GetDirectoryList", &LuaStateWrapper::DirectoryList, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("GetFileList", &LuaStateWrapper::FileList, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) - .def("FileExists", &LuaStateWrapper::FileExists) - .def("DirectoryExists", &LuaStateWrapper::DirectoryExists) - .def("IsValidModulePath", &LuaStateWrapper::IsValidModulePath) - .def("FileOpen", &LuaStateWrapper::FileOpen) - .def("FileClose", &LuaStateWrapper::FileClose) - .def("FileRemove", &LuaStateWrapper::FileRemove) - .def("DirectoryCreate", &LuaStateWrapper::DirectoryCreate1) - .def("DirectoryCreate", &LuaStateWrapper::DirectoryCreate2) - .def("DirectoryRemove", &LuaStateWrapper::DirectoryRemove1) - .def("DirectoryRemove", &LuaStateWrapper::DirectoryRemove2) - .def("FileRename", &LuaStateWrapper::FileRename) - .def("DirectoryRename", &LuaStateWrapper::DirectoryRename) - .def("FileReadLine", &LuaStateWrapper::FileReadLine) - .def("FileWriteLine", &LuaStateWrapper::FileWriteLine) - .def("FileEOF", &LuaStateWrapper::FileEOF), - - luabind::def("DeleteEntity", &LuaAdaptersUtility::DeleteEntity, luabind::adopt(_1)), // NOT a member function, so adopting _1 instead of the _2 for the first param, since there's no "this" pointer!! - luabind::def("LERP", &LERP), - luabind::def("EaseIn", &EaseIn), - luabind::def("EaseOut", &EaseOut), - luabind::def("EaseInOut", &EaseInOut), - luabind::def("Clamp", &Limit), - luabind::def("NormalizeAngleBetween0And2PI", &NormalizeAngleBetween0And2PI), - luabind::def("NormalizeAngleBetweenNegativePIAndPI", &NormalizeAngleBetweenNegativePIAndPI), - luabind::def("AngleWithinRange", &AngleWithinRange), - luabind::def("ClampAngle", &ClampAngle), - luabind::def("GetPPM", &LuaAdaptersUtility::GetPPM), - luabind::def("GetMPP", &LuaAdaptersUtility::GetMPP), - luabind::def("GetPPL", &LuaAdaptersUtility::GetPPL), - luabind::def("GetLPP", &LuaAdaptersUtility::GetLPP), - luabind::def("GetPathFindingDefaultDigStrength", &LuaAdaptersUtility::GetPathFindingDefaultDigStrength), - luabind::def("RoundFloatToPrecision", &RoundFloatToPrecision), - luabind::def("RoundToNearestMultiple", &RoundToNearestMultiple), - - RegisterLuaBindingsOfType(SystemLuaBindings, Vector), - RegisterLuaBindingsOfType(SystemLuaBindings, Box), - RegisterLuaBindingsOfType(EntityLuaBindings, Entity), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, SoundContainer), - RegisterLuaBindingsOfType(EntityLuaBindings, SoundSet), - RegisterLuaBindingsOfType(EntityLuaBindings, LimbPath), - RegisterLuaBindingsOfAbstractType(EntityLuaBindings, SceneObject), - RegisterLuaBindingsOfAbstractType(EntityLuaBindings, MovableObject), - RegisterLuaBindingsOfType(EntityLuaBindings, Material), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, MOPixel), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, TerrainObject), - RegisterLuaBindingsOfAbstractType(EntityLuaBindings, MOSprite), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, MOSParticle), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, MOSRotating), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Attachable), - RegisterLuaBindingsOfAbstractType(EntityLuaBindings, Emission), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, AEmitter), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, AEJetpack), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, PEmitter), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Actor), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ADoor), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Arm), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Leg), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, AHuman), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ACrab), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Turret), - RegisterLuaBindingsOfAbstractType(EntityLuaBindings, ACraft), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ACDropShip), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ACRocket), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, HeldDevice), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Magazine), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Round), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, HDFirearm), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ThrownDevice), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, TDExplosive), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, PieSlice), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, PieMenu), - RegisterLuaBindingsOfType(EntityLuaBindings, Gib), - RegisterLuaBindingsOfType(SystemLuaBindings, Controller), - RegisterLuaBindingsOfType(SystemLuaBindings, Timer), - RegisterLuaBindingsOfType(SystemLuaBindings, PathRequest), - RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Scene), - RegisterLuaBindingsOfType(EntityLuaBindings, SceneArea), - RegisterLuaBindingsOfType(EntityLuaBindings, SceneLayer), - RegisterLuaBindingsOfType(EntityLuaBindings, SLBackground), - RegisterLuaBindingsOfAbstractType(EntityLuaBindings, Deployment), - RegisterLuaBindingsOfType(SystemLuaBindings, DataModule), - RegisterLuaBindingsOfType(ActivityLuaBindings, Activity), - RegisterLuaBindingsOfAbstractType(ActivityLuaBindings, GameActivity), - RegisterLuaBindingsOfAbstractType(EntityLuaBindings, GlobalScript), - RegisterLuaBindingsOfType(EntityLuaBindings, MetaPlayer), - RegisterLuaBindingsOfType(GUILuaBindings, GUIBanner), - RegisterLuaBindingsOfType(GUILuaBindings, BuyMenuGUI), - RegisterLuaBindingsOfType(GUILuaBindings, SceneEditorGUI), - RegisterLuaBindingsOfType(ManagerLuaBindings, ActivityMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, AudioMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, CameraMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, ConsoleMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, FrameMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, MetaMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, MovableMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, PerformanceMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, PostProcessMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, PresetMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, PrimitiveMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, SceneMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, SettingsMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, TimerMan), - RegisterLuaBindingsOfType(ManagerLuaBindings, UInputMan), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, GraphicalPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, LinePrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, ArcPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, SplinePrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, BoxPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, BoxFillPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, RoundedBoxPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, RoundedBoxFillPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, CirclePrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, CircleFillPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, EllipsePrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, EllipseFillPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, TrianglePrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, TriangleFillPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, TextPrimitive), - RegisterLuaBindingsOfType(PrimitiveLuaBindings, BitmapPrimitive), - RegisterLuaBindingsOfType(InputLuaBindings, InputDevice), - RegisterLuaBindingsOfType(InputLuaBindings, InputElements), - RegisterLuaBindingsOfType(InputLuaBindings, JoyButtons), - RegisterLuaBindingsOfType(InputLuaBindings, JoyDirections), - RegisterLuaBindingsOfType(InputLuaBindings, MouseButtons), - RegisterLuaBindingsOfType(InputLuaBindings, SDL_Keycode), - RegisterLuaBindingsOfType(InputLuaBindings, SDL_Scancode), - RegisterLuaBindingsOfType(InputLuaBindings, SDL_GameControllerButton), - RegisterLuaBindingsOfType(InputLuaBindings, SDL_GameControllerAxis), - RegisterLuaBindingsOfType(MiscLuaBindings, AlarmEvent), - RegisterLuaBindingsOfType(MiscLuaBindings, Directions), - RegisterLuaBindingsOfType(MiscLuaBindings, DrawBlendMode) - ]; + luabind::module(m_State)[luabind::class_("LuaManager") + .property("TempEntity", &LuaStateWrapper::GetTempEntity) + .property("TempEntities", &LuaStateWrapper::GetTempEntityVector, luabind::return_stl_iterator) + .def("SelectRand", &LuaStateWrapper::SelectRand) + .def("RangeRand", &LuaStateWrapper::RangeRand) + .def("PosRand", &LuaStateWrapper::PosRand) + .def("NormalRand", &LuaStateWrapper::NormalRand) + .def("GetDirectoryList", &LuaStateWrapper::DirectoryList, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetFileList", &LuaStateWrapper::FileList, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("FileExists", &LuaStateWrapper::FileExists) + .def("DirectoryExists", &LuaStateWrapper::DirectoryExists) + .def("IsValidModulePath", &LuaStateWrapper::IsValidModulePath) + .def("FileOpen", &LuaStateWrapper::FileOpen) + .def("FileClose", &LuaStateWrapper::FileClose) + .def("FileRemove", &LuaStateWrapper::FileRemove) + .def("DirectoryCreate", &LuaStateWrapper::DirectoryCreate1) + .def("DirectoryCreate", &LuaStateWrapper::DirectoryCreate2) + .def("DirectoryRemove", &LuaStateWrapper::DirectoryRemove1) + .def("DirectoryRemove", &LuaStateWrapper::DirectoryRemove2) + .def("FileRename", &LuaStateWrapper::FileRename) + .def("DirectoryRename", &LuaStateWrapper::DirectoryRename) + .def("FileReadLine", &LuaStateWrapper::FileReadLine) + .def("FileWriteLine", &LuaStateWrapper::FileWriteLine) + .def("FileEOF", &LuaStateWrapper::FileEOF), + + luabind::def("DeleteEntity", &LuaAdaptersUtility::DeleteEntity, luabind::adopt(_1)), // NOT a member function, so adopting _1 instead of the _2 for the first param, since there's no "this" pointer!! + luabind::def("LERP", &LERP), + luabind::def("EaseIn", &EaseIn), + luabind::def("EaseOut", &EaseOut), + luabind::def("EaseInOut", &EaseInOut), + luabind::def("Clamp", &Limit), + luabind::def("NormalizeAngleBetween0And2PI", &NormalizeAngleBetween0And2PI), + luabind::def("NormalizeAngleBetweenNegativePIAndPI", &NormalizeAngleBetweenNegativePIAndPI), + luabind::def("AngleWithinRange", &AngleWithinRange), + luabind::def("ClampAngle", &ClampAngle), + luabind::def("GetPPM", &LuaAdaptersUtility::GetPPM), + luabind::def("GetMPP", &LuaAdaptersUtility::GetMPP), + luabind::def("GetPPL", &LuaAdaptersUtility::GetPPL), + luabind::def("GetLPP", &LuaAdaptersUtility::GetLPP), + luabind::def("GetPathFindingDefaultDigStrength", &LuaAdaptersUtility::GetPathFindingDefaultDigStrength), + luabind::def("RoundFloatToPrecision", &RoundFloatToPrecision), + luabind::def("RoundToNearestMultiple", &RoundToNearestMultiple), + + RegisterLuaBindingsOfType(SystemLuaBindings, Vector), + RegisterLuaBindingsOfType(SystemLuaBindings, Box), + RegisterLuaBindingsOfType(EntityLuaBindings, Entity), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, SoundContainer), + RegisterLuaBindingsOfType(EntityLuaBindings, SoundSet), + RegisterLuaBindingsOfType(EntityLuaBindings, LimbPath), + RegisterLuaBindingsOfAbstractType(EntityLuaBindings, SceneObject), + RegisterLuaBindingsOfAbstractType(EntityLuaBindings, MovableObject), + RegisterLuaBindingsOfType(EntityLuaBindings, Material), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, MOPixel), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, TerrainObject), + RegisterLuaBindingsOfAbstractType(EntityLuaBindings, MOSprite), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, MOSParticle), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, MOSRotating), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Attachable), + RegisterLuaBindingsOfAbstractType(EntityLuaBindings, Emission), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, AEmitter), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, AEJetpack), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, PEmitter), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Actor), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ADoor), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Arm), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Leg), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, AHuman), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ACrab), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Turret), + RegisterLuaBindingsOfAbstractType(EntityLuaBindings, ACraft), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ACDropShip), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ACRocket), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, HeldDevice), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Magazine), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Round), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, HDFirearm), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, ThrownDevice), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, TDExplosive), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, PieSlice), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, PieMenu), + RegisterLuaBindingsOfType(EntityLuaBindings, Gib), + RegisterLuaBindingsOfType(SystemLuaBindings, Controller), + RegisterLuaBindingsOfType(SystemLuaBindings, Timer), + RegisterLuaBindingsOfType(SystemLuaBindings, PathRequest), + RegisterLuaBindingsOfConcreteType(EntityLuaBindings, Scene), + RegisterLuaBindingsOfType(EntityLuaBindings, SceneArea), + RegisterLuaBindingsOfType(EntityLuaBindings, SceneLayer), + RegisterLuaBindingsOfType(EntityLuaBindings, SLBackground), + RegisterLuaBindingsOfAbstractType(EntityLuaBindings, Deployment), + RegisterLuaBindingsOfType(SystemLuaBindings, DataModule), + RegisterLuaBindingsOfType(ActivityLuaBindings, Activity), + RegisterLuaBindingsOfAbstractType(ActivityLuaBindings, GameActivity), + RegisterLuaBindingsOfAbstractType(EntityLuaBindings, GlobalScript), + RegisterLuaBindingsOfType(EntityLuaBindings, MetaPlayer), + RegisterLuaBindingsOfType(GUILuaBindings, GUIBanner), + RegisterLuaBindingsOfType(GUILuaBindings, BuyMenuGUI), + RegisterLuaBindingsOfType(GUILuaBindings, SceneEditorGUI), + RegisterLuaBindingsOfType(ManagerLuaBindings, ActivityMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, AudioMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, CameraMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, ConsoleMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, FrameMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, MetaMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, MovableMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, PerformanceMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, PostProcessMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, PresetMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, PrimitiveMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, SceneMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, SettingsMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, TimerMan), + RegisterLuaBindingsOfType(ManagerLuaBindings, UInputMan), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, GraphicalPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, LinePrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, ArcPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, SplinePrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, BoxPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, BoxFillPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, RoundedBoxPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, RoundedBoxFillPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, CirclePrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, CircleFillPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, EllipsePrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, EllipseFillPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, TrianglePrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, TriangleFillPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, TextPrimitive), + RegisterLuaBindingsOfType(PrimitiveLuaBindings, BitmapPrimitive), + RegisterLuaBindingsOfType(InputLuaBindings, InputDevice), + RegisterLuaBindingsOfType(InputLuaBindings, InputElements), + RegisterLuaBindingsOfType(InputLuaBindings, JoyButtons), + RegisterLuaBindingsOfType(InputLuaBindings, JoyDirections), + RegisterLuaBindingsOfType(InputLuaBindings, MouseButtons), + RegisterLuaBindingsOfType(InputLuaBindings, SDL_Keycode), + RegisterLuaBindingsOfType(InputLuaBindings, SDL_Scancode), + RegisterLuaBindingsOfType(InputLuaBindings, SDL_GameControllerButton), + RegisterLuaBindingsOfType(InputLuaBindings, SDL_GameControllerAxis), + RegisterLuaBindingsOfType(MiscLuaBindings, AlarmEvent), + RegisterLuaBindingsOfType(MiscLuaBindings, Directions), + RegisterLuaBindingsOfType(MiscLuaBindings, DrawBlendMode)]; // Assign the manager instances to globals in the lua master state luabind::globals(m_State)["TimerMan"] = &g_TimerMan; @@ -225,68 +225,67 @@ namespace RTE { m_RandomGenerator.Seed(seed); luaL_dostring(m_State, - // Add cls() as a shortcut to ConsoleMan:Clear(). - "cls = function() ConsoleMan:Clear(); end" - "\n" - // Override "print" in the lua state to output to the console. - "print = function(stringToPrint) ConsoleMan:PrintString(\"PRINT: \" .. tostring(stringToPrint)); end" - "\n" - // Override random functions to appear global instead of under LuaMan - "SelectRand = function(lower, upper) return LuaMan:SelectRand(lower, upper); end;\n" - "RangeRand = function(lower, upper) return LuaMan:RangeRand(lower, upper); end;\n" - "PosRand = function() return LuaMan:PosRand(); end;\n" - "NormalRand = function() return LuaMan:NormalRand(); end;\n" - // Override "math.random" in the lua state to use RTETools MT19937 implementation. Preserve return types of original to not break all the things. - "math.random = function(lower, upper) if lower ~= nil and upper ~= nil then return LuaMan:SelectRand(lower, upper); elseif lower ~= nil then return LuaMan:SelectRand(1, lower); else return LuaMan:PosRand(); end end" - "\n" - // Override "dofile"/"loadfile" to be able to account for Data/ or Mods/ directory. - "OriginalDoFile = dofile; dofile = function(filePath) filePath = PresetMan:GetFullModulePath(filePath); if filePath ~= '' then return OriginalDoFile(filePath); end end;" - "OriginalLoadFile = loadfile; loadfile = function(filePath) filePath = PresetMan:GetFullModulePath(filePath); if filePath ~= '' then return OriginalLoadFile(filePath); end end;" - // Internal helper functions to add callbacks for async pathing requests - "_AsyncPathCallbacks = {};" - "_AddAsyncPathCallback = function(id, callback) _AsyncPathCallbacks[id] = callback; end\n" - "_TriggerAsyncPathCallback = function(id, param) if _AsyncPathCallbacks[id] ~= nil then _AsyncPathCallbacks[id](param); _AsyncPathCallbacks[id] = nil; end end\n" - ); + // Add cls() as a shortcut to ConsoleMan:Clear(). + "cls = function() ConsoleMan:Clear(); end" + "\n" + // Override "print" in the lua state to output to the console. + "print = function(stringToPrint) ConsoleMan:PrintString(\"PRINT: \" .. tostring(stringToPrint)); end" + "\n" + // Override random functions to appear global instead of under LuaMan + "SelectRand = function(lower, upper) return LuaMan:SelectRand(lower, upper); end;\n" + "RangeRand = function(lower, upper) return LuaMan:RangeRand(lower, upper); end;\n" + "PosRand = function() return LuaMan:PosRand(); end;\n" + "NormalRand = function() return LuaMan:NormalRand(); end;\n" + // Override "math.random" in the lua state to use RTETools MT19937 implementation. Preserve return types of original to not break all the things. + "math.random = function(lower, upper) if lower ~= nil and upper ~= nil then return LuaMan:SelectRand(lower, upper); elseif lower ~= nil then return LuaMan:SelectRand(1, lower); else return LuaMan:PosRand(); end end" + "\n" + // Override "dofile"/"loadfile" to be able to account for Data/ or Mods/ directory. + "OriginalDoFile = dofile; dofile = function(filePath) filePath = PresetMan:GetFullModulePath(filePath); if filePath ~= '' then return OriginalDoFile(filePath); end end;" + "OriginalLoadFile = loadfile; loadfile = function(filePath) filePath = PresetMan:GetFullModulePath(filePath); if filePath ~= '' then return OriginalLoadFile(filePath); end end;" + // Internal helper functions to add callbacks for async pathing requests + "_AsyncPathCallbacks = {};" + "_AddAsyncPathCallback = function(id, callback) _AsyncPathCallbacks[id] = callback; end\n" + "_TriggerAsyncPathCallback = function(id, param) if _AsyncPathCallbacks[id] ~= nil then _AsyncPathCallbacks[id](param); _AsyncPathCallbacks[id] = nil; end end\n"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaStateWrapper::Destroy() { lua_close(m_State); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int LuaStateWrapper::SelectRand(int minInclusive, int maxInclusive) { return m_RandomGenerator.RandomNum(minInclusive, maxInclusive); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// double LuaStateWrapper::RangeRand(double minInclusive, double maxInclusive) { return m_RandomGenerator.RandomNum(minInclusive, maxInclusive); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// double LuaStateWrapper::NormalRand() { return m_RandomGenerator.RandomNormalNum(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// double LuaStateWrapper::PosRand() { return m_RandomGenerator.RandomNum(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Passthrough LuaMan Functions const std::vector* LuaStateWrapper::DirectoryList(const std::string& path) { return g_LuaMan.DirectoryList(path); } const std::vector* LuaStateWrapper::FileList(const std::string& path) { return g_LuaMan.FileList(path); } - bool LuaStateWrapper::FileExists(const std::string &path) { return g_LuaMan.FileExists(path); } - bool LuaStateWrapper::DirectoryExists(const std::string &path) { return g_LuaMan.DirectoryExists(path); } - bool LuaStateWrapper::IsValidModulePath(const std::string &path) { return g_LuaMan.IsValidModulePath(path); } + bool LuaStateWrapper::FileExists(const std::string& path) { return g_LuaMan.FileExists(path); } + bool LuaStateWrapper::DirectoryExists(const std::string& path) { return g_LuaMan.DirectoryExists(path); } + bool LuaStateWrapper::IsValidModulePath(const std::string& path) { return g_LuaMan.IsValidModulePath(path); } int LuaStateWrapper::FileOpen(const std::string& path, const std::string& accessMode) { return g_LuaMan.FileOpen(path, accessMode); } void LuaStateWrapper::FileClose(int fileIndex) { return g_LuaMan.FileClose(fileIndex); } void LuaStateWrapper::FileCloseAll() { return g_LuaMan.FileCloseAll(); } @@ -301,13 +300,13 @@ namespace RTE { void LuaStateWrapper::FileWriteLine(int fileIndex, const std::string& line) { return g_LuaMan.FileWriteLine(fileIndex, line); } bool LuaStateWrapper::FileEOF(int fileIndex) { return g_LuaMan.FileEOF(fileIndex); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::Clear() { m_OpenedFiles.fill(nullptr); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::Initialize() { m_MasterScriptState.Initialize(); @@ -318,57 +317,56 @@ namespace RTE { } m_ScriptStates = std::vector(luaStateCount); - for (LuaStateWrapper &luaState : m_ScriptStates) { + for (LuaStateWrapper& luaState: m_ScriptStates) { luaState.Initialize(); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - LuaStateWrapper & LuaMan::GetMasterScriptState() { - return m_MasterScriptState; - } + LuaStateWrapper& LuaMan::GetMasterScriptState() { + return m_MasterScriptState; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - LuaStatesArray & LuaMan::GetThreadedScriptStates() { + LuaStatesArray& LuaMan::GetThreadedScriptStates() { return m_ScriptStates; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - thread_local LuaStateWrapper * s_luaStateOverride = nullptr; - LuaStateWrapper * LuaMan::GetThreadLuaStateOverride() const { + thread_local LuaStateWrapper* s_luaStateOverride = nullptr; + LuaStateWrapper* LuaMan::GetThreadLuaStateOverride() const { return s_luaStateOverride; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaMan::SetThreadLuaStateOverride(LuaStateWrapper * luaState) { + void LuaMan::SetThreadLuaStateOverride(LuaStateWrapper* luaState) { s_luaStateOverride = luaState; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// thread_local LuaStateWrapper* s_currentLuaState = nullptr; LuaStateWrapper* LuaMan::GetThreadCurrentLuaState() const { return s_currentLuaState; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - LuaStateWrapper * LuaMan::GetAndLockFreeScriptState() { + LuaStateWrapper* LuaMan::GetAndLockFreeScriptState() { if (s_luaStateOverride) { // We're creating this object in a multithreaded environment, ensure that it's assigned to the same script state as us bool success = s_luaStateOverride->GetMutex().try_lock(); - RTEAssert(success, "Our lua state override for our thread already belongs to another thread!") - return s_luaStateOverride; + RTEAssert(success, "Our lua state override for our thread already belongs to another thread!") return s_luaStateOverride; } // TODO // It would be nice to assign to least-saturated state, but that's a bit tricky with MO registering... /*auto itr = std::min_element(m_ScriptStates.begin(), m_ScriptStates.end(), - [](const LuaStateWrapper& lhs, const LuaStateWrapper& rhs) { return lhs.GetRegisteredMOs().size() < rhs.GetRegisteredMOs().size(); } + [](const LuaStateWrapper& lhs, const LuaStateWrapper& rhs) { return lhs.GetRegisteredMOs().size() < rhs.GetRegisteredMOs().size(); } ); bool success = itr->GetMutex().try_lock(); @@ -385,32 +383,32 @@ namespace RTE { return &m_ScriptStates[ourState]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaMan::ClearUserModuleCache() { + void LuaMan::ClearUserModuleCache() { m_GarbageCollectionTask.wait(); m_MasterScriptState.ClearLuaScriptCache(); - for (LuaStateWrapper& luaState : m_ScriptStates) { + for (LuaStateWrapper& luaState: m_ScriptStates) { luaState.ClearLuaScriptCache(); } m_MasterScriptState.ClearUserModuleCache(); - for (LuaStateWrapper& luaState : m_ScriptStates) { + for (LuaStateWrapper& luaState: m_ScriptStates) { luaState.ClearUserModuleCache(); } - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaMan::AddLuaScriptCallback(const std::function &callback) { + void LuaMan::AddLuaScriptCallback(const std::function& callback) { std::scoped_lock lock(m_ScriptCallbacksMutex); m_ScriptCallbacks.emplace_back(callback); - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaMan::ExecuteLuaScriptCallbacks() { + void LuaMan::ExecuteLuaScriptCallbacks() { std::vector> callbacks; // Move our functions into the local buffer to clear the existing callbacks and to lock for as little time as possible @@ -419,17 +417,17 @@ namespace RTE { callbacks.swap(m_ScriptCallbacks); } - for (const std::function &callback : callbacks) { + for (const std::function& callback: callbacks) { callback(); } - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const std::unordered_map LuaMan::GetScriptTimings() const { std::unordered_map timings = m_MasterScriptState.GetScriptTimings(); - for (const LuaStateWrapper &luaState : m_ScriptStates) { - for (auto&& [functionName, timing] : luaState.GetScriptTimings()) { + for (const LuaStateWrapper& luaState: m_ScriptStates) { + for (auto&& [functionName, timing]: luaState.GetScriptTimings()) { auto& existing = timings[functionName]; existing.m_CallCount += timing.m_CallCount; existing.m_Time = std::max(existing.m_Time, timing.m_Time); @@ -438,7 +436,7 @@ namespace RTE { return timings; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::Destroy() { for (int i = 0; i < c_MaxOpenFiles; ++i) { @@ -447,48 +445,48 @@ namespace RTE { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaStateWrapper::ClearUserModuleCache() { luaL_dostring(m_State, "for m, n in pairs(package.loaded) do if type(n) == \"boolean\" then package.loaded[m] = nil; end; end;"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaStateWrapper::ClearLuaScriptCache() { m_ScriptCache.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Entity *LuaStateWrapper::GetTempEntity() const { - return m_TempEntity; - } + Entity* LuaStateWrapper::GetTempEntity() const { + return m_TempEntity; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaStateWrapper::SetTempEntity(Entity *entity) { + void LuaStateWrapper::SetTempEntity(Entity* entity) { m_TempEntity = entity; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::vector & LuaStateWrapper::GetTempEntityVector() const { - return m_TempEntityVector; - } + const std::vector& LuaStateWrapper::GetTempEntityVector() const { + return m_TempEntityVector; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaStateWrapper::SetTempEntityVector(const std::vector &entityVector) { + void LuaStateWrapper::SetTempEntityVector(const std::vector& entityVector) { m_TempEntityVector.reserve(entityVector.size()); - for (const Entity *entity : entityVector) { - m_TempEntityVector.push_back(const_cast(entity)); + for (const Entity* entity: entityVector) { + m_TempEntityVector.push_back(const_cast(entity)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaStateWrapper::SetLuaPath(const std::string &filePath) { + void LuaStateWrapper::SetLuaPath(const std::string& filePath) { const std::string moduleName = g_PresetMan.GetModuleNameFromPath(filePath); const std::string moduleFolder = g_PresetMan.IsModuleOfficial(moduleName) ? System::GetDataDirectory() : System::GetModDirectory(); const std::string scriptPath = moduleFolder + moduleName + "/?.lua"; @@ -508,60 +506,72 @@ namespace RTE { lua_pop(m_State, 1); // get rid of package table from top of stack. } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::unordered_map & LuaStateWrapper::GetScriptTimings() const { + const std::unordered_map& LuaStateWrapper::GetScriptTimings() const { return m_ScriptTimings; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaStateWrapper::RunScriptFunctionString(const std::string &functionName, const std::string &selfObjectName, const std::vector &variablesToSafetyCheck, const std::vector &functionEntityArguments, const std::vector &functionLiteralArguments) { + int LuaStateWrapper::RunScriptFunctionString(const std::string& functionName, const std::string& selfObjectName, const std::vector& variablesToSafetyCheck, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments) { std::stringstream scriptString; if (!variablesToSafetyCheck.empty()) { scriptString << "if "; - for (const std::string_view &variableToSafetyCheck : variablesToSafetyCheck) { - if (&variableToSafetyCheck != &variablesToSafetyCheck[0]) { scriptString << " and "; } + for (const std::string_view& variableToSafetyCheck: variablesToSafetyCheck) { + if (&variableToSafetyCheck != &variablesToSafetyCheck[0]) { + scriptString << " and "; + } scriptString << variableToSafetyCheck; } scriptString << " then "; } - if (!functionEntityArguments.empty()) { scriptString << "local entityArguments = LuaMan.TempEntities; "; } + if (!functionEntityArguments.empty()) { + scriptString << "local entityArguments = LuaMan.TempEntities; "; + } // Lock here, even though we also lock in RunScriptString(), to ensure that the temp entity vector isn't stomped by separate threads. std::lock_guard lock(m_Mutex); s_currentLuaState = this; scriptString << functionName + "("; - if (!selfObjectName.empty()) { scriptString << selfObjectName; } + if (!selfObjectName.empty()) { + scriptString << selfObjectName; + } bool isFirstFunctionArgument = selfObjectName.empty(); if (!functionEntityArguments.empty()) { SetTempEntityVector(functionEntityArguments); - for (const Entity *functionEntityArgument : functionEntityArguments) { - if (!isFirstFunctionArgument) { scriptString << ", "; } + for (const Entity* functionEntityArgument: functionEntityArguments) { + if (!isFirstFunctionArgument) { + scriptString << ", "; + } scriptString << "(To" + functionEntityArgument->GetClassName() + " and To" + functionEntityArgument->GetClassName() + "(entityArguments()) or entityArguments())"; isFirstFunctionArgument = false; } } if (!functionLiteralArguments.empty()) { - for (const std::string_view &functionLiteralArgument : functionLiteralArguments) { - if (!isFirstFunctionArgument) { scriptString << ", "; } + for (const std::string_view& functionLiteralArgument: functionLiteralArguments) { + if (!isFirstFunctionArgument) { + scriptString << ", "; + } scriptString << std::string(functionLiteralArgument); isFirstFunctionArgument = false; } } scriptString << ");"; - if (!variablesToSafetyCheck.empty()) { scriptString << " end;"; } + if (!variablesToSafetyCheck.empty()) { + scriptString << " end;"; + } int result = RunScriptString(scriptString.str()); m_TempEntityVector.clear(); return result; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaStateWrapper::RunScriptString(const std::string &scriptString, bool consoleErrors) { + int LuaStateWrapper::RunScriptString(const std::string& scriptString, bool consoleErrors) { if (scriptString.empty()) { return -1; } @@ -588,9 +598,9 @@ namespace RTE { return error; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaStateWrapper::RunScriptFunctionObject(const LuabindObjectWrapper *functionObject, const std::string &selfGlobalTableName, const std::string &selfGlobalTableKey, const std::vector &functionEntityArguments, const std::vector &functionLiteralArguments, const std::vector &functionObjectArguments) { + int LuaStateWrapper::RunScriptFunctionObject(const LuabindObjectWrapper* functionObject, const std::string& selfGlobalTableName, const std::string& selfGlobalTableKey, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments, const std::vector& functionObjectArguments) { int status = 0; std::lock_guard lock(m_Mutex); @@ -608,13 +618,13 @@ namespace RTE { argumentCount++; } - for (const Entity *functionEntityArgument : functionEntityArguments) { - std::unique_ptr downCastEntityAsLuabindObjectWrapper(LuaAdaptersEntityCast::s_EntityToLuabindObjectCastFunctions.at(functionEntityArgument->GetClassName())(const_cast(functionEntityArgument), m_State)); + for (const Entity* functionEntityArgument: functionEntityArguments) { + std::unique_ptr downCastEntityAsLuabindObjectWrapper(LuaAdaptersEntityCast::s_EntityToLuabindObjectCastFunctions.at(functionEntityArgument->GetClassName())(const_cast(functionEntityArgument), m_State)); downCastEntityAsLuabindObjectWrapper->GetLuabindObject()->push(m_State); } - for (const std::string_view &functionLiteralArgument : functionLiteralArguments) { - char *stringToDoubleConversionFailed = nullptr; + for (const std::string_view& functionLiteralArgument: functionLiteralArguments) { + char* stringToDoubleConversionFailed = nullptr; if (functionLiteralArgument == "nil") { lua_pushnil(m_State); } else if (functionLiteralArgument == "true" || functionLiteralArgument == "false") { @@ -626,7 +636,7 @@ namespace RTE { } } - for (const LuabindObjectWrapper *functionObjectArgument : functionObjectArguments) { + for (const LuabindObjectWrapper* functionObjectArgument: functionObjectArguments) { if (functionObjectArgument->GetLuabindObject()->interpreter() != m_State) { LuabindObjectWrapper copy = functionObjectArgument->GetCopyForState(*m_State); copy.GetLuabindObject()->push(m_State); @@ -663,9 +673,9 @@ namespace RTE { return status; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaStateWrapper::RunScriptFile(const std::string &filePath, bool consoleErrors, bool doInSandboxedEnvironment) { + int LuaStateWrapper::RunScriptFile(const std::string& filePath, bool consoleErrors, bool doInSandboxedEnvironment) { const std::string fullScriptPath = g_PresetMan.GetFullModulePath(filePath); if (fullScriptPath.empty()) { m_LastError = "Can't run a script file with an empty filepath!"; @@ -741,7 +751,7 @@ namespace RTE { return error; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaStateWrapper::RetrieveFunctions(const std::string& funcObjectName, const std::vector& functionNamesToLookFor, std::unordered_map& outFunctionNamesAndObjects) { std::lock_guard lock(m_Mutex); @@ -753,11 +763,11 @@ namespace RTE { } auto& newScript = m_ScriptCache[funcObjectName.c_str()]; - for (auto& pair : newScript.functionNamesAndObjects) { + for (auto& pair: newScript.functionNamesAndObjects) { delete pair.second; } newScript.functionNamesAndObjects.clear(); - for (const std::string& functionName : functionNamesToLookFor) { + for (const std::string& functionName: functionNamesToLookFor) { luabind::object functionObject = funcHoldingObject[functionName]; if (luabind::type(functionObject) == LUA_TFUNCTION) { luabind::object* functionObjectCopyForStoring = new luabind::object(functionObject); @@ -765,7 +775,7 @@ namespace RTE { } } - for (auto& pair : newScript.functionNamesAndObjects) { + for (auto& pair: newScript.functionNamesAndObjects) { luabind::object* functionObjectCopyForStoring = new luabind::object(*pair.second->GetLuabindObject()); outFunctionNamesAndObjects.try_emplace(pair.first, new LuabindObjectWrapper(functionObjectCopyForStoring, funcObjectName)); } @@ -773,9 +783,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaStateWrapper::RunScriptFileAndRetrieveFunctions(const std::string &filePath, const std::vector &functionNamesToLookFor, std::unordered_map &outFunctionNamesAndObjects, bool forceReload) { + int LuaStateWrapper::RunScriptFileAndRetrieveFunctions(const std::string& filePath, const std::vector& functionNamesToLookFor, std::unordered_map& outFunctionNamesAndObjects, bool forceReload) { static bool disableCaching = false; forceReload = forceReload || disableCaching; @@ -783,7 +793,7 @@ namespace RTE { // TODO - fix activity restarting needing to force reload auto cachedScript = m_ScriptCache.find(filePath); if (!forceReload && cachedScript != m_ScriptCache.end()) { - for (auto& pair : cachedScript->second.functionNamesAndObjects) { + for (auto& pair: cachedScript->second.functionNamesAndObjects) { luabind::object* functionObjectCopyForStoring = new luabind::object(*pair.second->GetLuabindObject()); outFunctionNamesAndObjects.try_emplace(pair.first, new LuabindObjectWrapper(functionObjectCopyForStoring, filePath)); } @@ -805,25 +815,25 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaStateWrapper::Update() { - for (MovableObject* mo : m_AddedRegisteredMOs) { + void LuaStateWrapper::Update() { + for (MovableObject* mo: m_AddedRegisteredMOs) { m_RegisteredMOs.insert(mo); } m_AddedRegisteredMOs.clear(); - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaStateWrapper::ClearScriptTimings() { m_ScriptTimings.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaStateWrapper::ExpressionIsTrue(const std::string &expression, bool consoleErrors) { - if (expression.empty()) { + bool LuaStateWrapper::ExpressionIsTrue(const std::string& expression, bool consoleErrors) { + if (expression.empty()) { return false; } bool result = false; @@ -846,11 +856,11 @@ namespace RTE { lua_pop(m_State, 1); return result; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaStateWrapper::SavePointerAsGlobal(void *objectToSave, const std::string &globalName) { + void LuaStateWrapper::SavePointerAsGlobal(void* objectToSave, const std::string& globalName) { std::lock_guard lock(m_Mutex); // Push the pointer onto the Lua stack. @@ -859,9 +869,9 @@ namespace RTE { lua_setglobal(m_State, globalName.c_str()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaStateWrapper::GlobalIsDefined(const std::string &globalName) { + bool LuaStateWrapper::GlobalIsDefined(const std::string& globalName) { std::lock_guard lock(m_Mutex); // Get the var you want onto the stack so we can check it. @@ -874,9 +884,9 @@ namespace RTE { return isDefined; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaStateWrapper::TableEntryIsDefined(const std::string &tableName, const std::string &indexName) { + bool LuaStateWrapper::TableEntryIsDefined(const std::string& tableName, const std::string& indexName) { std::lock_guard lock(m_Mutex); // Push the table onto the stack, checking if it even exists. @@ -896,25 +906,26 @@ namespace RTE { return isDefined; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaStateWrapper::ErrorExists() const { - return !m_LastError.empty();; - } + bool LuaStateWrapper::ErrorExists() const { + return !m_LastError.empty(); + ; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string LuaStateWrapper::GetLastError() const { - return m_LastError; - } + std::string LuaStateWrapper::GetLastError() const { + return m_LastError; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaStateWrapper::ClearErrors() { + void LuaStateWrapper::ClearErrors() { m_LastError.clear(); - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string LuaStateWrapper::DescribeLuaStack() { int indexOfTopOfStack = lua_gettop(m_State); @@ -939,54 +950,58 @@ namespace RTE { stackDescription << lua_typename(m_State, type); break; } - if (i - 1 > 0) { stackDescription << "\n"; } + if (i - 1 > 0) { + stackDescription << "\n"; + } } return stackDescription.str(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::vector * LuaMan::DirectoryList(const std::string &path) { + const std::vector* LuaMan::DirectoryList(const std::string& path) { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); - auto *directoryPaths = new std::vector(); + auto* directoryPaths = new std::vector(); if (IsValidModulePath(fullPath)) { #ifndef _WIN32 fullPath = GetCaseInsensitiveFullPath(fullPath); #endif - if (std::filesystem::exists(fullPath)) - { - for (const std::filesystem::directory_entry &directoryEntry : std::filesystem::directory_iterator(fullPath)) { - if (directoryEntry.is_directory()) { directoryPaths->emplace_back(directoryEntry.path().filename().generic_string()); } + if (std::filesystem::exists(fullPath)) { + for (const std::filesystem::directory_entry& directoryEntry: std::filesystem::directory_iterator(fullPath)) { + if (directoryEntry.is_directory()) { + directoryPaths->emplace_back(directoryEntry.path().filename().generic_string()); + } } } } return directoryPaths; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::vector * LuaMan::FileList(const std::string &path) { + const std::vector* LuaMan::FileList(const std::string& path) { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); - auto *filePaths = new std::vector(); + auto* filePaths = new std::vector(); if (IsValidModulePath(fullPath)) { #ifndef _WIN32 fullPath = GetCaseInsensitiveFullPath(fullPath); #endif - if (std::filesystem::exists(fullPath)) - { - for (const std::filesystem::directory_entry &directoryEntry : std::filesystem::directory_iterator(fullPath)) { - if (directoryEntry.is_regular_file()) { filePaths->emplace_back(directoryEntry.path().filename().generic_string()); } + if (std::filesystem::exists(fullPath)) { + for (const std::filesystem::directory_entry& directoryEntry: std::filesystem::directory_iterator(fullPath)) { + if (directoryEntry.is_regular_file()) { + filePaths->emplace_back(directoryEntry.path().filename().generic_string()); + } } } } return filePaths; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaMan::FileExists(const std::string &path) { + bool LuaMan::FileExists(const std::string& path) { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); if (IsValidModulePath(fullPath)) { #ifndef _WIN32 @@ -997,9 +1012,9 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool LuaMan::DirectoryExists(const std::string &path) { + bool LuaMan::DirectoryExists(const std::string& path) { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); if (IsValidModulePath(fullPath)) { #ifndef _WIN32 @@ -1010,16 +1025,16 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: Move to ModuleMan, once the ModuleMan PR has been merged - bool LuaMan::IsValidModulePath(const std::string &path) { + bool LuaMan::IsValidModulePath(const std::string& path) { return (path.find("..") == std::string::npos) && (path.find(System::GetModulePackageExtension()) != std::string::npos); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int LuaMan::FileOpen(const std::string &path, const std::string &accessMode) { + int LuaMan::FileOpen(const std::string& path, const std::string& accessMode) { if (c_FileAccessModes.find(accessMode) == c_FileAccessModes.end()) { g_ConsoleMan.PrintString("ERROR: Cannot open file, invalid file access mode specified."); return -1; @@ -1040,9 +1055,9 @@ namespace RTE { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); if (IsValidModulePath(fullPath)) { #ifdef _WIN32 - FILE *file = fopen(fullPath.c_str(), accessMode.c_str()); + FILE* file = fopen(fullPath.c_str(), accessMode.c_str()); #else - FILE *file = [&fullPath, &accessMode]() -> FILE* { + FILE* file = [&fullPath, &accessMode]() -> FILE* { if (std::filesystem::exists(fullPath)) { return fopen(fullPath.c_str(), accessMode.c_str()); } @@ -1056,7 +1071,7 @@ namespace RTE { // Iterate over all entries in the path part's directory, // to check if the path part is in there case insensitively - for (const std::filesystem::path &filesystemEntryPath : std::filesystem::directory_iterator(inspectedPath)) { + for (const std::filesystem::path& filesystemEntryPath: std::filesystem::directory_iterator(inspectedPath)) { if (StringsEqualCaseInsensitive(filesystemEntryPath.filename().generic_string(), relativeFilePathIterator->generic_string())) { inspectedPath = filesystemEntryPath; @@ -1090,7 +1105,7 @@ namespace RTE { return -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::FileClose(int fileIndex) { if (fileIndex > -1 && fileIndex < c_MaxOpenFiles && m_OpenedFiles.at(fileIndex)) { @@ -1099,7 +1114,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::FileCloseAll() { for (int file = 0; file < c_MaxOpenFiles; ++file) { @@ -1107,7 +1122,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaMan::FileRemove(const std::string& path) { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); @@ -1123,7 +1138,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaMan::DirectoryCreate(const std::string& path, bool recursive) { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); @@ -1137,13 +1152,13 @@ namespace RTE { } else { return std::filesystem::create_directory(fullPath); } - } catch (const std::filesystem::filesystem_error &e) {} + } catch (const std::filesystem::filesystem_error& e) {} } g_ConsoleMan.PrintString("ERROR: Failed to remove directory " + path); return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaMan::DirectoryRemove(const std::string& path, bool recursive) { std::string fullPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(path); @@ -1158,14 +1173,14 @@ namespace RTE { } else { return std::filesystem::remove(fullPath); } - } catch (const std::filesystem::filesystem_error &e) {} + } catch (const std::filesystem::filesystem_error& e) {} } } g_ConsoleMan.PrintString("ERROR: Failed to remove directory " + path); return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaMan::FileRename(const std::string& oldPath, const std::string& newPath) { std::string fullOldPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(oldPath); @@ -1177,19 +1192,18 @@ namespace RTE { #endif // Ensures parity between Linux which can overwrite an empty directory, while Windows can't // Ensures parity between Linux which can't rename a directory to a newPath that is a file in order to overwrite it, while Windows can - if (std::filesystem::is_regular_file(fullOldPath) && !std::filesystem::exists(fullNewPath)) - { + if (std::filesystem::is_regular_file(fullOldPath) && !std::filesystem::exists(fullNewPath)) { try { std::filesystem::rename(fullOldPath, fullNewPath); return true; - } catch (const std::filesystem::filesystem_error &e) {} + } catch (const std::filesystem::filesystem_error& e) {} } } g_ConsoleMan.PrintString("ERROR: Failed to rename oldPath " + oldPath + " to newPath " + newPath); return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaMan::DirectoryRename(const std::string& oldPath, const std::string& newPath) { std::string fullOldPath = System::GetWorkingDirectory() + g_PresetMan.GetFullModulePath(oldPath); @@ -1201,19 +1215,18 @@ namespace RTE { #endif // Ensures parity between Linux which can overwrite an empty directory, while Windows can't // Ensures parity between Linux which can't rename a directory to a newPath that is a file in order to overwrite it, while Windows can - if (std::filesystem::is_directory(fullOldPath) && !std::filesystem::exists(fullNewPath)) - { + if (std::filesystem::is_directory(fullOldPath) && !std::filesystem::exists(fullNewPath)) { try { std::filesystem::rename(fullOldPath, fullNewPath); return true; - } catch (const std::filesystem::filesystem_error &e) {} + } catch (const std::filesystem::filesystem_error& e) {} } } g_ConsoleMan.PrintString("ERROR: Failed to rename oldPath " + oldPath + " to newPath " + newPath); return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string LuaMan::FileReadLine(int fileIndex) { if (fileIndex > -1 && fileIndex < c_MaxOpenFiles && m_OpenedFiles.at(fileIndex)) { @@ -1227,9 +1240,9 @@ namespace RTE { return ""; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LuaMan::FileWriteLine(int fileIndex, const std::string &line) { + void LuaMan::FileWriteLine(int fileIndex, const std::string& line) { if (fileIndex > -1 && fileIndex < c_MaxOpenFiles && m_OpenedFiles.at(fileIndex)) { if (fputs(line.c_str(), m_OpenedFiles[fileIndex]) == EOF) { g_ConsoleMan.PrintString("ERROR: Failed to write to file. File might have been opened without writing permissions or is corrupt."); @@ -1239,7 +1252,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LuaMan::FileEOF(int fileIndex) { if (fileIndex > -1 && fileIndex < c_MaxOpenFiles && m_OpenedFiles.at(fileIndex)) { @@ -1249,13 +1262,13 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::Update() { ZoneScoped; m_MasterScriptState.Update(); - for (LuaStateWrapper &luaState : m_ScriptStates) { + for (LuaStateWrapper& luaState: m_ScriptStates) { luaState.Update(); } @@ -1263,10 +1276,10 @@ namespace RTE { m_GarbageCollectionTask.wait(); // Apply all deletions queued from lua - LuabindObjectWrapper::ApplyQueuedDeletions(); + LuabindObjectWrapper::ApplyQueuedDeletions(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::StartAsyncGarbageCollection() { ZoneScoped; @@ -1275,30 +1288,29 @@ namespace RTE { allStates.reserve(m_ScriptStates.size() + 1); allStates.push_back(&m_MasterScriptState); - for (LuaStateWrapper& wrapper : m_ScriptStates) { + for (LuaStateWrapper& wrapper: m_ScriptStates) { allStates.push_back(&wrapper); } m_GarbageCollectionTask = BS::multi_future(); - for (LuaStateWrapper* luaState : allStates) { + for (LuaStateWrapper* luaState: allStates) { m_GarbageCollectionTask.push_back( - g_ThreadMan.GetPriorityThreadPool().submit([luaState]() { - ZoneScopedN("Lua Garbage Collection"); - std::lock_guard lock(luaState->GetMutex()); - lua_gc(luaState->GetLuaState(), LUA_GCCOLLECT, 0); // we'd use GCSTEP but fuck lua it's trash - lua_gc(luaState->GetLuaState(), LUA_GCSTOP, 0); - }) - ); + g_ThreadMan.GetPriorityThreadPool().submit([luaState]() { + ZoneScopedN("Lua Garbage Collection"); + std::lock_guard lock(luaState->GetMutex()); + lua_gc(luaState->GetLuaState(), LUA_GCCOLLECT, 0); // we'd use GCSTEP but fuck lua it's trash + lua_gc(luaState->GetLuaState(), LUA_GCSTOP, 0); + })); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LuaMan::ClearScriptTimings() { m_MasterScriptState.ClearScriptTimings(); - for (LuaStateWrapper& luaState : m_ScriptStates) { + for (LuaStateWrapper& luaState: m_ScriptStates) { luaState.ClearScriptTimings(); } } -} +} // namespace RTE diff --git a/Source/Managers/LuaMan.h b/Source/Managers/LuaMan.h index d6358c615..e4192da1f 100644 --- a/Source/Managers/LuaMan.h +++ b/Source/Managers/LuaMan.h @@ -51,31 +51,31 @@ namespace RTE { /// Gets a temporary Entity that can be accessed in the Lua state. /// /// The temporary entity. Ownership is NOT transferred! - Entity * GetTempEntity() const; + Entity* GetTempEntity() const; /// /// Sets a temporary Entity that can be accessed in the Lua state. /// /// The temporary entity. Ownership is NOT transferred! - void SetTempEntity(Entity *entity); + void SetTempEntity(Entity* entity); /// /// Gets the temporary vector of Entities that can be accessed in the Lua state. /// /// The temporary vector of entities. Ownership is NOT transferred! - const std::vector & GetTempEntityVector() const; + const std::vector& GetTempEntityVector() const; /// /// Sets a temporary vector of Entities that can be accessed in the Lua state. These Entities are const_cast so they're non-const, for ease-of-use in Lua. /// /// The temporary vector of entities. Ownership is NOT transferred! - void SetTempEntityVector(const std::vector &entityVector); + void SetTempEntityVector(const std::vector& entityVector); /// /// Sets the proper package.path for the script to run. /// /// The path to the file to load and run. - void SetLuaPath(const std::string &filePath); + void SetLuaPath(const std::string& filePath); /// /// Gets this LuaStateWrapper's internal lua state. @@ -87,7 +87,7 @@ namespace RTE { /// Gets m_ScriptTimings. /// /// m_ScriptTimings. - const std::unordered_map & GetScriptTimings() const; + const std::unordered_map& GetScriptTimings() const; /// /// Gets the currently running script filepath, if applicable. @@ -107,13 +107,16 @@ namespace RTE { /// Unregisters an MO as using us. /// /// The MO to unregister as using us. Ownership is NOT transferred! - void UnregisterMO(MovableObject *moToUnregister) { m_RegisteredMOs.erase(moToUnregister); m_AddedRegisteredMOs.erase(moToUnregister); } + void UnregisterMO(MovableObject* moToUnregister) { + m_RegisteredMOs.erase(moToUnregister); + m_AddedRegisteredMOs.erase(moToUnregister); + } /// /// Gets a list of the MOs registed as using us. /// /// The MOs registed as using us. - const std::unordered_set & GetRegisteredMOs() const { return m_RegisteredMOs; } + const std::unordered_set& GetRegisteredMOs() const { return m_RegisteredMOs; } #pragma endregion #pragma region Script Execution Handling @@ -127,7 +130,7 @@ namespace RTE { /// Optional vector of entity pointers that should be passed into the Lua function. Their internal Lua states will not be accessible. Defaults to empty. /// Optional vector of strings that should be passed into the Lua function. Entries must be surrounded with escaped quotes (i.e.`\"`) they'll be passed in as-is, allowing them to act as booleans, etc. Defaults to empty. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int RunScriptFunctionString(const std::string &functionName, const std::string &selfObjectName, const std::vector &variablesToSafetyCheck = std::vector(), const std::vector &functionEntityArguments = std::vector(), const std::vector &functionLiteralArguments = std::vector()); + int RunScriptFunctionString(const std::string& functionName, const std::string& selfObjectName, const std::vector& variablesToSafetyCheck = std::vector(), const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector()); /// /// Takes a string containing a script snippet and runs it on the state. @@ -135,7 +138,7 @@ namespace RTE { /// The string with the script snippet. /// Whether to report any errors to the console immediately. /// Returns less than zero if any errors encountered when running this script. To get the actual error string, call GetLastError. - int RunScriptString(const std::string &scriptString, bool consoleErrors = true); + int RunScriptString(const std::string& scriptString, bool consoleErrors = true); /// /// Runs the given Lua function object. The first argument to the function will always be the self object. @@ -147,7 +150,7 @@ namespace RTE { /// Optional vector of entity pointers that should be passed into the Lua function. Their internal Lua states will not be accessible. Defaults to empty. /// Optional vector of strings that should be passed into the Lua function. Entries must be surrounded with escaped quotes (i.e.`\"`) they'll be passed in as-is, allowing them to act as booleans, etc.. Defaults to empty. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int RunScriptFunctionObject(const LuabindObjectWrapper *functionObjectWrapper, const std::string &selfGlobalTableName, const std::string &selfGlobalTableKey, const std::vector &functionEntityArguments = std::vector(), const std::vector &functionLiteralArguments = std::vector(), const std::vector &functionObjectArguments = std::vector()); + int RunScriptFunctionObject(const LuabindObjectWrapper* functionObjectWrapper, const std::string& selfGlobalTableName, const std::string& selfGlobalTableKey, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector(), const std::vector& functionObjectArguments = std::vector()); /// /// Opens and loads a file containing a script and runs it on the state. @@ -156,7 +159,7 @@ namespace RTE { /// Whether to report any errors to the console immediately. /// Whether to do it in a sandboxed environment, or the global environment. /// Returns less than zero if any errors encountered when running this script. To get the actual error string, call GetLastError. - int RunScriptFile(const std::string &filePath, bool consoleErrors = true, bool doInSandboxedEnvironment = true); + int RunScriptFile(const std::string& filePath, bool consoleErrors = true, bool doInSandboxedEnvironment = true); /// /// Retrieves all of the specified functions that exist into the output map, and refreshes the cache. @@ -175,7 +178,7 @@ namespace RTE { /// The map of function names to LuabindObjectWrappers to be retrieved from the script that was run. /// Whether caching shouldn't be used. /// Returns less than zero if any errors encountered when running this script. To get the actual error string, call GetLastError. - int RunScriptFileAndRetrieveFunctions(const std::string &filePath, const std::vector &functionNamesToLookFor, std::unordered_map &outFunctionNamesAndObjects, bool forceReload = false); + int RunScriptFileAndRetrieveFunctions(const std::string& filePath, const std::vector& functionNamesToLookFor, std::unordered_map& outFunctionNamesAndObjects, bool forceReload = false); #pragma endregion #pragma region Concrete Methods @@ -204,21 +207,21 @@ namespace RTE { /// The string with the expression to evaluate. /// Whether to report any errors to the console immediately. /// Whether the expression was true. - bool ExpressionIsTrue(const std::string &expression, bool consoleErrors); + bool ExpressionIsTrue(const std::string& expression, bool consoleErrors); /// /// Takes a pointer to an object and saves it in the Lua state as a global of a specified variable name. /// /// The pointer to the object to save. Ownership is NOT transferred! /// The name of the global var in the Lua state to save the pointer to. - void SavePointerAsGlobal(void *objectToSave, const std::string &globalName); + void SavePointerAsGlobal(void* objectToSave, const std::string& globalName); /// /// Checks if there is anything defined on a specific global var in Lua. /// /// The name of the global var in the Lua state to check. /// Whether that global var has been defined yet in the Lua state. - bool GlobalIsDefined(const std::string &globalName); + bool GlobalIsDefined(const std::string& globalName); /// /// Checks if there is anything defined in a specific index of a table. @@ -226,7 +229,7 @@ namespace RTE { /// The name of the table to look inside. /// The name of the index to check inside that table. /// Whether that table var has been defined yet in the Lua state. - bool TableEntryIsDefined(const std::string &tableName, const std::string &indexName); + bool TableEntryIsDefined(const std::string& tableName, const std::string& indexName); /// /// Clears internal Lua package tables from all user-defined modules. Those must be reloaded with ReloadAllScripts(). @@ -286,9 +289,9 @@ namespace RTE { #pragma region Passthrough LuaMan Functions const std::vector* DirectoryList(const std::string& path); const std::vector* FileList(const std::string& path); - bool FileExists(const std::string &path); - bool DirectoryExists(const std::string &path); - bool IsValidModulePath(const std::string &path); + bool FileExists(const std::string& path); + bool DirectoryExists(const std::string& path); + bool IsValidModulePath(const std::string& path); int FileOpen(const std::string& path, const std::string& accessMode); void FileClose(int fileIndex); void FileCloseAll(); @@ -315,12 +318,12 @@ namespace RTE { /// void Clear(); - std::unordered_set m_RegisteredMOs; //!< The objects using our lua state. - std::unordered_set m_AddedRegisteredMOs; //!< The objects using our lua state that were recently added. + std::unordered_set m_RegisteredMOs; //!< The objects using our lua state. + std::unordered_set m_AddedRegisteredMOs; //!< The objects using our lua state that were recently added. - lua_State *m_State; - Entity *m_TempEntity; //!< Temporary holder for an Entity object that we want to pass into the Lua state without fuss. Lets you export objects to lua easily. - std::vector m_TempEntityVector; //!< Temporary holder for a vector of Entities that we want to pass into the Lua state without a fuss. Usually used to pass arguments to special Lua functions. + lua_State* m_State; + Entity* m_TempEntity; //!< Temporary holder for an Entity object that we want to pass into the Lua state without fuss. Lets you export objects to lua easily. + std::vector m_TempEntityVector; //!< Temporary holder for a vector of Entities that we want to pass into the Lua state without a fuss. Usually used to pass arguments to special Lua functions. std::string m_LastError; //!< Description of the last error that occurred in the script execution. std::string_view m_CurrentlyRunningScriptPath; //!< The currently running script filepath. @@ -348,7 +351,6 @@ namespace RTE { friend class LuaStateWrapper; public: - #pragma region Creation /// /// Constructor method used to instantiate a LuaMan object in system memory. Initialize() should be called before using the object. @@ -378,19 +380,19 @@ namespace RTE { /// Returns our master script state (where activies, global scripts etc run). /// /// The master script state. - LuaStateWrapper & GetMasterScriptState(); + LuaStateWrapper& GetMasterScriptState(); /// /// Returns our threaded script states which movable objects use. /// /// A list of threaded script states. - LuaStatesArray & GetThreadedScriptStates(); + LuaStatesArray& GetThreadedScriptStates(); /// /// Gets the current thread lua state override that new objects created will be assigned to. /// /// The current lua state to force objects to be assigned to. - LuaStateWrapper * GetThreadLuaStateOverride() const; + LuaStateWrapper* GetThreadLuaStateOverride() const; /// /// Forces all new MOs created in this thread to be assigned to a particular lua state. @@ -410,7 +412,7 @@ namespace RTE { /// This will be locked to our thread and safe to use - ensure that it'll be unlocked after use! /// /// A script state. - LuaStateWrapper * GetAndLockFreeScriptState(); + LuaStateWrapper* GetAndLockFreeScriptState(); /// /// Clears internal Lua package tables from all user-defined modules. Those must be reloaded with ReloadAllScripts(). @@ -421,7 +423,7 @@ namespace RTE { /// Adds a function to be called prior to executing lua scripts. This is used to callback into lua from other threads safely. /// /// The callback function that will be executed. - void AddLuaScriptCallback(const std::function &callback); + void AddLuaScriptCallback(const std::function& callback); /// /// Executes and clears all pending script callbacks. @@ -435,41 +437,41 @@ namespace RTE { const std::unordered_map GetScriptTimings() const; #pragma endregion -#pragma region File I/O Handling +#pragma region File I / O Handling /// /// Returns a vector of all the directories in path, which is relative to the working directory. /// /// Directory path relative to the working directory. /// A vector of the directories in path. - const std::vector * DirectoryList(const std::string &path); + const std::vector* DirectoryList(const std::string& path); /// /// Returns a vector of all the files in path, which is relative to the working directory. /// /// Directory path relative to the working directory. /// A vector of the files in path. - const std::vector * FileList(const std::string &path); + const std::vector* FileList(const std::string& path); /// /// Returns whether or not the specified file exists. You can only check for files inside .rte folders in the working directory. /// /// Path to the file. All paths are made absolute by adding current working directory to the specified path. /// Whether or not the specified file exists. - bool FileExists(const std::string &path); + bool FileExists(const std::string& path); /// /// Returns whether or not the specified directory exists. You can only check for directories inside .rte folders in the working directory. /// /// Path to the directory. All paths are made absolute by adding current working directory to the specified path. /// Whether or not the specified file exists. - bool DirectoryExists(const std::string &path); + bool DirectoryExists(const std::string& path); /// /// Returns whether or not the path refers to an accessible file or directory. You can only check for files or directories inside .rte directories in the working directory. /// /// Path to the file or directory. All paths are made absolute by adding current working directory to the specified path. /// Whether or not the specified file exists. - bool IsValidModulePath(const std::string &path); + bool IsValidModulePath(const std::string& path); /// /// Opens a file or creates one if it does not exist, depending on access mode. You can open files only inside .rte folders in the working directory. You can't open more that c_MaxOpenFiles file simultaneously. @@ -478,7 +480,7 @@ namespace RTE { /// Path to the file. All paths are made absolute by adding current working directory to the specified path. /// File access mode. See 'fopen' for list of modes. /// File index in the opened files array. - int FileOpen(const std::string &path, const std::string &accessMode); + int FileOpen(const std::string& path, const std::string& accessMode); /// /// Closes a previously opened file. @@ -496,7 +498,7 @@ namespace RTE { /// /// Path to the file. All paths are made absolute by adding current working directory to the specified path. /// Whether or not the file was removed. - bool FileRemove(const std::string &path); + bool FileRemove(const std::string& path); /// /// Creates a directory, optionally recursively. @@ -504,7 +506,7 @@ namespace RTE { /// Path to the directory to be created. All paths are made absolute by adding current working directory to the specified path. /// Whether to recursively create parent directories. /// Whether or not the directory was removed. - bool DirectoryCreate(const std::string &path, bool recursive); + bool DirectoryCreate(const std::string& path, bool recursive); /// /// Removes a directory, optionally recursively. @@ -512,7 +514,7 @@ namespace RTE { /// Path to the directory to be removed. All paths are made absolute by adding current working directory to the specified path. /// Whether to recursively remove files and directories. /// Whether or not the directory was removed. - bool DirectoryRemove(const std::string &path, bool recursive); + bool DirectoryRemove(const std::string& path, bool recursive); /// /// Moves or renames the file oldPath to newPath. @@ -522,7 +524,7 @@ namespace RTE { /// Path to the filesystem object. All paths are made absolute by adding current working directory to the specified path. /// Path to the filesystem object. All paths are made absolute by adding current working directory to the specified path. /// Whether or not renaming succeeded. - bool FileRename(const std::string &oldPath, const std::string &newPath); + bool FileRename(const std::string& oldPath, const std::string& newPath); /// /// Moves or renames the directory oldPath to newPath. @@ -532,7 +534,7 @@ namespace RTE { /// Path to the filesystem object. All paths are made absolute by adding current working directory to the specified path. /// Path to the filesystem object. All paths are made absolute by adding current working directory to the specified path. /// Whether or not renaming succeeded. - bool DirectoryRename(const std::string &oldPath, const std::string &newPath); + bool DirectoryRename(const std::string& oldPath, const std::string& newPath); /// /// Reads a line from a file. @@ -546,7 +548,7 @@ namespace RTE { /// /// File index in the opened files array. /// String to write. - void FileWriteLine(int fileIndex, const std::string &line); + void FileWriteLine(int fileIndex, const std::string& line); /// /// Returns true if end of file was reached. @@ -574,11 +576,10 @@ namespace RTE { void ClearScriptTimings(); private: - static constexpr int c_MaxOpenFiles = 10; //!< The maximum number of files that can be opened with FileOpen at runtime. static const std::unordered_set c_FileAccessModes; //!< Valid file access modes when opening files with FileOpen. - std::array m_OpenedFiles; //!< Internal list of opened files used by File functions. + std::array m_OpenedFiles; //!< Internal list of opened files used by File functions. LuaStateWrapper m_MasterScriptState; LuaStatesArray m_ScriptStates; @@ -596,8 +597,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - LuaMan(const LuaMan &reference) = delete; - LuaMan & operator=(const LuaMan &rhs) = delete; + LuaMan(const LuaMan& reference) = delete; + LuaMan& operator=(const LuaMan& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Managers/MenuMan.cpp b/Source/Managers/MenuMan.cpp index 12dc74fe2..030825472 100644 --- a/Source/Managers/MenuMan.cpp +++ b/Source/Managers/MenuMan.cpp @@ -21,7 +21,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MenuMan::Initialize(bool firstTimeInit) { m_ActiveMenu = ActiveMenu::MenusDisabled; @@ -29,7 +29,9 @@ namespace RTE { m_GUIScreen = std::make_unique(g_FrameMan.GetBackBuffer32()); m_GUIInput = std::make_unique(-1, g_UInputMan.GetJoystickCount() > 0); - if (firstTimeInit) { g_LoadingScreen.Create(m_GUIScreen.get(), m_GUIInput.get(), g_SettingsMan.GetLoadingScreenProgressReportDisabled()); } + if (firstTimeInit) { + g_LoadingScreen.Create(m_GUIScreen.get(), m_GUIInput.get(), g_SettingsMan.GetLoadingScreenProgressReportDisabled()); + } m_TitleScreen = std::make_unique(m_GUIScreen.get()); m_MainMenu = std::make_unique(m_GUIScreen.get(), m_GUIInput.get()); @@ -41,7 +43,7 @@ namespace RTE { g_MetaMan.GetGUI()->Create(m_MenuController.get()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MenuMan::Reinitialize() { g_MetaMan.GetGUI()->Destroy(); @@ -55,7 +57,7 @@ namespace RTE { Initialize(false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MenuMan::SetActiveMenu() { ActiveMenu newActiveMenu = ActiveMenu::MenusDisabled; @@ -93,7 +95,7 @@ namespace RTE { if (g_MetaMan.GameInProgress()) { m_PauseMenu->SetBackButtonTargetName("Conquest"); } else { - if (const Activity *activity = g_ActivityMan.GetActivity(); activity && activity->GetPresetName() == "None") { + if (const Activity* activity = g_ActivityMan.GetActivity(); activity && activity->GetPresetName() == "None") { m_PauseMenu->SetBackButtonTargetName("Main"); } else { m_PauseMenu->SetBackButtonTargetName("Scenario"); @@ -106,7 +108,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MenuMan::HandleTransitionIntoMenuLoop() { if (g_MetaMan.GameInProgress()) { @@ -116,7 +118,7 @@ namespace RTE { m_TitleScreen->SetTitleTransitionState(TitleScreen::TitleTransition::PauseMenu); } } else if (!g_ActivityMan.ActivitySetToRestart()) { - if (const Activity *activity = g_ActivityMan.GetActivity(); activity) { + if (const Activity* activity = g_ActivityMan.GetActivity(); activity) { if (activity->GetPresetName() == "None") { // If we're in the editors or in online multiplayer then return to main menu instead of scenario menu. m_TitleScreen->SetTitleTransitionState(TitleScreen::TitleTransition::ScrollingFadeIn); @@ -133,7 +135,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MenuMan::Update() { m_TitleScreen->Update(); @@ -171,7 +173,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MenuMan::UpdateMainMenu() const { switch (m_MainMenu->Update()) { @@ -203,7 +205,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MenuMan::UpdateScenarioMenu() const { switch (m_ScenarioMenu->Update()) { @@ -216,7 +218,9 @@ namespace RTE { break; case ScenarioGUI::ScenarioMenuUpdateResult::ActivityStarted: m_TitleScreen->SetTitleTransitionState(TitleScreen::TitleTransition::FadeOut); - if (g_MetaMan.GameInProgress()) { g_MetaMan.EndGame(); } + if (g_MetaMan.GameInProgress()) { + g_MetaMan.EndGame(); + } g_ActivityMan.SetRestartActivity(); break; default: @@ -224,7 +228,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MenuMan::UpdateMetaGameMenu() const { g_MetaMan.GetGUI()->SetStationOrbitPos(m_TitleScreen->GetStationPos()); @@ -243,7 +247,7 @@ namespace RTE { return g_MetaMan.GetGUI()->QuitProgram(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MenuMan::UpdatePauseMenu() const { switch (m_PauseMenu->Update()) { @@ -259,7 +263,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MenuMan::Draw() const { g_FrameMan.ClearBackBuffer32(); @@ -297,19 +301,23 @@ namespace RTE { int mouseX = 0; int mouseY = 0; m_GUIInput->GetMousePosition(&mouseX, &mouseY); - BITMAP *deviceIcon = g_UInputMan.GetDeviceIcon(device)->GetBitmaps32()[0]; - if (deviceIcon) { draw_sprite(g_FrameMan.GetBackBuffer32(), deviceIcon, mouseX + (deviceIcon->w / 2), mouseY - (deviceIcon->h / 5)); } + BITMAP* deviceIcon = g_UInputMan.GetDeviceIcon(device)->GetBitmaps32()[0]; + if (deviceIcon) { + draw_sprite(g_FrameMan.GetBackBuffer32(), deviceIcon, mouseX + (deviceIcon->w / 2), mouseY - (deviceIcon->h / 5)); + } } // Show which joysticks are detected by the game. for (int playerIndex = Players::PlayerOne; playerIndex < Players::MaxPlayerCount; playerIndex++) { if (g_UInputMan.JoystickActive(playerIndex)) { int matchedDevice = InputDevice::DEVICE_GAMEPAD_1 + playerIndex; if (matchedDevice != device) { - BITMAP *deviceIcon = g_UInputMan.GetDeviceIcon(matchedDevice)->GetBitmaps32()[0]; - if (deviceIcon) { draw_sprite(g_FrameMan.GetBackBuffer32(), deviceIcon, g_WindowMan.GetResX() - 30 * g_UInputMan.GetJoystickCount() + 30 * playerIndex, g_WindowMan.GetResY() - 25); } + BITMAP* deviceIcon = g_UInputMan.GetDeviceIcon(matchedDevice)->GetBitmaps32()[0]; + if (deviceIcon) { + draw_sprite(g_FrameMan.GetBackBuffer32(), deviceIcon, g_WindowMan.GetResX() - 30 * g_UInputMan.GetJoystickCount() + 30 * playerIndex, g_WindowMan.GetResY() - 25); + } } } } } } -} +} // namespace RTE diff --git a/Source/Managers/MenuMan.h b/Source/Managers/MenuMan.h index 80d45da93..677b1a6ef 100644 --- a/Source/Managers/MenuMan.h +++ b/Source/Managers/MenuMan.h @@ -21,7 +21,6 @@ namespace RTE { class MenuMan : public Singleton { public: - #pragma region Creation /// /// Constructor method used to instantiate a MenuMan object in system memory. Initialize() should be called before using the object. @@ -59,7 +58,6 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for the different menu screens that are active based on transition states. /// @@ -112,8 +110,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - MenuMan(const MenuMan &reference) = delete; - MenuMan & operator=(const MenuMan &rhs) = delete; + MenuMan(const MenuMan& reference) = delete; + MenuMan& operator=(const MenuMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/MetaMan.cpp b/Source/Managers/MetaMan.cpp index 0805c3bab..6a7e47d9a 100644 --- a/Source/Managers/MetaMan.cpp +++ b/Source/Managers/MetaMan.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -28,1474 +27,1314 @@ namespace RTE { -const std::string MetaMan::c_ClassName = "MetaMan"; + const std::string MetaMan::c_ClassName = "MetaMan"; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MetaMan, effectively + // resetting the members of this abstraction level only. + + void MetaMan::Clear() { + m_pMetaGUI = 0; + m_GameState = NOGAME; + m_StateChanged = true; + m_Suspended = false; + m_GameSaved = false; + m_GameName = DEFAULTGAMENAME; + m_Players.clear(); + m_TeamCount = 0; + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) + m_TeamIcons[team].Reset(); + m_CurrentRound = 0; + m_Scenes.clear(); + m_RevealedScenes = 0; + m_RevealRate = 0.5; + m_RevealExtra = 3.0; + m_RoundOffensives.clear(); + m_CurrentOffensive = 0; + m_PhaseTimer.Reset(); + m_Difficulty = Activity::MediumDifficulty; + + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; team++) + m_TeamAISkill[team] = Activity::DefaultSkill; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MetaMan object ready for use. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MetaMan, effectively -// resetting the members of this abstraction level only. - -void MetaMan::Clear() -{ - m_pMetaGUI = 0; - m_GameState = NOGAME; - m_StateChanged = true; - m_Suspended = false; - m_GameSaved = false; - m_GameName = DEFAULTGAMENAME; - m_Players.clear(); - m_TeamCount = 0; - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - m_TeamIcons[team].Reset(); - m_CurrentRound = 0; - m_Scenes.clear(); - m_RevealedScenes = 0; - m_RevealRate = 0.5; - m_RevealExtra = 3.0; - m_RoundOffensives.clear(); - m_CurrentOffensive = 0; - m_PhaseTimer.Reset(); - m_Difficulty = Activity::MediumDifficulty; - - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; team++) - m_TeamAISkill[team] = Activity::DefaultSkill; -} + int MetaMan::Initialize() { + // if (Serializable::Create() < 0) + // return -1; + // Allocate the metagame interface; it gets created manually later in Main + if (!m_pMetaGUI) + m_pMetaGUI = new MetagameGUI(); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MetaMan object ready for use. - -int MetaMan::Initialize() -{ -// if (Serializable::Create() < 0) -// return -1; - - // Allocate the metagame interface; it gets created manually later in Main - if (!m_pMetaGUI) - m_pMetaGUI = new MetagameGUI(); + return 0; + } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: NewGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Wipes any current and sets up a new game based on a size parameter. + int MetaMan::NewGame(int gameSize) { + // Grab a random selection of Scene presets from all available + std::list scenePresets; + SelectScenePresets(gameSize, &scenePresets); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: NewGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Wipes any current and sets up a new game based on a size parameter. - -int MetaMan::NewGame(int gameSize) -{ - // Grab a random selection of Scene presets from all available - std::list scenePresets; - SelectScenePresets(gameSize, &scenePresets); - - // Destroy and clear any pre-existing scenes from previous games - for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - { - delete *sItr; - *sItr = 0; - } - m_Scenes.clear(); - - // Make deep copies of the selected Scene presets for use in the actual game about to start - for (std::list::iterator pItr = scenePresets.begin(); pItr != scenePresets.end(); ++pItr) - { - // List for found metascenes to choose from - std::vector metascenesList; - // Add our actual scene to the list as it should always be there to be selected later - metascenesList.push_back(*pItr); - - // Look for additional metascenes which can be used instead of this scene - std::list sceneList; - g_PresetMan.GetAllOfType(sceneList, "Scene"); - - // Go through the list and add all compatible metascenes to the list - for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) - { - Scene * pScene = dynamic_cast(*itr); - if (pScene) - { - if (pScene->GetMetasceneParent() == (*pItr)->GetModuleAndPresetName()) - metascenesList.push_back(pScene); - } + // Destroy and clear any pre-existing scenes from previous games + for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) { + delete *sItr; + *sItr = 0; } - // Finally select some random metascene - int selection = RandomNum(0, metascenesList.size() - 1); - Scene * pSelectedScene = metascenesList.at(selection); - - //Copy selected scene - m_Scenes.push_back(dynamic_cast(pSelectedScene->Clone())); - // So we're messing with metascene, change it's name to conseal it's true nature - if (selection > 0) - { - m_Scenes.back()->SetPresetName((*pItr)->GetPresetName()); - m_Scenes.back()->SetDescription((*pItr)->GetDescription()); - m_Scenes.back()->SetLocation((*pItr)->GetLocation()); - m_Scenes.back()->SetLocationOffset((*pItr)->GetLocationOffset()); - m_Scenes.back()->SetMetagameInternal(true); + m_Scenes.clear(); + + // Make deep copies of the selected Scene presets for use in the actual game about to start + for (std::list::iterator pItr = scenePresets.begin(); pItr != scenePresets.end(); ++pItr) { + // List for found metascenes to choose from + std::vector metascenesList; + // Add our actual scene to the list as it should always be there to be selected later + metascenesList.push_back(*pItr); + + // Look for additional metascenes which can be used instead of this scene + std::list sceneList; + g_PresetMan.GetAllOfType(sceneList, "Scene"); + + // Go through the list and add all compatible metascenes to the list + for (std::list::iterator itr = sceneList.begin(); itr != sceneList.end(); ++itr) { + Scene* pScene = dynamic_cast(*itr); + if (pScene) { + if (pScene->GetMetasceneParent() == (*pItr)->GetModuleAndPresetName()) + metascenesList.push_back(pScene); + } + } + // Finally select some random metascene + int selection = RandomNum(0, metascenesList.size() - 1); + Scene* pSelectedScene = metascenesList.at(selection); + + // Copy selected scene + m_Scenes.push_back(dynamic_cast(pSelectedScene->Clone())); + // So we're messing with metascene, change it's name to conseal it's true nature + if (selection > 0) { + m_Scenes.back()->SetPresetName((*pItr)->GetPresetName()); + m_Scenes.back()->SetDescription((*pItr)->GetDescription()); + m_Scenes.back()->SetLocation((*pItr)->GetLocation()); + m_Scenes.back()->SetLocationOffset((*pItr)->GetLocationOffset()); + m_Scenes.back()->SetMetagameInternal(true); + } + // Add a metagame base area + Scene::Area newArea(METABASE_AREA_NAME); + newArea.AddBox(Box(0, 0, 1, 1)); // Add an empty box, or the area won't be saved + m_Scenes.back()->AddArea(newArea); + + // Make sure they are all hidden at game start + m_Scenes.back()->SetRevealed(false); + // Make them unique presets in their own Data Module so they don't get referenced from the original presets they were made from + m_Scenes.back()->MigrateToModule(g_PresetMan.GetModuleID(METASAVEMODULENAME)); + // Make them unexplored by all teams + for (int team = Activity::TeamOne; team < m_TeamCount; ++team) + m_Scenes.back()->FillUnseenLayer(Vector(25, 25), team, false); + + // Go through all AI plan elements and expand all bunker schemes to concrete assemblies + // with fixed prices and place deployments + m_Scenes.back()->ExpandAIPlanAssemblySchemes(); } - // Add a metagame base area - Scene::Area newArea(METABASE_AREA_NAME); - newArea.AddBox(Box(0,0,1,1)); // Add an empty box, or the area won't be saved - m_Scenes.back()->AddArea(newArea); - - - // Make sure they are all hidden at game start - m_Scenes.back()->SetRevealed(false); - // Make them unique presets in their own Data Module so they don't get referenced from the original presets they were made from - m_Scenes.back()->MigrateToModule(g_PresetMan.GetModuleID(METASAVEMODULENAME)); - // Make them unexplored by all teams - for (int team = Activity::TeamOne; team < m_TeamCount; ++team) - m_Scenes.back()->FillUnseenLayer(Vector(25, 25), team, false); - - // Go through all AI plan elements and expand all bunker schemes to concrete assemblies - // with fixed prices and place deployments - m_Scenes.back()->ExpandAIPlanAssemblySchemes(); - } - - // The game that is currently being played is known as - m_GameName = DEFAULTGAMENAME; - - // Start the game/intro - m_CurrentRound = 0; - m_RevealedScenes = 0; -// TODO: Refine these, taking team numbers and total game size into account - // Set the reveal rate of new sites each round - m_RevealRate = 0.3; - // Set the number of sites initially found at the start of the game - m_RevealExtra = m_Players.size(); - m_GameState = GAMEINTRO; - m_StateChanged = true; - SetSuspend(false); - - ClearActivities(); - - return 0; -} + // The game that is currently being played is known as + m_GameName = DEFAULTGAMENAME; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: EndGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Wipes any current metagame and sets things back to as if program start. -// Arguments: None. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. + // Start the game/intro + m_CurrentRound = 0; + m_RevealedScenes = 0; + // TODO: Refine these, taking team numbers and total game size into account + // Set the reveal rate of new sites each round + m_RevealRate = 0.3; + // Set the number of sites initially found at the start of the game + m_RevealExtra = m_Players.size(); + m_GameState = GAMEINTRO; + m_StateChanged = true; + SetSuspend(false); -int MetaMan::EndGame() -{ - //Reset metagame UI - m_pMetaGUI->SetToStartNewGame(); + ClearActivities(); - // Destroy and clear any pre-existing scenes from previous games - for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - { - delete *sItr; - *sItr = 0; - } - m_Scenes.clear(); + return 0; + } - // The game that is currently being played is known as - m_GameName = DEFAULTGAMENAME; + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: EndGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Wipes any current metagame and sets things back to as if program start. + // Arguments: None. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int MetaMan::EndGame() { + // Reset metagame UI + m_pMetaGUI->SetToStartNewGame(); + + // Destroy and clear any pre-existing scenes from previous games + for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) { + delete *sItr; + *sItr = 0; + } + m_Scenes.clear(); - m_GameState = NOGAME; - m_StateChanged = true; - SetSuspend(false); + // The game that is currently being played is known as + m_GameName = DEFAULTGAMENAME; - g_ActivityMan.EndActivity(); + m_GameState = NOGAME; + m_StateChanged = true; + SetSuspend(false); - g_MetaMan.m_Players.clear(); + g_ActivityMan.EndActivity(); - ClearActivities(); + g_MetaMan.m_Players.clear(); - return 0; -} + ClearActivities(); + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Load -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Load a MetaMan from disk out of the special MetaMan.rte data module + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Load + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Load a MetaMan from disk out of the special MetaMan.rte data module -int MetaMan::Load(const MetaSave *pSave) -{ - if (!pSave) - return -1; + int MetaMan::Load(const MetaSave* pSave) { + if (!pSave) + return -1; - // Reset Metaman's AI skill in case those won't be loaded from older saves - for (int team = Activity::TeamOne ; team < Activity::MaxTeamCount; team++) - m_TeamAISkill[team] = Activity::DefaultSkill; + // Reset Metaman's AI skill in case those won't be loaded from older saves + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; team++) + m_TeamAISkill[team] = Activity::DefaultSkill; - // Create the reader to read the metagame state from - Reader reader(pSave->GetSavePath().c_str(), false, 0, false); - if (!reader.ReaderOK()) - return -1; + // Create the reader to read the metagame state from + Reader reader(pSave->GetSavePath().c_str(), false, 0, false); + if (!reader.ReaderOK()) + return -1; - // Clear off players, scenes, and offensive activiies before filling up on new ones read from disk - m_Players.clear(); - for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - delete (*sItr); - m_Scenes.clear(); - for (std::vector::iterator aItr = m_RoundOffensives.begin(); aItr != m_RoundOffensives.end(); ++aItr) - delete (*aItr); - m_RoundOffensives.clear(); + // Clear off players, scenes, and offensive activiies before filling up on new ones read from disk + m_Players.clear(); + for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) + delete (*sItr); + m_Scenes.clear(); + for (std::vector::iterator aItr = m_RoundOffensives.begin(); aItr != m_RoundOffensives.end(); ++aItr) + delete (*aItr); + m_RoundOffensives.clear(); - // Now actually do the reading/loading from file - Serializable::Create(reader, true, false); + // Now actually do the reading/loading from file + Serializable::Create(reader, true, false); - // Make sure all labels etc get set properly after load - m_StateChanged = true; + // Make sure all labels etc get set properly after load + m_StateChanged = true; - return 0; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a Reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the Reader's position is untouched. + + int MetaMan::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Serializable::ReadProperty(propName, reader)); + + MatchProperty("GameState", { reader >> m_GameState; }); + MatchProperty("GameName", { reader >> m_GameName; }); + MatchProperty("AddPlayer", + { + MetaPlayer player; + reader >> player; + m_Players.push_back(player); + }); + MatchProperty("TeamCount", { reader >> m_TeamCount; }); + MatchProperty("Team1Icon", { reader >> m_TeamIcons[Activity::TeamOne]; }); + MatchProperty("Team2Icon", { reader >> m_TeamIcons[Activity::TeamTwo]; }); + MatchProperty("Team3Icon", { reader >> m_TeamIcons[Activity::TeamThree]; }); + MatchProperty("Team4Icon", { reader >> m_TeamIcons[Activity::TeamFour]; }); + MatchProperty("CurrentRound", { reader >> m_CurrentRound; }); + MatchProperty("AddScene", { + Scene* pScene = new Scene; + reader >> pScene; + m_Scenes.push_back(pScene); + }); + MatchProperty("RevealedScenes", { reader >> m_RevealedScenes; }); + MatchProperty("RevealRate", { reader >> m_RevealRate; }); + MatchProperty("RevealExtra", { reader >> m_RevealExtra; }); + MatchProperty("AddOffensive", { + GAScripted* pOffensive = new GAScripted(); + reader >> pOffensive; + m_RoundOffensives.push_back(pOffensive); + }); + MatchProperty("CurrentOffensive", { reader >> m_CurrentOffensive; }); + MatchProperty("Difficulty", { reader >> m_Difficulty; }); + MatchProperty("Team1AISkill", { reader >> m_TeamAISkill[Activity::TeamOne]; }); + MatchProperty("Team2AISkill", { reader >> m_TeamAISkill[Activity::TeamTwo]; }); + MatchProperty("Team3AISkill", { reader >> m_TeamAISkill[Activity::TeamThree]; }); + MatchProperty("Team4AISkill", { reader >> m_TeamAISkill[Activity::TeamFour]; }); + MatchProperty("MetaGUI", { reader >> m_pMetaGUI; }); + + EndPropertyList; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a Reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the Reader's position is untouched. - -int MetaMan::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Serializable::ReadProperty(propName, reader)); - - MatchProperty("GameState", { reader >> m_GameState; }); - MatchProperty("GameName", { reader >> m_GameName; }); - MatchProperty("AddPlayer", - { - MetaPlayer player; - reader >> player; - m_Players.push_back(player); - }); - MatchProperty("TeamCount", { reader >> m_TeamCount; }); - MatchProperty("Team1Icon", { reader >> m_TeamIcons[Activity::TeamOne]; }); - MatchProperty("Team2Icon", { reader >> m_TeamIcons[Activity::TeamTwo]; }); - MatchProperty("Team3Icon", { reader >> m_TeamIcons[Activity::TeamThree]; }); - MatchProperty("Team4Icon", { reader >> m_TeamIcons[Activity::TeamFour]; }); - MatchProperty("CurrentRound", { reader >> m_CurrentRound; }); - MatchProperty("AddScene", { - Scene *pScene = new Scene; - reader >> pScene; - m_Scenes.push_back(pScene); - }); - MatchProperty("RevealedScenes", { reader >> m_RevealedScenes; }); - MatchProperty("RevealRate", { reader >> m_RevealRate; }); - MatchProperty("RevealExtra", { reader >> m_RevealExtra; }); - MatchProperty("AddOffensive", { - GAScripted *pOffensive = new GAScripted(); - reader >> pOffensive; - m_RoundOffensives.push_back(pOffensive); - }); - MatchProperty("CurrentOffensive", { reader >> m_CurrentOffensive; }); - MatchProperty("Difficulty", { reader >> m_Difficulty; }); - MatchProperty("Team1AISkill", { reader >> m_TeamAISkill[Activity::TeamOne]; }); - MatchProperty("Team2AISkill", { reader >> m_TeamAISkill[Activity::TeamTwo]; }); - MatchProperty("Team3AISkill", { reader >> m_TeamAISkill[Activity::TeamThree]; }); - MatchProperty("Team4AISkill", { reader >> m_TeamAISkill[Activity::TeamFour]; }); - MatchProperty("MetaGUI", { reader >> m_pMetaGUI; }); - - EndPropertyList; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this MetaMan to an output stream for + // later recreation with Create(Reader &reader); + + int MetaMan::Save(Writer& writer) const { + Serializable::Save(writer); + + writer.NewPropertyWithValue("GameState", m_GameState); + writer.NewPropertyWithValue("GameName", m_GameName); + writer.NewPropertyWithValue("Difficulty", m_Difficulty); + writer.NewPropertyWithValue("Team1AISkill", m_TeamAISkill[Activity::TeamOne]); + writer.NewPropertyWithValue("Team2AISkill", m_TeamAISkill[Activity::TeamTwo]); + writer.NewPropertyWithValue("Team3AISkill", m_TeamAISkill[Activity::TeamThree]); + writer.NewPropertyWithValue("Team4AISkill", m_TeamAISkill[Activity::TeamFour]); + + for (const MetaPlayer& metaPlayer: m_Players) { + writer.NewPropertyWithValue("AddPlayer", metaPlayer); + } + writer.NewPropertyWithValue("TeamCount", m_TeamCount); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this MetaMan to an output stream for -// later recreation with Create(Reader &reader); - -int MetaMan::Save(Writer &writer) const { - Serializable::Save(writer); - - writer.NewPropertyWithValue("GameState", m_GameState); - writer.NewPropertyWithValue("GameName", m_GameName); - writer.NewPropertyWithValue("Difficulty", m_Difficulty); - writer.NewPropertyWithValue("Team1AISkill", m_TeamAISkill[Activity::TeamOne]); - writer.NewPropertyWithValue("Team2AISkill", m_TeamAISkill[Activity::TeamTwo]); - writer.NewPropertyWithValue("Team3AISkill", m_TeamAISkill[Activity::TeamThree]); - writer.NewPropertyWithValue("Team4AISkill", m_TeamAISkill[Activity::TeamFour]); - - for (const MetaPlayer &metaPlayer : m_Players) { - writer.NewPropertyWithValue("AddPlayer", metaPlayer); - } + if (m_TeamCount >= 1) { + writer.NewProperty("Team1Icon"); + m_TeamIcons[Activity::TeamOne].SavePresetCopy(writer); + } + if (m_TeamCount >= 2) { + writer.NewProperty("Team2Icon"); + m_TeamIcons[Activity::TeamTwo].SavePresetCopy(writer); + } + if (m_TeamCount >= 3) { + writer.NewProperty("Team3Icon"); + m_TeamIcons[Activity::TeamThree].SavePresetCopy(writer); + } + if (m_TeamCount >= 4) { + writer.NewProperty("Team4Icon"); + m_TeamIcons[Activity::TeamFour].SavePresetCopy(writer); + } + + writer.NewPropertyWithValue("CurrentRound", m_CurrentRound); + + for (const Scene* metaScene: m_Scenes) { + // Save the scene data to a good unique prefix for the Scene's layers' bitmap files as they are saved + // This should be handled separately from any .ini writing + //(*sItr)->SaveData(writer.GetFolderPath() + m_GameName + " - " + (*sItr)->GetPresetName(), false); + writer.NewPropertyWithValue("AddScene", metaScene); + } + + writer.NewPropertyWithValue("RevealedScenes", m_RevealedScenes); + writer.NewPropertyWithValue("RevealRate", m_RevealRate); + writer.NewPropertyWithValue("RevealExtra", m_RevealExtra); - writer.NewPropertyWithValue("TeamCount", m_TeamCount); + for (const GAScripted* metaOffensive: m_RoundOffensives) { + writer.NewPropertyWithValue("AddOffensive", metaOffensive); + } - if (m_TeamCount >= 1) { - writer.NewProperty("Team1Icon"); - m_TeamIcons[Activity::TeamOne].SavePresetCopy(writer); + writer.NewPropertyWithValue("CurrentOffensive", m_CurrentOffensive); + writer.NewPropertyWithValue("MetaGUI", m_pMetaGUI); + + return 0; } - if (m_TeamCount >= 2) { - writer.NewProperty("Team2Icon"); - m_TeamIcons[Activity::TeamTwo].SavePresetCopy(writer); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveSceneData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the bitmap data of all Scenes of this Metagame that are currently + // loaded. + + int MetaMan::SaveSceneData(std::string pathBase) { + for (std::vector::const_iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) { + // Only save the data of revealed scenes that have already had their layers built and saved into files + if ((*sItr)->IsRevealed() && (*sItr)->GetTerrain() && (*sItr)->GetTerrain()->IsLoadedFromDisk()) { + // Save the scene data to a good unique prefix for the Scene's layers' bitmap files as they are saved + if ((*sItr)->SaveData(pathBase + " - " + (*sItr)->GetPresetName(), false) < 0) + return -1; + } + } + return 0; } - if (m_TeamCount >= 3) { - writer.NewProperty("Team3Icon"); - m_TeamIcons[Activity::TeamThree].SavePresetCopy(writer); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadSceneData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads the bitmap data of all Scenes of this Metagame that have once + // been saved to files. + + int MetaMan::LoadSceneData() { + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Only load the data of revealed scenes that have already had their layers built and saved into files + if ((*sItr)->IsRevealed() && (*sItr)->GetTerrain() && (*sItr)->GetTerrain()->IsLoadedFromDisk()) { + // Only load the scene layer data, don't place objects or do any init for actually playing the scene + if ((*sItr)->LoadData(false, false) < 0) + return -1; + } + } + return 0; } - if (m_TeamCount >= 4) { - writer.NewProperty("Team4Icon"); - m_TeamIcons[Activity::TeamFour].SavePresetCopy(writer); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearSceneData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the bitmap data of all Scenes of this Metagame that have once + // been saved to files. + + int MetaMan::ClearSceneData() { + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + if ((*sItr)->ClearData() < 0) + return -1; + } + return 0; } - writer.NewPropertyWithValue("CurrentRound", m_CurrentRound); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MetaMan object. + + void MetaMan::Destroy() { + delete m_pMetaGUI; + + for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) + delete (*sItr); + for (std::vector::iterator aItr = m_RoundOffensives.begin(); aItr != m_RoundOffensives.end(); ++aItr) + delete (*aItr); - for (const Scene *metaScene : m_Scenes) { - // Save the scene data to a good unique prefix for the Scene's layers' bitmap files as they are saved - // This should be handled separately from any .ini writing - //(*sItr)->SaveData(writer.GetFolderPath() + m_GameName + " - " + (*sItr)->GetPresetName(), false); - writer.NewPropertyWithValue("AddScene", metaScene); + Clear(); } - writer.NewPropertyWithValue("RevealedScenes", m_RevealedScenes); - writer.NewPropertyWithValue("RevealRate", m_RevealRate); - writer.NewPropertyWithValue("RevealExtra", m_RevealExtra); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlayerTurn + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows which player's turn is now or coming up. + + int MetaMan::GetPlayerTurn() const { + // Player 1's turn is coming up on this round + if (g_MetaMan.m_GameState <= PLAYER1TURN) + return Players::PlayerOne; + // we're past the player turns on this round, so player 1 is up next again + else if ((g_MetaMan.m_GameState - PLAYER1TURN) > (m_Players.size() - 1)) + return Players::PlayerOne; + + // Return whos player's turn it is + return g_MetaMan.m_GameState - PLAYER1TURN; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMetaPlayerOfInGamePlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the MetaPlayer playing a specific in-game player, if any. + + MetaPlayer* MetaMan::GetMetaPlayerOfInGamePlayer(int inGamePlayer) { + for (std::vector::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { + if ((*itr).GetInGamePlayer() == inGamePlayer) + return &(*itr); + } - for (const GAScripted *metaOffensive : m_RoundOffensives) { - writer.NewPropertyWithValue("AddOffensive", metaOffensive); + // Didn't find any metaplayer that is using that in-game player + return 0; } - writer.NewPropertyWithValue("CurrentOffensive", m_CurrentOffensive); - writer.NewPropertyWithValue("MetaGUI", m_pMetaGUI); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextSceneOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next Scene in play that is owned by a specific player. - return 0; -} + const Scene* MetaMan::GetNextSceneOfPlayer(int player, const Scene* pStartScene) const { + if (m_Scenes.empty()) + return 0; + const Scene* pFoundScene = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveSceneData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the bitmap data of all Scenes of this Metagame that are currently -// loaded. - -int MetaMan::SaveSceneData(std::string pathBase) -{ - for (std::vector::const_iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - { - // Only save the data of revealed scenes that have already had their layers built and saved into files - if ((*sItr)->IsRevealed() && (*sItr)->GetTerrain() && (*sItr)->GetTerrain()->IsLoadedFromDisk()) - { - // Save the scene data to a good unique prefix for the Scene's layers' bitmap files as they are saved - if ((*sItr)->SaveData(pathBase + " - " + (*sItr)->GetPresetName(), false) < 0) - return -1; - } - } - return 0; -} + // If no valid start scene specified, just start search immediately + bool foundStart = !(pStartScene && pStartScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(player)); + // Search for the next scene owned by the currently animated player + int scenesSearched = 0; + for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Don't search beyond what has been revealed already + if (scenesSearched >= std::floor(m_RevealedScenes)) + break; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadSceneData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads the bitmap data of all Scenes of this Metagame that have once -// been saved to files. - -int MetaMan::LoadSceneData() -{ - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Only load the data of revealed scenes that have already had their layers built and saved into files - if ((*sItr)->IsRevealed() && (*sItr)->GetTerrain() && (*sItr)->GetTerrain()->IsLoadedFromDisk()) - { - // Only load the scene layer data, don't place objects or do any init for actually playing the scene - if ((*sItr)->LoadData(false, false) < 0) - return -1; - } - } - return 0; -} + // Find the place where to start the actual search for the next owned Scene from + if (!foundStart) { + // Ok, found the start, now begin actual search + if (*sItr == pStartScene) + foundStart = true; + } + // Now find the actual next owned Scene of this player + else if ((*sItr)->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(player)) { + pFoundScene = *sItr; + break; + } + ++scenesSearched; + } + return pFoundScene; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearSceneData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the bitmap data of all Scenes of this Metagame that have once -// been saved to files. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalBrainCountOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of brains that a player has, including ones of + // his that are resident down on sites. + + int MetaMan::GetTotalBrainCountOfPlayer(int metaPlayer, bool countPoolsOnly) const { + if (metaPlayer <= Players::NoPlayer || metaPlayer >= Players::MaxPlayerCount) + return 0; + + // Count the pool first + int brainCount = m_Players[metaPlayer].GetBrainPoolCount(); + // Plus any that are out travelling between sites + brainCount += m_Players[metaPlayer].GetBrainsInTransit(); + + if (!countPoolsOnly) { + for (std::vector::const_iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) { + // Add up any brains installed as resident on any sites + if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == GetTeamOfPlayer(metaPlayer) && (*sItr)->GetResidentBrain(m_Players[metaPlayer].GetInGamePlayer())) + brainCount += 1; + } + } -int MetaMan::ClearSceneData() -{ - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - if ((*sItr)->ClearData() < 0) - return -1; - } - return 0; -} + return brainCount; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldCountOfTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total gold funds of all the players of a specific team combined. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MetaMan object. + int MetaMan::GetGoldCountOfTeam(int team) const { + if (team <= Activity::NoTeam || team >= m_TeamCount) + return 0; -void MetaMan::Destroy() -{ - delete m_pMetaGUI; + float goldTotal = 0; + // Go through all players and add up the funds of all who belong to this team + for (int metaPlayer = Players::PlayerOne; metaPlayer < m_Players.size(); ++metaPlayer) { + if (m_Players[metaPlayer].GetTeam() == team) + goldTotal += m_Players[metaPlayer].GetFunds(); + } - for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - delete (*sItr); - for (std::vector::iterator aItr = m_RoundOffensives.begin(); aItr != m_RoundOffensives.end(); ++aItr) - delete (*aItr); + return goldTotal; + } - Clear(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneCountOfTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of bases that any specific team owns. + + int MetaMan::GetSceneCountOfTeam(int team) const { + if (team <= Activity::NoTeam || team >= m_TeamCount) + return 0; + + // Go through all scenes and add up all the ones owned by this team + int sceneCount = 0; + for (std::vector::const_iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) { + // Add up any brains installed as resident on any sites + if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == team) + ++sceneCount; + } + return sceneCount; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlayerTurn -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows which player's turn is now or coming up. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalBrainCountOfTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of brains that a team has, including ones that + // are resident down on sites. -int MetaMan::GetPlayerTurn() const -{ - // Player 1's turn is coming up on this round - if (g_MetaMan.m_GameState <= PLAYER1TURN) - return Players::PlayerOne; - // we're past the player turns on this round, so player 1 is up next again - else if ((g_MetaMan.m_GameState - PLAYER1TURN) > (m_Players.size() - 1)) - return Players::PlayerOne; + int MetaMan::GetTotalBrainCountOfTeam(int team, bool countPoolsOnly) const { + if (team <= Activity::NoTeam || team >= m_TeamCount) + return 0; - // Return whos player's turn it is - return g_MetaMan.m_GameState - PLAYER1TURN; -} + // Go through all players and add up the brains of the ones who are on this team + int brainCount = 0; + for (int metaPlayer = Players::PlayerOne; metaPlayer < m_Players.size(); ++metaPlayer) { + if (m_Players[metaPlayer].GetTeam() == team) + brainCount += GetTotalBrainCountOfPlayer(metaPlayer, countPoolsOnly); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMetaPlayerOfInGamePlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the MetaPlayer playing a specific in-game player, if any. + return brainCount; + } -MetaPlayer * MetaMan::GetMetaPlayerOfInGamePlayer(int inGamePlayer) -{ - for (std::vector::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) - { - if ((*itr).GetInGamePlayer() == inGamePlayer) - return &(*itr); - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnlyTeamWithAnyBrainPoolLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which team, if any, is the only one left with brains in its + // pool. + + int MetaMan::OnlyTeamWithAnyBrainPoolLeft() { + // See if only one team remains with any brains + int brainTeamCount = 0; + int brainTeam = Activity::NoTeam; + for (int t = Activity::TeamOne; t < m_TeamCount; ++t) { + // Only count brains in pools; not resident ones also + if (GetTotalBrainCountOfTeam(t, true) > 0) { + brainTeamCount++; + brainTeam = t; + } + } - // Didn't find any metaplayer that is using that in-game player - return 0; -} + // If exactly one team with brains, return that + if (brainTeamCount == 1) + return brainTeam; + // None OR more than two teams are left with brains! + return Activity::NoTeam; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextSceneOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next Scene in play that is owned by a specific player. - -const Scene * MetaMan::GetNextSceneOfPlayer(int player, const Scene *pStartScene) const -{ - if (m_Scenes.empty()) - return 0; - - const Scene *pFoundScene = 0; - - // If no valid start scene specified, just start search immediately - bool foundStart = !(pStartScene && pStartScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(player)); - - // Search for the next scene owned by the currently animated player - int scenesSearched = 0; - for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Don't search beyond what has been revealed already - if (scenesSearched >= std::floor(m_RevealedScenes)) - break; - - // Find the place where to start the actual search for the next owned Scene from - if (!foundStart) - { - // Ok, found the start, now begin actual search - if (*sItr == pStartScene) - foundStart = true; - } - // Now find the actual next owned Scene of this player - else if ((*sItr)->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(player)) - { - pFoundScene = *sItr; - break; - } - ++scenesSearched; - } - - return pFoundScene; -} + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OneOrNoneTeamsLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether there is less than two teams left in this game with + // a brain in its ranks at all. + + bool MetaMan::OneOrNoneTeamsLeft() + { + // See if only one team remains with any brains + int brainTeamCount = 0; + int brainTeam = Activity::NoTeam; + for (int t = Activity::TeamOne; t < m_TeamCount; ++t) + { + // Any brains left on this team? If so, they're a potential winner + if (GetTotalBrainCountOfTeam(t) > 0) + { + brainTeamCount++; + brainTeam = t; + } + } + + // If less than two teams left with any brains, they get indicated + // Also, if NO teams with brain are left, that is indicated with NoTeam + if (brainTeamCount <= 1) + return true; + + return false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalBrainCountOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of brains that a player has, including ones of -// his that are resident down on sites. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WhichTeamLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which single team is left, if any. + // Arguments: None. + + int MetaMan::WhichTeamLeft() + { + int whichTeam = Activity::NoTeam; + + // See if only one team remains with any brains + int brainTeamCount = 0; + int brainTeam = Activity::NoTeam; + for (int t = Activity::TeamOne; t < m_TeamCount; ++t) + { + if (GetTotalBrainCountOfTeam(t) > 0) + { + brainTeamCount++; + brainTeam = t; + } + } + + // If exactly one team with brains, return that + if (brainTeamCount == 1) + return brainTeam; + + // No team is left with brains! + return Activity::NoTeam; + } + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NoBrainsLeftInAnyPool + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether there are no brains left in any active player's pool + // at all. This does NOT count deployed brain in bases. + + bool MetaMan::NoBrainsLeftInAnyPool() { + // Go through all players and check each for any brains in any pool + for (std::vector::iterator mpItr = m_Players.begin(); mpItr != m_Players.end(); ++mpItr) { + if ((*mpItr).GetBrainPoolCount() > 0) + return false; + } + return true; + } -int MetaMan::GetTotalBrainCountOfPlayer(int metaPlayer, bool countPoolsOnly) const -{ - if (metaPlayer <= Players::NoPlayer || metaPlayer >= Players::MaxPlayerCount) - return 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WhichTeamIsLeading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which single team has the most owned bases, and if there's a + // tie between two teams, total owned gold funds is used as a tiebreaker. + + int MetaMan::WhichTeamIsLeading() { + int leaderTeam = Activity::NoTeam; + bool tiedTeams[Activity::MaxTeamCount]; + for (int t = Activity::TeamOne; t < m_TeamCount; ++t) + tiedTeams[t] = false; + + int baseCount = 0; + // If we have a tie between two teams + bool baseCountTie = false; + // This is the record so far; negative so the first team with 0 won't detect as tied + int highestBaseCount = -1; + for (int team = Activity::TeamOne; team < m_TeamCount; ++team) { + baseCount = GetSceneCountOfTeam(team); + // We have a tie! + if (baseCount == highestBaseCount) { + // No leader - there's a tie + leaderTeam = Activity::NoTeam; + tiedTeams[team] = true; + baseCountTie = true; + } + // In the lead; clear all other tie flags + if (baseCount > highestBaseCount) { + // Leader! + leaderTeam = team; + highestBaseCount = baseCount; + // No more tie + for (int t = Activity::TeamOne; t < m_TeamCount; ++t) + tiedTeams[t] = false; + // This team is now tied with itself (ie not tied) + tiedTeams[team] = true; + // There's no tie as of now + baseCountTie = false; + } + } - // Count the pool first - int brainCount = m_Players[metaPlayer].GetBrainPoolCount(); - // Plus any that are out travelling between sites - brainCount += m_Players[metaPlayer].GetBrainsInTransit(); + // If we have a tie in base count; then break the tie by looking at total gold funds of all tied teams + if (baseCountTie) { + float highestGold = 0; + // Go through all tied teams + for (int team = Activity::TeamOne; team < m_TeamCount; ++team) { + // One of the teams tied in bases + if (tiedTeams[team]) { + if (GetGoldCountOfTeam(team) >= highestGold) { + // New leader! + highestGold = GetGoldCountOfTeam(team); + leaderTeam = team; + } + } + } + } - if (!countPoolsOnly) - { - for (std::vector::const_iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - { - // Add up any brains installed as resident on any sites - if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == GetTeamOfPlayer(metaPlayer) && (*sItr)->GetResidentBrain(m_Players[metaPlayer].GetInGamePlayer())) - brainCount += 1; - } - } + // We have a winner! + return leaderTeam; + } - return brainCount; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneIncomeOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total income from all scenes owned by a specific player. + float MetaMan::GetSceneIncomeOfPlayer(int metaPlayer) const { + float totalIncome = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldCountOfTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total gold funds of all the players of a specific team combined. + for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Add up all the generated income for this player this round + if ((*sItr)->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer)) + totalIncome += (*sItr)->GetRoundIncome(); + } + return totalIncome; + } -int MetaMan::GetGoldCountOfTeam(int team) const -{ - if (team <= Activity::NoTeam || team >= m_TeamCount) - return 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBudgetedRatioOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ratio of funds already allocated to budgets of this player. - float goldTotal = 0; - // Go through all players and add up the funds of all who belong to this team - for (int metaPlayer = Players::PlayerOne; metaPlayer < m_Players.size(); ++metaPlayer) - { - if (m_Players[metaPlayer].GetTeam() == team) - goldTotal += m_Players[metaPlayer].GetFunds(); - } + float MetaMan::GetBudgetedRatioOfPlayer(int metaPlayer, const Scene* pException, bool includeOffensive, bool includeDefensive) const { + float totalAllocated = 0; - return goldTotal; -} + // Counting defensive allocations + if (includeDefensive) { + for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Add up all the allocated funds so far this round, first of bases we're building + if ((*sItr)->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer) && *sItr != pException) + totalAllocated += (*sItr)->GetBuildBudget(m_Players[metaPlayer].GetInGamePlayer()); + } + } + // Also the money allocated for offensive action + if (includeOffensive && !m_Players[metaPlayer].GetOffensiveTargetName().empty() && (!pException || (pException && pException->GetPresetName() != m_Players[metaPlayer].GetOffensiveTargetName()))) + totalAllocated += m_Players[metaPlayer].GetOffensiveBudget(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneCountOfTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of bases that any specific team owns. + return totalAllocated / m_Players[metaPlayer].GetFunds(); + } -int MetaMan::GetSceneCountOfTeam(int team) const -{ - if (team <= Activity::NoTeam || team >= m_TeamCount) - return 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSuspend + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Suspends or unsuspends the game so exclusive GUIs and menus can be + // shown + + void MetaMan::SetSuspend(bool suspend) { + if (suspend && !m_Suspended) { + m_Suspended = true; + m_GameSaved = false; + } else if (!suspend && m_Suspended) { + m_Suspended = false; + m_GameSaved = false; + } + } - // Go through all scenes and add up all the ones owned by this team - int sceneCount = 0; - for (std::vector::const_iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - { - // Add up any brains installed as resident on any sites - if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == team) - ++sceneCount; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WhichTeamOwnsAllSites + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether one team has ownership of all revealed sites. + + int MetaMan::WhichTeamOwnsAllSites() { + int owner = Activity::NoTeam; + for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) { + if ((*sItr)->IsRevealed()) { + // A site with no owner means that not all sites have been taken duh + if ((*sItr)->GetTeamOwnership() == Activity::NoTeam) { + owner = Activity::NoTeam; + break; + } + + // So the site is owned by someone, and that someone is the only encountered owner yet + if (owner == Activity::NoTeam || (*sItr)->GetTeamOwnership() == owner) + owner = (*sItr)->GetTeamOwnership(); + // We found two diff teams owning sites, so noone owns em all + else { + owner = Activity::NoTeam; + break; + } + } + } + return owner; + } - return sceneCount; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsGameOver + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks for game over condition + bool MetaMan::IsGameOver() { + // This is the old condition of all sites being conquered + // if (m_RevealedScenes >= m_Scenes.size() && WhichTeamOwnsAllSites() != Activity::NoTeam) + // return true; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalBrainCountOfTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of brains that a team has, including ones that -// are resident down on sites. + // GAME IS OVER: + // IF no players have any brains left in their respective pool, OR only one team does AND they are the leader in sites owned + int onlyTeamLeft = OnlyTeamWithAnyBrainPoolLeft(); + if (NoBrainsLeftInAnyPool() || (onlyTeamLeft != Activity::NoTeam && WhichTeamIsLeading() == onlyTeamLeft)) + return true; -int MetaMan::GetTotalBrainCountOfTeam(int team, bool countPoolsOnly) const -{ - if (team <= Activity::NoTeam || team >= m_TeamCount) - return 0; + return false; + } - // Go through all players and add up the brains of the ones who are on this team - int brainCount = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TotalScenePresets + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Yields a set of ALL eligible Scene presets for a new game. + + int MetaMan::TotalScenePresets(std::list* pScenes) { + int totalCount = 0; + // Get the list of ALL read-in Scene presets + std::list allScenePresets; + g_PresetMan.GetAllOfType(allScenePresets, "Scene"); + Scene* pScenePreset = 0; + + // Temporary list of planet locations already being used + std::list usedLocations; + bool locationOK = true; + + if (pScenes) + pScenes->clear(); + + // Go through the preset list and count/copy over all eligible ones + for (std::list::iterator sItr = allScenePresets.begin(); sItr != allScenePresets.end(); ++sItr) { + pScenePreset = dynamic_cast(*sItr); + // Filter out editor or special scenes, or ones that don't have locations defined. + if (pScenePreset && !pScenePreset->GetLocation().IsZero() && pScenePreset->IsMetagamePlayable() && pScenePreset->GetMetasceneParent() == "") { + // Make sure this exact site location on the planet isn't occupied already + locationOK = true; + for (std::list::iterator vItr = usedLocations.begin(); vItr != usedLocations.end(); ++vItr) { + if (pScenePreset->GetLocation() == *vItr) { + locationOK = false; + break; + } + } + + if (locationOK) { + // Add this unique location to the list of locations that are now occupied + usedLocations.push_back(pScenePreset->GetLocation()); + // Add to list if there is a list + if (pScenes) + pScenes->push_back(pScenePreset); + // Count the eligible scene + totalCount++; + } + } + } - for (int metaPlayer = Players::PlayerOne; metaPlayer < m_Players.size(); ++metaPlayer) - { - if (m_Players[metaPlayer].GetTeam() == team) - brainCount += GetTotalBrainCountOfPlayer(metaPlayer, countPoolsOnly); - } + return totalCount; + } - return brainCount; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SelectScenePresets + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Yields a set of randomly selected Scene presets for a new game. + + int MetaMan::SelectScenePresets(int gameSize, std::list* pSelected) { + // Get the list of ALL eligible read-in Scene presets + std::list scenePresets; + TotalScenePresets(&scenePresets); + + // If we need to actually fill the list, do so + if (pSelected) { + // Go through the list and randomly knock out as many presets as necessary to reach the number we need for this game + int randomIndex; + int currentIndex; + while (scenePresets.size() > gameSize) { + // Randomly select one of the scenes and remove it + currentIndex = 0; + randomIndex = RandomNum(0, scenePresets.size() - 1); + for (std::list::iterator pItr = scenePresets.begin(); pItr != scenePresets.end(); ++pItr) { + if (currentIndex == randomIndex) { + scenePresets.erase(pItr); + break; + } + currentIndex++; + } + } + // Cast and copy (not deep!) to fill the provided list + pSelected->clear(); + for (Scene* scenePointer: scenePresets) { + pSelected->push_back(scenePointer); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnlyTeamWithAnyBrainPoolLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which team, if any, is the only one left with brains in its -// pool. - -int MetaMan::OnlyTeamWithAnyBrainPoolLeft() -{ - // See if only one team remains with any brains - int brainTeamCount = 0; - int brainTeam = Activity::NoTeam; - for (int t = Activity::TeamOne; t < m_TeamCount; ++t) - { - // Only count brains in pools; not resident ones also - if (GetTotalBrainCountOfTeam(t, true) > 0) - { - brainTeamCount++; - brainTeam = t; - } - } - - // If exactly one team with brains, return that - if (brainTeamCount == 1) - return brainTeam; - - // None OR more than two teams are left with brains! - return Activity::NoTeam; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OneOrNoneTeamsLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether there is less than two teams left in this game with -// a brain in its ranks at all. - -bool MetaMan::OneOrNoneTeamsLeft() -{ - // See if only one team remains with any brains - int brainTeamCount = 0; - int brainTeam = Activity::NoTeam; - for (int t = Activity::TeamOne; t < m_TeamCount; ++t) - { - // Any brains left on this team? If so, they're a potential winner - if (GetTotalBrainCountOfTeam(t) > 0) - { - brainTeamCount++; - brainTeam = t; - } - } - - // If less than two teams left with any brains, they get indicated - // Also, if NO teams with brain are left, that is indicated with NoTeam - if (brainTeamCount <= 1) - return true; - - return false; -} + return gameSize; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearActivities + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out all the lined-up activities for the current round. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WhichTeamLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which single team is left, if any. -// Arguments: None. - -int MetaMan::WhichTeamLeft() -{ - int whichTeam = Activity::NoTeam; - - // See if only one team remains with any brains - int brainTeamCount = 0; - int brainTeam = Activity::NoTeam; - for (int t = Activity::TeamOne; t < m_TeamCount; ++t) - { - if (GetTotalBrainCountOfTeam(t) > 0) - { - brainTeamCount++; - brainTeam = t; - } - } - - // If exactly one team with brains, return that - if (brainTeamCount == 1) - return brainTeam; - - // No team is left with brains! - return Activity::NoTeam; -} -*/ + void MetaMan::ClearActivities() { + for (std::vector::iterator aItr = m_RoundOffensives.begin(); aItr != m_RoundOffensives.end(); ++aItr) + delete (*aItr); + m_RoundOffensives.clear(); + m_CurrentOffensive = 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NoBrainsLeftInAnyPool -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether there are no brains left in any active player's pool -// at all. This does NOT count deployed brain in bases. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AIPlayerTurn + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does all the things an AI player needs to do during his turn. -bool MetaMan::NoBrainsLeftInAnyPool() -{ - // Go through all players and check each for any brains in any pool - for (std::vector::iterator mpItr = m_Players.begin(); mpItr != m_Players.end(); ++mpItr) - { - if ((*mpItr).GetBrainPoolCount() > 0) - return false; - } - return true; -} + void MetaMan::AIPlayerTurn(int metaPlayer) { + if (metaPlayer < 0 || metaPlayer >= m_Players.size()) + return; + MetaPlayer* pThisPlayer = &(m_Players[metaPlayer]); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WhichTeamIsLeading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which single team has the most owned bases, and if there's a -// tie between two teams, total owned gold funds is used as a tiebreaker. - -int MetaMan::WhichTeamIsLeading() -{ - int leaderTeam = Activity::NoTeam; - bool tiedTeams[Activity::MaxTeamCount]; - for (int t = Activity::TeamOne; t < m_TeamCount; ++t) - tiedTeams[t] = false; - - int baseCount = 0; - // If we have a tie between two teams - bool baseCountTie = false; - // This is the record so far; negative so the first team with 0 won't detect as tied - int highestBaseCount = -1; - for (int team = Activity::TeamOne; team < m_TeamCount; ++team) - { - baseCount = GetSceneCountOfTeam(team); - // We have a tie! - if (baseCount == highestBaseCount) - { - // No leader - there's a tie - leaderTeam = Activity::NoTeam; - tiedTeams[team] = true; - baseCountTie = true; - } - // In the lead; clear all other tie flags - if (baseCount > highestBaseCount) - { - // Leader! - leaderTeam = team; - highestBaseCount = baseCount; - // No more tie - for (int t = Activity::TeamOne; t < m_TeamCount; ++t) - tiedTeams[t] = false; - // This team is now tied with itself (ie not tied) - tiedTeams[team] = true; - // There's no tie as of now - baseCountTie = false; - } - } - - // If we have a tie in base count; then break the tie by looking at total gold funds of all tied teams - if (baseCountTie) - { - float highestGold = 0; - // Go through all tied teams - for (int team = Activity::TeamOne; team < m_TeamCount; ++team) - { - // One of the teams tied in bases - if (tiedTeams[team]) - { - if (GetGoldCountOfTeam(team) >= highestGold) - { - // New leader! - highestGold = GetGoldCountOfTeam(team); - leaderTeam = team; - } - } - } - } - - // We have a winner! - return leaderTeam; -} + // If this player has no brains at all left, then do nothing + if (GetTotalBrainCountOfPlayer(metaPlayer) <= 0) { + pThisPlayer->SetGameOverRound(m_CurrentRound); + pThisPlayer->SetOffensiveBudget(0); + return; + } + // Tally up all the scenes according to who owns them + int sceneCount = 0; + int revealedScenes = std::floor(m_RevealedScenes); + std::vector ownedScenes; + std::vector enemyScenes; + std::vector unclaimedScenes; + + float sceneMark = 0; + Scene* pBestAttackCandidateScene = 0; + + for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) { + float currentMark = 0; + + // We are only concerned with Scenes that are currently revealed and in play + ++sceneCount; + if (sceneCount > revealedScenes) + break; + + // Scene is owned by this guy's team + if ((*sItr)->GetTeamOwnership() == pThisPlayer->GetTeam()) + ownedScenes.push_back(*sItr); + // Enemy-owned scene + else if ((*sItr)->GetTeamOwnership() != Activity::NoTeam) { + enemyScenes.push_back(*sItr); + // Scenes with heavy investment owned by a team with lots of funds are less likely to attack + currentMark = -((*sItr)->GetTotalInvestment() + GetGoldCountOfTeam((*sItr)->GetTeamOwnership())); + } + // Unoccupied scene + else { + unclaimedScenes.push_back(*sItr); + // Unclaimed scenes are guaranteed to attack + currentMark = 1000; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneIncomeOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total income from all scenes owned by a specific player. + // Set new attack candidate if we have some better options to attack + if (currentMark != 0 && currentMark > sceneMark) { + sceneMark = currentMark; + pBestAttackCandidateScene = (*sItr); + } + } -float MetaMan::GetSceneIncomeOfPlayer(int metaPlayer) const -{ - float totalIncome = 0; + // Decide how much of current budget to spend on offense vs defense, and also unassigned countering budget for when we are attacked at a base + float counterRatio = 0.15; + float offenseRatio = pThisPlayer->GetAggressiveness() * 0.8; + float attackGoldThreshold = 250 + ownedScenes.size() * 250; + + if (!unclaimedScenes.empty()) + attackGoldThreshold = 250; + + // Special case: no brains left in pool to attack with + if (pThisPlayer->GetBrainPoolCount() <= 0) { + // Save for someone attacking back + counterRatio = 0.5; + // Nothing to attack with + offenseRatio = 0; + pThisPlayer->SetOffensiveTargetName(""); + } + // Special case: no owned bases + else if (ownedScenes.empty()) { + // Don't save anything for counter or defenses if we don't have any bases! + counterRatio = 0; + // Also don't hold back anything for defense if we don't have any bases to spend on + offenseRatio = 1.0; + // Always attack now matter how low the funds are, there's no way to get them anyway + attackGoldThreshold = -1; + } - for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Add up all the generated income for this player this round - if ((*sItr)->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer)) - totalIncome += (*sItr)->GetRoundIncome(); - } - return totalIncome; -} + // What remains is for defense + float defenseRatio = 1.0 - offenseRatio - counterRatio; + + // Set the attack budget, if there's anything to attack, and anything to attack with + if ((!enemyScenes.empty() || !unclaimedScenes.empty()) && offenseRatio > 0 && pThisPlayer->GetFunds() * offenseRatio >= attackGoldThreshold) { + pThisPlayer->SetOffensiveBudget(pThisPlayer->GetFunds() * offenseRatio); + // Use two methods to select which scene to attack, first one is based on the previously obtained scene mark and the second is mostly random + if (RandomNum() < 0.6F && pBestAttackCandidateScene) { + pThisPlayer->SetOffensiveTargetName(pBestAttackCandidateScene->GetPresetName()); + } else { + // And the target scene, randomly selected for now from all unfriendly targets + int unfriendlySceneCount = enemyScenes.size() + unclaimedScenes.size(); + int targetIndex = RandomNum(0, unfriendlySceneCount - 1); + // Give it a strong preference for unclaimed scenes! They make more strategic sense than to attack a hardened target + if (!unclaimedScenes.empty() && targetIndex >= unclaimedScenes.size()) + targetIndex = RandomNum() < 0.75F ? RandomNum(0, unclaimedScenes.size() - 1) : targetIndex; + // From index to actual Scene and selection + Scene* selectedTarget = targetIndex < unclaimedScenes.size() ? unclaimedScenes[targetIndex] : enemyScenes[targetIndex - unclaimedScenes.size()]; + if (selectedTarget) + pThisPlayer->SetOffensiveTargetName(selectedTarget->GetPresetName()); + } + } + // All on defense instead after all + else { + pThisPlayer->SetOffensiveBudget(0); + defenseRatio = 1.0; + } + // Spread out the defensive budgets on the owned sites + float totalDefenseBudget = pThisPlayer->GetFunds() * defenseRatio; + int player = pThisPlayer->GetInGamePlayer(); + for (std::vector::iterator sItr = ownedScenes.begin(); sItr != ownedScenes.end(); ++sItr) { + // Evenly, for now.. later, might want to prioritize sites with established bases, or opposite? + (*sItr)->SetBuildBudget(player, totalDefenseBudget / ownedScenes.size()); + + // Save the build budget ratio that was selected as well, so it can be re-used next round? + // (AI doesn't really need to use this since they re-do their allocation algo above each round) + if (pThisPlayer->GetFunds() > 0) + (*sItr)->SetBuildBudgetRatio(player, (*sItr)->GetBuildBudget(player) / pThisPlayer->GetFunds()); + else + (*sItr)->SetBuildBudgetRatio(player, 0); + + // Move building pieces from the Scene's AI blueprint queue to the actual blueprints, but only approximately as much as can afford, so the entire AI pre-built base plan isn't revealed + (*sItr)->ApplyAIPlan(player); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBudgetedRatioOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ratio of funds already allocated to budgets of this player. + // TODO: Pay for and schedule to scan a random unfriendly site to keep things fair + } -float MetaMan::GetBudgetedRatioOfPlayer(int metaPlayer, const Scene *pException, bool includeOffensive, bool includeDefensive) const -{ - float totalAllocated = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this. Supposed to be done every frame before drawing. - // Counting defensive allocations - if (includeDefensive) - { - for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Add up all the allocated funds so far this round, first of bases we're building - if ((*sItr)->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer) && *sItr != pException) - totalAllocated += (*sItr)->GetBuildBudget(m_Players[metaPlayer].GetInGamePlayer()); - } - } + void MetaMan::Update() { + m_pMetaGUI->Update(); - // Also the money allocated for offensive action - if (includeOffensive && !m_Players[metaPlayer].GetOffensiveTargetName().empty() && (!pException || (pException && pException->GetPresetName() != m_Players[metaPlayer].GetOffensiveTargetName()))) - totalAllocated += m_Players[metaPlayer].GetOffensiveBudget(); + //////////////////////////////////////////// + // METAGAME STATE MACHINE UPDATER - return totalAllocated / m_Players[metaPlayer].GetFunds(); -} + // Game is temporarily suspended, don't do anything + if (m_Suspended) { + } + // Game not started; the GUI will show the new game dialog + else if (m_GameState == NOGAME) { + // Show suspended so the new game dialog will show up + m_Suspended = true; + + // State end + if (m_pMetaGUI->ContinuePhase()) { + m_GameState = GAMEINTRO; + m_StateChanged = true; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSuspend -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Suspends or unsuspends the game so exclusive GUIs and menus can be -// shown - -void MetaMan::SetSuspend(bool suspend) -{ - if (suspend && !m_Suspended) - { - m_Suspended = true; - m_GameSaved = false; - } - else if (!suspend && m_Suspended) - { - m_Suspended = false; - m_GameSaved = false; - } -} + // INTRO + // Show some nice graphical intro of the campaign + else if (m_GameState == GAMEINTRO) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + } + // State body -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WhichTeamOwnsAllSites -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether one team has ownership of all revealed sites. - -int MetaMan::WhichTeamOwnsAllSites() -{ - int owner = Activity::NoTeam; - for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - { - if ((*sItr)->IsRevealed()) - { - // A site with no owner means that not all sites have been taken duh - if ((*sItr)->GetTeamOwnership() == Activity::NoTeam) - { - owner = Activity::NoTeam; - break; - } - - // So the site is owned by someone, and that someone is the only encountered owner yet - if (owner == Activity::NoTeam || (*sItr)->GetTeamOwnership() == owner) - owner = (*sItr)->GetTeamOwnership(); - // We found two diff teams owning sites, so noone owns em all - else - { - owner = Activity::NoTeam; - break; - } - } - } - return owner; -} + // State end + if (1) // m_pMetaGUI->ContinuePhase()) + { + m_GameState = NEWROUND; + m_StateChanged = true; + } + } + // NEW ROUND + // Show a nice banner for the new round and its number + else if (m_GameState == NEWROUND) { + // State init + if (m_StateChanged) { + // New day; clear out old activities + ClearActivities(); + m_PhaseTimer.Reset(); + m_StateChanged = false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsGameOver -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks for game over condition + // State body -bool MetaMan::IsGameOver() -{ -// This is the old condition of all sites being conquered -// if (m_RevealedScenes >= m_Scenes.size() && WhichTeamOwnsAllSites() != Activity::NoTeam) -// return true; + // State end + if (m_pMetaGUI->ContinuePhase()) { + m_GameState = REVEALSCENES; + m_StateChanged = true; + } + } - // GAME IS OVER: - // IF no players have any brains left in their respective pool, OR only one team does AND they are the leader in sites owned - int onlyTeamLeft = OnlyTeamWithAnyBrainPoolLeft(); - if (NoBrainsLeftInAnyPool() || (onlyTeamLeft != Activity::NoTeam && WhichTeamIsLeading() == onlyTeamLeft)) - return true; + // REVEAL SCENES + // If not all the sites are revealed yet, reveal one or two (depending on how many players playing?) + else if (m_GameState == REVEALSCENES) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + } - return false; -} + // State body + // State end + if (m_pMetaGUI->ContinuePhase()) { + m_GameState = COUNTINCOME; + m_StateChanged = true; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TotalScenePresets -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Yields a set of ALL eligible Scene presets for a new game. - -int MetaMan::TotalScenePresets(std::list *pScenes) -{ - int totalCount = 0; - // Get the list of ALL read-in Scene presets - std::list allScenePresets; - g_PresetMan.GetAllOfType(allScenePresets, "Scene"); - Scene *pScenePreset = 0; - - // Temporary list of planet locations already being used - std::list usedLocations; - bool locationOK = true; - - if (pScenes) - pScenes->clear(); - - // Go through the preset list and count/copy over all eligible ones - for (std::list::iterator sItr = allScenePresets.begin(); sItr != allScenePresets.end(); ++sItr) - { - pScenePreset = dynamic_cast(*sItr); - // Filter out editor or special scenes, or ones that don't have locations defined. - if (pScenePreset && !pScenePreset->GetLocation().IsZero() && pScenePreset->IsMetagamePlayable() && pScenePreset->GetMetasceneParent() == "") - { - // Make sure this exact site location on the planet isn't occupied already - locationOK = true; - for (std::list::iterator vItr = usedLocations.begin(); vItr != usedLocations.end(); ++vItr) - { - if (pScenePreset->GetLocation() == *vItr) - { - locationOK = false; - break; - } - } - - if (locationOK) - { - // Add this unique location to the list of locations that are now occupied - usedLocations.push_back(pScenePreset->GetLocation()); - // Add to list if there is a list - if (pScenes) - pScenes->push_back(pScenePreset); - // Count the eligible scene - totalCount++; - } - } - } - - return totalCount; -} + // COUNT INCOME + // Count all the income from all owned bases, add to respective players' funds: + // Show this with lines from the bases adding to the floating player counters, showing income ratios, and leave the lines there to show base ownership and value during turns + else if (m_GameState == COUNTINCOME) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + } + // State body -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SelectScenePresets -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Yields a set of randomly selected Scene presets for a new game. - -int MetaMan::SelectScenePresets(int gameSize, std::list *pSelected) -{ - // Get the list of ALL eligible read-in Scene presets - std::list scenePresets; - TotalScenePresets(&scenePresets); - - // If we need to actually fill the list, do so - if (pSelected) - { - // Go through the list and randomly knock out as many presets as necessary to reach the number we need for this game - int randomIndex; - int currentIndex; - while (scenePresets.size() > gameSize) - { - // Randomly select one of the scenes and remove it - currentIndex = 0; - randomIndex = RandomNum(0, scenePresets.size() - 1); - for (std::list::iterator pItr = scenePresets.begin(); pItr != scenePresets.end(); ++pItr) - { - if (currentIndex == randomIndex) - { - scenePresets.erase(pItr); - break; - } - currentIndex++; - } - } - - // Cast and copy (not deep!) to fill the provided list - pSelected->clear(); - for (Scene *scenePointer : scenePresets) { - pSelected->push_back(scenePointer); + // State end + if (m_pMetaGUI->ContinuePhase()) { + m_GameState = PLAYER1TURN; + m_StateChanged = true; + } } - } - return gameSize; -} + // PLAYER TURNS + // Player-controlled player turn sequence: + // Show planet and current known sites, allow inspection of each + // Allow to zoom in on each site owned by this player: + // Build blueprints (allocating defense budget) in Scene Editor Activity until player done + // Allow clicking on sites unvisited by anyone + // Allocate expedition budget to this site with a slider + // Allow clicking on sites already claimed by other player + // Allocate attack budget to this site with a slider + // [Question: allow more than one expedition/offense action per turn?? - A: no] + // Wait til player hits [End Turn] button + // AI-controlled player turn sequence: + // Determine offense/defense ratio of funds based on AI temperament/aggressiveness setting + // Select expansion site(s??), allocate the offense funds if we decide to go with more than one expansion/round + // Build as much as can afford on owned sites, based on the pre-defined base templates of the Scenes + else if (m_GameState >= PLAYER1TURN && m_GameState <= PLAYER4TURN) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + } + int metaPlayer = m_GameState - PLAYER1TURN; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearActivities -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out all the lined-up activities for the current round. + // If an AI player, do the AI player's logic now and go to next player immediately afterward + if (!m_Players[metaPlayer].IsHuman()) + AIPlayerTurn(metaPlayer); -void MetaMan::ClearActivities() -{ - for (std::vector::iterator aItr = m_RoundOffensives.begin(); aItr != m_RoundOffensives.end(); ++aItr) - delete (*aItr); - m_RoundOffensives.clear(); - m_CurrentOffensive = 0; -} + // State end - skip A.I. metaplayer turns in the GUI; also skip human player who have been knocked out of the game in previous rounds + if (m_pMetaGUI->ContinuePhase() || !m_Players[metaPlayer].IsHuman() || m_Players[metaPlayer].IsGameOverByRound(m_CurrentRound)) { + // If this player is now done for, mark him as such so he'll be completely skipped in future rounds + if (GetTotalBrainCountOfPlayer(metaPlayer) <= 0 && !m_Players[metaPlayer].IsGameOverByRound(m_CurrentRound)) + m_Players[metaPlayer].SetGameOverRound(m_CurrentRound); + // Find the next player which is not out of the game yet + do { + // Next player, if any left + m_GameState++; + metaPlayer = m_GameState - PLAYER1TURN; + } while (m_GameState <= PLAYER4TURN && metaPlayer < m_Players.size() && m_Players[metaPlayer].IsGameOverByRound(m_CurrentRound)); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AIPlayerTurn -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does all the things an AI player needs to do during his turn. - -void MetaMan::AIPlayerTurn(int metaPlayer) -{ - if (metaPlayer < 0 || metaPlayer >= m_Players.size()) - return; - - MetaPlayer *pThisPlayer = &(m_Players[metaPlayer]); - - // If this player has no brains at all left, then do nothing - if (GetTotalBrainCountOfPlayer(metaPlayer) <= 0) - { - pThisPlayer->SetGameOverRound(m_CurrentRound); - pThisPlayer->SetOffensiveBudget(0); - return; - } - - // Tally up all the scenes according to who owns them - int sceneCount = 0; - int revealedScenes = std::floor(m_RevealedScenes); - std::vector ownedScenes; - std::vector enemyScenes; - std::vector unclaimedScenes; - - float sceneMark = 0; - Scene * pBestAttackCandidateScene = 0; - - for (std::vector::iterator sItr = m_Scenes.begin(); sItr != m_Scenes.end(); ++sItr) - { - float currentMark = 0; - - // We are only concerned with Scenes that are currently revealed and in play - ++sceneCount; - if (sceneCount > revealedScenes) - break; - - // Scene is owned by this guy's team - if ((*sItr)->GetTeamOwnership() == pThisPlayer->GetTeam()) - ownedScenes.push_back(*sItr); - // Enemy-owned scene - else if ((*sItr)->GetTeamOwnership() != Activity::NoTeam) - { - enemyScenes.push_back(*sItr); - // Scenes with heavy investment owned by a team with lots of funds are less likely to attack - currentMark = -((*sItr)->GetTotalInvestment() + GetGoldCountOfTeam((*sItr)->GetTeamOwnership())); - } - // Unoccupied scene - else - { - unclaimedScenes.push_back(*sItr); - // Unclaimed scenes are guaranteed to attack - currentMark = 1000; + // If not, jump to building bases + if (m_GameState > PLAYER4TURN || metaPlayer >= m_Players.size()) + m_GameState = BUILDBASES; + + m_StateChanged = true; + } } - // Set new attack candidate if we have some better options to attack - if (currentMark != 0 && currentMark > sceneMark) - { - sceneMark = currentMark; - pBestAttackCandidateScene = (*sItr); + // BUILD BASES + // Apply all blueprint pieces to all claimed/base sites (or just save them in list and apply at next load of Scene?) + // In sequence, graphically show all defense investments of each player with lines from the floating funds meters to the bases spent on + else if (m_GameState == BUILDBASES) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + } + + // State body + + // State end + if (m_pMetaGUI->ContinuePhase()) { + m_GameState = RUNACTIVITIES; + m_StateChanged = true; + } } - } - - // Decide how much of current budget to spend on offense vs defense, and also unassigned countering budget for when we are attacked at a base - float counterRatio = 0.15; - float offenseRatio = pThisPlayer->GetAggressiveness() * 0.8; - float attackGoldThreshold = 250 + ownedScenes.size() * 250; - - if (!unclaimedScenes.empty()) - attackGoldThreshold = 250; - - // Special case: no brains left in pool to attack with - if (pThisPlayer->GetBrainPoolCount() <= 0) - { - // Save for someone attacking back - counterRatio = 0.5; - // Nothing to attack with - offenseRatio = 0; - pThisPlayer->SetOffensiveTargetName(""); - } - // Special case: no owned bases - else if (ownedScenes.empty()) - { - // Don't save anything for counter or defenses if we don't have any bases! - counterRatio = 0; - // Also don't hold back anything for defense if we don't have any bases to spend on - offenseRatio = 1.0; - // Always attack now matter how low the funds are, there's no way to get them anyway - attackGoldThreshold = -1; - } - - // What remains is for defense - float defenseRatio = 1.0 - offenseRatio - counterRatio; - - // Set the attack budget, if there's anything to attack, and anything to attack with - if ((!enemyScenes.empty() || !unclaimedScenes.empty()) && offenseRatio > 0 && pThisPlayer->GetFunds() * offenseRatio >= attackGoldThreshold) - { - pThisPlayer->SetOffensiveBudget(pThisPlayer->GetFunds() * offenseRatio); - // Use two methods to select which scene to attack, first one is based on the previously obtained scene mark and the second is mostly random - if (RandomNum() < 0.6F && pBestAttackCandidateScene) - { - pThisPlayer->SetOffensiveTargetName(pBestAttackCandidateScene->GetPresetName()); + + // RUN ACTIVITIES + // Generate and go through list of all Activities caused by player offensive moves during their turns: + // Init the Activity with the corresponding Scene and player setups as dictated by the round's situation + // LOAD the Scene from disk, from the current metagame folder where all terrain damage etc is preserved + // Let the Activity play out til the end + // Show some stats of the outcome of the Activity + // Have the outcome reflected in the Metagame: Funds won/lost, site ownership change, etc + // SAVE the Scene to disk, preserving the Terrain + else if (m_GameState == RUNACTIVITIES) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + } + + // State body + + // State end, either as signaled by the GUI, or by the fact that we are out of things to run + if (m_pMetaGUI->ContinuePhase() || m_CurrentOffensive >= m_RoundOffensives.size()) { + m_GameState = ENDROUND; + m_StateChanged = true; + } } - else - { - // And the target scene, randomly selected for now from all unfriendly targets - int unfriendlySceneCount = enemyScenes.size() + unclaimedScenes.size(); - int targetIndex = RandomNum(0, unfriendlySceneCount - 1); - // Give it a strong preference for unclaimed scenes! They make more strategic sense than to attack a hardened target - if (!unclaimedScenes.empty() && targetIndex >= unclaimedScenes.size()) - targetIndex = RandomNum() < 0.75F ? RandomNum(0, unclaimedScenes.size() - 1) : targetIndex; - // From index to actual Scene and selection - Scene *selectedTarget = targetIndex < unclaimedScenes.size() ? unclaimedScenes[targetIndex] : enemyScenes[targetIndex - unclaimedScenes.size()]; - if (selectedTarget) - pThisPlayer->SetOffensiveTargetName(selectedTarget->GetPresetName()); + + // END ROUND + // If all sites of this metagame have been revealed, check if any player owns all the of them now - if so, GAME OVER + else if (m_GameState == ENDROUND) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + + // Check for GAME OVER condition + if (IsGameOver()) { + m_GameState = GAMEOVER; + m_StateChanged = true; + } + } + + // State body + + // Game isn't over yet, so start the next round when user is done looking at stats + if (m_pMetaGUI->ContinuePhase()) { + m_CurrentRound++; + m_GameState = NEWROUND; + m_StateChanged = true; + } } - } - // All on defense instead after all - else - { - pThisPlayer->SetOffensiveBudget(0); - defenseRatio = 1.0; - } - - // Spread out the defensive budgets on the owned sites - float totalDefenseBudget = pThisPlayer->GetFunds() * defenseRatio; - int player = pThisPlayer->GetInGamePlayer(); - for (std::vector::iterator sItr = ownedScenes.begin(); sItr != ownedScenes.end(); ++sItr) - { - // Evenly, for now.. later, might want to prioritize sites with established bases, or opposite? - (*sItr)->SetBuildBudget(player, totalDefenseBudget / ownedScenes.size()); - - // Save the build budget ratio that was selected as well, so it can be re-used next round? - // (AI doesn't really need to use this since they re-do their allocation algo above each round) - if (pThisPlayer->GetFunds() > 0) - (*sItr)->SetBuildBudgetRatio(player, (*sItr)->GetBuildBudget(player) / pThisPlayer->GetFunds()); - else - (*sItr)->SetBuildBudgetRatio(player, 0); - - // Move building pieces from the Scene's AI blueprint queue to the actual blueprints, but only approximately as much as can afford, so the entire AI pre-built base plan isn't revealed - (*sItr)->ApplyAIPlan(player); - } - -// TODO: Pay for and schedule to scan a random unfriendly site to keep things fair - -} + // GAME OVER + // Show some game over graphical thing and perhaps stats + else if (m_GameState == GAMEOVER) { + // State init + if (m_StateChanged) { + m_PhaseTimer.Reset(); + m_StateChanged = false; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this. Supposed to be done every frame before drawing. - -void MetaMan::Update() -{ - m_pMetaGUI->Update(); - - //////////////////////////////////////////// - // METAGAME STATE MACHINE UPDATER - - // Game is temporarily suspended, don't do anything - if (m_Suspended) - { - - } - // Game not started; the GUI will show the new game dialog - else if (m_GameState == NOGAME) - { - // Show suspended so the new game dialog will show up - m_Suspended = true; - - // State end - if (m_pMetaGUI->ContinuePhase()) - { - m_GameState = GAMEINTRO; - m_StateChanged = true; - } - } - - // INTRO - // Show some nice graphical intro of the campaign - else if (m_GameState == GAMEINTRO) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - // State body - - // State end - if (1)//m_pMetaGUI->ContinuePhase()) - { - m_GameState = NEWROUND; - m_StateChanged = true; - } - } - - // NEW ROUND - // Show a nice banner for the new round and its number - else if (m_GameState == NEWROUND) - { - // State init - if (m_StateChanged) - { - // New day; clear out old activities - ClearActivities(); - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - // State body - - - // State end - if (m_pMetaGUI->ContinuePhase()) - { - m_GameState = REVEALSCENES; - m_StateChanged = true; - } - } - - // REVEAL SCENES - // If not all the sites are revealed yet, reveal one or two (depending on how many players playing?) - else if (m_GameState == REVEALSCENES) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - // State body - - // State end - if (m_pMetaGUI->ContinuePhase()) - { - m_GameState = COUNTINCOME; - m_StateChanged = true; - } - } - - // COUNT INCOME - // Count all the income from all owned bases, add to respective players' funds: - // Show this with lines from the bases adding to the floating player counters, showing income ratios, and leave the lines there to show base ownership and value during turns - else if (m_GameState == COUNTINCOME) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - // State body - - - // State end - if (m_pMetaGUI->ContinuePhase()) - { - m_GameState = PLAYER1TURN; - m_StateChanged = true; - } - } - - // PLAYER TURNS - // Player-controlled player turn sequence: - // Show planet and current known sites, allow inspection of each - // Allow to zoom in on each site owned by this player: - // Build blueprints (allocating defense budget) in Scene Editor Activity until player done - // Allow clicking on sites unvisited by anyone - // Allocate expedition budget to this site with a slider - // Allow clicking on sites already claimed by other player - // Allocate attack budget to this site with a slider - // [Question: allow more than one expedition/offense action per turn?? - A: no] - // Wait til player hits [End Turn] button - // AI-controlled player turn sequence: - // Determine offense/defense ratio of funds based on AI temperament/aggressiveness setting - // Select expansion site(s??), allocate the offense funds if we decide to go with more than one expansion/round - // Build as much as can afford on owned sites, based on the pre-defined base templates of the Scenes - else if (m_GameState >= PLAYER1TURN && m_GameState <= PLAYER4TURN) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - int metaPlayer = m_GameState - PLAYER1TURN; - - // If an AI player, do the AI player's logic now and go to next player immediately afterward - if (!m_Players[metaPlayer].IsHuman()) - AIPlayerTurn(metaPlayer); - - // State end - skip A.I. metaplayer turns in the GUI; also skip human player who have been knocked out of the game in previous rounds - if (m_pMetaGUI->ContinuePhase() || !m_Players[metaPlayer].IsHuman() || m_Players[metaPlayer].IsGameOverByRound(m_CurrentRound)) - { - // If this player is now done for, mark him as such so he'll be completely skipped in future rounds - if (GetTotalBrainCountOfPlayer(metaPlayer) <= 0 && !m_Players[metaPlayer].IsGameOverByRound(m_CurrentRound)) - m_Players[metaPlayer].SetGameOverRound(m_CurrentRound); - - // Find the next player which is not out of the game yet - do - { - // Next player, if any left - m_GameState++; - metaPlayer = m_GameState - PLAYER1TURN; - } - while (m_GameState <= PLAYER4TURN && metaPlayer < m_Players.size() && m_Players[metaPlayer].IsGameOverByRound(m_CurrentRound)); - - // If not, jump to building bases - if (m_GameState > PLAYER4TURN || metaPlayer >= m_Players.size()) - m_GameState = BUILDBASES; - - m_StateChanged = true; - } - } - - // BUILD BASES - // Apply all blueprint pieces to all claimed/base sites (or just save them in list and apply at next load of Scene?) - // In sequence, graphically show all defense investments of each player with lines from the floating funds meters to the bases spent on - else if (m_GameState == BUILDBASES) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - // State body - - // State end - if (m_pMetaGUI->ContinuePhase()) - { - m_GameState = RUNACTIVITIES; - m_StateChanged = true; - } - } - - // RUN ACTIVITIES - // Generate and go through list of all Activities caused by player offensive moves during their turns: - // Init the Activity with the corresponding Scene and player setups as dictated by the round's situation - // LOAD the Scene from disk, from the current metagame folder where all terrain damage etc is preserved - // Let the Activity play out til the end - // Show some stats of the outcome of the Activity - // Have the outcome reflected in the Metagame: Funds won/lost, site ownership change, etc - // SAVE the Scene to disk, preserving the Terrain - else if (m_GameState == RUNACTIVITIES) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - // State body - - // State end, either as signaled by the GUI, or by the fact that we are out of things to run - if (m_pMetaGUI->ContinuePhase() || m_CurrentOffensive >= m_RoundOffensives.size()) - { - m_GameState = ENDROUND; - m_StateChanged = true; - } - } - - // END ROUND - // If all sites of this metagame have been revealed, check if any player owns all the of them now - if so, GAME OVER - else if (m_GameState == ENDROUND) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - - // Check for GAME OVER condition - if (IsGameOver()) - { - m_GameState = GAMEOVER; - m_StateChanged = true; - } - } - - // State body - - // Game isn't over yet, so start the next round when user is done looking at stats - if (m_pMetaGUI->ContinuePhase()) - { - m_CurrentRound++; - m_GameState = NEWROUND; - m_StateChanged = true; - } - } - - // GAME OVER - // Show some game over graphical thing and perhaps stats - else if (m_GameState == GAMEOVER) - { - // State init - if (m_StateChanged) - { - m_PhaseTimer.Reset(); - m_StateChanged = false; - } - - // State body -/* finito! - // State end - if (m_pMetaGUI->ContinuePhase()) - { - // Next player - m_GameState = GAMEOVER; - m_StateChanged = true; - } -*/ - } - - // Whoops, state is f'd up, restart the last round - else - { - RTEAbort("Metagame State is out of bounds!?"); - m_GameState = REVEALSCENES; - } -} + // State body + /* finito! + // State end + if (m_pMetaGUI->ContinuePhase()) + { + // Next player + m_GameState = GAMEOVER; + m_StateChanged = true; + } + */ + } + // Whoops, state is f'd up, restart the last round + else { + RTEAbort("Metagame State is out of bounds!?"); + m_GameState = REVEALSCENES; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MetaMan's current graphical representation to a -// BITMAP of choice. This includes all game-related graphics. - -void MetaMan::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) -{ -/* - GUIFont *pLargeFont = g_FrameMan.GetLargeFont(); - GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); - AllegroBitmap pBitmapInt(pTargetBitmap); - - // Iterate through all players - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - ; - } -*/ - - m_pMetaGUI->Draw(pTargetBitmap); -} -} // namespace RTE \ No newline at end of file + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MetaMan's current graphical representation to a + // BITMAP of choice. This includes all game-related graphics. + + void MetaMan::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + /* + GUIFont *pLargeFont = g_FrameMan.GetLargeFont(); + GUIFont *pSmallFont = g_FrameMan.GetSmallFont(); + AllegroBitmap pBitmapInt(pTargetBitmap); + + // Iterate through all players + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) + { + ; + } + */ + + m_pMetaGUI->Draw(pTargetBitmap); + } +} // namespace RTE diff --git a/Source/Managers/MetaMan.h b/Source/Managers/MetaMan.h index e974d2a2e..21d97d1e7 100644 --- a/Source/Managers/MetaMan.h +++ b/Source/Managers/MetaMan.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -29,623 +28,567 @@ #include "Icon.h" #include "GUIBanner.h" -namespace RTE -{ +namespace RTE { #define DEFAULTGAMENAME "NewGame" #define AUTOSAVENAME "AutoSave" #define METASAVEPATH System::GetUserdataDirectory() + c_UserConquestSavesModuleName + "/" #define METASAVEMODULENAME c_UserConquestSavesModuleName -class MetagameGUI; -class MetaSave; -class Scene; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: MetaMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The singleton manager of the Metagame of Cortex Command, ie the -// games played out in the campaign screen. -// Parent(s): Singleton, serializable -// Class history: 10/10/2009 MetaMan created. - -class MetaMan : public Singleton, public Serializable { - friend struct ManagerLuaBindings; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - -friend class MetagameGUI; -friend class MetaSave; - - SerializableClassNameGetter; - SerializableOverrideMethods; - - enum MetagameState - { - NOGAME = -1, - GAMEINTRO = 0, - NEWROUND, - REVEALSCENES, - COUNTINCOME, - PLAYER1TURN, - PLAYER2TURN, - PLAYER3TURN, - PLAYER4TURN, - BUILDBASES, - RUNACTIVITIES, - ENDROUND, - GAMEOVER - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MetaMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a MetaMan object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - MetaMan() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~MetaMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a MetaMan object before deletion -// from system memory. -// Arguments: None. - - ~MetaMan() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MetaMan object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Initialize(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NewGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Wipes any current and sets up a new game based on a size parameter. -// Arguments: The size of the new Metagame, which will affect how -// many Scenes/Sites will ultimately be used. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int NewGame(int gameSize = 3); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EndGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Wipes any current metagame and sets things back to as if program start. -// Arguments: None. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int EndGame(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Load -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Load a Metagame from disk out of the special Metagame.rte data module -// Arguments: The MetaSave object to load from - Ownership Is Not Transferred! -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int Load(const MetaSave *pSave); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveSceneData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the bitmap data of all Scenes of this Metagame that are currently -// loaded. -// Arguments: The filepath base to the where to save the Bitmap data. This means -// everything up to and including the unique name of the game. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int SaveSceneData(std::string pathBase); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadSceneData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads the bitmap data of all Scenes of this Metagame that have once -// been saved to files. -// Arguments: None. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int LoadSceneData(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearSceneData -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the bitmap data of all Scenes of this Metagame that have once -// been saved to files. -// Arguments: None. -// Return value: An error return value signaling success or any particular failure. -// Anything below 0 is an error signal. - - int ClearSceneData(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire MetaMan, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MetaMan object. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetGameName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the name of the currently played Metagame. It's what's used when -// saving to disk. -// Arguments: The Metagame's name. -// Return value: None. - - void SetGameName(std::string newName) { m_GameName = newName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGameName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the name of the currently played Metagame. It's what's used when -// saving to disk. -// Arguments: None. -// Return value: The name of the current metagame. - - std::string GetGameName() const { return m_GameName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the GUI controller of this Metagame. -// Arguments: None. -// Return value: The GUI controller of the metagame. - - MetagameGUI *GetGUI() { return m_pMetaGUI; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlayerTurn -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows which player's turn is now or coming up. -// Arguments: None. -// Return value: The player who is currently doing his turn, or coming up next in an -// intermediate phase. - - int GetPlayerTurn() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlayerCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets current number of MetaPlayers -// Arguments: None -// Return value: The number of meta players in the current game. - - int GetPlayerCount() const { return m_Players.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTeamOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the designated team of a specific player -// Arguments: Which player. -// Return value: The team of that player. - - int GetTeamOfPlayer(int metaPlayer) const { return metaPlayer >= Players::PlayerOne && metaPlayer < m_Players.size() ? m_Players[metaPlayer].GetTeam() : Activity::NoTeam; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the specified MetaPlayer -// Arguments: Which player. -// Return value: The requested MetaPlayer - - MetaPlayer * GetPlayer(int metaPlayer) { return (metaPlayer >= Players::PlayerOne && metaPlayer < m_Players.size()) ? &(m_Players[metaPlayer]) : 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMetaPlayerOfInGamePlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the MetaPlayer playing a specific in-game player, if any. -// Arguments: Which in-game player to translate into a metaplayer. -// Return value: The requested MetaPlayer, if any is playing that in-game player. If not -// 0 is returned. - - MetaPlayer * GetMetaPlayerOfInGamePlayer(int inGamePlayer); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTeamIcon -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the flag Icon of a specific team -// Arguments: The team to get the Team icon of. -// Return value: A reference to the Icon. - - Icon & GetTeamIcon(int team) { return m_TeamIcons[team]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextSceneOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next Scene in play that is owned by a specific player. -// Arguments: The player to get the next owned Scene of. -// The Scene to start searching from in the current roster of Scenes, OWNERSHIP IS NOT TRANSFERRED! -// Return value: A pointer to the next Scene found in the sequence. OWNERSHIP IS NOT TRANSFERRED! - - const Scene * GetNextSceneOfPlayer(int metaPlayer, const Scene *pScene = 0) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalBrainCountOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of brains that a player has, including ones of -// his that are resident down on sites. -// Arguments: The metagame player to get the total brain count from. -// Whether to only count the brains in the pools, or to also include all -// resident brains as well. -// Return value: The total number of brains that belong to the metagame player. - - int GetTotalBrainCountOfPlayer(int metaPlayer, bool countPoolsOnly = false) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGoldCountOfTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total gold funds of all the players of a specific team combined. -// Arguments: The metagame team to get the total gold funds of. -// Return value: The total amount of ounces of gold this team has. - - int GetGoldCountOfTeam(int team) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneCountOfTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of bases that any specific team owns. -// Arguments: The team to get the scene/site ownership count of. -// Return value: The count of scenes owned by this team. - - int GetSceneCountOfTeam(int team) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalBrainCountOfTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of brains that a team has, including ones that -// are resident down on sites. -// Arguments: The metagame team to get the total brain count from. -// Whether to only count the brains in the pools, or to also include all -// resident brains as well. -// Return value: The total number of brains that belong to the metagame team. - - int GetTotalBrainCountOfTeam(int team, bool countPoolsOnly = false) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OnlyTeamWithAnyBrainPoolLeft -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which team, if any, is the only one left with brains in its -// pool. -// Arguments: None. -// Return value: Which team, if any, is the sole remaining with any brains left in its -// players' brain pools. - - int OnlyTeamWithAnyBrainPoolLeft(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NoBrainsLeftInAnyPool -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether there are no brains left in any active player's pool -// at all. This does NOT count deployed brain in bases. -// Arguments: None. -// Return value: Whether there are no brains left in any player's brain pool. - - bool NoBrainsLeftInAnyPool(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WhichTeamIsLeading -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates which single team has the most owned bases, and if there's a -// tie between two teams, total owned gold funds is used as a tiebreaker. -// Arguments: None. -// Return value: Which team is currently in the lead. - - int WhichTeamIsLeading(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneIncomeOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total income from all scenes owned by a specific metaPlayer. -// Arguments: The metagame player to get the total scene income from. -// Return value: The amount of income, in oz, the player made this round from its scenes. - - float GetSceneIncomeOfPlayer(int metaPlayer) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetBudgetedRatioOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ratio of funds already allocated to budgets of this player. -// Arguments: The metagame player to get the budget ratio of. -// A scene to exclude from the tally, if any. -// Whether to count the money allocated for offensive action. -// Whether to count the money allocated for defensive actions. -// Return value: The amount, in ratio, that this player already has allocated. - - float GetBudgetedRatioOfPlayer(int metaPlayer, const Scene *pException = 0, bool includeOffensive = true, bool includeDefensive = true) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRemainingFundsOfPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the count of funds still unbudgeted and available of a player. -// Arguments: The metagame player to get the unallocated funds of. -// A scene to exclude from the tally, if any. -// Whether to count the money allocated for offensive action as remaining. -// Whether to count the money allocated for defensive action as remaining. -// Return value: The amount, in oz, that this player unallocated and unused this turn. - - float GetRemainingFundsOfPlayer(int metaPlayer, const Scene *pException = 0, bool deductOffensive = false, bool deductDefensive = false) const { return m_Players[metaPlayer].GetFunds() - m_Players[metaPlayer].GetFunds() * GetBudgetedRatioOfPlayer(metaPlayer, pException, !deductOffensive, !deductDefensive); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GameInProgress -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether a game is currently in progress -// Arguments: None. -// Return value: Whether a game is going or not. - - bool GameInProgress() { return m_GameState >= GAMEINTRO && m_GameState <= ENDROUND; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsSuspended -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether game is suspended or not. -// Arguments: None. -// Return value: Whether suspended or not. - - bool IsSuspended() { return m_Suspended; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSuspend -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Suspends or unsuspends the game so exclusive GUIs and menus can be -// shown. -// Arguments: Whether to suspend or not. -// Return value: None. - - void SetSuspend(bool suspend); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsActivePlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks wheter a certain player index is valid for the current game -// Arguments: None. -// Return value: Whether the player index passed in is active for the current game. - - bool IsActivePlayer(int metaPlayer) { return metaPlayer >= Players::PlayerOne && metaPlayer < m_Players.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsActiveTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks wheter a certain team index is valid for the current game -// Arguments: None. -// Return value: Whether the team index passed in is active for the current game. - - bool IsActiveTeam(int team) { return team >= Activity::TeamOne && team < m_TeamCount; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WhichTeamOwnsAllSites -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether one team has ownership of all revealed sites. -// Arguments: None. -// Return value: Which team has all sites, if any. If not NoTeam is returned. - - int WhichTeamOwnsAllSites(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsGameOver -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks for game over condition -// Arguments: None. -// Return value: Whether the game over conditions have been met - - bool IsGameOver(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GameIsSaved -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether the game has been saved and no data loss will result -// if program is quit right now. -// Arguments: None. -// Return value: Whether the game is saved. - - bool GameIsSaved() { return m_GameSaved || m_GameState <= NOGAME || m_GameState >= GAMEOVER; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TotalScenePresets -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Yields a set of ALL eligible Scene presets for a new game. -// Arguments: The list to fill with all the eligible presets. If no list is passed -// it will be ignored. Presets returned in list are NOT OWNED there. -// Return value: The count of total number preset scenes eligible for gameplay. - - int TotalScenePresets(std::list *pScenes = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SelectScenePresets -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Yields a set of randomly selected Scene presets for a new game. -// Arguments: The size of the set. -// The list to fill with the selected presets, depending on currently -// set player numbers and loaded eligible scenes. If no list is passed -// it will be ignored. Presets returned in list are NOT OWNED there. -// Return value: The count of selected preset scenes. - - int SelectScenePresets(int gameSize, std::list *pSelected = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearActivities -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out all the lined-up activities for the current round. -// Arguments: None. -// Return value: None. - - void ClearActivities(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AIPlayerTurn -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Does all the things an AI metaPlayer needs to do during his turn. -// Arguments: Which AI metaPlayer we're going to process. -// Return value: None. - - void AIPlayerTurn(int metaPlayer); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this and the current Metagame. Supposed to be -// done every frame before drawing. -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MetaMan's current graphical representation to a BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // GUI controller, owned - MetagameGUI *m_pMetaGUI; - - // Current Metagame state - int m_GameState; - // Whether the state just changed - bool m_StateChanged; - // Whether the game is currently suspended (e.g. in the menu) - bool m_Suspended; - // Whether game has been saved since the last suspension of it - bool m_GameSaved; - - // The save name of the currently played metagame - std::string m_GameName; - // The players of the metagame - std::vector m_Players; - // The number of Team:s in play this game - int m_TeamCount; - // The flag icons of all teams - Icon m_TeamIcons[Activity::MaxTeamCount]; - // The current round the game is on, starting with count on 0 - int m_CurrentRound; - // All Scenes of the current game, OWNED by this. Stored sequentially in order of revealing - std::vector m_Scenes; - // How many of the scenes have been revealed so far - the whole number. It's a float to increase it slower than once a round - float m_RevealedScenes; - // How many scenes to reveal each round.. can be a fractional that adds up over several days - float m_RevealRate; - // Any extra reveals to make next reveal phase - float m_RevealExtra; - - // The Activities generated by the current round's offensive maneuvers - std::vector m_RoundOffensives; - // The current offensive action that we're about to play next - int m_CurrentOffensive; - // Game difficulty - int m_Difficulty; - // Teams AI Skill - int m_TeamAISkill[Activity::MaxTeamCount]; - - // Timer for measuring how long each phase has gone for - Timer m_PhaseTimer; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MetaMan, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - MetaMan(const MetaMan &reference) = delete; - MetaMan & operator=(const MetaMan &rhs) = delete; - -}; + class MetagameGUI; + class MetaSave; + class Scene; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: MetaMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The singleton manager of the Metagame of Cortex Command, ie the + // games played out in the campaign screen. + // Parent(s): Singleton, serializable + // Class history: 10/10/2009 MetaMan created. + + class MetaMan : public Singleton, public Serializable { + friend struct ManagerLuaBindings; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + friend class MetagameGUI; + friend class MetaSave; + + SerializableClassNameGetter; + SerializableOverrideMethods; + + enum MetagameState { + NOGAME = -1, + GAMEINTRO = 0, + NEWROUND, + REVEALSCENES, + COUNTINCOME, + PLAYER1TURN, + PLAYER2TURN, + PLAYER3TURN, + PLAYER4TURN, + BUILDBASES, + RUNACTIVITIES, + ENDROUND, + GAMEOVER + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MetaMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a MetaMan object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + MetaMan() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~MetaMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a MetaMan object before deletion + // from system memory. + // Arguments: None. + + ~MetaMan() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MetaMan object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Initialize(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NewGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Wipes any current and sets up a new game based on a size parameter. + // Arguments: The size of the new Metagame, which will affect how + // many Scenes/Sites will ultimately be used. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int NewGame(int gameSize = 3); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EndGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Wipes any current metagame and sets things back to as if program start. + // Arguments: None. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int EndGame(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Load + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Load a Metagame from disk out of the special Metagame.rte data module + // Arguments: The MetaSave object to load from - Ownership Is Not Transferred! + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int Load(const MetaSave* pSave); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveSceneData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the bitmap data of all Scenes of this Metagame that are currently + // loaded. + // Arguments: The filepath base to the where to save the Bitmap data. This means + // everything up to and including the unique name of the game. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int SaveSceneData(std::string pathBase); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadSceneData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads the bitmap data of all Scenes of this Metagame that have once + // been saved to files. + // Arguments: None. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int LoadSceneData(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearSceneData + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the bitmap data of all Scenes of this Metagame that have once + // been saved to files. + // Arguments: None. + // Return value: An error return value signaling success or any particular failure. + // Anything below 0 is an error signal. + + int ClearSceneData(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire MetaMan, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MetaMan object. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetGameName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the name of the currently played Metagame. It's what's used when + // saving to disk. + // Arguments: The Metagame's name. + // Return value: None. + + void SetGameName(std::string newName) { m_GameName = newName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGameName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of the currently played Metagame. It's what's used when + // saving to disk. + // Arguments: None. + // Return value: The name of the current metagame. + + std::string GetGameName() const { return m_GameName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the GUI controller of this Metagame. + // Arguments: None. + // Return value: The GUI controller of the metagame. + + MetagameGUI* GetGUI() { return m_pMetaGUI; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlayerTurn + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows which player's turn is now or coming up. + // Arguments: None. + // Return value: The player who is currently doing his turn, or coming up next in an + // intermediate phase. + + int GetPlayerTurn() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlayerCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets current number of MetaPlayers + // Arguments: None + // Return value: The number of meta players in the current game. + + int GetPlayerCount() const { return m_Players.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTeamOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the designated team of a specific player + // Arguments: Which player. + // Return value: The team of that player. + + int GetTeamOfPlayer(int metaPlayer) const { return metaPlayer >= Players::PlayerOne && metaPlayer < m_Players.size() ? m_Players[metaPlayer].GetTeam() : Activity::NoTeam; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the specified MetaPlayer + // Arguments: Which player. + // Return value: The requested MetaPlayer + + MetaPlayer* GetPlayer(int metaPlayer) { return (metaPlayer >= Players::PlayerOne && metaPlayer < m_Players.size()) ? &(m_Players[metaPlayer]) : 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMetaPlayerOfInGamePlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the MetaPlayer playing a specific in-game player, if any. + // Arguments: Which in-game player to translate into a metaplayer. + // Return value: The requested MetaPlayer, if any is playing that in-game player. If not + // 0 is returned. + + MetaPlayer* GetMetaPlayerOfInGamePlayer(int inGamePlayer); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTeamIcon + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the flag Icon of a specific team + // Arguments: The team to get the Team icon of. + // Return value: A reference to the Icon. + + Icon& GetTeamIcon(int team) { return m_TeamIcons[team]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextSceneOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next Scene in play that is owned by a specific player. + // Arguments: The player to get the next owned Scene of. + // The Scene to start searching from in the current roster of Scenes, OWNERSHIP IS NOT TRANSFERRED! + // Return value: A pointer to the next Scene found in the sequence. OWNERSHIP IS NOT TRANSFERRED! + + const Scene* GetNextSceneOfPlayer(int metaPlayer, const Scene* pScene = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalBrainCountOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of brains that a player has, including ones of + // his that are resident down on sites. + // Arguments: The metagame player to get the total brain count from. + // Whether to only count the brains in the pools, or to also include all + // resident brains as well. + // Return value: The total number of brains that belong to the metagame player. + + int GetTotalBrainCountOfPlayer(int metaPlayer, bool countPoolsOnly = false) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGoldCountOfTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total gold funds of all the players of a specific team combined. + // Arguments: The metagame team to get the total gold funds of. + // Return value: The total amount of ounces of gold this team has. + + int GetGoldCountOfTeam(int team) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneCountOfTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of bases that any specific team owns. + // Arguments: The team to get the scene/site ownership count of. + // Return value: The count of scenes owned by this team. + + int GetSceneCountOfTeam(int team) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalBrainCountOfTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of brains that a team has, including ones that + // are resident down on sites. + // Arguments: The metagame team to get the total brain count from. + // Whether to only count the brains in the pools, or to also include all + // resident brains as well. + // Return value: The total number of brains that belong to the metagame team. + + int GetTotalBrainCountOfTeam(int team, bool countPoolsOnly = false) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OnlyTeamWithAnyBrainPoolLeft + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which team, if any, is the only one left with brains in its + // pool. + // Arguments: None. + // Return value: Which team, if any, is the sole remaining with any brains left in its + // players' brain pools. + + int OnlyTeamWithAnyBrainPoolLeft(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NoBrainsLeftInAnyPool + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether there are no brains left in any active player's pool + // at all. This does NOT count deployed brain in bases. + // Arguments: None. + // Return value: Whether there are no brains left in any player's brain pool. + + bool NoBrainsLeftInAnyPool(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WhichTeamIsLeading + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates which single team has the most owned bases, and if there's a + // tie between two teams, total owned gold funds is used as a tiebreaker. + // Arguments: None. + // Return value: Which team is currently in the lead. + + int WhichTeamIsLeading(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneIncomeOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total income from all scenes owned by a specific metaPlayer. + // Arguments: The metagame player to get the total scene income from. + // Return value: The amount of income, in oz, the player made this round from its scenes. + + float GetSceneIncomeOfPlayer(int metaPlayer) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetBudgetedRatioOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ratio of funds already allocated to budgets of this player. + // Arguments: The metagame player to get the budget ratio of. + // A scene to exclude from the tally, if any. + // Whether to count the money allocated for offensive action. + // Whether to count the money allocated for defensive actions. + // Return value: The amount, in ratio, that this player already has allocated. + + float GetBudgetedRatioOfPlayer(int metaPlayer, const Scene* pException = 0, bool includeOffensive = true, bool includeDefensive = true) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRemainingFundsOfPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the count of funds still unbudgeted and available of a player. + // Arguments: The metagame player to get the unallocated funds of. + // A scene to exclude from the tally, if any. + // Whether to count the money allocated for offensive action as remaining. + // Whether to count the money allocated for defensive action as remaining. + // Return value: The amount, in oz, that this player unallocated and unused this turn. + + float GetRemainingFundsOfPlayer(int metaPlayer, const Scene* pException = 0, bool deductOffensive = false, bool deductDefensive = false) const { return m_Players[metaPlayer].GetFunds() - m_Players[metaPlayer].GetFunds() * GetBudgetedRatioOfPlayer(metaPlayer, pException, !deductOffensive, !deductDefensive); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GameInProgress + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether a game is currently in progress + // Arguments: None. + // Return value: Whether a game is going or not. + + bool GameInProgress() { return m_GameState >= GAMEINTRO && m_GameState <= ENDROUND; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsSuspended + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether game is suspended or not. + // Arguments: None. + // Return value: Whether suspended or not. + + bool IsSuspended() { return m_Suspended; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSuspend + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Suspends or unsuspends the game so exclusive GUIs and menus can be + // shown. + // Arguments: Whether to suspend or not. + // Return value: None. + + void SetSuspend(bool suspend); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsActivePlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks wheter a certain player index is valid for the current game + // Arguments: None. + // Return value: Whether the player index passed in is active for the current game. + + bool IsActivePlayer(int metaPlayer) { return metaPlayer >= Players::PlayerOne && metaPlayer < m_Players.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsActiveTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks wheter a certain team index is valid for the current game + // Arguments: None. + // Return value: Whether the team index passed in is active for the current game. + + bool IsActiveTeam(int team) { return team >= Activity::TeamOne && team < m_TeamCount; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WhichTeamOwnsAllSites + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether one team has ownership of all revealed sites. + // Arguments: None. + // Return value: Which team has all sites, if any. If not NoTeam is returned. + + int WhichTeamOwnsAllSites(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsGameOver + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks for game over condition + // Arguments: None. + // Return value: Whether the game over conditions have been met + + bool IsGameOver(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GameIsSaved + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether the game has been saved and no data loss will result + // if program is quit right now. + // Arguments: None. + // Return value: Whether the game is saved. + + bool GameIsSaved() { return m_GameSaved || m_GameState <= NOGAME || m_GameState >= GAMEOVER; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TotalScenePresets + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Yields a set of ALL eligible Scene presets for a new game. + // Arguments: The list to fill with all the eligible presets. If no list is passed + // it will be ignored. Presets returned in list are NOT OWNED there. + // Return value: The count of total number preset scenes eligible for gameplay. + + int TotalScenePresets(std::list* pScenes = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SelectScenePresets + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Yields a set of randomly selected Scene presets for a new game. + // Arguments: The size of the set. + // The list to fill with the selected presets, depending on currently + // set player numbers and loaded eligible scenes. If no list is passed + // it will be ignored. Presets returned in list are NOT OWNED there. + // Return value: The count of selected preset scenes. + + int SelectScenePresets(int gameSize, std::list* pSelected = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearActivities + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out all the lined-up activities for the current round. + // Arguments: None. + // Return value: None. + + void ClearActivities(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AIPlayerTurn + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Does all the things an AI metaPlayer needs to do during his turn. + // Arguments: Which AI metaPlayer we're going to process. + // Return value: None. + + void AIPlayerTurn(int metaPlayer); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this and the current Metagame. Supposed to be + // done every frame before drawing. + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MetaMan's current graphical representation to a BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // GUI controller, owned + MetagameGUI* m_pMetaGUI; + + // Current Metagame state + int m_GameState; + // Whether the state just changed + bool m_StateChanged; + // Whether the game is currently suspended (e.g. in the menu) + bool m_Suspended; + // Whether game has been saved since the last suspension of it + bool m_GameSaved; + + // The save name of the currently played metagame + std::string m_GameName; + // The players of the metagame + std::vector m_Players; + // The number of Team:s in play this game + int m_TeamCount; + // The flag icons of all teams + Icon m_TeamIcons[Activity::MaxTeamCount]; + // The current round the game is on, starting with count on 0 + int m_CurrentRound; + // All Scenes of the current game, OWNED by this. Stored sequentially in order of revealing + std::vector m_Scenes; + // How many of the scenes have been revealed so far - the whole number. It's a float to increase it slower than once a round + float m_RevealedScenes; + // How many scenes to reveal each round.. can be a fractional that adds up over several days + float m_RevealRate; + // Any extra reveals to make next reveal phase + float m_RevealExtra; + + // The Activities generated by the current round's offensive maneuvers + std::vector m_RoundOffensives; + // The current offensive action that we're about to play next + int m_CurrentOffensive; + // Game difficulty + int m_Difficulty; + // Teams AI Skill + int m_TeamAISkill[Activity::MaxTeamCount]; + + // Timer for measuring how long each phase has gone for + Timer m_PhaseTimer; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MetaMan, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + MetaMan(const MetaMan& reference) = delete; + MetaMan& operator=(const MetaMan& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Managers/MovableMan.cpp b/Source/Managers/MovableMan.cpp index ec29af0c4..6172abddb 100644 --- a/Source/Managers/MovableMan.cpp +++ b/Source/Managers/MovableMan.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -41,2147 +40,2002 @@ namespace RTE { -AlarmEvent::AlarmEvent(const Vector &pos, int team, float range) -{ - m_ScenePos = pos; - m_Team = (Activity::Teams)team; - m_Range = range * g_FrameMan.GetPlayerScreenWidth() * 0.51F; -} + AlarmEvent::AlarmEvent(const Vector& pos, int team, float range) { + m_ScenePos = pos; + m_Team = (Activity::Teams)team; + m_Range = range * g_FrameMan.GetPlayerScreenWidth() * 0.51F; + } -const std::string MovableMan::c_ClassName = "MovableMan"; + const std::string MovableMan::c_ClassName = "MovableMan"; + + // Comparison functor for sorting movable objects by their X position using STL's sort + struct MOXPosComparison { + bool operator()(MovableObject* pRhs, MovableObject* pLhs) { return pRhs->GetPos().m_X < pLhs->GetPos().m_X; } + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MovableMan, effectively + // resetting the members of this abstraction level only. + + void MovableMan::Clear() { + m_Actors.clear(); + m_ContiguousActorIDs.clear(); + m_Items.clear(); + m_Particles.clear(); + m_AddedActors.clear(); + m_AddedItems.clear(); + m_AddedParticles.clear(); + m_ValidActors.clear(); + m_ValidItems.clear(); + m_ValidParticles.clear(); + m_ActorRoster[Activity::TeamOne].clear(); + m_ActorRoster[Activity::TeamTwo].clear(); + m_ActorRoster[Activity::TeamThree].clear(); + m_ActorRoster[Activity::TeamFour].clear(); + m_SortTeamRoster[Activity::TeamOne] = false; + m_SortTeamRoster[Activity::TeamTwo] = false; + m_SortTeamRoster[Activity::TeamThree] = false; + m_SortTeamRoster[Activity::TeamFour] = false; + m_AddedAlarmEvents.clear(); + m_AlarmEvents.clear(); + m_MOIDIndex.clear(); + m_SplashRatio = 0.75; + m_MaxDroppedItems = 100; + m_SettlingEnabled = true; + m_MOSubtractionEnabled = true; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MovableMan object ready for use. -// Comparison functor for sorting movable objects by their X position using STL's sort -struct MOXPosComparison { - bool operator()(MovableObject *pRhs, MovableObject *pLhs) { return pRhs->GetPos().m_X < pLhs->GetPos().m_X; } -}; + int MovableMan::Initialize() { + // TODO: Increase this number, or maybe only for certain classes? + Entity::ClassInfo::FillAllPools(); + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MovableMan, effectively -// resetting the members of this abstraction level only. + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: ReadProperty + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a property value from a reader stream. If the name isn't + // recognized by this class, then ReadProperty of the parent class + // is called. If the property isn't recognized by any of the base classes, + // false is returned, and the reader's position is untouched. -void MovableMan::Clear() -{ - m_Actors.clear(); - m_ContiguousActorIDs.clear(); - m_Items.clear(); - m_Particles.clear(); - m_AddedActors.clear(); - m_AddedItems.clear(); - m_AddedParticles.clear(); - m_ValidActors.clear(); - m_ValidItems.clear(); - m_ValidParticles.clear(); - m_ActorRoster[Activity::TeamOne].clear(); - m_ActorRoster[Activity::TeamTwo].clear(); - m_ActorRoster[Activity::TeamThree].clear(); - m_ActorRoster[Activity::TeamFour].clear(); - m_SortTeamRoster[Activity::TeamOne] = false; - m_SortTeamRoster[Activity::TeamTwo] = false; - m_SortTeamRoster[Activity::TeamThree] = false; - m_SortTeamRoster[Activity::TeamFour] = false; - m_AddedAlarmEvents.clear(); - m_AlarmEvents.clear(); - m_MOIDIndex.clear(); - m_SplashRatio = 0.75; - m_MaxDroppedItems = 100; - m_SettlingEnabled = true; - m_MOSubtractionEnabled = true; -} + int MovableMan::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Serializable::ReadProperty(propName, reader)); + MatchProperty("AddEffect", { g_PresetMan.GetEntityPreset(reader); }); + MatchProperty("AddAmmo", { g_PresetMan.GetEntityPreset(reader); }); + MatchProperty("AddDevice", { g_PresetMan.GetEntityPreset(reader); }); + MatchProperty("AddActor", { g_PresetMan.GetEntityPreset(reader); }); + MatchProperty("SplashRatio", { reader >> m_SplashRatio; }); -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MovableMan object ready for use. + EndPropertyList; + } -int MovableMan::Initialize() -{ - // TODO: Increase this number, or maybe only for certain classes? - Entity::ClassInfo::FillAllPools(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this MovableMan with a Writer for + // later recreation with Create(Reader &reader); - return 0; -} + int MovableMan::Save(Writer& writer) const { + Serializable::Save(writer); + writer << m_Actors.size(); + for (std::deque::const_iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) + writer << **itr; -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: ReadProperty -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a property value from a reader stream. If the name isn't -// recognized by this class, then ReadProperty of the parent class -// is called. If the property isn't recognized by any of the base classes, -// false is returned, and the reader's position is untouched. + writer << m_Particles.size(); + for (std::deque::const_iterator itr2 = m_Particles.begin(); itr2 != m_Particles.end(); ++itr2) + writer << **itr2; -int MovableMan::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Serializable::ReadProperty(propName, reader)); - - MatchProperty("AddEffect", { g_PresetMan.GetEntityPreset(reader); }); - MatchProperty("AddAmmo", { g_PresetMan.GetEntityPreset(reader); }); - MatchProperty("AddDevice", { g_PresetMan.GetEntityPreset(reader); }); - MatchProperty("AddActor", { g_PresetMan.GetEntityPreset(reader); }); - MatchProperty("SplashRatio", { reader >> m_SplashRatio; }); - - EndPropertyList; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MovableMan object. -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this MovableMan with a Writer for -// later recreation with Create(Reader &reader); + void MovableMan::Destroy() { + for (std::deque::iterator it1 = m_Actors.begin(); it1 != m_Actors.end(); ++it1) + delete (*it1); + for (std::deque::iterator it2 = m_Items.begin(); it2 != m_Items.end(); ++it2) + delete (*it2); + for (std::deque::iterator it3 = m_Particles.begin(); it3 != m_Particles.end(); ++it3) + delete (*it3); -int MovableMan::Save(Writer &writer) const -{ - Serializable::Save(writer); + Clear(); + } - writer << m_Actors.size(); - for (std::deque::const_iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) - writer << **itr; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMOFromID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a MO from its MOID. Note that MOID's are only valid during the + // same frame as they were assigned to the MOs! - writer << m_Particles.size(); - for (std::deque::const_iterator itr2 = m_Particles.begin(); itr2 != m_Particles.end(); ++itr2) - writer << **itr2; + MovableObject* MovableMan::GetMOFromID(MOID whichID) { + if (whichID != g_NoMOID && whichID != 0 && whichID < m_MOIDIndex.size()) { + return m_MOIDIndex[whichID]; + } + return nullptr; + } - return 0; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + MOID MovableMan::GetMOIDPixel(int pixelX, int pixelY, const std::vector& moidList) { + // Note - We loop through the MOs in reverse to make sure that the topmost (last drawn) MO that overlaps the specified coordinates is the one returned. + for (auto itr = moidList.rbegin(), itrEnd = moidList.rend(); itr < itrEnd; ++itr) { + MOID moid = *itr; + const MovableObject* mo = GetMOFromID(moid); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MovableMan object. + RTEAssert(mo, "Null MO found in MOID list!"); + if (mo == nullptr) { + continue; + } -void MovableMan::Destroy() -{ - for (std::deque::iterator it1 = m_Actors.begin(); it1 != m_Actors.end(); ++it1) - delete (*it1); - for (std::deque::iterator it2 = m_Items.begin(); it2 != m_Items.end(); ++it2) - delete (*it2); - for (std::deque::iterator it3 = m_Particles.begin(); it3 != m_Particles.end(); ++it3) - delete (*it3); - - Clear(); -} + if (mo->GetScale() == 0.0f) { + return g_NoMOID; + } else if (mo->HitTestAtPixel(pixelX, pixelY)) { + return moid; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMOFromID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a MO from its MOID. Note that MOID's are only valid during the -// same frame as they were assigned to the MOs! + return g_NoMOID; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RegisterObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers an object in a global Map collection so it could be found later with FindObjectByUniqueId + // Arguments: MO to register. + // Return value: None. + + void MovableMan::RegisterObject(MovableObject* mo) { + if (!mo) { + return; + } -MovableObject * MovableMan::GetMOFromID(MOID whichID) { - if (whichID != g_NoMOID && whichID != 0 && whichID < m_MOIDIndex.size()) { - return m_MOIDIndex[whichID]; + std::lock_guard guard(m_ObjectRegisteredMutex); + m_KnownObjects[mo->GetUniqueID()] = mo; } - return nullptr; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UnregisterObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes an object from the global lookup collection + // Arguments: MO to remove. + // Return value: None. -MOID MovableMan::GetMOIDPixel(int pixelX, int pixelY, const std::vector &moidList) { - // Note - We loop through the MOs in reverse to make sure that the topmost (last drawn) MO that overlaps the specified coordinates is the one returned. - for (auto itr = moidList.rbegin(), itrEnd = moidList.rend(); itr < itrEnd; ++itr) { - MOID moid = *itr; - const MovableObject *mo = GetMOFromID(moid); + void MovableMan::UnregisterObject(MovableObject* mo) { + if (!mo) { + return; + } - RTEAssert(mo, "Null MO found in MOID list!"); - if (mo == nullptr) { - continue; - } + std::lock_guard guard(m_ObjectRegisteredMutex); + m_KnownObjects.erase(mo->GetUniqueID()); + } - if (mo->GetScale() == 0.0f) { - return g_NoMOID; - } else if (mo->HitTestAtPixel(pixelX, pixelY)) { - return moid; - } - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return g_NoMOID; -} + const std::vector* MovableMan::GetMOsInBox(const Box& box, int ignoreTeam, bool getsHitByMOsOnly) const { + std::vector* vectorForLua = new std::vector(); + *vectorForLua = std::move(g_SceneMan.GetMOIDGrid().GetMOsInBox(box, ignoreTeam, getsHitByMOsOnly)); + return vectorForLua; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RegisterObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registers an object in a global Map collection so it could be found later with FindObjectByUniqueId -// Arguments: MO to register. -// Return value: None. + const std::vector* MovableMan::GetMOsInRadius(const Vector& centre, float radius, int ignoreTeam, bool getsHitByMOsOnly) const { + std::vector* vectorForLua = new std::vector(); + *vectorForLua = std::move(g_SceneMan.GetMOIDGrid().GetMOsInRadius(centre, radius, ignoreTeam, getsHitByMOsOnly)); + return vectorForLua; + } -void MovableMan::RegisterObject(MovableObject * mo) -{ - if (!mo) { - return; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PurgeAllMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out all MovableObject:s out of this. Effectively empties the world + // of anything moving, without resetting all of this' settings. - std::lock_guard guard(m_ObjectRegisteredMutex); - m_KnownObjects[mo->GetUniqueID()] = mo; -} + void MovableMan::PurgeAllMOs() { + for (std::deque::iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) { + (*itr)->DestroyScriptState(); + } + for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) { + (*itr)->DestroyScriptState(); + } + for (std::deque::iterator itr = m_Particles.begin(); itr != m_Particles.end(); ++itr) { + (*itr)->DestroyScriptState(); + } + for (std::deque::iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) { + delete (*itr); + } + for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) { + delete (*itr); + } + for (std::deque::iterator itr = m_Particles.begin(); itr != m_Particles.end(); ++itr) { + delete (*itr); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UnregisterObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes an object from the global lookup collection -// Arguments: MO to remove. -// Return value: None. + m_Actors.clear(); + m_Items.clear(); + m_Particles.clear(); + m_AddedActors.clear(); + m_AddedItems.clear(); + m_AddedParticles.clear(); + m_ValidActors.clear(); + m_ValidItems.clear(); + m_ValidParticles.clear(); + m_ActorRoster[Activity::TeamOne].clear(); + m_ActorRoster[Activity::TeamTwo].clear(); + m_ActorRoster[Activity::TeamThree].clear(); + m_ActorRoster[Activity::TeamFour].clear(); + m_SortTeamRoster[Activity::TeamOne] = false; + m_SortTeamRoster[Activity::TeamTwo] = false; + m_SortTeamRoster[Activity::TeamThree] = false; + m_SortTeamRoster[Activity::TeamFour] = false; + m_AddedAlarmEvents.clear(); + m_AlarmEvents.clear(); + m_MOIDIndex.clear(); + // We want to keep known objects around, 'cause these can exist even when not in the simulation (they're here from creation till deletion, regardless of whether they are in sim) + // m_KnownObjects.clear(); + } -void MovableMan::UnregisterObject(MovableObject * mo) -{ - if (!mo) { - return; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextActorInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the first Actor in the internal Actor list that is + // of a specifc group, alternatively the first one AFTER a specific actor! + + Actor* MovableMan::GetNextActorInGroup(std::string group, Actor* pAfterThis) { + if (group.empty()) + return 0; + + // Begin at the beginning + std::deque::const_iterator aIt = m_Actors.begin(); + + // Search for the actor to start search from, if specified + if (pAfterThis) { + // Make the iterator point to the specified starting point actor + for (; aIt != m_Actors.end() && !((*aIt)->IsInGroup(group) && *aIt == pAfterThis); ++aIt) + ; + + // If we couldn't find the one to search for, + // then just start at the beginning again and get the first actor at the next step + if (aIt == m_Actors.end()) + aIt = m_Actors.begin(); + // Go one more step so we're not pointing at the one we're not supposed to get + else + ++aIt; + } - std::lock_guard guard(m_ObjectRegisteredMutex); - m_KnownObjects.erase(mo->GetUniqueID()); -} + // Now search for the first actor of the team from the search point (beginning or otherwise) + for (; aIt != m_Actors.end() && !(*aIt)->IsInGroup(group); ++aIt) + ; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // If nothing found between a specified actor and the end, + // then restart and see if there's anything between beginning and that specified actor + if (pAfterThis && aIt == m_Actors.end()) { + for (aIt = m_Actors.begin(); aIt != m_Actors.end() && !(*aIt)->IsInGroup(group); ++aIt) + ; -const std::vector * MovableMan::GetMOsInBox(const Box &box, int ignoreTeam, bool getsHitByMOsOnly) const { - std::vector *vectorForLua = new std::vector(); - *vectorForLua = std::move(g_SceneMan.GetMOIDGrid().GetMOsInBox(box, ignoreTeam, getsHitByMOsOnly)); - return vectorForLua; -} + // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! + // RTEAssert(aIt != m_Actors.end(), "Search for something after specified actor, and didn't even find the specified actor!?"); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Still nothing, so return nothing + if (aIt == m_Actors.end()) + return 0; -const std::vector * MovableMan::GetMOsInRadius(const Vector ¢re, float radius, int ignoreTeam, bool getsHitByMOsOnly) const { - std::vector *vectorForLua = new std::vector(); - *vectorForLua = std::move(g_SceneMan.GetMOIDGrid().GetMOsInRadius(centre, radius, ignoreTeam, getsHitByMOsOnly)); - return vectorForLua; -} + if ((*aIt)->IsInGroup(group)) + return *aIt; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PurgeAllMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out all MovableObject:s out of this. Effectively empties the world -// of anything moving, without resetting all of this' settings. + return 0; + } -void MovableMan::PurgeAllMOs() -{ - for (std::deque::iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) { - (*itr)->DestroyScriptState(); - } - for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) { - (*itr)->DestroyScriptState(); - } - for (std::deque::iterator itr = m_Particles.begin(); itr != m_Particles.end(); ++itr) { - (*itr)->DestroyScriptState(); - } - - for (std::deque::iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) { - delete (*itr); - } - for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) { - delete (*itr); - } - for (std::deque::iterator itr = m_Particles.begin(); itr != m_Particles.end(); ++itr) { - delete (*itr); - } - - m_Actors.clear(); - m_Items.clear(); - m_Particles.clear(); - m_AddedActors.clear(); - m_AddedItems.clear(); - m_AddedParticles.clear(); - m_ValidActors.clear(); - m_ValidItems.clear(); - m_ValidParticles.clear(); - m_ActorRoster[Activity::TeamOne].clear(); - m_ActorRoster[Activity::TeamTwo].clear(); - m_ActorRoster[Activity::TeamThree].clear(); - m_ActorRoster[Activity::TeamFour].clear(); - m_SortTeamRoster[Activity::TeamOne] = false; - m_SortTeamRoster[Activity::TeamTwo] = false; - m_SortTeamRoster[Activity::TeamThree] = false; - m_SortTeamRoster[Activity::TeamFour] = false; - m_AddedAlarmEvents.clear(); - m_AlarmEvents.clear(); - m_MOIDIndex.clear(); - // We want to keep known objects around, 'cause these can exist even when not in the simulation (they're here from creation till deletion, regardless of whether they are in sim) - //m_KnownObjects.clear(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPrevActorInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the last Actor in the internal Actor list that is + // of a specifc group, alternatively the last one BEFORE a specific actor! + + Actor* MovableMan::GetPrevActorInGroup(std::string group, Actor* pBeforeThis) { + if (group.empty()) + return 0; + + // Begin at the reverse beginning + std::deque::reverse_iterator aIt = m_Actors.rbegin(); + + // Search for the actor to start search from, if specified + if (pBeforeThis) { + // Make the iterator point to the specified starting point actor + for (; aIt != m_Actors.rend() && !((*aIt)->IsInGroup(group) && *aIt == pBeforeThis); ++aIt) + ; + + // If we couldn't find the one to search for, + // then just start at the beginning again and get the first actor at the next step + if (aIt == m_Actors.rend()) + aIt = m_Actors.rbegin(); + // Go one more step so we're not pointing at the one we're not supposed to get + else + ++aIt; + } + // Now search for the first actor of the team from the search point (beginning or otherwise) + for (; aIt != m_Actors.rend() && !(*aIt)->IsInGroup(group); ++aIt) + ; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextActorInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the first Actor in the internal Actor list that is -// of a specifc group, alternatively the first one AFTER a specific actor! + // If nothing found between a specified actor and the end, + // then restart and see if there's anything between beginning and that specified actor + if (pBeforeThis && aIt == m_Actors.rend()) { + for (aIt = m_Actors.rbegin(); aIt != m_Actors.rend() && !(*aIt)->IsInGroup(group); ++aIt) + ; -Actor * MovableMan::GetNextActorInGroup(std::string group, Actor *pAfterThis) -{ - if (group.empty()) - return 0; - - // Begin at the beginning - std::deque::const_iterator aIt = m_Actors.begin(); - - // Search for the actor to start search from, if specified - if (pAfterThis) - { - // Make the iterator point to the specified starting point actor - for (; aIt != m_Actors.end() && !((*aIt)->IsInGroup(group) && *aIt == pAfterThis); ++aIt) - ; - - // If we couldn't find the one to search for, - // then just start at the beginning again and get the first actor at the next step - if (aIt == m_Actors.end()) - aIt = m_Actors.begin(); - // Go one more step so we're not pointing at the one we're not supposed to get - else - ++aIt; - } - - // Now search for the first actor of the team from the search point (beginning or otherwise) - for (; aIt != m_Actors.end() && !(*aIt)->IsInGroup(group); ++aIt) - ; - - // If nothing found between a specified actor and the end, - // then restart and see if there's anything between beginning and that specified actor - if (pAfterThis && aIt == m_Actors.end()) - { - for (aIt = m_Actors.begin(); aIt != m_Actors.end() && !(*aIt)->IsInGroup(group); ++aIt) - ; - - // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! -// RTEAssert(aIt != m_Actors.end(), "Search for something after specified actor, and didn't even find the specified actor!?"); - } - - // Still nothing, so return nothing - if (aIt == m_Actors.end()) - return 0; - - if ((*aIt)->IsInGroup(group)) - return *aIt; - - return 0; -} + // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! + // RTEAssert(aIt != m_Actors.rend(), "Search for something after specified actor, and didn't even find the specified actor!?"); + } + // Still nothing, so return nothing + if (aIt == m_Actors.rend()) + return 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPrevActorInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the last Actor in the internal Actor list that is -// of a specifc group, alternatively the last one BEFORE a specific actor! + if ((*aIt)->IsInGroup(group)) + return *aIt; -Actor * MovableMan::GetPrevActorInGroup(std::string group, Actor *pBeforeThis) -{ - if (group.empty()) - return 0; - - // Begin at the reverse beginning - std::deque::reverse_iterator aIt = m_Actors.rbegin(); - - // Search for the actor to start search from, if specified - if (pBeforeThis) - { - // Make the iterator point to the specified starting point actor - for (; aIt != m_Actors.rend() && !((*aIt)->IsInGroup(group) && *aIt == pBeforeThis); ++aIt) - ; - - // If we couldn't find the one to search for, - // then just start at the beginning again and get the first actor at the next step - if (aIt == m_Actors.rend()) - aIt = m_Actors.rbegin(); - // Go one more step so we're not pointing at the one we're not supposed to get - else - ++aIt; - } - - // Now search for the first actor of the team from the search point (beginning or otherwise) - for (; aIt != m_Actors.rend() && !(*aIt)->IsInGroup(group); ++aIt) - ; - - // If nothing found between a specified actor and the end, - // then restart and see if there's anything between beginning and that specified actor - if (pBeforeThis && aIt == m_Actors.rend()) - { - for (aIt = m_Actors.rbegin(); aIt != m_Actors.rend() && !(*aIt)->IsInGroup(group); ++aIt) - ; - - // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! -// RTEAssert(aIt != m_Actors.rend(), "Search for something after specified actor, and didn't even find the specified actor!?"); - } - - // Still nothing, so return nothing - if (aIt == m_Actors.rend()) - return 0; - - if ((*aIt)->IsInGroup(group)) - return *aIt; - - return 0; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextTeamActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the first Actor in the internal Actor list that is + // of a specifc team, alternatively the first one AFTER a specific actor! + + Actor* MovableMan::GetNextTeamActor(int team, Actor* pAfterThis) { + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount || m_ActorRoster[team].empty()) + return 0; + /* + // Begin at the beginning + std::deque::const_iterator aIt = m_Actors.begin(); + + // Search for the actor to start search from, if specified + if (pAfterThis) + { + // Make the iterator point to the specified starting point actor + for (; aIt != m_Actors.end() && !((*aIt)->GetTeam() == team && *aIt == pAfterThis); ++aIt) + ; + + // If we couldn't find the one to search for, + // then just start at the beginning again and get the first actor at the next step + if (aIt == m_Actors.end()) + aIt = m_Actors.begin(); + // Go one more step so we're not pointing at the one we're not supposed to get + else + ++aIt; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextTeamActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the first Actor in the internal Actor list that is -// of a specifc team, alternatively the first one AFTER a specific actor! + // Now search for the first actor of the team from the search point (beginning or otherwise) + for (; aIt != m_Actors.end() && (*aIt)->GetTeam() != team; ++aIt) + ; -Actor * MovableMan::GetNextTeamActor(int team, Actor *pAfterThis) -{ - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount || m_ActorRoster[team].empty()) - return 0; -/* - // Begin at the beginning - std::deque::const_iterator aIt = m_Actors.begin(); - - // Search for the actor to start search from, if specified - if (pAfterThis) - { - // Make the iterator point to the specified starting point actor - for (; aIt != m_Actors.end() && !((*aIt)->GetTeam() == team && *aIt == pAfterThis); ++aIt) - ; - - // If we couldn't find the one to search for, - // then just start at the beginning again and get the first actor at the next step - if (aIt == m_Actors.end()) - aIt = m_Actors.begin(); - // Go one more step so we're not pointing at the one we're not supposed to get - else - ++aIt; - } - - // Now search for the first actor of the team from the search point (beginning or otherwise) - for (; aIt != m_Actors.end() && (*aIt)->GetTeam() != team; ++aIt) - ; - - // If nothing found between a specified actor and the end, - // then restart and see if there's anything between beginning and that specified actor - if (pAfterThis && aIt == m_Actors.end()) - { - for (aIt = m_Actors.begin(); aIt != m_Actors.end() && (*aIt)->GetTeam() != team; ++aIt) - ; - - // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! -// RTEAssert(aIt != m_Actors.end(), "Search for something after specified actor, and didn't even find the specified actor!?"); - } - - // Still nothing, so return nothing - if (aIt == m_Actors.end()) - return 0; - - if ((*aIt)->GetTeam() == team) - return *aIt; - - return 0; -*/ - // First sort the roster - m_ActorRoster[team].sort(MOXPosComparison()); - - // Begin at the beginning - std::list::const_iterator aIt = m_ActorRoster[team].begin(); - - // Search for the actor to start search from, if specified - if (pAfterThis) - { - // Make the iterator point to the specified starting point actor - for (; aIt != m_ActorRoster[team].end() && *aIt != pAfterThis; ++aIt) - ; - - // If we couldn't find the one to search for, then just return the first one - if (aIt == m_ActorRoster[team].end()) - aIt = m_ActorRoster[team].begin(); - // Go one more step so we're not pointing at the one we're not supposed to get - else - { - ++aIt; - // If that was the last one, then return the first in the list - if (aIt == m_ActorRoster[team].end()) - aIt = m_ActorRoster[team].begin(); - } - } - - RTEAssert((*aIt)->GetTeam() == team, "Actor of wrong team found in the wrong roster!"); - return *aIt; -} + // If nothing found between a specified actor and the end, + // then restart and see if there's anything between beginning and that specified actor + if (pAfterThis && aIt == m_Actors.end()) + { + for (aIt = m_Actors.begin(); aIt != m_Actors.end() && (*aIt)->GetTeam() != team; ++aIt) + ; + // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! + // RTEAssert(aIt != m_Actors.end(), "Search for something after specified actor, and didn't even find the specified actor!?"); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPrevTeamActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the last Actor in the internal Actor list that is -// of a specifc team, alternatively the last one BEFORE a specific actor! + // Still nothing, so return nothing + if (aIt == m_Actors.end()) + return 0; + + if ((*aIt)->GetTeam() == team) + return *aIt; + + return 0; + */ + // First sort the roster + m_ActorRoster[team].sort(MOXPosComparison()); + + // Begin at the beginning + std::list::const_iterator aIt = m_ActorRoster[team].begin(); + + // Search for the actor to start search from, if specified + if (pAfterThis) { + // Make the iterator point to the specified starting point actor + for (; aIt != m_ActorRoster[team].end() && *aIt != pAfterThis; ++aIt) + ; + + // If we couldn't find the one to search for, then just return the first one + if (aIt == m_ActorRoster[team].end()) + aIt = m_ActorRoster[team].begin(); + // Go one more step so we're not pointing at the one we're not supposed to get + else { + ++aIt; + // If that was the last one, then return the first in the list + if (aIt == m_ActorRoster[team].end()) + aIt = m_ActorRoster[team].begin(); + } + } -Actor * MovableMan::GetPrevTeamActor(int team, Actor *pBeforeThis) -{ - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount || m_Actors.empty() || m_ActorRoster[team].empty()) - return 0; -/* Obsolete, now uses team rosters which are sorted - // Begin at the reverse beginning - std::deque::const_reverse_iterator aIt = m_Actors.rbegin(); - - // Search for the actor to start search from, if specified - if (pBeforeThis) - { - // Make the iterator point to the specified starting point actor - for (; aIt != m_Actors.rend() && !((*aIt)->GetTeam() == team && *aIt == pBeforeThis); ++aIt) - ; - - // If we couldn't find the one to search for, - // then just start at the beginning again and get the first actor at the next step - if (aIt == m_Actors.rend()) - aIt = m_Actors.rbegin(); - // Go one more step so we're not pointing at the one we're not supposed to get - else - ++aIt; - } - - // Now search for the first actor of the team from the search point (beginning or otherwise) - for (; aIt != m_Actors.rend() && (*aIt)->GetTeam() != team; ++aIt) - ; - - // If nothing found between a specified actor and the end, - // then restart and see if there's anything between beginning and that specified actor - if (pBeforeThis && aIt == m_Actors.rend()) - { - for (aIt = m_Actors.rbegin(); aIt != m_Actors.rend() && (*aIt)->GetTeam() != team; ++aIt) - ; - - // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! -// RTEAssert(aIt != m_Actors.rend(), "Search for something after specified actor, and didn't even find the specified actor!?"); - } - - // Still nothing, so return nothing - if (aIt == m_Actors.rend()) - return 0; - - if ((*aIt)->GetTeam() == team) - return *aIt; - - return 0; -*/ - // First sort the roster - m_ActorRoster[team].sort(MOXPosComparison()); - - // Begin at the reverse beginning of roster - std::list::reverse_iterator aIt = m_ActorRoster[team].rbegin(); - - // Search for the actor to start search from, if specified - if (pBeforeThis) - { - // Make the iterator point to the specified starting point actor - for (; aIt != m_ActorRoster[team].rend() && *aIt != pBeforeThis; ++aIt) - ; - - // If we couldn't find the one to search for, then just return the one at the end - if (aIt == m_ActorRoster[team].rend()) - aIt = m_ActorRoster[team].rbegin(); - // Go one more step so we're not pointing at the one we're not supposed to get - else - { - ++aIt; - // If that was the first one, then return the last in the list - if (aIt == m_ActorRoster[team].rend()) - aIt = m_ActorRoster[team].rbegin(); - } - } - - RTEAssert((*aIt)->GetTeam() == team, "Actor of wrong team found in the wrong roster!"); - return *aIt; -} + RTEAssert((*aIt)->GetTeam() == team, "Actor of wrong team found in the wrong roster!"); + return *aIt; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPrevTeamActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the last Actor in the internal Actor list that is + // of a specifc team, alternatively the last one BEFORE a specific actor! + + Actor* MovableMan::GetPrevTeamActor(int team, Actor* pBeforeThis) { + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount || m_Actors.empty() || m_ActorRoster[team].empty()) + return 0; + /* Obsolete, now uses team rosters which are sorted + // Begin at the reverse beginning + std::deque::const_reverse_iterator aIt = m_Actors.rbegin(); + + // Search for the actor to start search from, if specified + if (pBeforeThis) + { + // Make the iterator point to the specified starting point actor + for (; aIt != m_Actors.rend() && !((*aIt)->GetTeam() == team && *aIt == pBeforeThis); ++aIt) + ; + + // If we couldn't find the one to search for, + // then just start at the beginning again and get the first actor at the next step + if (aIt == m_Actors.rend()) + aIt = m_Actors.rbegin(); + // Go one more step so we're not pointing at the one we're not supposed to get + else + ++aIt; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestTeamActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to an Actor in the internal Actor list that is of a -// specifc team and closest to a specific scene point. + // Now search for the first actor of the team from the search point (beginning or otherwise) + for (; aIt != m_Actors.rend() && (*aIt)->GetTeam() != team; ++aIt) + ; -Actor * MovableMan::GetClosestTeamActor(int team, int player, const Vector &scenePoint, int maxRadius, Vector &getDistance, bool onlyPlayerControllableActors, const Actor *excludeThis) -{ - if (team < Activity::NoTeam || team >= Activity::MaxTeamCount || m_Actors.empty() || m_ActorRoster[team].empty()) - return 0; - - Activity *pActivity = g_ActivityMan.GetActivity(); - - float sqrShortestDistance = static_cast(maxRadius * maxRadius); - Actor *pClosestActor = 0; - - // If we're looking for a noteam actor, then go through the entire actor list instead - if (team == Activity::NoTeam) - { - for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) - { - if ((*aIt) == excludeThis || (*aIt)->GetTeam() != Activity::NoTeam || (onlyPlayerControllableActors && !(*aIt)->IsPlayerControllable())) { - continue; - } - - // Check if even within search radius - float sqrDistance = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()).GetSqrMagnitude(); - if (sqrDistance < sqrShortestDistance) - { - sqrShortestDistance = sqrDistance; - pClosestActor = *aIt; - } - } - } - // A specific team, so use the rosters instead - else - { - for (std::list::iterator aIt = m_ActorRoster[team].begin(); aIt != m_ActorRoster[team].end(); ++aIt) - { - if ((*aIt) == excludeThis || (onlyPlayerControllableActors && !(*aIt)->IsPlayerControllable()) || (player != NoPlayer && ((*aIt)->GetController()->IsPlayerControlled(player) || (pActivity && pActivity->IsOtherPlayerBrain(*aIt, player))))) { + // If nothing found between a specified actor and the end, + // then restart and see if there's anything between beginning and that specified actor + if (pBeforeThis && aIt == m_Actors.rend()) + { + for (aIt = m_Actors.rbegin(); aIt != m_Actors.rend() && (*aIt)->GetTeam() != team; ++aIt) + ; + + // Still nothing?? Should at least get the specified actor and return it! - EDIT No becuase it just may not be there! + // RTEAssert(aIt != m_Actors.rend(), "Search for something after specified actor, and didn't even find the specified actor!?"); + } + + // Still nothing, so return nothing + if (aIt == m_Actors.rend()) + return 0; + + if ((*aIt)->GetTeam() == team) + return *aIt; + + return 0; + */ + // First sort the roster + m_ActorRoster[team].sort(MOXPosComparison()); + + // Begin at the reverse beginning of roster + std::list::reverse_iterator aIt = m_ActorRoster[team].rbegin(); + + // Search for the actor to start search from, if specified + if (pBeforeThis) { + // Make the iterator point to the specified starting point actor + for (; aIt != m_ActorRoster[team].rend() && *aIt != pBeforeThis; ++aIt) + ; + + // If we couldn't find the one to search for, then just return the one at the end + if (aIt == m_ActorRoster[team].rend()) + aIt = m_ActorRoster[team].rbegin(); + // Go one more step so we're not pointing at the one we're not supposed to get + else { + ++aIt; + // If that was the first one, then return the last in the list + if (aIt == m_ActorRoster[team].rend()) + aIt = m_ActorRoster[team].rbegin(); + } + } + + RTEAssert((*aIt)->GetTeam() == team, "Actor of wrong team found in the wrong roster!"); + return *aIt; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestTeamActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to an Actor in the internal Actor list that is of a + // specifc team and closest to a specific scene point. + + Actor* MovableMan::GetClosestTeamActor(int team, int player, const Vector& scenePoint, int maxRadius, Vector& getDistance, bool onlyPlayerControllableActors, const Actor* excludeThis) { + if (team < Activity::NoTeam || team >= Activity::MaxTeamCount || m_Actors.empty() || m_ActorRoster[team].empty()) + return 0; + + Activity* pActivity = g_ActivityMan.GetActivity(); + + float sqrShortestDistance = static_cast(maxRadius * maxRadius); + Actor* pClosestActor = 0; + + // If we're looking for a noteam actor, then go through the entire actor list instead + if (team == Activity::NoTeam) { + for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) { + if ((*aIt) == excludeThis || (*aIt)->GetTeam() != Activity::NoTeam || (onlyPlayerControllableActors && !(*aIt)->IsPlayerControllable())) { + continue; + } + + // Check if even within search radius + float sqrDistance = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()).GetSqrMagnitude(); + if (sqrDistance < sqrShortestDistance) { + sqrShortestDistance = sqrDistance; + pClosestActor = *aIt; + } + } + } + // A specific team, so use the rosters instead + else { + for (std::list::iterator aIt = m_ActorRoster[team].begin(); aIt != m_ActorRoster[team].end(); ++aIt) { + if ((*aIt) == excludeThis || (onlyPlayerControllableActors && !(*aIt)->IsPlayerControllable()) || (player != NoPlayer && ((*aIt)->GetController()->IsPlayerControlled(player) || (pActivity && pActivity->IsOtherPlayerBrain(*aIt, player))))) { + continue; + } + + Vector distanceVec = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); + + // Check if even within search radius + float sqrDistance = distanceVec.GetSqrMagnitude(); + if (sqrDistance < sqrShortestDistance) { + sqrShortestDistance = sqrDistance; + pClosestActor = *aIt; + getDistance.SetXY(distanceVec.GetX(), distanceVec.GetY()); + } + } + } + + return pClosestActor; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestEnemyActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to an Actor in the internal Actor list that is is not of + // the specified team and closest to a specific scene point. + + Actor* MovableMan::GetClosestEnemyActor(int team, const Vector& scenePoint, int maxRadius, Vector& getDistance) { + if (team < Activity::NoTeam || team >= Activity::MaxTeamCount || m_Actors.empty()) + return 0; + + Activity* pActivity = g_ActivityMan.GetActivity(); + + float sqrShortestDistance = static_cast(maxRadius * maxRadius); + Actor* pClosestActor = 0; + + for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) { + if ((*aIt)->GetTeam() == team) continue; + + Vector distanceVec = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); + + // Check if even within search radius + float sqrDistance = distanceVec.GetSqrMagnitude(); + if (sqrDistance < sqrShortestDistance) { + sqrShortestDistance = sqrDistance; + pClosestActor = *aIt; + getDistance.SetXY(distanceVec.GetX(), distanceVec.GetY()); } + } + + return pClosestActor; + } - Vector distanceVec = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to an Actor in the internal Actor list that is closest + // to a specific scene point. - // Check if even within search radius - float sqrDistance = distanceVec.GetSqrMagnitude(); - if (sqrDistance < sqrShortestDistance) - { - sqrShortestDistance = sqrDistance; - pClosestActor = *aIt; + Actor* MovableMan::GetClosestActor(const Vector& scenePoint, int maxRadius, Vector& getDistance, const Actor* pExcludeThis) { + if (m_Actors.empty()) + return 0; + + Activity* pActivity = g_ActivityMan.GetActivity(); + + float sqrShortestDistance = static_cast(maxRadius * maxRadius); + Actor* pClosestActor = 0; + + for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) { + if ((*aIt) == pExcludeThis) + continue; + + Vector distanceVec = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); + + // Check if even within search radius + float sqrDistance = distanceVec.GetSqrMagnitude(); + if (sqrDistance < sqrShortestDistance) { + sqrShortestDistance = sqrDistance; + pClosestActor = *aIt; getDistance.SetXY(distanceVec.GetX(), distanceVec.GetY()); - } - } - } + } + } - return pClosestActor; -} + return pClosestActor; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestBrainActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the brain actor of a specific team that is closest to + // a scene point. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestEnemyActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to an Actor in the internal Actor list that is is not of -// the specified team and closest to a specific scene point. + Actor* MovableMan::GetClosestBrainActor(int team, const Vector& scenePoint) const { + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount || m_ActorRoster[team].empty()) + return 0; -Actor * MovableMan::GetClosestEnemyActor(int team, const Vector &scenePoint, int maxRadius, Vector &getDistance) -{ - if (team < Activity::NoTeam || team >= Activity::MaxTeamCount || m_Actors.empty()) - return 0; - - Activity *pActivity = g_ActivityMan.GetActivity(); - - float sqrShortestDistance = static_cast(maxRadius * maxRadius); - Actor *pClosestActor = 0; - - for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) - { - if ((*aIt)->GetTeam() == team) - continue; - - Vector distanceVec = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); - - // Check if even within search radius - float sqrDistance = distanceVec.GetSqrMagnitude(); - if (sqrDistance < sqrShortestDistance) - { - sqrShortestDistance = sqrDistance; - pClosestActor = *aIt; - getDistance.SetXY(distanceVec.GetX(), distanceVec.GetY()); - } - } - - return pClosestActor; -} + float sqrShortestDistance = std::numeric_limits::infinity(); + sqrShortestDistance *= sqrShortestDistance; + Actor* pClosestBrain = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to an Actor in the internal Actor list that is closest -// to a specific scene point. + for (std::list::const_iterator aIt = m_ActorRoster[team].begin(); aIt != m_ActorRoster[team].end(); ++aIt) { + if (!(*aIt)->HasObjectInGroup("Brains")) + continue; -Actor * MovableMan::GetClosestActor(const Vector &scenePoint, int maxRadius, Vector &getDistance, const Actor *pExcludeThis) -{ - if (m_Actors.empty()) - return 0; + // Check if closer than best so far + float sqrDistance = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()).GetSqrMagnitude(); + if (sqrDistance < sqrShortestDistance) { + sqrShortestDistance = sqrDistance; + pClosestBrain = *aIt; + } + } - Activity *pActivity = g_ActivityMan.GetActivity(); + return pClosestBrain; + } - float sqrShortestDistance = static_cast(maxRadius * maxRadius); - Actor *pClosestActor = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestOtherBrainActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the brain actor NOT of a specific team that is closest + // to a scene point. + + Actor* MovableMan::GetClosestOtherBrainActor(int notOfTeam, const Vector& scenePoint) const { + if (notOfTeam < Activity::TeamOne || notOfTeam >= Activity::MaxTeamCount || m_Actors.empty()) + return 0; + + float sqrShortestDistance = std::numeric_limits::infinity(); + sqrShortestDistance *= sqrShortestDistance; + + Actor* pClosestBrain = 0; + Actor* pContenderBrain = 0; + + for (int t = Activity::TeamOne; t < g_ActivityMan.GetActivity()->GetTeamCount(); ++t) { + if (t != notOfTeam) { + pContenderBrain = GetClosestBrainActor(t, scenePoint); + float sqrDistance = (pContenderBrain->GetPos() - scenePoint).GetSqrMagnitude(); + if (sqrDistance < sqrShortestDistance) { + sqrShortestDistance = sqrDistance; + pClosestBrain = pContenderBrain; + } + } + } + return pClosestBrain; + } - for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) - { - if ((*aIt) == pExcludeThis) - continue; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetUnassignedBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the brain actor of a specific team. + // Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. - Vector distanceVec = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()); + Actor* MovableMan::GetUnassignedBrain(int team) const { + if (/*m_Actors.empty() || */ m_ActorRoster[team].empty()) + return 0; - // Check if even within search radius - float sqrDistance = distanceVec.GetSqrMagnitude(); - if (sqrDistance < sqrShortestDistance) - { - sqrShortestDistance = sqrDistance; - pClosestActor = *aIt; - getDistance.SetXY(distanceVec.GetX(), distanceVec.GetY()); - } - } + for (std::list::const_iterator aIt = m_ActorRoster[team].begin(); aIt != m_ActorRoster[team].end(); ++aIt) { + if ((*aIt)->HasObjectInGroup("Brains") && !g_ActivityMan.GetActivity()->IsAssignedBrain(*aIt)) + return *aIt; + } - return pClosestActor; -} + // Also need to look through all the actors added this frame, one might be a brain. + int actorTeam = Activity::NoTeam; + for (std::deque::const_iterator aaIt = m_AddedActors.begin(); aaIt != m_AddedActors.end(); ++aaIt) { + int actorTeam = (*aaIt)->GetTeam(); + // Accept no-team brains too - ACTUALLY, DON'T + if ((actorTeam == team /* || actorTeam == Activity::NoTeam*/) && (*aaIt)->HasObjectInGroup("Brains") && !g_ActivityMan.GetActivity()->IsAssignedBrain(*aaIt)) + return *aaIt; + } + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestBrainActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the brain actor of a specific team that is closest to -// a scene point. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool MovableMan::AddMO(MovableObject* movableObjectToAdd) { + if (!movableObjectToAdd) { + return false; + } + + if (Actor* actorToAdd = dynamic_cast(movableObjectToAdd)) { + AddActor(actorToAdd); + return true; + } else if (HeldDevice* heldDeviceToAdd = dynamic_cast(movableObjectToAdd)) { + AddItem(heldDeviceToAdd); + return true; + } + AddParticle(movableObjectToAdd); + + return true; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableMan::AddActor(Actor* actorToAdd) { + if (actorToAdd) { + actorToAdd->SetAsAddedToMovableMan(); + actorToAdd->CorrectAttachableAndWoundPositionsAndRotations(); + + if (actorToAdd->IsTooFast()) { + actorToAdd->SetToDelete(true); + } else { + if (!dynamic_cast(actorToAdd)) { + actorToAdd->MoveOutOfTerrain(g_MaterialGrass); + } + if (actorToAdd->IsStatus(Actor::INACTIVE)) { + actorToAdd->SetStatus(Actor::STABLE); + } + actorToAdd->NotResting(); + actorToAdd->NewFrame(); + actorToAdd->SetAge(g_TimerMan.GetDeltaTimeMS() * -1.0f); + } + + { + std::lock_guard lock(m_AddedActorsMutex); + m_AddedActors.push_back(actorToAdd); + m_ValidActors.insert(actorToAdd); + + // This will call SetTeam and subsequently force the team as active. + AddActorToTeamRoster(actorToAdd); + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableMan::AddItem(HeldDevice* itemToAdd) { + if (itemToAdd) { + g_ActivityMan.GetActivity()->ForceSetTeamAsActive(itemToAdd->GetTeam()); + itemToAdd->SetAsAddedToMovableMan(); + itemToAdd->CorrectAttachableAndWoundPositionsAndRotations(); + + if (itemToAdd->IsTooFast()) { + itemToAdd->SetToDelete(true); + } else { + if (!itemToAdd->IsSetToDelete()) { + itemToAdd->MoveOutOfTerrain(g_MaterialGrass); + } + itemToAdd->NotResting(); + itemToAdd->NewFrame(); + itemToAdd->SetAge(g_TimerMan.GetDeltaTimeMS() * -1.0f); + } + + std::lock_guard lock(m_AddedItemsMutex); + m_AddedItems.push_back(itemToAdd); + m_ValidItems.insert(itemToAdd); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableMan::AddParticle(MovableObject* particleToAdd) { + if (particleToAdd) { + g_ActivityMan.GetActivity()->ForceSetTeamAsActive(particleToAdd->GetTeam()); + particleToAdd->SetAsAddedToMovableMan(); + if (MOSRotating* particleToAddAsMOSRotating = dynamic_cast(particleToAdd)) { + particleToAddAsMOSRotating->CorrectAttachableAndWoundPositionsAndRotations(); + } + + if (particleToAdd->IsTooFast()) { + particleToAdd->SetToDelete(true); + } else { + // TODO consider moving particles out of grass. It's old code that was removed because it's slow to do this for every particle. + particleToAdd->NotResting(); + particleToAdd->NewFrame(); + particleToAdd->SetAge(g_TimerMan.GetDeltaTimeMS() * -1.0f); + } + if (particleToAdd->IsDevice()) { + std::lock_guard lock(m_AddedItemsMutex); + m_AddedItems.push_back(particleToAdd); + m_ValidItems.insert(particleToAdd); + } else { + std::lock_guard lock(m_AddedParticlesMutex); + m_AddedParticles.push_back(particleToAdd); + m_ValidParticles.insert(particleToAdd); + } + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes an Actor from the internal list of MO:s. After the Actor is + // removed, ownership is effectively released and transferred to whatever + // client called this method. + + Actor* MovableMan::RemoveActor(MovableObject* pActorToRem) { + Actor* removed = nullptr; + + if (pActorToRem) { + for (std::deque::iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) { + if (*itr == pActorToRem) { + std::lock_guard lock(m_ActorsMutex); + removed = *itr; + m_ValidActors.erase(*itr); + m_Actors.erase(itr); + break; + } + } + // Try the newly added actors if we couldn't find it in the regular deque + if (!removed) { + for (std::deque::iterator itr = m_AddedActors.begin(); itr != m_AddedActors.end(); ++itr) { + if (*itr == pActorToRem) { + std::lock_guard lock(m_AddedActorsMutex); + removed = *itr; + m_ValidActors.erase(*itr); + m_AddedActors.erase(itr); + break; + } + } + } + RemoveActorFromTeamRoster(dynamic_cast(pActorToRem)); + pActorToRem->SetAsAddedToMovableMan(false); + } + return removed; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a pickup-able MovableObject item from the internal list of + // MO:s. After the item is removed, ownership is effectively released and + // transferred to whatever client called this method. + + MovableObject* MovableMan::RemoveItem(MovableObject* pItemToRem) { + MovableObject* removed = nullptr; + + if (pItemToRem) { + for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) { + if (*itr == pItemToRem) { + std::lock_guard lock(m_ItemsMutex); + removed = *itr; + m_ValidItems.erase(*itr); + m_Items.erase(itr); + break; + } + } + // Try the newly added items if we couldn't find it in the regular deque + if (!removed) { + for (std::deque::iterator itr = m_AddedItems.begin(); itr != m_AddedItems.end(); ++itr) { + if (*itr == pItemToRem) { + std::lock_guard lock(m_AddedItemsMutex); + removed = *itr; + m_ValidItems.erase(*itr); + m_AddedItems.erase(itr); + break; + } + } + } + pItemToRem->SetAsAddedToMovableMan(false); + } + return removed; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveParticle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a MovableObject from the internal list of MO:s. After the + // MO is removed, ownership is effectively released and transferred to + // whatever client called this method. + + MovableObject* MovableMan::RemoveParticle(MovableObject* pMOToRem) { + MovableObject* removed = nullptr; + + if (pMOToRem) { + for (std::deque::iterator itr = m_Particles.begin(); itr != m_Particles.end(); ++itr) { + if (*itr == pMOToRem) { + std::lock_guard lock(m_ParticlesMutex); + removed = *itr; + m_ValidParticles.erase(*itr); + m_Particles.erase(itr); + break; + } + } + // Try the newly added particles if we couldn't find it in the regular deque + if (!removed) { + for (std::deque::iterator itr = m_AddedParticles.begin(); itr != m_AddedParticles.end(); ++itr) { + if (*itr == pMOToRem) { + std::lock_guard lock(m_AddedParticlesMutex); + removed = *itr; + m_ValidParticles.erase(*itr); + m_AddedParticles.erase(itr); + break; + } + } + } + pMOToRem->SetAsAddedToMovableMan(false); + } + return removed; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddActorToTeamRoster + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds actor to internal team roster + // Arguments: Pointer to actor + // Return value: None. + + void MovableMan::AddActorToTeamRoster(Actor* pActorToAdd) { + if (!pActorToAdd) { + return; + } + + // Add to the team roster and then sort it too + int team = pActorToAdd->GetTeam(); + // Also re-set the TEam so that the Team Icons get set up properly + pActorToAdd->SetTeam(team); + // Only add to a roster if it's on a team AND is controllable (eg doors are not) + if (team >= Activity::TeamOne && team < Activity::MaxTeamCount && pActorToAdd->IsControllable()) { + std::lock_guard lock(m_ActorRosterMutex); + m_ActorRoster[pActorToAdd->GetTeam()].push_back(pActorToAdd); + m_ActorRoster[pActorToAdd->GetTeam()].sort(MOXPosComparison()); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveActorToTeamRoster + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes actor from internal team roster + // Arguments: Pointer to actor + // Return value: None. + + void MovableMan::RemoveActorFromTeamRoster(Actor* pActorToRem) { + if (!pActorToRem) { + return; + } + + int team = pActorToRem->GetTeam(); + + // Remove from roster as well + if (team >= Activity::TeamOne && team < Activity::MaxTeamCount) { + std::lock_guard lock(m_ActorRosterMutex); + m_ActorRoster[team].remove(pActorToRem); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeActorTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes actor team and updates team rosters. + + void MovableMan::ChangeActorTeam(Actor* pActor, int team) { + if (!pActor) { + return; + } + + if (pActor->IsPlayerControlled()) { + g_ActivityMan.GetActivity()->LoseControlOfActor(pActor->GetController()->GetPlayer()); + } + + RemoveActorFromTeamRoster(pActor); + pActor->SetTeam(team); + AddActorToTeamRoster(pActor); + + // Because doors affect the team-based pathfinders, we need to tell them there's been a change. + // This is hackily done by erasing the door material, updating the pathfinders, then redrawing it and updating them again so they properly account for the door's new team. + if (ADoor* actorAsADoor = dynamic_cast(pActor); actorAsADoor && actorAsADoor->GetDoorMaterialDrawn()) { + actorAsADoor->TempEraseOrRedrawDoorMaterial(true); + g_SceneMan.GetTerrain()->AddUpdatedMaterialArea(actorAsADoor->GetBoundingBox()); + g_SceneMan.GetScene()->UpdatePathFinding(); + actorAsADoor->TempEraseOrRedrawDoorMaterial(false); + g_SceneMan.GetTerrain()->AddUpdatedMaterialArea(actorAsADoor->GetBoundingBox()); + g_SceneMan.GetScene()->UpdatePathFinding(); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ValidateMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through and checks that all MOID's have valid MO pointers + // associated with them. This shuold only be used for testing, as it will + // crash the app if validation fails. + + bool MovableMan::ValidateMOIDs() { +#ifdef DEBUG_BUILD + for (const MovableObject* mo: m_MOIDIndex) { + RTEAssert(mo, "Null MO found!"); + } +#endif + return true; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ValidMO + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject pointer points to an + // MO that's currently active in the simulation, and kept by this MovableMan. + + bool MovableMan::ValidMO(const MovableObject* pMOToCheck) { + bool exists = m_ValidActors.find(pMOToCheck) != m_ValidActors.end() || + m_ValidItems.find(pMOToCheck) != m_ValidItems.end() || + m_ValidParticles.find(pMOToCheck) != m_ValidParticles.end(); + + return pMOToCheck && exists; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject is an active Actor kept + // by this MovableMan or not. + + bool MovableMan::IsActor(const MovableObject* pMOToCheck) { + return pMOToCheck && m_ValidActors.find(pMOToCheck) != m_ValidActors.end(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject is an active Item kept + // by this MovableMan or not. + + bool MovableMan::IsDevice(const MovableObject* pMOToCheck) { + return pMOToCheck && m_ValidItems.find(pMOToCheck) != m_ValidItems.end(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsParticle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject is an active Item kept + // by this MovableMan or not. + + bool MovableMan::IsParticle(const MovableObject* pMOToCheck) { + return pMOToCheck && m_ValidParticles.find(pMOToCheck) != m_ValidParticles.end(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsOfActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MOID is that of an MO which either is + // or is parented to an active Actor by this MovableMan, or not. + + bool MovableMan::IsOfActor(MOID checkMOID) { + if (checkMOID == g_NoMOID) + return false; + + bool found = false; + MovableObject* pMO = GetMOFromID(checkMOID); + + if (pMO) { + MOID rootMOID = pMO->GetRootID(); + if (checkMOID != g_NoMOID) { + for (std::deque::iterator itr = m_Actors.begin(); !found && itr != m_Actors.end(); ++itr) { + if ((*itr)->GetID() == checkMOID || (*itr)->GetID() == rootMOID) { + found = true; + break; + } + } + // Check actors just added this frame + if (!found) { + for (std::deque::iterator itr = m_AddedActors.begin(); !found && itr != m_AddedActors.end(); ++itr) { + if ((*itr)->GetID() == checkMOID || (*itr)->GetID() == rootMOID) { + found = true; + break; + } + } + } + } + } + return found; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + int MovableMan::GetContiguousActorID(const Actor* actor) const { + auto itr = m_ContiguousActorIDs.find(actor); + if (itr == m_ContiguousActorIDs.end()) { + return -1; + } + + return itr->second; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRootMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Produces the root MOID of the MOID of a potential child MO to another MO. + + MOID MovableMan::GetRootMOID(MOID checkMOID) { + MovableObject* pMO = GetMOFromID(checkMOID); + if (pMO) + return pMO->GetRootID(); + + return g_NoMOID; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveMO + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a MovableObject from the any and all internal lists of MO:s. + // After the MO is removed, ownership is effectively released and + // transferred to whatever client called this method. + + bool MovableMan::RemoveMO(MovableObject* pMOToRem) { + if (pMOToRem) { + if (RemoveActor(pMOToRem)) + return true; + if (RemoveItem(pMOToRem)) + return true; + if (RemoveParticle(pMOToRem)) + return true; + } + + return false; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableMan::KillAllTeamActors(int teamToKill) const { + int killCount = 0; + + for (std::deque actorList: {m_Actors, m_AddedActors}) { + for (Actor* actor: actorList) { + if (actor->GetTeam() == teamToKill) { + const AHuman* actorAsHuman = dynamic_cast(actor); + if (actorAsHuman && actorAsHuman->GetHead()) { + actorAsHuman->GetHead()->GibThis(); + } else { + actor->GibThis(); + } + killCount++; + } + } + } + + return killCount; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableMan::KillAllEnemyActors(int teamNotToKill) const { + int killCount = 0; + + for (std::deque actorList: {m_Actors, m_AddedActors}) { + for (Actor* actor: actorList) { + if (actor->GetTeam() != teamNotToKill) { + const AHuman* actorAsHuman = dynamic_cast(actor); + if (actorAsHuman && actorAsHuman->GetHead()) { + actorAsHuman->GetHead()->GibThis(); + } else { + actor->GibThis(); + } + killCount++; + } + } + } + + return killCount; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableMan::GetAllActors(bool transferOwnership, std::list& actorList, int onlyTeam, bool noBrains) { + int addedCount = 0; + + // Add all regular Actors + for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) { + Actor* actor = *aIt; + // Only grab ones of a specific team; delete all others + if ((onlyTeam == Activity::NoTeam || actor->GetTeam() == onlyTeam) && (!noBrains || !actor->HasObjectInGroup("Brains"))) { + actorList.push_back(actor); + addedCount++; + } else if (transferOwnership) { + delete actor; + } + } + + // Add all Actors added this frame + for (std::deque::iterator aIt = m_AddedActors.begin(); aIt != m_AddedActors.end(); ++aIt) { + Actor* actor = *aIt; + // Only grab ones of a specific team; delete all others + if ((onlyTeam == Activity::NoTeam || actor->GetTeam() == onlyTeam) && (!noBrains || !actor->HasObjectInGroup("Brains"))) { + actorList.push_back(actor); + addedCount++; + } else if (transferOwnership) { + delete actor; + } + } + + if (transferOwnership) { + // Clear the internal Actor lists; we transferred the ownership of them + m_Actors.clear(); + m_AddedActors.clear(); + m_ValidActors.clear(); + + // Also clear the actor rosters + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + m_ActorRoster[team].clear(); + } + } + + return addedCount; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableMan::GetAllItems(bool transferOwnership, std::list& itemList) { + int addedCount = 0; + + // Add all regular Items + for (std::deque::iterator iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt) { + itemList.push_back((*iIt)); + addedCount++; + } + + // Add all Items added this frame + for (std::deque::iterator iIt = m_AddedItems.begin(); iIt != m_AddedItems.end(); ++iIt) { + itemList.push_back((*iIt)); + addedCount++; + } + + if (transferOwnership) { + // Clear the internal Item list; we transferred the ownership of them + m_Items.clear(); + m_AddedItems.clear(); + m_ValidItems.clear(); + } + + return addedCount; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableMan::GetAllParticles(bool transferOwnership, std::list& particleList) { + int addedCount = 0; + + // Add all regular particles + for (std::deque::iterator iIt = m_Particles.begin(); iIt != m_Particles.end(); ++iIt) { + particleList.push_back((*iIt)); + addedCount++; + } + + // Add all particles added this frame + for (std::deque::iterator iIt = m_AddedParticles.begin(); iIt != m_AddedParticles.end(); ++iIt) { + particleList.push_back((*iIt)); + addedCount++; + } + + if (transferOwnership) { + // Clear the internal Particle list; we transferred the ownership of them + m_Particles.clear(); + m_AddedParticles.clear(); + m_ValidParticles.clear(); + } + + return addedCount; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int MovableMan::GetTeamMOIDCount(int team) const { + if (team > Activity::NoTeam && team < Activity::MaxTeamCount) + return m_TeamMOIDCount[team]; + else + return 0; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void MovableMan::OpenAllDoors(bool open, int team) const { + for (std::deque actorDeque: {m_Actors, m_AddedActors}) { + for (Actor* actor: actorDeque) { + if (ADoor* actorAsADoor = dynamic_cast(actor); actorAsADoor && (team == Activity::NoTeam || actorAsADoor->GetTeam() == team)) { + if (actorAsADoor->GetDoorState() != (open ? ADoor::DoorState::OPEN : ADoor::DoorState::CLOSED)) { + actorAsADoor->Update(); + actorAsADoor->SetClosedByDefault(!open); + } + actorAsADoor->ResetSensorTimer(); + if (open) { + actorAsADoor->OpenDoor(); + } else { + actorAsADoor->CloseDoor(); + } + } + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // TODO: Completely tear out and delete this. + // It shouldn't belong to MovableMan, instead it probably ought to be on the pathfinder. On that note, pathfinders shouldn't be part of the scene! + // AIMan? PathingMan? Something like that. Ideally, we completely tear out this hack, and allow for doors in a completely different way. + void MovableMan::OverrideMaterialDoors(bool eraseDoorMaterial, int team) const { + for (std::deque actorDeque: {m_Actors, m_AddedActors}) { + for (Actor* actor: actorDeque) { + if (ADoor* actorAsDoor = dynamic_cast(actor); actorAsDoor && (team == Activity::NoTeam || actorAsDoor->GetTeam() == team)) { + actorAsDoor->TempEraseOrRedrawDoorMaterial(eraseDoorMaterial); + } + } + } + } -Actor * MovableMan::GetClosestBrainActor(int team, const Vector &scenePoint) const -{ - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount || m_ActorRoster[team].empty()) - return 0; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - float sqrShortestDistance = std::numeric_limits::infinity(); - sqrShortestDistance *= sqrShortestDistance; + void MovableMan::RegisterAlarmEvent(const AlarmEvent& newEvent) { + std::lock_guard lock(m_AddedAlarmEventsMutex); + m_AddedAlarmEvents.push_back(newEvent); + } - Actor *pClosestBrain = 0; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RedrawOverlappingMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces all objects potnetially overlapping a specific MO to re-draw + // this MOID representations onto the MOID bitmap. - for (std::list::const_iterator aIt = m_ActorRoster[team].begin(); aIt != m_ActorRoster[team].end(); ++aIt) - { - if (!(*aIt)->HasObjectInGroup("Brains")) - continue; + void MovableMan::RedrawOverlappingMOIDs(MovableObject* pOverlapsThis) { + for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) { + (*aIt)->DrawMOIDIfOverlapping(pOverlapsThis); + } - // Check if closer than best so far - float sqrDistance = g_SceneMan.ShortestDistance((*aIt)->GetPos(), scenePoint, g_SceneMan.SceneWrapsX() || g_SceneMan.SceneWrapsY()).GetSqrMagnitude(); - if (sqrDistance < sqrShortestDistance) - { - sqrShortestDistance = sqrDistance; - pClosestBrain = *aIt; - } - } + for (std::deque::iterator iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt) { + (*iIt)->DrawMOIDIfOverlapping(pOverlapsThis); + } - return pClosestBrain; -} + for (std::deque::iterator parIt = m_Particles.begin(); parIt != m_Particles.end(); ++parIt) { + (*parIt)->DrawMOIDIfOverlapping(pOverlapsThis); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestOtherBrainActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the brain actor NOT of a specific team that is closest -// to a scene point. + void callLuaFunctionOnMORecursive(MovableObject* mo, const std::string& functionName, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments, const std::vector& functionObjectArguments) { + if (MOSRotating* mosr = dynamic_cast(mo)) { + for (auto attachablrItr = mosr->GetAttachableList().begin(); attachablrItr != mosr->GetAttachableList().end();) { + Attachable* attachable = *attachablrItr; + ++attachablrItr; -Actor * MovableMan::GetClosestOtherBrainActor(int notOfTeam, const Vector &scenePoint) const -{ - if (notOfTeam < Activity::TeamOne || notOfTeam >= Activity::MaxTeamCount || m_Actors.empty()) - return 0; - - float sqrShortestDistance = std::numeric_limits::infinity(); - sqrShortestDistance *= sqrShortestDistance; - - Actor *pClosestBrain = 0; - Actor *pContenderBrain = 0; - - for (int t = Activity::TeamOne; t < g_ActivityMan.GetActivity()->GetTeamCount(); ++t) - { - if (t != notOfTeam) - { - pContenderBrain = GetClosestBrainActor(t, scenePoint); - float sqrDistance = (pContenderBrain->GetPos() - scenePoint).GetSqrMagnitude(); - if (sqrDistance < sqrShortestDistance) - { - sqrShortestDistance = sqrDistance; - pClosestBrain = pContenderBrain; - } - } - } - return pClosestBrain; -} + attachable->RunScriptedFunctionInAppropriateScripts(functionName, false, false, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + callLuaFunctionOnMORecursive(attachable, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } + for (auto woundItr = mosr->GetWoundList().begin(); woundItr != mosr->GetWoundList().end();) { + AEmitter* wound = *woundItr; + ++woundItr; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetUnassignedBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the brain actor of a specific team. -// Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. + wound->RunScriptedFunctionInAppropriateScripts(functionName, false, false, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + callLuaFunctionOnMORecursive(wound, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } + } -Actor * MovableMan::GetUnassignedBrain(int team) const -{ - if (/*m_Actors.empty() || */m_ActorRoster[team].empty()) - return 0; - - for (std::list::const_iterator aIt = m_ActorRoster[team].begin(); aIt != m_ActorRoster[team].end(); ++aIt) - { - if ((*aIt)->HasObjectInGroup("Brains") && !g_ActivityMan.GetActivity()->IsAssignedBrain(*aIt)) - return *aIt; - } - - // Also need to look through all the actors added this frame, one might be a brain. - int actorTeam = Activity::NoTeam; - for (std::deque::const_iterator aaIt = m_AddedActors.begin(); aaIt != m_AddedActors.end(); ++aaIt) - { - int actorTeam = (*aaIt)->GetTeam(); - // Accept no-team brains too - ACTUALLY, DON'T - if ((actorTeam == team/* || actorTeam == Activity::NoTeam*/) && (*aaIt)->HasObjectInGroup("Brains") && !g_ActivityMan.GetActivity()->IsAssignedBrain(*aaIt)) - return *aaIt; - } - - return 0; -} + mo->RunScriptedFunctionInAppropriateScripts(functionName, false, false, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + }; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool MovableMan::AddMO(MovableObject *movableObjectToAdd) { - if (!movableObjectToAdd) { - return false; - } + void MovableMan::RunLuaFunctionOnAllMOs(const std::string& functionName, bool includeAdded, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments, const std::vector& functionObjectArguments) { + if (includeAdded) { + for (Actor* actor: m_AddedActors) { + callLuaFunctionOnMORecursive(actor, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } - if (Actor *actorToAdd = dynamic_cast(movableObjectToAdd)) { - AddActor(actorToAdd); - return true; - } else if (HeldDevice *heldDeviceToAdd = dynamic_cast(movableObjectToAdd)) { - AddItem(heldDeviceToAdd); - return true; - } - AddParticle(movableObjectToAdd); + for (MovableObject* item: m_AddedItems) { + callLuaFunctionOnMORecursive(item, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } - return true; -} + for (MovableObject* particle: m_AddedParticles) { + callLuaFunctionOnMORecursive(particle, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + for (Actor* actor: m_Actors) { + callLuaFunctionOnMORecursive(actor, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } -void MovableMan::AddActor(Actor *actorToAdd) { - if (actorToAdd) { - actorToAdd->SetAsAddedToMovableMan(); - actorToAdd->CorrectAttachableAndWoundPositionsAndRotations(); + for (MovableObject* item: m_Items) { + callLuaFunctionOnMORecursive(item, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } - if (actorToAdd->IsTooFast()) { - actorToAdd->SetToDelete(true); - } else { - if (!dynamic_cast(actorToAdd)) { actorToAdd->MoveOutOfTerrain(g_MaterialGrass); } - if (actorToAdd->IsStatus(Actor::INACTIVE)) { actorToAdd->SetStatus(Actor::STABLE); } - actorToAdd->NotResting(); - actorToAdd->NewFrame(); - actorToAdd->SetAge(g_TimerMan.GetDeltaTimeMS() * -1.0f); - } - - { - std::lock_guard lock(m_AddedActorsMutex); - m_AddedActors.push_back(actorToAdd); - m_ValidActors.insert(actorToAdd); - - // This will call SetTeam and subsequently force the team as active. - AddActorToTeamRoster(actorToAdd); - } - } -} + for (MovableObject* particle: m_Particles) { + callLuaFunctionOnMORecursive(particle, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MovableMan::AddItem(HeldDevice *itemToAdd) { - if (itemToAdd) { - g_ActivityMan.GetActivity()->ForceSetTeamAsActive(itemToAdd->GetTeam()); - itemToAdd->SetAsAddedToMovableMan(); - itemToAdd->CorrectAttachableAndWoundPositionsAndRotations(); - - if (itemToAdd->IsTooFast()) { - itemToAdd->SetToDelete(true); - } else { - if (!itemToAdd->IsSetToDelete()) { itemToAdd->MoveOutOfTerrain(g_MaterialGrass); } - itemToAdd->NotResting(); - itemToAdd->NewFrame(); - itemToAdd->SetAge(g_TimerMan.GetDeltaTimeMS() * -1.0f); - } - - std::lock_guard lock(m_AddedItemsMutex); - m_AddedItems.push_back(itemToAdd); - m_ValidItems.insert(itemToAdd); - } -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void reloadLuaFunctionsOnMORecursive(MovableObject* mo) { + if (MOSRotating* mosr = dynamic_cast(mo)) { + for (auto attachablrItr = mosr->GetAttachableList().begin(); attachablrItr != mosr->GetAttachableList().end();) { + Attachable* attachable = *attachablrItr; + ++attachablrItr; -void MovableMan::AddParticle(MovableObject *particleToAdd){ - if (particleToAdd) { - g_ActivityMan.GetActivity()->ForceSetTeamAsActive(particleToAdd->GetTeam()); - particleToAdd->SetAsAddedToMovableMan(); - if (MOSRotating *particleToAddAsMOSRotating = dynamic_cast(particleToAdd)) { particleToAddAsMOSRotating->CorrectAttachableAndWoundPositionsAndRotations(); } + attachable->ReloadScripts(); + reloadLuaFunctionsOnMORecursive(attachable); + } - if (particleToAdd->IsTooFast()) { - particleToAdd->SetToDelete(true); - } else { - //TODO consider moving particles out of grass. It's old code that was removed because it's slow to do this for every particle. - particleToAdd->NotResting(); - particleToAdd->NewFrame(); - particleToAdd->SetAge(g_TimerMan.GetDeltaTimeMS() * -1.0f); - } - if (particleToAdd->IsDevice()) { - std::lock_guard lock(m_AddedItemsMutex); - m_AddedItems.push_back(particleToAdd); - m_ValidItems.insert(particleToAdd); - } else { - std::lock_guard lock(m_AddedParticlesMutex); - m_AddedParticles.push_back(particleToAdd); - m_ValidParticles.insert(particleToAdd); - } - } -} + for (auto woundItr = mosr->GetWoundList().begin(); woundItr != mosr->GetWoundList().end();) { + AEmitter* wound = *woundItr; + ++woundItr; + wound->ReloadScripts(); + reloadLuaFunctionsOnMORecursive(wound); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes an Actor from the internal list of MO:s. After the Actor is -// removed, ownership is effectively released and transferred to whatever -// client called this method. + mo->ReloadScripts(); + }; -Actor * MovableMan::RemoveActor(MovableObject *pActorToRem) -{ - Actor *removed = nullptr; - - if (pActorToRem) - { - for (std::deque::iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) - { - if (*itr == pActorToRem) - { - std::lock_guard lock(m_ActorsMutex); - removed = *itr; - m_ValidActors.erase(*itr); - m_Actors.erase(itr); - break; - } - } - // Try the newly added actors if we couldn't find it in the regular deque - if (!removed) - { - for (std::deque::iterator itr = m_AddedActors.begin(); itr != m_AddedActors.end(); ++itr) - { - if (*itr == pActorToRem) - { - std::lock_guard lock(m_AddedActorsMutex); - removed = *itr; - m_ValidActors.erase(*itr); - m_AddedActors.erase(itr); - break; - } - } - } - RemoveActorFromTeamRoster(dynamic_cast(pActorToRem)); - pActorToRem->SetAsAddedToMovableMan(false); - } - return removed; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void MovableMan::ReloadLuaScripts() { + for (Actor* actor: m_AddedActors) { + reloadLuaFunctionsOnMORecursive(actor); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a pickup-able MovableObject item from the internal list of -// MO:s. After the item is removed, ownership is effectively released and -// transferred to whatever client called this method. + for (MovableObject* item: m_AddedItems) { + reloadLuaFunctionsOnMORecursive(item); + } -MovableObject * MovableMan::RemoveItem(MovableObject *pItemToRem) -{ - MovableObject *removed = nullptr; - - if (pItemToRem) - { - for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) - { - if (*itr == pItemToRem) - { - std::lock_guard lock(m_ItemsMutex); - removed = *itr; - m_ValidItems.erase(*itr); - m_Items.erase(itr); - break; - } - } - // Try the newly added items if we couldn't find it in the regular deque - if (!removed) - { - for (std::deque::iterator itr = m_AddedItems.begin(); itr != m_AddedItems.end(); ++itr) - { - if (*itr == pItemToRem) - { - std::lock_guard lock(m_AddedItemsMutex); - removed = *itr; - m_ValidItems.erase(*itr); - m_AddedItems.erase(itr); - break; - } - } - } - pItemToRem->SetAsAddedToMovableMan(false); - } - return removed; -} + for (MovableObject* particle: m_AddedParticles) { + reloadLuaFunctionsOnMORecursive(particle); + } + for (Actor* actor: m_Actors) { + reloadLuaFunctionsOnMORecursive(actor); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveParticle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a MovableObject from the internal list of MO:s. After the -// MO is removed, ownership is effectively released and transferred to -// whatever client called this method. + for (MovableObject* item: m_Items) { + reloadLuaFunctionsOnMORecursive(item); + } -MovableObject * MovableMan::RemoveParticle(MovableObject *pMOToRem) -{ - MovableObject *removed = nullptr; - - if (pMOToRem) - { - for (std::deque::iterator itr = m_Particles.begin(); itr != m_Particles.end(); ++itr) - { - if (*itr == pMOToRem) - { - std::lock_guard lock(m_ParticlesMutex); - removed = *itr; - m_ValidParticles.erase(*itr); - m_Particles.erase(itr); - break; - } - } - // Try the newly added particles if we couldn't find it in the regular deque - if (!removed) - { - for (std::deque::iterator itr = m_AddedParticles.begin(); itr != m_AddedParticles.end(); ++itr) - { - if (*itr == pMOToRem) - { - std::lock_guard lock(m_AddedParticlesMutex); - removed = *itr; - m_ValidParticles.erase(*itr); - m_AddedParticles.erase(itr); - break; - } - } - } - pMOToRem->SetAsAddedToMovableMan(false); - } - return removed; -} + for (MovableObject* particle: m_Particles) { + reloadLuaFunctionsOnMORecursive(particle); + } + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this MovableMan. Supposed to be done every frame. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddActorToTeamRoster -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds actor to internal team roster -// Arguments: Pointer to actor -// Return value: None. + void MovableMan::Update() { + ZoneScoped; -void MovableMan::AddActorToTeamRoster(Actor * pActorToAdd) -{ - if (!pActorToAdd) { - return; - } - - // Add to the team roster and then sort it too - int team = pActorToAdd->GetTeam(); - // Also re-set the TEam so that the Team Icons get set up properly - pActorToAdd->SetTeam(team); - // Only add to a roster if it's on a team AND is controllable (eg doors are not) - if (team >= Activity::TeamOne && team < Activity::MaxTeamCount && pActorToAdd->IsControllable()) - { - std::lock_guard lock(m_ActorRosterMutex); - m_ActorRoster[pActorToAdd->GetTeam()].push_back(pActorToAdd); - m_ActorRoster[pActorToAdd->GetTeam()].sort(MOXPosComparison()); - } -} + // Don't update if paused + if (g_ActivityMan.GetActivity() && g_ActivityMan.ActivityPaused()) { + return; + } + m_SimUpdateFrameNumber++; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveActorToTeamRoster -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes actor from internal team roster -// Arguments: Pointer to actor -// Return value: None. + // ---TEMP --- + // These are here for multithreaded AI, but will be unnecessary when multithreaded-sim-and-render is in! + // Clear the MO color layer only if this is a drawn update + if (g_TimerMan.DrawnSimUpdate()) { + g_SceneMan.ClearMOColorLayer(); + } -void MovableMan::RemoveActorFromTeamRoster(Actor * pActorToRem) -{ - if (!pActorToRem) { - return; - } + // If this is the first sim update since a drawn one, then clear the post effects + if (g_TimerMan.SimUpdatesSinceDrawn() == 0) { + g_PostProcessMan.ClearScenePostEffects(); + } + // ---TEMP--- + + // Reset the draw HUD roster line settings + m_SortTeamRoster[Activity::TeamOne] = false; + m_SortTeamRoster[Activity::TeamTwo] = false; + m_SortTeamRoster[Activity::TeamThree] = false; + m_SortTeamRoster[Activity::TeamFour] = false; + + // Move all last frame's alarm events into the proper buffer, and clear out the new one to fill up with this frame's + m_AlarmEvents.clear(); + for (std::vector::iterator aeItr = m_AddedAlarmEvents.begin(); aeItr != m_AddedAlarmEvents.end(); ++aeItr) { + m_AlarmEvents.push_back(*aeItr); + } + m_AddedAlarmEvents.clear(); - int team = pActorToRem->GetTeam(); + // Travel MOs + Travel(); - // Remove from roster as well - if (team >= Activity::TeamOne && team < Activity::MaxTeamCount) { - std::lock_guard lock(m_ActorRosterMutex); - m_ActorRoster[team].remove(pActorToRem); - } -} + // If our debug settings switch is forcing all pathing requests to immediately complete, make sure they're done here + if (g_SettingsMan.GetForceImmediatePathingRequestCompletion() && g_SceneMan.GetScene()) { + g_SceneMan.GetScene()->BlockUntilAllPathingRequestsComplete(); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeActorTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes actor team and updates team rosters. + // Prior to controller/AI update, execute lua callbacks + g_LuaMan.ExecuteLuaScriptCallbacks(); -void MovableMan::ChangeActorTeam(Actor * pActor, int team) -{ - if (!pActor) { - return; - } - - if (pActor->IsPlayerControlled()) { g_ActivityMan.GetActivity()->LoseControlOfActor(pActor->GetController()->GetPlayer()); } - - RemoveActorFromTeamRoster(pActor); - pActor->SetTeam(team); - AddActorToTeamRoster(pActor); - - // Because doors affect the team-based pathfinders, we need to tell them there's been a change. - // This is hackily done by erasing the door material, updating the pathfinders, then redrawing it and updating them again so they properly account for the door's new team. - if (ADoor *actorAsADoor = dynamic_cast(pActor); actorAsADoor && actorAsADoor->GetDoorMaterialDrawn()) { - actorAsADoor->TempEraseOrRedrawDoorMaterial(true); - g_SceneMan.GetTerrain()->AddUpdatedMaterialArea(actorAsADoor->GetBoundingBox()); - g_SceneMan.GetScene()->UpdatePathFinding(); - actorAsADoor->TempEraseOrRedrawDoorMaterial(false); - g_SceneMan.GetTerrain()->AddUpdatedMaterialArea(actorAsADoor->GetBoundingBox()); - g_SceneMan.GetScene()->UpdatePathFinding(); - } -} + // Updates everything needed prior to AI/user input being processed + // Fugly hack to keep backwards compat with scripts that rely on weird frame-delay-ordering behaviours + // TODO, cleanup the pre-controller update and post-controller updates to have some consistent logic of what goes where + PreControllerUpdate(); + // Updates AI/user input + UpdateControllers(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ValidateMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through and checks that all MOID's have valid MO pointers -// associated with them. This shuold only be used for testing, as it will -// crash the app if validation fails. + // Will use some common iterators + std::deque::iterator aIt; + std::deque::iterator amidIt; + std::deque::iterator iIt; + std::deque::iterator imidIt; + std::deque::iterator parIt; + std::deque::iterator midIt; -bool MovableMan::ValidateMOIDs() { -#ifdef DEBUG_BUILD - for (const MovableObject *mo : m_MOIDIndex) { - RTEAssert(mo, "Null MO found!"); - } -#endif - return true; -} + // Update all multithreaded scripts for all objects + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); + { + ZoneScopedN("Multithreaded Scripts Update"); + const std::string threadedUpdate = "ThreadedUpdate"; // avoid string reconstruction -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ValidMO -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject pointer points to an -// MO that's currently active in the simulation, and kept by this MovableMan. + LuaStatesArray& luaStates = g_LuaMan.GetThreadedScriptStates(); + g_ThreadMan.GetPriorityThreadPool().parallelize_loop(luaStates.size(), + [&](int start, int end) { + RTEAssert(start + 1 == end, "Threaded script state being updated across multiple threads!"); + LuaStateWrapper& luaState = luaStates[start]; + g_LuaMan.SetThreadLuaStateOverride(&luaState); -bool MovableMan::ValidMO(const MovableObject *pMOToCheck) { - bool exists = m_ValidActors.find(pMOToCheck) != m_ValidActors.end() || - m_ValidItems.find(pMOToCheck) != m_ValidItems.end() || - m_ValidParticles.find(pMOToCheck) != m_ValidParticles.end(); + for (MovableObject* mo: luaState.GetRegisteredMOs()) { + mo->RunScriptedFunctionInAppropriateScripts(threadedUpdate, false, false, {}, {}, {}); + } - return pMOToCheck && exists; -} + g_LuaMan.SetThreadLuaStateOverride(nullptr); + }) + .wait(); + } + { + ZoneScopedN("Multithreaded Scripts SyncedUpdate"); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject is an active Actor kept -// by this MovableMan or not. + const std::string syncedUpdate = "SyncedUpdate"; // avoid string reconstruction -bool MovableMan::IsActor(const MovableObject *pMOToCheck) -{ - return pMOToCheck && m_ValidActors.find(pMOToCheck) != m_ValidActors.end(); -} + for (LuaStateWrapper& luaState: g_LuaMan.GetThreadedScriptStates()) { + g_LuaMan.SetThreadLuaStateOverride(&luaState); + for (MovableObject* mo: luaState.GetRegisteredMOs()) { + if (mo->HasRequestedSyncedUpdate()) { + mo->RunScriptedFunctionInAppropriateScripts(syncedUpdate, false, false, {}, {}, {}); + mo->ResetRequestedSyncedUpdateFlag(); + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject is an active Item kept -// by this MovableMan or not. + g_LuaMan.SetThreadLuaStateOverride(nullptr); + } + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); -bool MovableMan::IsDevice(const MovableObject *pMOToCheck) -{ - return pMOToCheck && m_ValidItems.find(pMOToCheck) != m_ValidItems.end(); -} + { + {ZoneScopedN("Actors Update"); + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsUpdate); + for (Actor* actor: m_Actors) { + actor->Update(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsParticle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject is an active Item kept -// by this MovableMan or not. + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); + actor->UpdateScripts(); + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); -bool MovableMan::IsParticle(const MovableObject *pMOToCheck) -{ - return pMOToCheck && m_ValidParticles.find(pMOToCheck) != m_ValidParticles.end(); -} + actor->ApplyImpulses(); + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsUpdate); + } + { + ZoneScopedN("Items Update"); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsOfActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MOID is that of an MO which either is -// or is parented to an active Actor by this MovableMan, or not. + int count = 0; + int itemLimit = m_Items.size() - m_MaxDroppedItems; + for (iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt, ++count) { + (*iIt)->Update(); -bool MovableMan::IsOfActor(MOID checkMOID) -{ - if (checkMOID == g_NoMOID) - return false; - - bool found = false; - MovableObject *pMO = GetMOFromID(checkMOID); - - if (pMO) - { - MOID rootMOID = pMO->GetRootID(); - if (checkMOID != g_NoMOID) - { - for (std::deque::iterator itr = m_Actors.begin(); !found && itr != m_Actors.end(); ++itr) - { - if ((*itr)->GetID() == checkMOID || (*itr)->GetID() == rootMOID) - { - found = true; - break; - } - } - // Check actors just added this frame - if (!found) - { - for (std::deque::iterator itr = m_AddedActors.begin(); !found && itr != m_AddedActors.end(); ++itr) - { - if ((*itr)->GetID() == checkMOID || (*itr)->GetID() == rootMOID) - { - found = true; - break; - } - } - } - } - } - return found; -} + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); + (*iIt)->UpdateScripts(); + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); -////////////////////////////////////////////////////////////////////////////////////////// + (*iIt)->ApplyImpulses(); + if (count <= itemLimit) { + (*iIt)->SetToSettle(true); + } + } + } -int MovableMan::GetContiguousActorID(const Actor *actor) const { - auto itr = m_ContiguousActorIDs.find(actor); - if (itr == m_ContiguousActorIDs.end()) { - return -1; - } + { + ZoneScopedN("Particles Update"); - return itr->second; -} + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ParticlesUpdate); + for (MovableObject* particle: m_Particles) { + particle->Update(); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRootMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Produces the root MOID of the MOID of a potential child MO to another MO. + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); + particle->UpdateScripts(); + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); -MOID MovableMan::GetRootMOID(MOID checkMOID) -{ - MovableObject *pMO = GetMOFromID(checkMOID); - if (pMO) - return pMO->GetRootID(); + particle->ApplyImpulses(); + particle->RestDetection(); + // Copy particles that are at rest to the terrain and mark them for deletion. + if (particle->IsAtRest()) { + particle->SetToSettle(true); + } + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ParticlesUpdate); + } - return g_NoMOID; -} + { + ZoneScopedN("Post Update"); + for (Actor* actor: m_Actors) { + actor->PostUpdate(); + } + for (MovableObject* item: m_Items) { + item->PostUpdate(); + } + for (MovableObject* particle: m_Particles) { + particle->PostUpdate(); + } + } +} // namespace RTE -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveMO -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a MovableObject from the any and all internal lists of MO:s. -// After the MO is removed, ownership is effectively released and -// transferred to whatever client called this method. +////////////////////////////////////////////////////////////////////// +// TRANSFER ALL MOs ADDED THIS FRAME +// All Actors, Items, and Particles added this frame now are officially added -bool MovableMan::RemoveMO(MovableObject *pMOToRem) { - if (pMOToRem) - { - if (RemoveActor(pMOToRem)) - return true; - if (RemoveItem(pMOToRem)) - return true; - if (RemoveParticle(pMOToRem)) - return true; - } - - return false; -} + ZoneScopedN("MO Transfer and Deletion"); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int MovableMan::KillAllTeamActors(int teamToKill) const { - int killCount = 0; - - for (std::deque actorList : { m_Actors, m_AddedActors }) { - for (Actor *actor : actorList) { - if (actor->GetTeam() == teamToKill) { - const AHuman *actorAsHuman = dynamic_cast(actor); - if (actorAsHuman && actorAsHuman->GetHead()) { - actorAsHuman->GetHead()->GibThis(); - } else { - actor->GibThis(); - } - killCount++; - } - } - } - - return killCount; -} + { + // Actors + for (aIt = m_AddedActors.begin(); aIt != m_AddedActors.end(); ++aIt) { + // Delete instead if it's marked for it + if (!(*aIt)->IsSetToDelete()) + m_Actors.push_back(*aIt); + else { + m_ValidActors.erase(*aIt); + + // Also remove actor from the roster + if ((*aIt)->GetTeam() >= 0) { + // m_ActorRoster[(*aIt)->GetTeam()].remove(*aIt); + RemoveActorFromTeamRoster(*aIt); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int MovableMan::KillAllEnemyActors(int teamNotToKill) const { - int killCount = 0; - - for (std::deque actorList : { m_Actors, m_AddedActors }) { - for (Actor *actor : actorList) { - if (actor->GetTeam() != teamNotToKill) { - const AHuman *actorAsHuman = dynamic_cast(actor); - if (actorAsHuman && actorAsHuman->GetHead()) { - actorAsHuman->GetHead()->GibThis(); - } else { - actor->GibThis(); - } - killCount++; - } - } - } - - return killCount; -} + (*aIt)->DestroyScriptState(); + delete (*aIt); + } + } + m_AddedActors.clear(); + + // Items + for (iIt = m_AddedItems.begin(); iIt != m_AddedItems.end(); ++iIt) { + // Delete instead if it's marked for it + if (!(*iIt)->IsSetToDelete()) { + m_Items.push_back(*iIt); + } else { + m_ValidItems.erase(*iIt); + (*iIt)->DestroyScriptState(); + delete (*iIt); + } + } + m_AddedItems.clear(); + + // Particles + for (parIt = m_AddedParticles.begin(); parIt != m_AddedParticles.end(); ++parIt) { + // Delete instead if it's marked for it + if (!(*parIt)->IsSetToDelete()) { + m_Particles.push_back(*parIt); + } else { + m_ValidParticles.erase(*parIt); + (*parIt)->DestroyScriptState(); + delete (*parIt); + } + } + m_AddedParticles.clear(); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + // Copy (Settle) Pass -int MovableMan::GetAllActors(bool transferOwnership, std::list &actorList, int onlyTeam, bool noBrains) -{ - int addedCount = 0; - - // Add all regular Actors - for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) - { - Actor *actor = *aIt; - // Only grab ones of a specific team; delete all others - if ((onlyTeam == Activity::NoTeam || actor->GetTeam() == onlyTeam) && (!noBrains || !actor->HasObjectInGroup("Brains"))) - { - actorList.push_back(actor); - addedCount++; - } - else if (transferOwnership) - { - delete actor; - } - } - - // Add all Actors added this frame - for (std::deque::iterator aIt = m_AddedActors.begin(); aIt != m_AddedActors.end(); ++aIt) - { - Actor *actor = *aIt; - // Only grab ones of a specific team; delete all others - if ((onlyTeam == Activity::NoTeam || actor->GetTeam() == onlyTeam) && (!noBrains || !actor->HasObjectInGroup("Brains"))) - { - actorList.push_back(actor); - addedCount++; - } - else if (transferOwnership) - { - delete actor; - } - } - - if (transferOwnership) - { - // Clear the internal Actor lists; we transferred the ownership of them - m_Actors.clear(); - m_AddedActors.clear(); - m_ValidActors.clear(); - - // Also clear the actor rosters - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - m_ActorRoster[team].clear(); - } - } - - return addedCount; -} + { + // DEATH ////////////////////////////////////////////////////////// + // Transfer dead actors from Actor list to particle list + aIt = partition(m_Actors.begin(), m_Actors.end(), std::not_fn(std::mem_fn(&Actor::IsDead))); + amidIt = aIt; + + // Move dead Actor to particles list + if (amidIt != m_Actors.end() /* && m_Actors.size() > 1*/) { + while (aIt != m_Actors.end()) { + // Report the death of the actor to the game + g_ActivityMan.GetActivity()->ReportDeath((*aIt)->GetTeam()); + + // Add to the particles list + m_Particles.push_back(*aIt); + m_ValidParticles.insert(*aIt); + // Remove from the team roster + + if ((*aIt)->GetTeam() >= 0) { + // m_ActorRoster[(*aIt)->GetTeam()].remove(*aIt); + RemoveActorFromTeamRoster(*aIt); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m_ValidActors.erase(*aIt); + aIt++; + } + // Try to set the existing iterator to a safer value, erase can crash in debug mode otherwise? + aIt = m_Actors.begin(); + m_Actors.erase(amidIt, m_Actors.end()); + } -int MovableMan::GetAllItems(bool transferOwnership, std::list &itemList) -{ - int addedCount = 0; - - // Add all regular Items - for (std::deque::iterator iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt) - { - itemList.push_back((*iIt)); - addedCount++; - } - - // Add all Items added this frame - for (std::deque::iterator iIt = m_AddedItems.begin(); iIt != m_AddedItems.end(); ++iIt) - { - itemList.push_back((*iIt)); - addedCount++; - } - - if (transferOwnership) - { - // Clear the internal Item list; we transferred the ownership of them - m_Items.clear(); - m_AddedItems.clear(); - m_ValidItems.clear(); - } - - return addedCount; -} + // ITEM SETTLE ////////////////////////////////////////////////////////// + // Transfer excess items to particle list - use stable partition, item orde is important + iIt = stable_partition(m_Items.begin(), m_Items.end(), std::not_fn(std::mem_fn(&MovableObject::ToSettle))); + imidIt = iIt; + + // Move force-settled items to particles list + if (imidIt != m_Items.end() /* && m_Items.size() > 1*/) { + while (iIt != m_Items.end()) { + (*iIt)->SetToSettle(false); + // Disable TDExplosive's immunity to settling + if ((*iIt)->GetRestThreshold() < 0) { + (*iIt)->SetRestThreshold(500); + } + m_ValidItems.erase(*iIt); + m_Particles.push_back(*iIt); + iIt++; + } + m_Items.erase(imidIt, m_Items.end()); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // DELETE ////////////////////////////////////////////////////////// + // Only delete after all travels & updates are done + // Actors + aIt = partition(m_Actors.begin(), m_Actors.end(), std::not_fn(std::mem_fn(&MovableObject::ToDelete))); + amidIt = aIt; -int MovableMan::GetAllParticles(bool transferOwnership, std::list &particleList) -{ - int addedCount = 0; - - // Add all regular particles - for (std::deque::iterator iIt = m_Particles.begin(); iIt != m_Particles.end(); ++iIt) - { - particleList.push_back((*iIt)); - addedCount++; - } - - // Add all particles added this frame - for (std::deque::iterator iIt = m_AddedParticles.begin(); iIt != m_AddedParticles.end(); ++iIt) - { - particleList.push_back((*iIt)); - addedCount++; - } - - if (transferOwnership) - { - // Clear the internal Particle list; we transferred the ownership of them - m_Particles.clear(); - m_AddedParticles.clear(); - m_ValidParticles.clear(); - } - - return addedCount; -} + while (aIt != m_Actors.end()) { + // Set brain to 0 to avoid crashes due to brain deletion + Activity* pActivity = g_ActivityMan.GetActivity(); + if (pActivity) { + if (pActivity->IsAssignedBrain(*aIt)) + pActivity->SetPlayerBrain(0, pActivity->IsBrainOfWhichPlayer(*aIt)); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + pActivity->ReportDeath((*aIt)->GetTeam()); + } -int MovableMan::GetTeamMOIDCount(int team) const -{ - if (team > Activity::NoTeam && team < Activity::MaxTeamCount) - return m_TeamMOIDCount[team]; - else - return 0; -} + // Remove from team rosters + if ((*aIt)->GetTeam() >= Activity::TeamOne && (*aIt)->GetTeam() < Activity::MaxTeamCount) + // m_ActorRoster[(*aIt)->GetTeam()].remove(*aIt); + RemoveActorFromTeamRoster(*aIt); + + // Delete + m_ValidActors.erase(*aIt); + (*aIt)->DestroyScriptState(); + delete (*aIt); + aIt++; + } + // Try to set the existing iterator to a safer value, erase can crash in debug mode otherwise? + aIt = m_Actors.begin(); + m_Actors.erase(amidIt, m_Actors.end()); + + // Items + iIt = stable_partition(m_Items.begin(), m_Items.end(), std::not_fn(std::mem_fn(&MovableObject::ToDelete))); + imidIt = iIt; + + while (iIt != m_Items.end()) { + m_ValidItems.erase(*iIt); + (*iIt)->DestroyScriptState(); + delete (*iIt); + iIt++; + } + m_Items.erase(imidIt, m_Items.end()); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Particles + parIt = partition(m_Particles.begin(), m_Particles.end(), std::not_fn(std::mem_fn(&MovableObject::ToDelete))); + midIt = parIt; -void MovableMan::OpenAllDoors(bool open, int team) const { - for (std::deque actorDeque : { m_Actors, m_AddedActors }) { - for (Actor *actor : actorDeque) { - if (ADoor *actorAsADoor = dynamic_cast(actor); actorAsADoor && (team == Activity::NoTeam || actorAsADoor->GetTeam() == team)) { - if (actorAsADoor->GetDoorState() != (open ? ADoor::DoorState::OPEN : ADoor::DoorState::CLOSED)) { - actorAsADoor->Update(); - actorAsADoor->SetClosedByDefault(!open); - } - actorAsADoor->ResetSensorTimer(); - if (open) { - actorAsADoor->OpenDoor(); - } else { - actorAsADoor->CloseDoor(); - } - } + while (parIt != m_Particles.end()) { + m_ValidParticles.erase(*parIt); + (*parIt)->DestroyScriptState(); + delete (*parIt); + parIt++; } + m_Particles.erase(midIt, m_Particles.end()); } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// TODO: Completely tear out and delete this. -// It shouldn't belong to MovableMan, instead it probably ought to be on the pathfinder. On that note, pathfinders shouldn't be part of the scene! -// AIMan? PathingMan? Something like that. Ideally, we completely tear out this hack, and allow for doors in a completely different way. -void MovableMan::OverrideMaterialDoors(bool eraseDoorMaterial, int team) const { - for (std::deque actorDeque : { m_Actors, m_AddedActors }) { - for (Actor *actor : actorDeque) { - if (ADoor *actorAsDoor = dynamic_cast(actor); actorAsDoor && (team == Activity::NoTeam || actorAsDoor->GetTeam() == team)) { - actorAsDoor->TempEraseOrRedrawDoorMaterial(eraseDoorMaterial); + // SETTLE PARTICLES ////////////////////////////////////////////////// + // Only settle after all updates and deletions are done + if (m_SettlingEnabled) { + parIt = partition(m_Particles.begin(), m_Particles.end(), std::not_fn(std::mem_fn(&MovableObject::ToSettle))); + midIt = parIt; + + while (parIt != m_Particles.end()) { + Vector parPos((*parIt)->GetPos()); + Material const* terrMat = g_SceneMan.GetMaterialFromID(g_SceneMan.GetTerrain()->GetMaterialPixel(parPos.GetFloorIntX(), parPos.GetFloorIntY())); + int piling = (*parIt)->GetMaterial()->GetPiling(); + if (piling > 0) { + for (int s = 0; s < piling && (terrMat->GetIndex() == (*parIt)->GetMaterial()->GetIndex() || terrMat->GetIndex() == (*parIt)->GetMaterial()->GetSettleMaterial()); ++s) { + if ((piling - s) % 2 == 0) { + parPos.m_Y -= 1.0F; + } else { + parPos.m_X += (RandomNum() >= 0.5F ? 1.0F : -1.0F); + } + terrMat = g_SceneMan.GetMaterialFromID(g_SceneMan.GetTerrain()->GetMaterialPixel(parPos.GetFloorIntX(), parPos.GetFloorIntY())); + } + (*parIt)->SetPos(parPos.GetFloored()); + } + if ((*parIt)->GetDrawPriority() >= terrMat->GetPriority()) { + (*parIt)->DrawToTerrain(g_SceneMan.GetTerrain()); } + m_ValidParticles.erase(*parIt); + (*parIt)->DestroyScriptState(); + delete (*parIt); + parIt++; } + m_Particles.erase(midIt, m_Particles.end()); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// We've finished stuff that can interact with lua script, so it's the ideal time to start a gc run +g_LuaMan.StartAsyncGarbageCollection(); -void MovableMan::RegisterAlarmEvent(const AlarmEvent &newEvent) -{ - std::lock_guard lock(m_AddedAlarmEventsMutex); - m_AddedAlarmEvents.push_back(newEvent); -} +//////////////////////////////////////////////////////////////////////// +// Draw the MO matter and IDs to their layers for next frame +m_DrawMOIDsTask = g_ThreadMan.GetPriorityThreadPool().submit([this]() { + UpdateDrawMOIDs(g_SceneMan.GetMOIDBitmap()); +}); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RedrawOverlappingMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces all objects potnetially overlapping a specific MO to re-draw -// this MOID representations onto the MOID bitmap. +//////////////////////////////////////////////////////////////////// +// Draw the MO colors ONLY if this is a drawn update! -void MovableMan::RedrawOverlappingMOIDs(MovableObject *pOverlapsThis) +if (g_TimerMan.DrawnSimUpdate()) + Draw(g_SceneMan.GetMOColorBitmap()); + +// Sort team rosters if necessary { - for (std::deque::iterator aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) - { - (*aIt)->DrawMOIDIfOverlapping(pOverlapsThis); - } - - for (std::deque::iterator iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt) - { - (*iIt)->DrawMOIDIfOverlapping(pOverlapsThis); - } - - for (std::deque::iterator parIt = m_Particles.begin(); parIt != m_Particles.end(); ++parIt) - { - (*parIt)->DrawMOIDIfOverlapping(pOverlapsThis); - } + if (m_SortTeamRoster[Activity::TeamOne]) + m_ActorRoster[Activity::TeamOne].sort(MOXPosComparison()); + if (m_SortTeamRoster[Activity::TeamTwo]) + m_ActorRoster[Activity::TeamTwo].sort(MOXPosComparison()); + if (m_SortTeamRoster[Activity::TeamThree]) + m_ActorRoster[Activity::TeamThree].sort(MOXPosComparison()); + if (m_SortTeamRoster[Activity::TeamFour]) + m_ActorRoster[Activity::TeamFour].sort(MOXPosComparison()); } - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void callLuaFunctionOnMORecursive(MovableObject* mo, const std::string& functionName, const std::vector& functionEntityArguments, const std::vector& functionLiteralArguments, const std::vector& functionObjectArguments) { - if (MOSRotating* mosr = dynamic_cast(mo)) { - for (auto attachablrItr = mosr->GetAttachableList().begin(); attachablrItr != mosr->GetAttachableList().end(); ) { - Attachable* attachable = *attachablrItr; - ++attachablrItr; - - attachable->RunScriptedFunctionInAppropriateScripts(functionName, false, false, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - callLuaFunctionOnMORecursive(attachable, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } - - for (auto woundItr = mosr->GetWoundList().begin(); woundItr != mosr->GetWoundList().end(); ) { - AEmitter* wound = *woundItr; - ++woundItr; - - wound->RunScriptedFunctionInAppropriateScripts(functionName, false, false, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - callLuaFunctionOnMORecursive(wound, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } - } - - mo->RunScriptedFunctionInAppropriateScripts(functionName, false, false, functionEntityArguments, functionLiteralArguments, functionObjectArguments); -}; - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MovableMan::RunLuaFunctionOnAllMOs(const std::string &functionName, bool includeAdded, const std::vector &functionEntityArguments, const std::vector &functionLiteralArguments, const std::vector &functionObjectArguments) { - if (includeAdded) { - for (Actor* actor : m_AddedActors) { - callLuaFunctionOnMORecursive(actor, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } - - for (MovableObject *item : m_AddedItems) { - callLuaFunctionOnMORecursive(item, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } - - for (MovableObject* particle : m_AddedParticles) { - callLuaFunctionOnMORecursive(particle, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } - } - - for (Actor *actor : m_Actors) { - callLuaFunctionOnMORecursive(actor, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } - - for (MovableObject *item : m_Items) { - callLuaFunctionOnMORecursive(item, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } - - for (MovableObject* particle : m_Particles) { - callLuaFunctionOnMORecursive(particle, functionName, functionEntityArguments, functionLiteralArguments, functionObjectArguments); - } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void reloadLuaFunctionsOnMORecursive(MovableObject* mo) { - if (MOSRotating* mosr = dynamic_cast(mo)) { - for (auto attachablrItr = mosr->GetAttachableList().begin(); attachablrItr != mosr->GetAttachableList().end(); ) { - Attachable* attachable = *attachablrItr; - ++attachablrItr; - - attachable->ReloadScripts(); - reloadLuaFunctionsOnMORecursive(attachable); - } - - for (auto woundItr = mosr->GetWoundList().begin(); woundItr != mosr->GetWoundList().end(); ) { - AEmitter* wound = *woundItr; - ++woundItr; - - wound->ReloadScripts(); - reloadLuaFunctionsOnMORecursive(wound); - } - } - - mo->ReloadScripts(); -}; - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void MovableMan::ReloadLuaScripts() { - for (Actor* actor : m_AddedActors) { - reloadLuaFunctionsOnMORecursive(actor); - } +////////////////////////////////////////////////////////////////////////////////////////// - for (MovableObject* item : m_AddedItems) { - reloadLuaFunctionsOnMORecursive(item); - } +void MovableMan::Travel() { + ZoneScoped; - for (MovableObject* particle : m_AddedParticles) { - reloadLuaFunctionsOnMORecursive(particle); - } + if (m_DrawMOIDsTask.valid()) { + m_DrawMOIDsTask.wait(); + } - for (Actor* actor : m_Actors) { - reloadLuaFunctionsOnMORecursive(actor); - } + // Travel Actors + { + ZoneScopedN("Actors Travel"); + + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsTravel); + for (auto aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) { + if (!((*aIt)->IsUpdated())) { + (*aIt)->ApplyForces(); + (*aIt)->PreTravel(); + (*aIt)->Travel(); + (*aIt)->PostTravel(); + } + (*aIt)->NewFrame(); + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsTravel); + } - for (MovableObject* item : m_Items) { - reloadLuaFunctionsOnMORecursive(item); - } + // Travel items + { + ZoneScopedN("Items Travel"); + + for (auto iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt) { + if (!((*iIt)->IsUpdated())) { + (*iIt)->ApplyForces(); + (*iIt)->PreTravel(); + (*iIt)->Travel(); + (*iIt)->PostTravel(); + } + (*iIt)->NewFrame(); + } + } - for (MovableObject* particle : m_Particles) { - reloadLuaFunctionsOnMORecursive(particle); - } + // Travel particles + { + ZoneScopedN("Particles Travel"); + + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ParticlesTravel); + for (auto parIt = m_Particles.begin(); parIt != m_Particles.end(); ++parIt) { + if (!((*parIt)->IsUpdated())) { + (*parIt)->ApplyForces(); + (*parIt)->PreTravel(); + (*parIt)->Travel(); + (*parIt)->PostTravel(); + } + (*parIt)->NewFrame(); + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ParticlesTravel); + } } ////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this MovableMan. Supposed to be done every frame. -void MovableMan::Update() -{ - ZoneScoped; - - // Don't update if paused - if (g_ActivityMan.GetActivity() && g_ActivityMan.ActivityPaused()) { - return; - } - - m_SimUpdateFrameNumber++; - - // ---TEMP --- - // These are here for multithreaded AI, but will be unnecessary when multithreaded-sim-and-render is in! - // Clear the MO color layer only if this is a drawn update - if (g_TimerMan.DrawnSimUpdate()) { - g_SceneMan.ClearMOColorLayer(); - } - - // If this is the first sim update since a drawn one, then clear the post effects - if (g_TimerMan.SimUpdatesSinceDrawn() == 0) { - g_PostProcessMan.ClearScenePostEffects(); - } - // ---TEMP--- - - // Reset the draw HUD roster line settings - m_SortTeamRoster[Activity::TeamOne] = false; - m_SortTeamRoster[Activity::TeamTwo] = false; - m_SortTeamRoster[Activity::TeamThree] = false; - m_SortTeamRoster[Activity::TeamFour] = false; - - // Move all last frame's alarm events into the proper buffer, and clear out the new one to fill up with this frame's - m_AlarmEvents.clear(); - for (std::vector::iterator aeItr = m_AddedAlarmEvents.begin(); aeItr != m_AddedAlarmEvents.end(); ++aeItr) { - m_AlarmEvents.push_back(*aeItr); - } - m_AddedAlarmEvents.clear(); - - // Travel MOs - Travel(); - - // If our debug settings switch is forcing all pathing requests to immediately complete, make sure they're done here - if (g_SettingsMan.GetForceImmediatePathingRequestCompletion() && g_SceneMan.GetScene()) { - g_SceneMan.GetScene()->BlockUntilAllPathingRequestsComplete(); - } - - // Prior to controller/AI update, execute lua callbacks - g_LuaMan.ExecuteLuaScriptCallbacks(); - - // Updates everything needed prior to AI/user input being processed - // Fugly hack to keep backwards compat with scripts that rely on weird frame-delay-ordering behaviours - // TODO, cleanup the pre-controller update and post-controller updates to have some consistent logic of what goes where - PreControllerUpdate(); - - // Updates AI/user input - UpdateControllers(); - - // Will use some common iterators - std::deque::iterator aIt; - std::deque::iterator amidIt; - std::deque::iterator iIt; - std::deque::iterator imidIt; - std::deque::iterator parIt; - std::deque::iterator midIt; - - // Update all multithreaded scripts for all objects - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - { - ZoneScopedN("Multithreaded Scripts Update"); - - const std::string threadedUpdate = "ThreadedUpdate"; // avoid string reconstruction - - LuaStatesArray& luaStates = g_LuaMan.GetThreadedScriptStates(); - g_ThreadMan.GetPriorityThreadPool().parallelize_loop(luaStates.size(), - [&](int start, int end) { - RTEAssert(start + 1 == end, "Threaded script state being updated across multiple threads!"); - LuaStateWrapper& luaState = luaStates[start]; - g_LuaMan.SetThreadLuaStateOverride(&luaState); - - for (MovableObject *mo : luaState.GetRegisteredMOs()) { - mo->RunScriptedFunctionInAppropriateScripts(threadedUpdate, false, false, {}, {}, {}); - } - - g_LuaMan.SetThreadLuaStateOverride(nullptr); - }).wait(); - } - - { - ZoneScopedN("Multithreaded Scripts SyncedUpdate"); - - const std::string syncedUpdate = "SyncedUpdate"; // avoid string reconstruction - - for (LuaStateWrapper& luaState : g_LuaMan.GetThreadedScriptStates()) { - g_LuaMan.SetThreadLuaStateOverride(&luaState); - - for (MovableObject* mo : luaState.GetRegisteredMOs()) { - if (mo->HasRequestedSyncedUpdate()) { - mo->RunScriptedFunctionInAppropriateScripts(syncedUpdate, false, false, {}, {}, {}); - mo->ResetRequestedSyncedUpdateFlag(); - } - } - - g_LuaMan.SetThreadLuaStateOverride(nullptr); - } - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - - { - { - ZoneScopedN("Actors Update"); - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsUpdate); - for (Actor* actor : m_Actors) { - actor->Update(); - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - actor->UpdateScripts(); - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - - actor->ApplyImpulses(); - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsUpdate); - } - - { - ZoneScopedN("Items Update"); - - int count = 0; - int itemLimit = m_Items.size() - m_MaxDroppedItems; - for (iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt, ++count) { - (*iIt)->Update(); - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - (*iIt)->UpdateScripts(); - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - - (*iIt)->ApplyImpulses(); - if (count <= itemLimit) { - (*iIt)->SetToSettle(true); - } - } - } - - { - ZoneScopedN("Particles Update"); - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ParticlesUpdate); - for (MovableObject* particle : m_Particles) { - particle->Update(); - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - particle->UpdateScripts(); - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ScriptsUpdate); - - particle->ApplyImpulses(); - particle->RestDetection(); - // Copy particles that are at rest to the terrain and mark them for deletion. - if (particle->IsAtRest()) { - particle->SetToSettle(true); - } - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ParticlesUpdate); - } - - { - ZoneScopedN("Post Update"); - - for (Actor* actor : m_Actors) { - actor->PostUpdate(); - } - for (MovableObject* item : m_Items) { - item->PostUpdate(); - } - for (MovableObject* particle : m_Particles) { - particle->PostUpdate(); - } - } - } - - ////////////////////////////////////////////////////////////////////// - // TRANSFER ALL MOs ADDED THIS FRAME - // All Actors, Items, and Particles added this frame now are officially added - - { - ZoneScopedN("MO Transfer and Deletion"); - - { - // Actors - for (aIt = m_AddedActors.begin(); aIt != m_AddedActors.end(); ++aIt) - { - // Delete instead if it's marked for it - if (!(*aIt)->IsSetToDelete()) - m_Actors.push_back(*aIt); - else - { - m_ValidActors.erase(*aIt); - - // Also remove actor from the roster - if ((*aIt)->GetTeam() >= 0) { - //m_ActorRoster[(*aIt)->GetTeam()].remove(*aIt); - RemoveActorFromTeamRoster(*aIt); - } - - (*aIt)->DestroyScriptState(); - delete (*aIt); - } - } - m_AddedActors.clear(); - - // Items - for (iIt = m_AddedItems.begin(); iIt != m_AddedItems.end(); ++iIt) - { - // Delete instead if it's marked for it - if (!(*iIt)->IsSetToDelete()) { - m_Items.push_back(*iIt); - } else { - m_ValidItems.erase(*iIt); - (*iIt)->DestroyScriptState(); - delete (*iIt); - } - } - m_AddedItems.clear(); - - // Particles - for (parIt = m_AddedParticles.begin(); parIt != m_AddedParticles.end(); ++parIt) - { - // Delete instead if it's marked for it - if (!(*parIt)->IsSetToDelete()) { - m_Particles.push_back(*parIt); - } else { - m_ValidParticles.erase(*parIt); - (*parIt)->DestroyScriptState(); - delete (*parIt); - } - } - m_AddedParticles.clear(); - } - - //////////////////////////////////////////////////////////////////////////// - // Copy (Settle) Pass - - { - // DEATH ////////////////////////////////////////////////////////// - // Transfer dead actors from Actor list to particle list - aIt = partition(m_Actors.begin(), m_Actors.end(), std::not_fn(std::mem_fn(&Actor::IsDead))); - amidIt = aIt; - - // Move dead Actor to particles list - if (amidIt != m_Actors.end()/* && m_Actors.size() > 1*/) - { - while (aIt != m_Actors.end()) - { - // Report the death of the actor to the game - g_ActivityMan.GetActivity()->ReportDeath((*aIt)->GetTeam()); - - // Add to the particles list - m_Particles.push_back(*aIt); - m_ValidParticles.insert(*aIt); - // Remove from the team roster - - if ((*aIt)->GetTeam() >= 0) { - //m_ActorRoster[(*aIt)->GetTeam()].remove(*aIt); - RemoveActorFromTeamRoster(*aIt); - } - - m_ValidActors.erase(*aIt); - aIt++; - } - // Try to set the existing iterator to a safer value, erase can crash in debug mode otherwise? - aIt = m_Actors.begin(); - m_Actors.erase(amidIt, m_Actors.end()); - } - - // ITEM SETTLE ////////////////////////////////////////////////////////// - // Transfer excess items to particle list - use stable partition, item orde is important - iIt = stable_partition(m_Items.begin(), m_Items.end(), std::not_fn(std::mem_fn(&MovableObject::ToSettle))); - imidIt = iIt; - - // Move force-settled items to particles list - if (imidIt != m_Items.end()/* && m_Items.size() > 1*/) - { - while (iIt != m_Items.end()) - { - (*iIt)->SetToSettle(false); - // Disable TDExplosive's immunity to settling - if ((*iIt)->GetRestThreshold() < 0) { - (*iIt)->SetRestThreshold(500); - } - m_ValidItems.erase(*iIt); - m_Particles.push_back(*iIt); - iIt++; - } - m_Items.erase(imidIt, m_Items.end()); - } - - // DELETE ////////////////////////////////////////////////////////// - // Only delete after all travels & updates are done - // Actors - aIt = partition(m_Actors.begin(), m_Actors.end(), std::not_fn(std::mem_fn(&MovableObject::ToDelete))); - amidIt = aIt; - - while (aIt != m_Actors.end()) - { - // Set brain to 0 to avoid crashes due to brain deletion - Activity * pActivity = g_ActivityMan.GetActivity(); - if (pActivity) - { - if (pActivity->IsAssignedBrain(*aIt)) - pActivity->SetPlayerBrain(0, pActivity->IsBrainOfWhichPlayer(*aIt)); - - pActivity->ReportDeath((*aIt)->GetTeam()); - } - - // Remove from team rosters - if ((*aIt)->GetTeam() >= Activity::TeamOne && (*aIt)->GetTeam() < Activity::MaxTeamCount) - //m_ActorRoster[(*aIt)->GetTeam()].remove(*aIt); - RemoveActorFromTeamRoster(*aIt); - - // Delete - m_ValidActors.erase(*aIt); - (*aIt)->DestroyScriptState(); - delete (*aIt); - aIt++; - } - // Try to set the existing iterator to a safer value, erase can crash in debug mode otherwise? - aIt = m_Actors.begin(); - m_Actors.erase(amidIt, m_Actors.end()); - - // Items - iIt = stable_partition(m_Items.begin(), m_Items.end(), std::not_fn(std::mem_fn(&MovableObject::ToDelete))); - imidIt = iIt; - - while (iIt != m_Items.end()) { - m_ValidItems.erase(*iIt); - (*iIt)->DestroyScriptState(); - delete (*iIt); - iIt++; - } - m_Items.erase(imidIt, m_Items.end()); - - // Particles - parIt = partition(m_Particles.begin(), m_Particles.end(), std::not_fn(std::mem_fn(&MovableObject::ToDelete))); - midIt = parIt; - - while (parIt != m_Particles.end()) { - m_ValidParticles.erase(*parIt); - (*parIt)->DestroyScriptState(); - delete (*parIt); - parIt++; - } - m_Particles.erase(midIt, m_Particles.end()); - } - - // SETTLE PARTICLES ////////////////////////////////////////////////// - // Only settle after all updates and deletions are done - if (m_SettlingEnabled) { - parIt = partition(m_Particles.begin(), m_Particles.end(), std::not_fn(std::mem_fn(&MovableObject::ToSettle))); - midIt = parIt; - - while (parIt != m_Particles.end()) { - Vector parPos((*parIt)->GetPos()); - Material const * terrMat = g_SceneMan.GetMaterialFromID(g_SceneMan.GetTerrain()->GetMaterialPixel(parPos.GetFloorIntX(), parPos.GetFloorIntY())); - int piling = (*parIt)->GetMaterial()->GetPiling(); - if (piling > 0) { - for (int s = 0; s < piling && (terrMat->GetIndex() == (*parIt)->GetMaterial()->GetIndex() || terrMat->GetIndex() == (*parIt)->GetMaterial()->GetSettleMaterial()); ++s) { - if ((piling - s) % 2 == 0) { - parPos.m_Y -= 1.0F; - } else { - parPos.m_X += (RandomNum() >= 0.5F ? 1.0F : -1.0F); - } - terrMat = g_SceneMan.GetMaterialFromID(g_SceneMan.GetTerrain()->GetMaterialPixel(parPos.GetFloorIntX(), parPos.GetFloorIntY())); - } - (*parIt)->SetPos(parPos.GetFloored()); - } - if ((*parIt)->GetDrawPriority() >= terrMat->GetPriority()) { (*parIt)->DrawToTerrain(g_SceneMan.GetTerrain()); } - m_ValidParticles.erase(*parIt); - (*parIt)->DestroyScriptState(); - delete (*parIt); - parIt++; - } - m_Particles.erase(midIt, m_Particles.end()); - } - } - - // We've finished stuff that can interact with lua script, so it's the ideal time to start a gc run - g_LuaMan.StartAsyncGarbageCollection(); - - //////////////////////////////////////////////////////////////////////// - // Draw the MO matter and IDs to their layers for next frame - m_DrawMOIDsTask = g_ThreadMan.GetPriorityThreadPool().submit([this]() { - UpdateDrawMOIDs(g_SceneMan.GetMOIDBitmap()); - }); - - - //////////////////////////////////////////////////////////////////// - // Draw the MO colors ONLY if this is a drawn update! - - if (g_TimerMan.DrawnSimUpdate()) - Draw(g_SceneMan.GetMOColorBitmap()); - - // Sort team rosters if necessary - { - if (m_SortTeamRoster[Activity::TeamOne]) - m_ActorRoster[Activity::TeamOne].sort(MOXPosComparison()); - if (m_SortTeamRoster[Activity::TeamTwo]) - m_ActorRoster[Activity::TeamTwo].sort(MOXPosComparison()); - if (m_SortTeamRoster[Activity::TeamThree]) - m_ActorRoster[Activity::TeamThree].sort(MOXPosComparison()); - if (m_SortTeamRoster[Activity::TeamFour]) - m_ActorRoster[Activity::TeamFour].sort(MOXPosComparison()); - } -} +void MovableMan::UpdateControllers() { + ZoneScoped; -////////////////////////////////////////////////////////////////////////////////////////// + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsAI); + { + for (Actor* actor: m_Actors) { + actor->GetController()->Update(); + } -void MovableMan::Travel() -{ - ZoneScoped; - - if (m_DrawMOIDsTask.valid()) { - m_DrawMOIDsTask.wait(); - } - - // Travel Actors - { - ZoneScopedN("Actors Travel"); - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsTravel); - for (auto aIt = m_Actors.begin(); aIt != m_Actors.end(); ++aIt) - { - if (!((*aIt)->IsUpdated())) - { - (*aIt)->ApplyForces(); - (*aIt)->PreTravel(); - (*aIt)->Travel(); - (*aIt)->PostTravel(); - } - (*aIt)->NewFrame(); - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsTravel); - } - - // Travel items - { - ZoneScopedN("Items Travel"); - - for (auto iIt = m_Items.begin(); iIt != m_Items.end(); ++iIt) - { - if (!((*iIt)->IsUpdated())) - { - (*iIt)->ApplyForces(); - (*iIt)->PreTravel(); - (*iIt)->Travel(); - (*iIt)->PostTravel(); - } - (*iIt)->NewFrame(); - } - } - - // Travel particles - { - ZoneScopedN("Particles Travel"); - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ParticlesTravel); - for (auto parIt = m_Particles.begin(); parIt != m_Particles.end(); ++parIt) - { - if (!((*parIt)->IsUpdated())) - { - (*parIt)->ApplyForces(); - (*parIt)->PreTravel(); - (*parIt)->Travel(); - (*parIt)->PostTravel(); - } - (*parIt)->NewFrame(); - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ParticlesTravel); - } + LuaStatesArray& luaStates = g_LuaMan.GetThreadedScriptStates(); + g_ThreadMan.GetPriorityThreadPool().parallelize_loop(luaStates.size(), + [&](int start, int end) { + RTEAssert(start + 1 == end, "Threaded script state being updated across multiple threads!"); + LuaStateWrapper& luaState = luaStates[start]; + g_LuaMan.SetThreadLuaStateOverride(&luaState); + for (Actor* actor: m_Actors) { + if (actor->GetLuaState() == &luaState && actor->GetController()->ShouldUpdateAIThisFrame()) { + actor->RunScriptedFunctionInAppropriateScripts("ThreadedUpdateAI", false, true, {}, {}, {}); + } + } + g_LuaMan.SetThreadLuaStateOverride(nullptr); + }) + .wait(); + + for (Actor* actor: m_Actors) { + if (actor->GetController()->ShouldUpdateAIThisFrame()) { + actor->RunScriptedFunctionInAppropriateScripts("UpdateAI", false, true, {}, {}, {}); + } + } + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsAI); } ////////////////////////////////////////////////////////////////////////////////////////// -void MovableMan::UpdateControllers() -{ - ZoneScoped; - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsAI); - { - for (Actor* actor : m_Actors) { - actor->GetController()->Update(); - } - - LuaStatesArray& luaStates = g_LuaMan.GetThreadedScriptStates(); - g_ThreadMan.GetPriorityThreadPool().parallelize_loop(luaStates.size(), - [&](int start, int end) { - RTEAssert(start + 1 == end, "Threaded script state being updated across multiple threads!"); - LuaStateWrapper& luaState = luaStates[start]; - g_LuaMan.SetThreadLuaStateOverride(&luaState); - for (Actor *actor : m_Actors) { - if (actor->GetLuaState() == &luaState && actor->GetController()->ShouldUpdateAIThisFrame()) { - actor->RunScriptedFunctionInAppropriateScripts("ThreadedUpdateAI", false, true, {}, {}, {}); - } - } - g_LuaMan.SetThreadLuaStateOverride(nullptr); - }).wait(); - - for (Actor* actor : m_Actors) { - if (actor->GetController()->ShouldUpdateAIThisFrame()) { - actor->RunScriptedFunctionInAppropriateScripts("UpdateAI", false, true, {}, {}, {}); - } - } - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsAI); -} +void MovableMan::PreControllerUpdate() { + ZoneScoped; -////////////////////////////////////////////////////////////////////////////////////////// + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsUpdate); + for (Actor* actor: m_Actors) { + actor->PreControllerUpdate(); + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsUpdate); -void MovableMan::PreControllerUpdate() -{ - ZoneScoped; - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ActorsUpdate); - for (Actor *actor : m_Actors) { - actor->PreControllerUpdate(); - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ActorsUpdate); - - for (MovableObject* item : m_Items) { - item->PreControllerUpdate(); - } - - g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ParticlesUpdate); - for (MovableObject* particle : m_Particles) { - particle->PreControllerUpdate(); - } - g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ParticlesUpdate); + for (MovableObject* item: m_Items) { + item->PreControllerUpdate(); + } + + g_PerformanceMan.StartPerformanceMeasurement(PerformanceMan::ParticlesUpdate); + for (MovableObject* particle: m_Particles) { + particle->PreControllerUpdate(); + } + g_PerformanceMan.StopPerformanceMeasurement(PerformanceMan::ParticlesUpdate); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2190,14 +2044,13 @@ void MovableMan::PreControllerUpdate() // Description: Draws this MovableMan's all MO's current material representations to a // BITMAP of choice. -void MovableMan::DrawMatter(BITMAP *pTargetBitmap, Vector &targetPos) -{ - // Draw objects to accumulation bitmap - for (std::deque::iterator aIt = --m_Actors.end(); aIt != --m_Actors.begin(); --aIt) - (*aIt)->Draw(pTargetBitmap, targetPos, g_DrawMaterial); +void MovableMan::DrawMatter(BITMAP* pTargetBitmap, Vector& targetPos) { + // Draw objects to accumulation bitmap + for (std::deque::iterator aIt = --m_Actors.end(); aIt != --m_Actors.begin(); --aIt) + (*aIt)->Draw(pTargetBitmap, targetPos, g_DrawMaterial); - for (std::deque::iterator parIt = --m_Particles.end(); parIt != --m_Particles.begin(); --parIt) - (*parIt)->Draw(pTargetBitmap, targetPos, g_DrawMaterial); + for (std::deque::iterator parIt = --m_Particles.end(); parIt != --m_Particles.begin(); --parIt) + (*parIt)->Draw(pTargetBitmap, targetPos, g_DrawMaterial); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2207,29 +2060,24 @@ void MovableMan::DrawMatter(BITMAP *pTargetBitmap, Vector &targetPos) // Arguments: None. // Return value: None. -void MovableMan::VerifyMOIDIndex() -{ +void MovableMan::VerifyMOIDIndex() { int count = 0; - for (std::vector::iterator aIt = m_MOIDIndex.begin(); aIt != m_MOIDIndex.end(); ++aIt) - { - if (*aIt) - { + for (std::vector::iterator aIt = m_MOIDIndex.begin(); aIt != m_MOIDIndex.end(); ++aIt) { + if (*aIt) { RTEAssert((*aIt)->GetID() == g_NoMOID || (*aIt)->GetID() == count, "MOIDIndex broken!"); RTEAssert((*aIt)->GetRootID() == g_NoMOID || ((*aIt)->GetRootID() >= 0 && (*aIt)->GetRootID() < g_MovableMan.GetMOIDCount()), "MOIDIndex broken!"); } count++; - if (count == g_NoMOID) count++; + if (count == g_NoMOID) + count++; } - - for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) - { + for (std::deque::iterator itr = m_Items.begin(); itr != m_Items.end(); ++itr) { RTEAssert((*itr)->GetID() == g_NoMOID || (*itr)->GetID() < GetMOIDCount(), "MOIDIndex broken!"); RTEAssert((*itr)->GetRootID() == g_NoMOID || ((*itr)->GetRootID() >= 0 && (*itr)->GetRootID() < g_MovableMan.GetMOIDCount()), "MOIDIndex broken!"); } // Try the items just added this frame - for (std::deque::iterator itr = m_AddedItems.begin(); itr != m_AddedItems.end(); ++itr) - { + for (std::deque::iterator itr = m_AddedItems.begin(); itr != m_AddedItems.end(); ++itr) { RTEAssert((*itr)->GetID() == g_NoMOID || (*itr)->GetID() < GetMOIDCount(), "MOIDIndex broken!"); RTEAssert((*itr)->GetRootID() == g_NoMOID || ((*itr)->GetRootID() >= 0 && (*itr)->GetRootID() < g_MovableMan.GetMOIDCount()), "MOIDIndex broken!"); } @@ -2241,71 +2089,69 @@ void MovableMan::VerifyMOIDIndex() // Description: Updates the MOIDs of all current MOs and draws their ID's to a BITMAP // of choice. -void MovableMan::UpdateDrawMOIDs(BITMAP *pTargetBitmap) -{ - ZoneScoped; +void MovableMan::UpdateDrawMOIDs(BITMAP* pTargetBitmap) { + ZoneScoped; - /////////////////////////////////////////////////// - // Clear the MOID layer before starting to delete stuff which may be in the MOIDIndex - g_SceneMan.ClearAllMOIDDrawings(); + /////////////////////////////////////////////////// + // Clear the MOID layer before starting to delete stuff which may be in the MOIDIndex + g_SceneMan.ClearAllMOIDDrawings(); - // Clear the index each frame and do it over because MO's get added and deleted between each frame. - m_MOIDIndex.clear(); - m_ContiguousActorIDs.clear(); + // Clear the index each frame and do it over because MO's get added and deleted between each frame. + m_MOIDIndex.clear(); + m_ContiguousActorIDs.clear(); - // Add a null and start counter at 1 because MOID == 0 means no MO. - // - Update: This isnt' true anymore, but still keep 0 free just to be safe - m_MOIDIndex.push_back(0); + // Add a null and start counter at 1 because MOID == 0 means no MO. + // - Update: This isnt' true anymore, but still keep 0 free just to be safe + m_MOIDIndex.push_back(0); - MOID currentMOID = 1; + MOID currentMOID = 1; - int actorID = 0; - for (Actor *actor : m_Actors) { - m_ContiguousActorIDs[actor] = actorID++; + int actorID = 0; + for (Actor* actor: m_Actors) { + m_ContiguousActorIDs[actor] = actorID++; if (!actor->IsSetToDelete()) { - actor->UpdateMOID(m_MOIDIndex); - actor->Draw(pTargetBitmap, Vector(), g_DrawMOID, true); - currentMOID = m_MOIDIndex.size(); - } else { - actor->SetAsNoID(); - } - } - - for (MovableObject *item : m_Items) { - if (!item->IsSetToDelete()) { - item->UpdateMOID(m_MOIDIndex); - item->Draw(pTargetBitmap, Vector(), g_DrawMOID, true); - currentMOID = m_MOIDIndex.size(); - } else { - item->SetAsNoID(); - } - } - - for (MovableObject *particle : m_Particles) { - if (!particle->IsSetToDelete()) { - particle->UpdateMOID(m_MOIDIndex); - particle->Draw(pTargetBitmap, Vector(), g_DrawMOID, true); - currentMOID = m_MOIDIndex.size(); - } else { - particle->SetAsNoID(); - } - } - - // COUNT MOID USAGE PER TEAM ////////////////////////////////////////////////// - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; team++) { - m_TeamMOIDCount[team] = 0; - } - - for (auto itr = m_MOIDIndex.begin(); itr != m_MOIDIndex.end(); ++itr) { - if (*itr) { - int team = (*itr)->GetTeam(); - if (team > Activity::NoTeam && team < Activity::MaxTeamCount) { - m_TeamMOIDCount[team]++; - } - } - } -} + actor->UpdateMOID(m_MOIDIndex); + actor->Draw(pTargetBitmap, Vector(), g_DrawMOID, true); + currentMOID = m_MOIDIndex.size(); + } else { + actor->SetAsNoID(); + } + } + + for (MovableObject* item: m_Items) { + if (!item->IsSetToDelete()) { + item->UpdateMOID(m_MOIDIndex); + item->Draw(pTargetBitmap, Vector(), g_DrawMOID, true); + currentMOID = m_MOIDIndex.size(); + } else { + item->SetAsNoID(); + } + } + + for (MovableObject* particle: m_Particles) { + if (!particle->IsSetToDelete()) { + particle->UpdateMOID(m_MOIDIndex); + particle->Draw(pTargetBitmap, Vector(), g_DrawMOID, true); + currentMOID = m_MOIDIndex.size(); + } else { + particle->SetAsNoID(); + } + } + + // COUNT MOID USAGE PER TEAM ////////////////////////////////////////////////// + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; team++) { + m_TeamMOIDCount[team] = 0; + } + for (auto itr = m_MOIDIndex.begin(); itr != m_MOIDIndex.end(); ++itr) { + if (*itr) { + int team = (*itr)->GetTeam(); + if (team > Activity::NoTeam && team < Activity::MaxTeamCount) { + m_TeamMOIDCount[team]++; + } + } + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: Draw @@ -2313,54 +2159,51 @@ void MovableMan::UpdateDrawMOIDs(BITMAP *pTargetBitmap) // Description: Draws this MovableMan's current graphical representation to a // BITMAP of choice. -void MovableMan::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) -{ - ZoneScoped; +void MovableMan::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) { + ZoneScoped; - // Draw objects to accumulation bitmap, in reverse order so actors appear on top. + // Draw objects to accumulation bitmap, in reverse order so actors appear on top. - { - ZoneScopedN("Particles Draw"); + { + ZoneScopedN("Particles Draw"); - for (std::deque::iterator parIt = m_Particles.begin(); parIt != m_Particles.end(); ++parIt) { - (*parIt)->Draw(pTargetBitmap, targetPos); - } - } + for (std::deque::iterator parIt = m_Particles.begin(); parIt != m_Particles.end(); ++parIt) { + (*parIt)->Draw(pTargetBitmap, targetPos); + } + } - { - ZoneScopedN("Items Draw"); + { + ZoneScopedN("Items Draw"); - for (std::deque::reverse_iterator itmIt = m_Items.rbegin(); itmIt != m_Items.rend(); ++itmIt) { - (*itmIt)->Draw(pTargetBitmap, targetPos); - } - } + for (std::deque::reverse_iterator itmIt = m_Items.rbegin(); itmIt != m_Items.rend(); ++itmIt) { + (*itmIt)->Draw(pTargetBitmap, targetPos); + } + } - { - ZoneScopedN("Actors Draw"); + { + ZoneScopedN("Actors Draw"); - for (std::deque::reverse_iterator aIt = m_Actors.rbegin(); aIt != m_Actors.rend(); ++aIt) { - (*aIt)->Draw(pTargetBitmap, targetPos); - } - } + for (std::deque::reverse_iterator aIt = m_Actors.rbegin(); aIt != m_Actors.rend(); ++aIt) { + (*aIt)->Draw(pTargetBitmap, targetPos); + } + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: DrawHUD ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws this MovableMan's current graphical representation to a // BITMAP of choice. -void MovableMan::DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos, int which, bool playerControlled) -{ - ZoneScoped; +void MovableMan::DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos, int which, bool playerControlled) { + ZoneScoped; - // Draw HUD elements - for (std::deque::reverse_iterator itmIt = m_Items.rbegin(); itmIt != m_Items.rend(); ++itmIt) - (*itmIt)->DrawHUD(pTargetBitmap, targetPos, which); + // Draw HUD elements + for (std::deque::reverse_iterator itmIt = m_Items.rbegin(); itmIt != m_Items.rend(); ++itmIt) + (*itmIt)->DrawHUD(pTargetBitmap, targetPos, which); - for (std::deque::reverse_iterator aIt = m_Actors.rbegin(); aIt != m_Actors.rend(); ++aIt) - (*aIt)->DrawHUD(pTargetBitmap, targetPos, which); + for (std::deque::reverse_iterator aIt = m_Actors.rbegin(); aIt != m_Actors.rend(); ++aIt) + (*aIt)->DrawHUD(pTargetBitmap, targetPos, which); } } // namespace RTE diff --git a/Source/Managers/MovableMan.h b/Source/Managers/MovableMan.h index 39a0bfcb2..d4c8aec97 100644 --- a/Source/Managers/MovableMan.h +++ b/Source/Managers/MovableMan.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,1053 +19,998 @@ #define g_MovableMan MovableMan::Instance() -namespace RTE -{ - -class MovableObject; -class Actor; -class HeldDevice; -class MOPixel; -class MOSprite; -class AHuman; -class SceneLayer; -class SceneObject; -class Box; -class LuabindObjectWrapper; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Struct: AlarmEvent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A struct to keep all data about a an alarming event for the AI Actors. -// Parent(s): None. -// Class history: 10/3/2008 AlarmEvent created. - -struct AlarmEvent { - AlarmEvent() { m_ScenePos.Reset(); m_Team = Activity::NoTeam; m_Range = 1.0F; } - // TODO: Stop relying on screen width for this shit! - AlarmEvent(const Vector &pos, int team = Activity::NoTeam, float range = 1.0F); - - // Absolute position in the scene where this occurred - Vector m_ScenePos; - // The team of whatever object that caused this event - Activity::Teams m_Team; - // The range multiplier, that this alarming event can be heard - float m_Range; -}; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: MovableMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The singleton manager of all movable objects in the RTE. -// Parent(s): Singleton, Serializable. -// Class history: 12/25/2001 MovableMan created. - -class MovableMan : public Singleton, public Serializable { - friend class SettingsMan; - friend struct ManagerLuaBindings; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableClassNameGetter; - SerializableOverrideMethods; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MovableMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a MovableMan object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - MovableMan() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~MovableMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a MovableMan object before deletion -// from system memory. -// Arguments: None. - - ~MovableMan() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MovableMan object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Initialize(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire MovableMan, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MovableMan object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMOFromID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a MO from its MOID. Note that MOID's are only valid during the -// same frame as they were assigned to the MOs! -// Arguments: The MOID to get the matching MO from. -// Return value: A pointer to the requested MovableObject instance. 0 if no MO with that -// MOID was found. 0 if 0 was passed in as MOID (no MOID). Ownership is -// *NOT* transferred!! - - MovableObject * GetMOFromID(MOID whichID); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMOIDCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of MOID's currently in use this frame. -// Arguments: None. -// Return value: The count of MOIDs in use this frame. - - int GetMOIDCount() { return m_MOIDIndex.size(); } - - /// - /// Gets a MOID from pixel coordinates in the Scene. - /// - /// The X coordinate of the Scene pixel to get the MOID of. - /// The Y coordinate of the Scene pixel to get the MOID of. - /// The collection of MOIDs to check the against the specified coordinates. - /// The topmost MOID currently at the specified pixel coordinates. - MOID GetMOIDPixel(int pixelX, int pixelY, const std::vector &moidList); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTeamMOIDCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns MO count for specified team -// Arguments: Team to count MO's -// Return value: MO's count owned by this team - - int GetTeamMOIDCount(int team) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PurgeAllMOs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears out all MovableObject:s out of this. Effectively empties the world -// of anything moving, without resetting all of this' settings. -// Arguments: None. -// Return value: None. - - void PurgeAllMOs(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextActorInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the first Actor in the internal Actor list that is -// of a specifc group, alternatively the first one AFTER a specific actor! -// Arguments: Which group to try to get an Actor for. -// A pointer to an Actor to use as starting point in the forward search. -// Ownership NOT xferred! -// Return value: An Actor pointer to the requested team's first Actor encountered -// in the list. 0 if there are no Actors of that team. - - Actor * GetNextActorInGroup(std::string group, Actor *pAfterThis = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPrevActorInGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the last Actor in the internal Actor list that is -// of a specifc group, alternatively the last one BEFORE a specific actor! -// Arguments: Which group to try to get an Actor for. -// A pointer to an Actor to use as starting point in the backward search. -// Ownership NOT xferred! -// Return value: An Actor pointer to the requested team's last Actor encountered -// in the list. 0 if there are no Actors of that team. - - Actor * GetPrevActorInGroup(std::string group, Actor *pBeforeThis = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTeamRoster -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of all actors on one team, ordered by their X positions. -// Arguments: Which team to try to get the roster for. -// Return value: A pointer to the list of all the actors on the specified team, sorted -// ascending by their X posistions. Ownership of the list or contained -// actors is NOT transferred! - - std::list * GetTeamRoster(int team = 0) { return &(m_ActorRoster[team]); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextTeamActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the first Actor in the internal Actor list that is -// of a specifc team, alternatively the first one AFTER a specific actor! -// Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. -// A pointer to an Actor to use as starting point in the forward search. -// Ownership NOT xferred! -// Return value: An Actor pointer to the requested team's first Actor encountered -// in the list. 0 if there are no Actors of that team. - - Actor * GetNextTeamActor(int team = 0, Actor *pAfterThis = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPrevTeamActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the last Actor in the internal Actor list that is -// of a specifc team, alternatively the last one BEFORE a specific actor! -// Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. -// A pointer to an Actor to use as starting point in the backward search. -// Ownership NOT xferred! -// Return value: An Actor pointer to the requested team's last Actor encountered -// in the list. 0 if there are no Actors of that team. - - Actor * GetPrevTeamActor(int team = 0, Actor *pBeforeThis = 0); - - /// - /// Get a pointer to an Actor in the internal Actor list that is of a specifc team and closest to a specific scene point. - /// - /// Which team to try to get an Actor for. 0 means first team, 1 means 2nd. - /// The player to get the Actor for. This affects which brain can be marked. - /// The Scene point to search for the closest to. - /// The maximum radius around that scene point to search. - /// A Vector to be filled out with the distance of the returned closest to the search point. Will be unaltered if no object was found within radius. - /// An Actor to exclude from the search. OWNERSHIP IS NOT TRANSFERRED! - /// An Actor pointer to the requested team's Actor closest to the Scene point, but not outside the max radius. If no Actor other than the excluded one was found within the radius of the point, nullptr is returned. - Actor * GetClosestTeamActor(int team, int player, const Vector &scenePoint, int maxRadius, Vector &getDistance, const Actor *excludeThis = nullptr) { return GetClosestTeamActor(team, player, scenePoint, maxRadius, getDistance, false, excludeThis); } - - /// - /// Get a pointer to an Actor in the internal Actor list that is of a specifc team and closest to a specific scene point. - /// - /// Which team to try to get an Actor for. 0 means first team, 1 means 2nd. - /// The player to get the Actor for. This affects which brain can be marked. - /// The Scene point to search for the closest to. - /// The maximum radius around that scene point to search. - /// A Vector to be filled out with the distance of the returned closest to the search point. Will be unaltered if no object was found within radius. - /// Whether to only get Actors that are flagged as player controllable. - /// An Actor to exclude from the search. OWNERSHIP IS NOT TRANSFERRED! - /// An Actor pointer to the requested team's Actor closest to the Scene point, but not outside the max radius. If no Actor other than the excluded one was found within the radius of the point, nullptr is returned. - Actor * GetClosestTeamActor(int team, int player, const Vector &scenePoint, int maxRadius, Vector &getDistance, bool onlyPlayerControllableActors, const Actor *excludeThis = nullptr); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestEnemyActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to an Actor in the internal Actor list that is is not of -// the specified team and closest to a specific scene point. -// Arguments: Which team to try to get an enemy Actor for. NoTeam means all teams. -// The Scene point to search for the closest to. -// The maximum radius around that scene point to search. -// A Vector to be filled out with the distance of the returned closest to -// the search point. Will be unaltered if no object was found within radius. -// Return value: An Actor pointer to the enemy closest to the Scene -// point, but not outside the max radius. If no Actor -// was found within the radius of the point, 0 is returned. - - Actor * GetClosestEnemyActor(int team, const Vector &scenePoint, int maxRadius, Vector &getDistance); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFirstTeamActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to first best Actor in the internal Actor list that is -// of a specifc team. -// Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. -// The player to get the Actor for. This affects which brain can be marked. -// Return value: An Actor pointer to the first one of the requested team. If no Actor -// is in that team, 0 is returned. - - Actor * GetFirstTeamActor(int team, int player) { Vector temp; return GetClosestTeamActor(team, player, Vector(), 10000000, temp); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to an Actor in the internal Actor list that is closest -// to a specific scene point. -// Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. -// The Scene point to search for the closest to. -// The maximum radius around that scene point to search. -// A Vector to be filled out with the distance of the returned closest to -// the search point. Will be unaltered if no object was found within radius. -// An Actor to exclude from the search. OWNERSHIP IS NOT TRANSFERRED! -// Return value: An Actor pointer to the requested Actor closest to the Scene -// point, but not outside the max radius. If no Actor other than the -// excluded one was found within the radius of the point, 0 is returned. - - Actor * GetClosestActor(const Vector &scenePoint, int maxRadius, Vector &getDistance, const Actor *pExcludeThis = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestBrainActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the brain actor of a specific team that is closest to -// a scene point. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. -// The point in the scene where to look for the closest opposite team brain. -// Return value: An Actor pointer to the requested team's brain closest to the point. -// 0 if there are no brains of that team. OWNERSHIP IS NOT TRANSFERRED! - - Actor * GetClosestBrainActor(int team, const Vector &scenePoint) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFirstBrainActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the brain actor of a specific team that is closest to -// a scene point. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. -// The point in the scene where to look for the closest opposite team brain. -// Return value: An Actor pointer to the requested team's brain closest to the point. -// 0 if there are no brains of that team. OWNERSHIP IS NOT TRANSFERRED! - - Actor * GetFirstBrainActor(int team) const { return GetClosestBrainActor(team, Vector()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetClosestOtherBrainActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the brain actor NOT of a specific team that is closest -// to a scene point. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: Which team to NOT get the brain for. 0 means first team, 1 means 2nd. -// The point where to look for the closest brain not of this team. -// Return value: An Actor pointer to the requested brain closest to the point. -// 0 if there are no brains not on that team. OWNERSHIP IS NOT TRANSFERRED! - - Actor * GetClosestOtherBrainActor(int notOfTeam, const Vector &scenePoint) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetFirstOtherBrainActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the brain actor NOT of a specific team. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: Which team to NOT get the brain for. 0 means first team, 1 means 2nd. -// Return value: An Actor pointer to the requested brain of that team. -// 0 if there are no brains not on that team. OWNERSHIP IS NOT TRANSFERRED! - - Actor * GetFirstOtherBrainActor(int notOfTeam) const { return GetClosestOtherBrainActor(notOfTeam, Vector()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetUnassignedBrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Get a pointer to the first brain actor of a specific team which hasn't -// been assigned to a player yet. -// Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. -// Return value: An Actor pointer to the requested team's first brain encountered -// in the list that hasn't been assigned to a player. 0 if there are no -// unassigned brains of that team. - - Actor * GetUnassignedBrain(int team = 0) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActorCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of actors currently held. -// Arguments: None. -// Return value: The number of actors. - - long GetActorCount() const { return m_Actors.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetParticleCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the number of particles (MOPixel:s) currently held. -// Arguments: None. -// Return value: The number of particles. - - long GetParticleCount() const { return m_Particles.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSplashRatio -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the global setting for how much splash MOPixels should be created -// an MO penetrates the terrain deeply. -// Arguments: None. -// Return value: A float with the global splash amount setting, form 1.0 to 0.0. - - float GetSplashRatio() const { return m_SplashRatio; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMaxDroppedItems -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the max number of dropped items that will be reached before the -// first dropped with be copied to the terrain. -// Arguments: An int spefifying the limit. -// Return value: None. - - void SetMaxDroppedItems(int newLimit) { m_MaxDroppedItems = newLimit; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaxDroppedItems -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the max number of dropped items that will be reached before the -// first dropped with be copied to the terrain. -// Arguments: None. -// Return value: An int spefifying the limit. - - int GetMaxDroppedItems() const { return m_MaxDroppedItems; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SortTeamRoster -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets this to draw HUD lines for a specific team's roster this frame. -// Arguments: Which team to have lines drawn of. -// Return value: None. - - void SortTeamRoster(int team) { m_SortTeamRoster[team] = true; } - - /// - /// Adds a MovableObject to this, after it is determined what it is and the best way to add it is. E.g. if it's an Actor, it will be added as such. Ownership IS transferred! - /// - /// A pointer to the MovableObject to add. Ownership IS transferred! - /// Whether the MovableObject was successfully added or not. Note that Ownership IS transferred either way, but the MovableObject will be deleted if this is not successful. - bool AddMO(MovableObject *movableObjectToAdd); - - /// - /// Adds an Actor to the internal list of Actors. Destruction and deletion will be taken care of automatically. Ownership IS transferred! - /// - /// A pointer to the Actor to add. Ownership IS transferred! - void AddActor(Actor *actorToAdd); - - /// - /// Adds a pickup-able item to the internal list of items. Destruction and deletion will be taken care of automatically. Ownership IS transferred! - /// - /// A pointer to the item to add. Ownership IS transferred! - void AddItem(HeldDevice *itemToAdd); - - /// - /// Adds a MovableObject to the internal list of particles. Destruction and deletion will be taken care of automatically. Ownership IS transferred! - /// - /// A pointer to the MovableObject to add. Ownership is transferred! - void AddParticle(MovableObject *particleToAdd); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes an Actor from the internal list of MO:s. After the Actor is -// removed, ownership is effectively released and transferred to whatever -// client called this method. -// Arguments: A pointer to the MovableObject to remove. -// Return value: Whether the object was found in the particle list, and consequently -// removed. If the particle entry wasn't found, false is returned. - - Actor * RemoveActor(MovableObject *pActorToRem); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a pickup-able MovableObject item from the internal list of -// MO:s. After the item is removed, ownership is effectively released and -// transferred to whatever client called this method. -// Arguments: A pointer to the MovableObject to remove. -// Return value: Whether the object was found in the particle list, and consequently -// removed. If the particle entry wasn't found, false is returned. - - MovableObject * RemoveItem(MovableObject *pItemToRem); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveParticle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a MovableObject from the internal list of MO:s. After the -// MO is removed, ownership is effectively released and transferred to -// whatever client called this method. -// Arguments: A pointer to the MovableObject to remove. -// Return value: Whether the object was found in the particle list, and consequently -// removed. If the particle entry wasn't found, false is returned. - - MovableObject * RemoveParticle(MovableObject *pMOToRem); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeActorTeam -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes actor team and updates team rosters. -// Arguments: Pointer to actor, new team value -// Return value: None. - - void ChangeActorTeam(Actor * pActor, int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddActorToTeamRoster -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds actor to internal team roster -// Arguments: Pointer to actor -// Return value: None. - - void AddActorToTeamRoster(Actor * pActorToAdd); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveActorToTeamRoster -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes actor from internal team roster -// Arguments: Pointer to actor -// Return value: None. - - void RemoveActorFromTeamRoster(Actor * pActorToRem); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ValidateMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Goes through and checks that all MOID's have valid MO pointers -// associated with them. This shuold only be used for testing, as it will -// crash the app if validation fails. -// Arguments: None. -// Return value: All MOIDs valid. - - bool ValidateMOIDs(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ValidMO -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject pointer points to an -// MO that's currently active in the simulation, and kept by this -// MovableMan. Internal optimization is made so that the same MO can -// efficiently be checked many times during the same frame. -// Arguments: A pointer to the MovableObject to check for being actively kept by -// this MovableMan. -// Return value: Whether the MO instance was found in the active list or not. - - bool ValidMO(const MovableObject *pMOToCheck); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject is an active Actor kept -// by this MovableMan or not. -// Arguments: A pointer to the MovableObject to check for Actorness. -// Return value: Whether the object was found in the Actor list or not. - - bool IsActor(const MovableObject *pMOToCheck); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsDevice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject is an active Item kept -// by this MovableMan or not. -// Arguments: A pointer to the MovableObject to check for Itemness. -// Return value: Whether the object was found in the Item list or not. - - bool IsDevice(const MovableObject *pMOToCheck); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsParticle -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MovableObject is an active Item kept -// by this MovableMan or not. -// Arguments: A pointer to the MovableObject to check for Itemness. -// Return value: Whether the object was found in the Particle list or not. - - bool IsParticle(const MovableObject *pMOToCheck); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsOfActor -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the passed in MOID is that of an MO which either is -// or is parented to an active Actor by this MovableMan, or not. -// Arguments: An MOID to check for Actorness. -// Return value: Whether the object was found or owned by an MO in the Actor list or not. - - bool IsOfActor(MOID checkMOID); - - /// - /// Gives a unique, contiguous id per-actor. This is regenerated every frame. - /// - /// The actor to get a contiguous id for. - /// A contiguous id for the actor. Returns -1 if the actor doesn't exist in MovableMan. - /// This function is used for AI throttling. - int GetContiguousActorID(const Actor *actor) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRootMOID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Produces the root MOID of the MOID of a potential child MO to another MO. -// Arguments: An MOID to get the root MOID of. -// Return value: The MOID of the root MO of the MO the passed-in MOID represents. This -// will be the same as the MOID passed in if the MO is a root itself. It will -// be equal to g_NoMOID if the MOID isn't allocated to an MO. - - MOID GetRootMOID(MOID checkMOID); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveMO -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a MovableObject from the any and all internal lists of MO:s. -// After the MO is removed, ownership is effectively released and -// transferred to whatever client called this method. -// Arguments: A pointer to the MovableObject to remove. -// Return value: Whether the object was found in MovableMan's custody, and consequently -// removed. If the MO entry wasn't found, false is returned. - - bool RemoveMO(MovableObject *pMOToRem); - - /// - /// Kills and destroys all Actors of a specific Team. - /// - /// The team to annihilate. If NoTeam is passed in, then NO Actors die. - /// How many Actors were killed. - int KillAllTeamActors(int teamToKill) const; - - /// - /// Kills and destroys all enemy Actors of a specific Team. - /// - /// The team to NOT annihilate. If NoTeam is passed in, then ALL Actors die. - /// How many Actors were killed. - int KillAllEnemyActors(int teamNotToKill = Activity::NoTeam) const; - - /// - /// Adds all Actors in MovableMan to the given list. - /// - /// Whether or not ownership of the Actors should be transferred from MovableMan to the list. - /// The list to be filled with Actors. - /// The team to get Actors of. If NoTeam, then all teams will be used. - /// Whether or not to get brain Actors. - /// The number of Actors added to the list. - int GetAllActors(bool transferOwnership, std::list &actorList, int onlyTeam = -1, bool noBrains = false); - - /// - /// Whether or not ownershp of the items shoudl be transferred from MovableMan to the list. - /// The list to be filled with items. - /// The number of items added to the list. - int GetAllItems(bool transferOwnership, std::list &itemList); - - /// - /// Adds all particles in MovableMan to the given list. - /// - /// Whether or not ownership of the particles should be transferred from MovableMan to the list. - /// The list to be filled with particles. - /// The number of particles added to the list. - int GetAllParticles(bool transferOwnership, std::list &particleList); - - /// - /// Opens all doors and keeps them open until this is called again with false. - /// - /// Whether to open all doors (true), or close all doors (false). - /// Which team to open doors for. NoTeam means all teams. - void OpenAllDoors(bool open = true, int team = Activity::NoTeam) const; - - /// - /// Temporarily erases or redraws any material door representations of a specific team. - /// Used to make pathfinding work better, allowing Actors to navigate through firendly bases despite the door material layer. - /// - /// Whether to erase door material, thereby overriding it, or redraw it and undo the override. - /// Which team to do this for, NoTeam means all teams. - void OverrideMaterialDoors(bool eraseDoorMaterial, int team = Activity::NoTeam) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RegisterAlarmEvent -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registers an AlarmEvent to notify things around that somehting alarming -// like a gunshot or explosion just happened. -// Arguments: The AlarmEvent to register. -// Return value: None. - - void RegisterAlarmEvent(const AlarmEvent &newEvent); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAlarmEvents -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of AlarmEvent:s from last frame's update. -// Arguments: None. -// Return value: The const list of AlarmEvent:s. - - const std::vector & GetAlarmEvents() const { return m_AlarmEvents; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsParticleSettlingEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whetehr particles are set to get copied to the terrain upon -// settling -// Arguments: None. -// Return value: Whether enabled or not. - - bool IsParticleSettlingEnabled() { return m_SettlingEnabled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnableParticleSettling -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether particles will get copied into the terrain upon them -// settling down. -// Arguments: Whether to enable or not. -// Return value: None. - - void EnableParticleSettling(bool enable = true) { m_SettlingEnabled = enable; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsMOSubtractionEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether MO's sihouettes can get subtracted from the terrain at all. -// Arguments: None. -// Return value: Whether enabled or not. - - bool IsMOSubtractionEnabled() { return m_MOSubtractionEnabled; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RedrawOverlappingMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces all objects potnetially overlapping a specific MO to re-draw -// this MOID representations onto the MOID bitmap. -// Arguments: A pointer to the MO to check for overlaps against. Ownerhip is NOT -// transferred. -// Return value: None. - - void RedrawOverlappingMOIDs(MovableObject *pOverlapsThis); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this MovableMan. Supposed to be done every frame. -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawMatter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MovableMan's all MO's current material representations to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void DrawMatter(BITMAP *pTargetBitmap, Vector& targetPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateDrawMOIDs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the MOIDs of all current MOs and draws their ID's to a BITMAP -// of choice. If there are more than 255 MO's to draw, some will not be. -// Arguments: A pointer to a BITMAP to draw on. -// Return value: None. - - void UpdateDrawMOIDs(BITMAP *pTargetBitmap); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this MovableMan's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawHUD -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the HUDs of all MovableObject:s of this MovableMan to a BITMAP -// of choice. -// Arguments: A pointer to a BITMAP to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Which player's screen is being drawn. Tis affects which actor's HUDs -// get drawn. -// Return value: None. - - void DrawHUD(BITMAP *pTargetBitmap, const Vector &targetPos = Vector(), int which = 0, bool playerControlled = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: VerifyMOIDIndex -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Verifieis whether all elements of MOID index has correct ID. Should be used in Debug mode only. -// Arguments: None. -// Return value: None. - - void VerifyMOIDIndex(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RegisterObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registers an object in a global Map collection so it could be found later with FindObjectByUniqueId -// Arguments: MO to register. -// Return value: None. - - void RegisterObject(MovableObject * mo); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UnregisterObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes an object from the global lookup collection -// Arguments: MO to remove. -// Return value: None. - - void UnregisterObject(MovableObject * mo); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FindObjectByUniqueId -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Uses a global lookup map to find an object by it's unique id. -// Arguments: Unique Id to look for. -// Return value: Object found or 0 if not found any. - - MovableObject * FindObjectByUniqueID(long int id) { if (m_KnownObjects.count(id) > 0) return m_KnownObjects[id]; else return 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetKnownObjectsCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the size of the object registry collection -// Arguments: None. -// Return value: Size of the objects registry. - - unsigned int GetKnownObjectsCount() { return m_KnownObjects.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSimUpdateFrameNumber -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the current sim update frame number -// Arguments: None. -// Return value: Current sim update frame number. - - unsigned int GetSimUpdateFrameNumber() const { return m_SimUpdateFrameNumber; } - - /// - /// Gets pointers to the MOs that are within the given Box, and whose team is not ignored. - /// - /// The Box to get MOs within. - /// The team to ignore. - /// Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. - /// Pointers to the MOs that are within the given Box, and whose team is not ignored. - const std::vector *GetMOsInBox(const Box &box, int ignoreTeam, bool getsHitByMOsOnly) const; - - /// - /// Gets pointers to the MOs that are within the given Box, and whose team is not ignored. - /// - /// The Box to get MOs within. - /// The team to ignore. - /// Pointers to the MOs that are within the given Box, and whose team is not ignored. - const std::vector *GetMOsInBox(const Box &box, int ignoreTeam) const { return GetMOsInBox(box, ignoreTeam, false); } - - /// - /// Gets pointers to the MOs that are within the given Box. - /// - /// The Box to get MOs within. - /// Pointers to the MOs that are within the given Box. - const std::vector * GetMOsInBox(const Box &box) const { return GetMOsInBox(box, Activity::NoTeam); } - - /// - /// Gets pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. - /// - /// The position to check for MOs in. - /// The radius to check for MOs within. - /// The team to ignore. - /// Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. - /// Pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. - const std::vector *GetMOsInRadius(const Vector ¢re, float radius, int ignoreTeam, bool getsHitByMOsOnly) const; - - /// - /// Gets pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. - /// - /// The position to check for MOs in. - /// The radius to check for MOs within. - /// The team to ignore. - /// Pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. - const std::vector *GetMOsInRadius(const Vector ¢re, float radius, int ignoreTeam) const { return GetMOsInRadius(centre, radius, ignoreTeam, false); } - - /// - /// Gets pointers to the MOs that are within the specified radius of the given centre position. - /// - /// The position to check for MOs in. - /// The radius to check for MOs within. - /// Pointers to the MOs that are within the specified radius of the given centre position. - const std::vector * GetMOsInRadius(const Vector ¢re, float radius) const { return GetMOsInRadius(centre, radius, Activity::NoTeam); } - - /// - /// Runs a lua function on all MOs in the simulation, including owned child MOs. - /// - void RunLuaFunctionOnAllMOs(const std::string& functionName, bool includeAdded, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector(), const std::vector& functionObjectArguments = std::vector()); - - /// - /// Clears all cached lua functions on all MOs, including owned child MOs. - /// - void ReloadLuaScripts(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // All actors in the scene - std::deque m_Actors; - // A map to give a unique contiguous identifier per-actor. This is re-created per frame. - std::unordered_map m_ContiguousActorIDs; - // List of items that are pickup-able by actors - std::deque m_Items; - // List of free, dead particles flying around - std::deque m_Particles; - // These are the actors/items/particles which were added during a frame. - // They are moved to the containers above at the end of the frame. - std::deque m_AddedActors; - std::deque m_AddedItems; - std::deque m_AddedParticles; - - // Currently active MOs in the simulation. This is required because the code is awful and ownership isn't transported to/from lua in any sensible way. - // It's entirely possible that stuff is deleted in the game but a reference to it is kept in Lua. Which is awful. Obviously. - // Or perhaps even more concerningly, stuff can be deleted, re-allocated over the same space, and then readded to movableman. Which even this solution does nothing to fix. - // Anyways, until we fix up ownership semantics... this is the best we can do. - std::unordered_set m_ValidActors; - std::unordered_set m_ValidItems; - std::unordered_set m_ValidParticles; - - // Mutexes to ensure MOs aren't being removed from separate threads at the same time - std::mutex m_ActorsMutex; - std::mutex m_ItemsMutex; - std::mutex m_ParticlesMutex; - - // Mutexes to ensure MOs aren't being added from separate threads at the same time - std::mutex m_AddedActorsMutex; - std::mutex m_AddedItemsMutex; - std::mutex m_AddedParticlesMutex; - - // Mutex to ensure objects aren't registered/deregistered from separate threads at the same time - std::mutex m_ObjectRegisteredMutex; - - // Mutex to ensure actors don't change team roster from seperate threads at the same time - std::mutex m_ActorRosterMutex; - - // Async to draw MOIDs while rendering - std::future m_DrawMOIDsTask; - - // Roster of each team's actors, sorted by their X positions in the scene. Actors not owned here - std::list m_ActorRoster[Activity::MaxTeamCount]; - // Whether to draw HUD lines between the actors of a specific team - bool m_SortTeamRoster[Activity::MaxTeamCount]; - // Every team's MO footprint - int m_TeamMOIDCount[Activity::MaxTeamCount]; - - // The alarm events on the scene where something alarming happened, for use with AI firings awareness os they react to shots fired etc. - // This is the last frame's events, is the one for Actors to poll for events, should be cleaned out and refilled each frame. - std::vector m_AlarmEvents; - // The alarm events on the scene where something alarming happened, for use with AI firings awareness os they react to shots fired etc. - // This is the current frame's events, will be filled up during MovableMan Updates, should be transferred to Last Frame at end of update. - std::vector m_AddedAlarmEvents; - - // Mutexes to ensure alarm events aren't being added from separate threads at the same time - std::mutex m_AddedAlarmEventsMutex; - - // The list created each frame to register all the current MO's - std::vector m_MOIDIndex; - - // The ration of terrain pixels to be converted into MOPixel:s upon - // deep impact of MO. - float m_SplashRatio; - // The maximum number of loose items allowed. - int m_MaxDroppedItems; - - // Whether settling of particles is enabled or not - bool m_SettlingEnabled; - // Whtehr MO's vcanng et subtracted form the terrain at all - bool m_MOSubtractionEnabled; - - unsigned int m_SimUpdateFrameNumber; - - // Global map which stores all objects so they could be foud by their unique ID - std::map m_KnownObjects; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MovableMan, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - /// - /// Travels all of our MOs, updating their location/velocity/physical characteristics. - /// - void Travel(); - - /// - /// Updates the controllers of all the actors we own. - /// This is needed for a tricky reason - we want the controller from the activity to override the normal controller state - /// So we need to update the controller state prior to activity, so the changes from activity are layered on top. - /// - void UpdateControllers(); - - /// - /// Updates all things that need to be done before we update the controllers. - /// This is needed because of a very awkward and ugly old code path where controllers were updated in the middle of update, and various mods relied of this behaviour for actions that were therefore delayed by a frame - /// Ideally we wouldn't need this, but this is all very fragile code and I'd prefer to avoid breaking things. - /// - void PreControllerUpdate(); - - // Disallow the use of some implicit methods. - MovableMan(const MovableMan &reference) = delete; - MovableMan & operator=(const MovableMan &rhs) = delete; - -}; +namespace RTE { + + class MovableObject; + class Actor; + class HeldDevice; + class MOPixel; + class MOSprite; + class AHuman; + class SceneLayer; + class SceneObject; + class Box; + class LuabindObjectWrapper; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Struct: AlarmEvent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A struct to keep all data about a an alarming event for the AI Actors. + // Parent(s): None. + // Class history: 10/3/2008 AlarmEvent created. + + struct AlarmEvent { + AlarmEvent() { + m_ScenePos.Reset(); + m_Team = Activity::NoTeam; + m_Range = 1.0F; + } + // TODO: Stop relying on screen width for this shit! + AlarmEvent(const Vector& pos, int team = Activity::NoTeam, float range = 1.0F); + + // Absolute position in the scene where this occurred + Vector m_ScenePos; + // The team of whatever object that caused this event + Activity::Teams m_Team; + // The range multiplier, that this alarming event can be heard + float m_Range; + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: MovableMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The singleton manager of all movable objects in the RTE. + // Parent(s): Singleton, Serializable. + // Class history: 12/25/2001 MovableMan created. + + class MovableMan : public Singleton, public Serializable { + friend class SettingsMan; + friend struct ManagerLuaBindings; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableClassNameGetter; + SerializableOverrideMethods; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MovableMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a MovableMan object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + MovableMan() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~MovableMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a MovableMan object before deletion + // from system memory. + // Arguments: None. + + ~MovableMan() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MovableMan object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Initialize(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire MovableMan, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MovableMan object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMOFromID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a MO from its MOID. Note that MOID's are only valid during the + // same frame as they were assigned to the MOs! + // Arguments: The MOID to get the matching MO from. + // Return value: A pointer to the requested MovableObject instance. 0 if no MO with that + // MOID was found. 0 if 0 was passed in as MOID (no MOID). Ownership is + // *NOT* transferred!! + + MovableObject* GetMOFromID(MOID whichID); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMOIDCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of MOID's currently in use this frame. + // Arguments: None. + // Return value: The count of MOIDs in use this frame. + + int GetMOIDCount() { return m_MOIDIndex.size(); } + + /// + /// Gets a MOID from pixel coordinates in the Scene. + /// + /// The X coordinate of the Scene pixel to get the MOID of. + /// The Y coordinate of the Scene pixel to get the MOID of. + /// The collection of MOIDs to check the against the specified coordinates. + /// The topmost MOID currently at the specified pixel coordinates. + MOID GetMOIDPixel(int pixelX, int pixelY, const std::vector& moidList); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTeamMOIDCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns MO count for specified team + // Arguments: Team to count MO's + // Return value: MO's count owned by this team + + int GetTeamMOIDCount(int team) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PurgeAllMOs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears out all MovableObject:s out of this. Effectively empties the world + // of anything moving, without resetting all of this' settings. + // Arguments: None. + // Return value: None. + + void PurgeAllMOs(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextActorInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the first Actor in the internal Actor list that is + // of a specifc group, alternatively the first one AFTER a specific actor! + // Arguments: Which group to try to get an Actor for. + // A pointer to an Actor to use as starting point in the forward search. + // Ownership NOT xferred! + // Return value: An Actor pointer to the requested team's first Actor encountered + // in the list. 0 if there are no Actors of that team. + + Actor* GetNextActorInGroup(std::string group, Actor* pAfterThis = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPrevActorInGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the last Actor in the internal Actor list that is + // of a specifc group, alternatively the last one BEFORE a specific actor! + // Arguments: Which group to try to get an Actor for. + // A pointer to an Actor to use as starting point in the backward search. + // Ownership NOT xferred! + // Return value: An Actor pointer to the requested team's last Actor encountered + // in the list. 0 if there are no Actors of that team. + + Actor* GetPrevActorInGroup(std::string group, Actor* pBeforeThis = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTeamRoster + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of all actors on one team, ordered by their X positions. + // Arguments: Which team to try to get the roster for. + // Return value: A pointer to the list of all the actors on the specified team, sorted + // ascending by their X posistions. Ownership of the list or contained + // actors is NOT transferred! + + std::list* GetTeamRoster(int team = 0) { return &(m_ActorRoster[team]); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextTeamActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the first Actor in the internal Actor list that is + // of a specifc team, alternatively the first one AFTER a specific actor! + // Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. + // A pointer to an Actor to use as starting point in the forward search. + // Ownership NOT xferred! + // Return value: An Actor pointer to the requested team's first Actor encountered + // in the list. 0 if there are no Actors of that team. + + Actor* GetNextTeamActor(int team = 0, Actor* pAfterThis = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPrevTeamActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the last Actor in the internal Actor list that is + // of a specifc team, alternatively the last one BEFORE a specific actor! + // Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. + // A pointer to an Actor to use as starting point in the backward search. + // Ownership NOT xferred! + // Return value: An Actor pointer to the requested team's last Actor encountered + // in the list. 0 if there are no Actors of that team. + + Actor* GetPrevTeamActor(int team = 0, Actor* pBeforeThis = 0); + + /// + /// Get a pointer to an Actor in the internal Actor list that is of a specifc team and closest to a specific scene point. + /// + /// Which team to try to get an Actor for. 0 means first team, 1 means 2nd. + /// The player to get the Actor for. This affects which brain can be marked. + /// The Scene point to search for the closest to. + /// The maximum radius around that scene point to search. + /// A Vector to be filled out with the distance of the returned closest to the search point. Will be unaltered if no object was found within radius. + /// An Actor to exclude from the search. OWNERSHIP IS NOT TRANSFERRED! + /// An Actor pointer to the requested team's Actor closest to the Scene point, but not outside the max radius. If no Actor other than the excluded one was found within the radius of the point, nullptr is returned. + Actor* GetClosestTeamActor(int team, int player, const Vector& scenePoint, int maxRadius, Vector& getDistance, const Actor* excludeThis = nullptr) { return GetClosestTeamActor(team, player, scenePoint, maxRadius, getDistance, false, excludeThis); } + + /// + /// Get a pointer to an Actor in the internal Actor list that is of a specifc team and closest to a specific scene point. + /// + /// Which team to try to get an Actor for. 0 means first team, 1 means 2nd. + /// The player to get the Actor for. This affects which brain can be marked. + /// The Scene point to search for the closest to. + /// The maximum radius around that scene point to search. + /// A Vector to be filled out with the distance of the returned closest to the search point. Will be unaltered if no object was found within radius. + /// Whether to only get Actors that are flagged as player controllable. + /// An Actor to exclude from the search. OWNERSHIP IS NOT TRANSFERRED! + /// An Actor pointer to the requested team's Actor closest to the Scene point, but not outside the max radius. If no Actor other than the excluded one was found within the radius of the point, nullptr is returned. + Actor* GetClosestTeamActor(int team, int player, const Vector& scenePoint, int maxRadius, Vector& getDistance, bool onlyPlayerControllableActors, const Actor* excludeThis = nullptr); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestEnemyActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to an Actor in the internal Actor list that is is not of + // the specified team and closest to a specific scene point. + // Arguments: Which team to try to get an enemy Actor for. NoTeam means all teams. + // The Scene point to search for the closest to. + // The maximum radius around that scene point to search. + // A Vector to be filled out with the distance of the returned closest to + // the search point. Will be unaltered if no object was found within radius. + // Return value: An Actor pointer to the enemy closest to the Scene + // point, but not outside the max radius. If no Actor + // was found within the radius of the point, 0 is returned. + + Actor* GetClosestEnemyActor(int team, const Vector& scenePoint, int maxRadius, Vector& getDistance); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFirstTeamActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to first best Actor in the internal Actor list that is + // of a specifc team. + // Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. + // The player to get the Actor for. This affects which brain can be marked. + // Return value: An Actor pointer to the first one of the requested team. If no Actor + // is in that team, 0 is returned. + + Actor* GetFirstTeamActor(int team, int player) { + Vector temp; + return GetClosestTeamActor(team, player, Vector(), 10000000, temp); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to an Actor in the internal Actor list that is closest + // to a specific scene point. + // Arguments: Which team to try to get an Actor for. 0 means first team, 1 means 2nd. + // The Scene point to search for the closest to. + // The maximum radius around that scene point to search. + // A Vector to be filled out with the distance of the returned closest to + // the search point. Will be unaltered if no object was found within radius. + // An Actor to exclude from the search. OWNERSHIP IS NOT TRANSFERRED! + // Return value: An Actor pointer to the requested Actor closest to the Scene + // point, but not outside the max radius. If no Actor other than the + // excluded one was found within the radius of the point, 0 is returned. + + Actor* GetClosestActor(const Vector& scenePoint, int maxRadius, Vector& getDistance, const Actor* pExcludeThis = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestBrainActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the brain actor of a specific team that is closest to + // a scene point. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. + // The point in the scene where to look for the closest opposite team brain. + // Return value: An Actor pointer to the requested team's brain closest to the point. + // 0 if there are no brains of that team. OWNERSHIP IS NOT TRANSFERRED! + + Actor* GetClosestBrainActor(int team, const Vector& scenePoint) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFirstBrainActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the brain actor of a specific team that is closest to + // a scene point. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. + // The point in the scene where to look for the closest opposite team brain. + // Return value: An Actor pointer to the requested team's brain closest to the point. + // 0 if there are no brains of that team. OWNERSHIP IS NOT TRANSFERRED! + + Actor* GetFirstBrainActor(int team) const { return GetClosestBrainActor(team, Vector()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetClosestOtherBrainActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the brain actor NOT of a specific team that is closest + // to a scene point. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: Which team to NOT get the brain for. 0 means first team, 1 means 2nd. + // The point where to look for the closest brain not of this team. + // Return value: An Actor pointer to the requested brain closest to the point. + // 0 if there are no brains not on that team. OWNERSHIP IS NOT TRANSFERRED! + + Actor* GetClosestOtherBrainActor(int notOfTeam, const Vector& scenePoint) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetFirstOtherBrainActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the brain actor NOT of a specific team. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: Which team to NOT get the brain for. 0 means first team, 1 means 2nd. + // Return value: An Actor pointer to the requested brain of that team. + // 0 if there are no brains not on that team. OWNERSHIP IS NOT TRANSFERRED! + + Actor* GetFirstOtherBrainActor(int notOfTeam) const { return GetClosestOtherBrainActor(notOfTeam, Vector()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetUnassignedBrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Get a pointer to the first brain actor of a specific team which hasn't + // been assigned to a player yet. + // Arguments: Which team to try to get the brain for. 0 means first team, 1 means 2nd. + // Return value: An Actor pointer to the requested team's first brain encountered + // in the list that hasn't been assigned to a player. 0 if there are no + // unassigned brains of that team. + + Actor* GetUnassignedBrain(int team = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActorCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of actors currently held. + // Arguments: None. + // Return value: The number of actors. + + long GetActorCount() const { return m_Actors.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetParticleCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the number of particles (MOPixel:s) currently held. + // Arguments: None. + // Return value: The number of particles. + + long GetParticleCount() const { return m_Particles.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSplashRatio + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the global setting for how much splash MOPixels should be created + // an MO penetrates the terrain deeply. + // Arguments: None. + // Return value: A float with the global splash amount setting, form 1.0 to 0.0. + + float GetSplashRatio() const { return m_SplashRatio; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMaxDroppedItems + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the max number of dropped items that will be reached before the + // first dropped with be copied to the terrain. + // Arguments: An int spefifying the limit. + // Return value: None. + + void SetMaxDroppedItems(int newLimit) { m_MaxDroppedItems = newLimit; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaxDroppedItems + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the max number of dropped items that will be reached before the + // first dropped with be copied to the terrain. + // Arguments: None. + // Return value: An int spefifying the limit. + + int GetMaxDroppedItems() const { return m_MaxDroppedItems; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SortTeamRoster + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets this to draw HUD lines for a specific team's roster this frame. + // Arguments: Which team to have lines drawn of. + // Return value: None. + + void SortTeamRoster(int team) { m_SortTeamRoster[team] = true; } + + /// + /// Adds a MovableObject to this, after it is determined what it is and the best way to add it is. E.g. if it's an Actor, it will be added as such. Ownership IS transferred! + /// + /// A pointer to the MovableObject to add. Ownership IS transferred! + /// Whether the MovableObject was successfully added or not. Note that Ownership IS transferred either way, but the MovableObject will be deleted if this is not successful. + bool AddMO(MovableObject* movableObjectToAdd); + + /// + /// Adds an Actor to the internal list of Actors. Destruction and deletion will be taken care of automatically. Ownership IS transferred! + /// + /// A pointer to the Actor to add. Ownership IS transferred! + void AddActor(Actor* actorToAdd); + + /// + /// Adds a pickup-able item to the internal list of items. Destruction and deletion will be taken care of automatically. Ownership IS transferred! + /// + /// A pointer to the item to add. Ownership IS transferred! + void AddItem(HeldDevice* itemToAdd); + + /// + /// Adds a MovableObject to the internal list of particles. Destruction and deletion will be taken care of automatically. Ownership IS transferred! + /// + /// A pointer to the MovableObject to add. Ownership is transferred! + void AddParticle(MovableObject* particleToAdd); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes an Actor from the internal list of MO:s. After the Actor is + // removed, ownership is effectively released and transferred to whatever + // client called this method. + // Arguments: A pointer to the MovableObject to remove. + // Return value: Whether the object was found in the particle list, and consequently + // removed. If the particle entry wasn't found, false is returned. + + Actor* RemoveActor(MovableObject* pActorToRem); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a pickup-able MovableObject item from the internal list of + // MO:s. After the item is removed, ownership is effectively released and + // transferred to whatever client called this method. + // Arguments: A pointer to the MovableObject to remove. + // Return value: Whether the object was found in the particle list, and consequently + // removed. If the particle entry wasn't found, false is returned. + + MovableObject* RemoveItem(MovableObject* pItemToRem); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveParticle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a MovableObject from the internal list of MO:s. After the + // MO is removed, ownership is effectively released and transferred to + // whatever client called this method. + // Arguments: A pointer to the MovableObject to remove. + // Return value: Whether the object was found in the particle list, and consequently + // removed. If the particle entry wasn't found, false is returned. + + MovableObject* RemoveParticle(MovableObject* pMOToRem); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeActorTeam + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes actor team and updates team rosters. + // Arguments: Pointer to actor, new team value + // Return value: None. + + void ChangeActorTeam(Actor* pActor, int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddActorToTeamRoster + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds actor to internal team roster + // Arguments: Pointer to actor + // Return value: None. + + void AddActorToTeamRoster(Actor* pActorToAdd); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveActorToTeamRoster + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes actor from internal team roster + // Arguments: Pointer to actor + // Return value: None. + + void RemoveActorFromTeamRoster(Actor* pActorToRem); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ValidateMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Goes through and checks that all MOID's have valid MO pointers + // associated with them. This shuold only be used for testing, as it will + // crash the app if validation fails. + // Arguments: None. + // Return value: All MOIDs valid. + + bool ValidateMOIDs(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ValidMO + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject pointer points to an + // MO that's currently active in the simulation, and kept by this + // MovableMan. Internal optimization is made so that the same MO can + // efficiently be checked many times during the same frame. + // Arguments: A pointer to the MovableObject to check for being actively kept by + // this MovableMan. + // Return value: Whether the MO instance was found in the active list or not. + + bool ValidMO(const MovableObject* pMOToCheck); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject is an active Actor kept + // by this MovableMan or not. + // Arguments: A pointer to the MovableObject to check for Actorness. + // Return value: Whether the object was found in the Actor list or not. + + bool IsActor(const MovableObject* pMOToCheck); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsDevice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject is an active Item kept + // by this MovableMan or not. + // Arguments: A pointer to the MovableObject to check for Itemness. + // Return value: Whether the object was found in the Item list or not. + + bool IsDevice(const MovableObject* pMOToCheck); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsParticle + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MovableObject is an active Item kept + // by this MovableMan or not. + // Arguments: A pointer to the MovableObject to check for Itemness. + // Return value: Whether the object was found in the Particle list or not. + + bool IsParticle(const MovableObject* pMOToCheck); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsOfActor + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the passed in MOID is that of an MO which either is + // or is parented to an active Actor by this MovableMan, or not. + // Arguments: An MOID to check for Actorness. + // Return value: Whether the object was found or owned by an MO in the Actor list or not. + + bool IsOfActor(MOID checkMOID); + + /// + /// Gives a unique, contiguous id per-actor. This is regenerated every frame. + /// + /// The actor to get a contiguous id for. + /// A contiguous id for the actor. Returns -1 if the actor doesn't exist in MovableMan. + /// This function is used for AI throttling. + int GetContiguousActorID(const Actor* actor) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRootMOID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Produces the root MOID of the MOID of a potential child MO to another MO. + // Arguments: An MOID to get the root MOID of. + // Return value: The MOID of the root MO of the MO the passed-in MOID represents. This + // will be the same as the MOID passed in if the MO is a root itself. It will + // be equal to g_NoMOID if the MOID isn't allocated to an MO. + + MOID GetRootMOID(MOID checkMOID); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveMO + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a MovableObject from the any and all internal lists of MO:s. + // After the MO is removed, ownership is effectively released and + // transferred to whatever client called this method. + // Arguments: A pointer to the MovableObject to remove. + // Return value: Whether the object was found in MovableMan's custody, and consequently + // removed. If the MO entry wasn't found, false is returned. + + bool RemoveMO(MovableObject* pMOToRem); + + /// + /// Kills and destroys all Actors of a specific Team. + /// + /// The team to annihilate. If NoTeam is passed in, then NO Actors die. + /// How many Actors were killed. + int KillAllTeamActors(int teamToKill) const; + + /// + /// Kills and destroys all enemy Actors of a specific Team. + /// + /// The team to NOT annihilate. If NoTeam is passed in, then ALL Actors die. + /// How many Actors were killed. + int KillAllEnemyActors(int teamNotToKill = Activity::NoTeam) const; + + /// + /// Adds all Actors in MovableMan to the given list. + /// + /// Whether or not ownership of the Actors should be transferred from MovableMan to the list. + /// The list to be filled with Actors. + /// The team to get Actors of. If NoTeam, then all teams will be used. + /// Whether or not to get brain Actors. + /// The number of Actors added to the list. + int GetAllActors(bool transferOwnership, std::list& actorList, int onlyTeam = -1, bool noBrains = false); + + /// + /// Whether or not ownershp of the items shoudl be transferred from MovableMan to the list. + /// The list to be filled with items. + /// The number of items added to the list. + int GetAllItems(bool transferOwnership, std::list& itemList); + + /// + /// Adds all particles in MovableMan to the given list. + /// + /// Whether or not ownership of the particles should be transferred from MovableMan to the list. + /// The list to be filled with particles. + /// The number of particles added to the list. + int GetAllParticles(bool transferOwnership, std::list& particleList); + + /// + /// Opens all doors and keeps them open until this is called again with false. + /// + /// Whether to open all doors (true), or close all doors (false). + /// Which team to open doors for. NoTeam means all teams. + void OpenAllDoors(bool open = true, int team = Activity::NoTeam) const; + + /// + /// Temporarily erases or redraws any material door representations of a specific team. + /// Used to make pathfinding work better, allowing Actors to navigate through firendly bases despite the door material layer. + /// + /// Whether to erase door material, thereby overriding it, or redraw it and undo the override. + /// Which team to do this for, NoTeam means all teams. + void OverrideMaterialDoors(bool eraseDoorMaterial, int team = Activity::NoTeam) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RegisterAlarmEvent + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers an AlarmEvent to notify things around that somehting alarming + // like a gunshot or explosion just happened. + // Arguments: The AlarmEvent to register. + // Return value: None. + + void RegisterAlarmEvent(const AlarmEvent& newEvent); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAlarmEvents + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of AlarmEvent:s from last frame's update. + // Arguments: None. + // Return value: The const list of AlarmEvent:s. + + const std::vector& GetAlarmEvents() const { return m_AlarmEvents; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsParticleSettlingEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whetehr particles are set to get copied to the terrain upon + // settling + // Arguments: None. + // Return value: Whether enabled or not. + + bool IsParticleSettlingEnabled() { return m_SettlingEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnableParticleSettling + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether particles will get copied into the terrain upon them + // settling down. + // Arguments: Whether to enable or not. + // Return value: None. + + void EnableParticleSettling(bool enable = true) { m_SettlingEnabled = enable; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsMOSubtractionEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether MO's sihouettes can get subtracted from the terrain at all. + // Arguments: None. + // Return value: Whether enabled or not. + + bool IsMOSubtractionEnabled() { return m_MOSubtractionEnabled; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RedrawOverlappingMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces all objects potnetially overlapping a specific MO to re-draw + // this MOID representations onto the MOID bitmap. + // Arguments: A pointer to the MO to check for overlaps against. Ownerhip is NOT + // transferred. + // Return value: None. + + void RedrawOverlappingMOIDs(MovableObject* pOverlapsThis); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this MovableMan. Supposed to be done every frame. + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawMatter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MovableMan's all MO's current material representations to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void DrawMatter(BITMAP* pTargetBitmap, Vector& targetPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateDrawMOIDs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the MOIDs of all current MOs and draws their ID's to a BITMAP + // of choice. If there are more than 255 MO's to draw, some will not be. + // Arguments: A pointer to a BITMAP to draw on. + // Return value: None. + + void UpdateDrawMOIDs(BITMAP* pTargetBitmap); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this MovableMan's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawHUD + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the HUDs of all MovableObject:s of this MovableMan to a BITMAP + // of choice. + // Arguments: A pointer to a BITMAP to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Which player's screen is being drawn. Tis affects which actor's HUDs + // get drawn. + // Return value: None. + + void DrawHUD(BITMAP* pTargetBitmap, const Vector& targetPos = Vector(), int which = 0, bool playerControlled = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: VerifyMOIDIndex + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Verifieis whether all elements of MOID index has correct ID. Should be used in Debug mode only. + // Arguments: None. + // Return value: None. + + void VerifyMOIDIndex(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RegisterObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers an object in a global Map collection so it could be found later with FindObjectByUniqueId + // Arguments: MO to register. + // Return value: None. + + void RegisterObject(MovableObject* mo); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UnregisterObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes an object from the global lookup collection + // Arguments: MO to remove. + // Return value: None. + + void UnregisterObject(MovableObject* mo); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FindObjectByUniqueId + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Uses a global lookup map to find an object by it's unique id. + // Arguments: Unique Id to look for. + // Return value: Object found or 0 if not found any. + + MovableObject* FindObjectByUniqueID(long int id) { + if (m_KnownObjects.count(id) > 0) + return m_KnownObjects[id]; + else + return 0; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetKnownObjectsCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the size of the object registry collection + // Arguments: None. + // Return value: Size of the objects registry. + + unsigned int GetKnownObjectsCount() { return m_KnownObjects.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSimUpdateFrameNumber + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the current sim update frame number + // Arguments: None. + // Return value: Current sim update frame number. + + unsigned int GetSimUpdateFrameNumber() const { return m_SimUpdateFrameNumber; } + + /// + /// Gets pointers to the MOs that are within the given Box, and whose team is not ignored. + /// + /// The Box to get MOs within. + /// The team to ignore. + /// Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. + /// Pointers to the MOs that are within the given Box, and whose team is not ignored. + const std::vector* GetMOsInBox(const Box& box, int ignoreTeam, bool getsHitByMOsOnly) const; + + /// + /// Gets pointers to the MOs that are within the given Box, and whose team is not ignored. + /// + /// The Box to get MOs within. + /// The team to ignore. + /// Pointers to the MOs that are within the given Box, and whose team is not ignored. + const std::vector* GetMOsInBox(const Box& box, int ignoreTeam) const { return GetMOsInBox(box, ignoreTeam, false); } + + /// + /// Gets pointers to the MOs that are within the given Box. + /// + /// The Box to get MOs within. + /// Pointers to the MOs that are within the given Box. + const std::vector* GetMOsInBox(const Box& box) const { return GetMOsInBox(box, Activity::NoTeam); } + + /// + /// Gets pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. + /// + /// The position to check for MOs in. + /// The radius to check for MOs within. + /// The team to ignore. + /// Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. + /// Pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. + const std::vector* GetMOsInRadius(const Vector& centre, float radius, int ignoreTeam, bool getsHitByMOsOnly) const; + + /// + /// Gets pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. + /// + /// The position to check for MOs in. + /// The radius to check for MOs within. + /// The team to ignore. + /// Pointers to the MOs that are within the specified radius of the given centre position, and whose team is not ignored. + const std::vector* GetMOsInRadius(const Vector& centre, float radius, int ignoreTeam) const { return GetMOsInRadius(centre, radius, ignoreTeam, false); } + + /// + /// Gets pointers to the MOs that are within the specified radius of the given centre position. + /// + /// The position to check for MOs in. + /// The radius to check for MOs within. + /// Pointers to the MOs that are within the specified radius of the given centre position. + const std::vector* GetMOsInRadius(const Vector& centre, float radius) const { return GetMOsInRadius(centre, radius, Activity::NoTeam); } + + /// + /// Runs a lua function on all MOs in the simulation, including owned child MOs. + /// + void RunLuaFunctionOnAllMOs(const std::string& functionName, bool includeAdded, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector(), const std::vector& functionObjectArguments = std::vector()); + + /// + /// Clears all cached lua functions on all MOs, including owned child MOs. + /// + void ReloadLuaScripts(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // All actors in the scene + std::deque m_Actors; + // A map to give a unique contiguous identifier per-actor. This is re-created per frame. + std::unordered_map m_ContiguousActorIDs; + // List of items that are pickup-able by actors + std::deque m_Items; + // List of free, dead particles flying around + std::deque m_Particles; + // These are the actors/items/particles which were added during a frame. + // They are moved to the containers above at the end of the frame. + std::deque m_AddedActors; + std::deque m_AddedItems; + std::deque m_AddedParticles; + + // Currently active MOs in the simulation. This is required because the code is awful and ownership isn't transported to/from lua in any sensible way. + // It's entirely possible that stuff is deleted in the game but a reference to it is kept in Lua. Which is awful. Obviously. + // Or perhaps even more concerningly, stuff can be deleted, re-allocated over the same space, and then readded to movableman. Which even this solution does nothing to fix. + // Anyways, until we fix up ownership semantics... this is the best we can do. + std::unordered_set m_ValidActors; + std::unordered_set m_ValidItems; + std::unordered_set m_ValidParticles; + + // Mutexes to ensure MOs aren't being removed from separate threads at the same time + std::mutex m_ActorsMutex; + std::mutex m_ItemsMutex; + std::mutex m_ParticlesMutex; + + // Mutexes to ensure MOs aren't being added from separate threads at the same time + std::mutex m_AddedActorsMutex; + std::mutex m_AddedItemsMutex; + std::mutex m_AddedParticlesMutex; + + // Mutex to ensure objects aren't registered/deregistered from separate threads at the same time + std::mutex m_ObjectRegisteredMutex; + + // Mutex to ensure actors don't change team roster from seperate threads at the same time + std::mutex m_ActorRosterMutex; + + // Async to draw MOIDs while rendering + std::future m_DrawMOIDsTask; + + // Roster of each team's actors, sorted by their X positions in the scene. Actors not owned here + std::list m_ActorRoster[Activity::MaxTeamCount]; + // Whether to draw HUD lines between the actors of a specific team + bool m_SortTeamRoster[Activity::MaxTeamCount]; + // Every team's MO footprint + int m_TeamMOIDCount[Activity::MaxTeamCount]; + + // The alarm events on the scene where something alarming happened, for use with AI firings awareness os they react to shots fired etc. + // This is the last frame's events, is the one for Actors to poll for events, should be cleaned out and refilled each frame. + std::vector m_AlarmEvents; + // The alarm events on the scene where something alarming happened, for use with AI firings awareness os they react to shots fired etc. + // This is the current frame's events, will be filled up during MovableMan Updates, should be transferred to Last Frame at end of update. + std::vector m_AddedAlarmEvents; + + // Mutexes to ensure alarm events aren't being added from separate threads at the same time + std::mutex m_AddedAlarmEventsMutex; + + // The list created each frame to register all the current MO's + std::vector m_MOIDIndex; + + // The ration of terrain pixels to be converted into MOPixel:s upon + // deep impact of MO. + float m_SplashRatio; + // The maximum number of loose items allowed. + int m_MaxDroppedItems; + + // Whether settling of particles is enabled or not + bool m_SettlingEnabled; + // Whtehr MO's vcanng et subtracted form the terrain at all + bool m_MOSubtractionEnabled; + + unsigned int m_SimUpdateFrameNumber; + + // Global map which stores all objects so they could be foud by their unique ID + std::map m_KnownObjects; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MovableMan, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + /// + /// Travels all of our MOs, updating their location/velocity/physical characteristics. + /// + void Travel(); + + /// + /// Updates the controllers of all the actors we own. + /// This is needed for a tricky reason - we want the controller from the activity to override the normal controller state + /// So we need to update the controller state prior to activity, so the changes from activity are layered on top. + /// + void UpdateControllers(); + + /// + /// Updates all things that need to be done before we update the controllers. + /// This is needed because of a very awkward and ugly old code path where controllers were updated in the middle of update, and various mods relied of this behaviour for actions that were therefore delayed by a frame + /// Ideally we wouldn't need this, but this is all very fragile code and I'd prefer to avoid breaking things. + /// + void PreControllerUpdate(); + + // Disallow the use of some implicit methods. + MovableMan(const MovableMan& reference) = delete; + MovableMan& operator=(const MovableMan& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Managers/NetworkClient.cpp b/Source/Managers/NetworkClient.cpp index 662ede604..23a5c2378 100644 --- a/Source/Managers/NetworkClient.cpp +++ b/Source/Managers/NetworkClient.cpp @@ -16,7 +16,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::Clear() { m_LastInputSentTime = 0; @@ -53,14 +53,14 @@ namespace RTE { m_MouseButtonReleasedState[i] = -1; } // Stop all sounds received from server - for (const auto &[channelIndex, soundContainer] : m_ServerSounds) { + for (const auto& [channelIndex, soundContainer]: m_ServerSounds) { soundContainer->Stop(); delete soundContainer; } m_ServerSounds.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int NetworkClient::Initialize() { // Record the first client that connects to us so we can pass it to the ping function @@ -70,7 +70,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::Connect(std::string serverName, unsigned short serverPort, std::string playerName) { g_ConsoleMan.PrintString("CLIENT: Connecting to " + serverName); @@ -85,7 +85,7 @@ namespace RTE { g_ConsoleMan.PrintString((connectionAttempt == RakNet::CONNECTION_ATTEMPT_STARTED) ? "CLIENT: Connect request sent" : "CLIENT: Unable to connect"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::ConnectNAT(RakNet::SystemAddress address) { g_ConsoleMan.PrintString("CLIENT: Connecting to server through NAT"); @@ -97,10 +97,12 @@ namespace RTE { g_ConsoleMan.PrintString((connectionAttempt == RakNet::CONNECTION_ATTEMPT_STARTED) ? "CLIENT: Connect request sent" : "CLIENT: Unable to connect"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::Disconnect() { - if (m_IsConnected || m_IsRegistered) { SendDisconnectMsg(); } + if (m_IsConnected || m_IsRegistered) { + SendDisconnectMsg(); + } m_IsRegistered = false; m_IsConnected = false; @@ -110,7 +112,7 @@ namespace RTE { g_ConsoleMan.PrintString("CLIENT: Disconnect"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::PerformNATPunchThrough(std::string serviceServerName, unsigned short serviceServerPort, std::string playerName, std::string serverName, std::string serverPassword) { m_UseNATPunchThroughService = true; @@ -134,14 +136,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - RakNet::SystemAddress NetworkClient::ConnectBlocking(RakNet::RakPeerInterface *rakPeer, const char *address, unsigned short port) { + RakNet::SystemAddress NetworkClient::ConnectBlocking(RakNet::RakPeerInterface* rakPeer, const char* address, unsigned short port) { if (rakPeer->Connect(address, port, nullptr, 0) != RakNet::CONNECTION_ATTEMPT_STARTED) { return RakNet::UNASSIGNED_SYSTEM_ADDRESS; } - RakNet::Packet *packet; + RakNet::Packet* packet; while (true) { for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive()) { if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) { @@ -155,9 +157,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - unsigned char NetworkClient::GetPacketIdentifier(RakNet::Packet *packet) const { + unsigned char NetworkClient::GetPacketIdentifier(RakNet::Packet* packet) const { if (packet == nullptr) { return 255; } @@ -169,7 +171,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::SendRegisterMsg() { MsgRegister msg = {}; @@ -177,47 +179,47 @@ namespace RTE { msg.ResolutionX = g_WindowMan.GetResX(); msg.ResolutionY = g_WindowMan.GetResY(); strncpy(msg.Name, m_PlayerName.c_str(), c_PlayerNameCharLimit); - m_Client->Send((const char *)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); + m_Client->Send((const char*)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); g_ConsoleMan.PrintString("CLIENT: Registration Sent"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::ReceiveAcceptedMsg() { g_ConsoleMan.PrintString("CLIENT: Registration accepted."); m_IsRegistered = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::SendDisconnectMsg() { MsgRegister msg = {}; msg.Id = ID_CLT_DISCONNECT; - m_Client->Send((const char *)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); + m_Client->Send((const char*)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); g_ConsoleMan.PrintString("CLIENT: Disconnection Sent"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::SendServerGUIDRequest(RakNet::SystemAddress address, std::string serverName, std::string serverPassword) { MsgGetServerRequest msg = {}; msg.Id = ID_NAT_SERVER_GET_SERVER_GUID; strncpy(msg.ServerName, serverName.c_str(), 62); strncpy(msg.ServerPassword, serverPassword.c_str(), 62); - m_Client->Send((const char *)&msg, sizeof(RTE::MsgGetServerRequest), IMMEDIATE_PRIORITY, RELIABLE, 0, address, false); + m_Client->Send((const char*)&msg, sizeof(RTE::MsgGetServerRequest), IMMEDIATE_PRIORITY, RELIABLE, 0, address, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveServerGUIDAnswer(RakNet::Packet *packet) { - const MsgGetServerAnswer *msg = (MsgGetServerAnswer *)packet->data; + void NetworkClient::ReceiveServerGUIDAnswer(RakNet::Packet* packet) { + const MsgGetServerAnswer* msg = (MsgGetServerAnswer*)packet->data; m_ServerGUID.FromString(msg->ServerGuid); m_NATPunchthroughClient.OpenNAT(m_ServerGUID, m_NATServiceServerID); g_ConsoleMan.PrintString("CLIENT: Open NAT to server"); g_ConsoleMan.PrintString(m_ServerGUID.ToString()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::SendInputMsg() { MsgInput msg = {}; @@ -253,24 +255,28 @@ namespace RTE { // Store element states as bit flags for (int i = 0; i < INPUT_COUNT; i++) { - if (g_UInputMan.ElementHeld(0, i)) { msg.InputElementState = msg.InputElementState | bitMask; } + if (g_UInputMan.ElementHeld(0, i)) { + msg.InputElementState = msg.InputElementState | bitMask; + } bitMask <<= 1; } g_UInputMan.ClearNetworkAccumulatedStates(); - m_Client->Send((const char *)&msg, sizeof(msg), IMMEDIATE_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); + m_Client->Send((const char*)&msg, sizeof(msg), IMMEDIATE_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveFrameSetupMsg(RakNet::Packet *packet) { - const MsgFrameSetup *frameData = (MsgFrameSetup *)packet->data; + void NetworkClient::ReceiveFrameSetupMsg(RakNet::Packet* packet) { + const MsgFrameSetup* frameData = (MsgFrameSetup*)packet->data; if (frameData->FrameNumber >= c_FramesToRemember) { return; } - if (!g_SettingsMan.UseExperimentalMultiplayerSpeedBoosts()) { DrawFrame(frameData->FrameNumber, frameData->Interlaced, !frameData->DeltaCompressed); } + if (!g_SettingsMan.UseExperimentalMultiplayerSpeedBoosts()) { + DrawFrame(frameData->FrameNumber, frameData->Interlaced, !frameData->DeltaCompressed); + } m_PostEffects[m_CurrentFrameNum].clear(); m_CurrentFrameNum = frameData->FrameNumber; @@ -289,14 +295,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveFrameLineMsg(RakNet::Packet *packet) { - const MsgFrameLine *frameData = (MsgFrameLine *)packet->data; + void NetworkClient::ReceiveFrameLineMsg(RakNet::Packet* packet) { + const MsgFrameLine* frameData = (MsgFrameLine*)packet->data; int lineNumber = frameData->LineNumber; m_CurrentSceneLayerReceived = -1; - BITMAP *bmp = nullptr; + BITMAP* bmp = nullptr; if (frameData->Layer == 0) { bmp = g_FrameMan.GetNetworkBackBufferIntermediate8Ready(0); @@ -320,21 +326,21 @@ namespace RTE { #ifdef _WIN32 memcpy_s(bmp->line[lineNumber], bmp->w, packet->data + sizeof(MsgFrameLine), pixels); #else - //Fallback to non safe memcpy + // Fallback to non safe memcpy memcpy(bmp->line[lineNumber], packet->data + sizeof(MsgFrameLine), pixels); #endif } else { - LZ4_decompress_safe((char *)(packet->data + sizeof(MsgFrameLine)), (char *)(bmp->line[lineNumber]), frameData->DataSize, bmp->w); + LZ4_decompress_safe((char*)(packet->data + sizeof(MsgFrameLine)), (char*)(bmp->line[lineNumber]), frameData->DataSize, bmp->w); } } } release_bitmap(bmp); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveFrameBoxMsg(RakNet::Packet *packet) { - const MsgFrameBox *frameData = (MsgFrameBox *)packet->data; + void NetworkClient::ReceiveFrameBoxMsg(RakNet::Packet* packet) { + const MsgFrameBox* frameData = (MsgFrameBox*)packet->data; if (m_CurrentBoxWidth == 0 || m_CurrentBoxHeight == 0) { return; @@ -344,7 +350,7 @@ namespace RTE { int bpy = frameData->BoxY * m_CurrentBoxHeight; m_CurrentSceneLayerReceived = -1; - BITMAP *bmp = nullptr; + BITMAP* bmp = nullptr; bool isDelta = frameData->Id == ID_SRV_FRAME_BOX_MO_DELTA || frameData->Id == ID_SRV_FRAME_BOX_UI_DELTA; if (frameData->Id == ID_SRV_FRAME_BOX_MO || frameData->Id == ID_SRV_FRAME_BOX_MO_DELTA) { @@ -359,13 +365,19 @@ namespace RTE { int maxHeight = m_CurrentBoxHeight; // If box with default size is out of bounds, then it was truncated by the screen edge - if (bpx + maxWidth >= bmp->w) { maxWidth = bmp->w - bpx; } - if (bpy + maxHeight >= bmp->h) { maxHeight = bmp->h - bpy; } + if (bpx + maxWidth >= bmp->w) { + maxWidth = bmp->w - bpx; + } + if (bpy + maxHeight >= bmp->h) { + maxHeight = bmp->h - bpy; + } int size = frameData->DataSize; int uncompressedSize = maxWidth * maxHeight; - if (m_CurrentFrameInterlaced) { uncompressedSize = maxWidth * (maxHeight / 2); } + if (m_CurrentFrameInterlaced) { + uncompressedSize = maxWidth * (maxHeight / 2); + } float compressionRatio = static_cast(size) / static_cast(uncompressedSize); @@ -385,20 +397,21 @@ namespace RTE { memcpy(m_PixelLineBuffer, packet->data + sizeof(MsgFrameBox), size); #endif } else { - LZ4_decompress_safe((char *)(packet->data + sizeof(MsgFrameBox)), (char *)(m_PixelLineBuffer), size, uncompressedSize); + LZ4_decompress_safe((char*)(packet->data + sizeof(MsgFrameBox)), (char*)(m_PixelLineBuffer), size, uncompressedSize); } - int lineStart = 0; int lineStep = 1; if (m_CurrentFrameInterlaced) { lineStep = 2; - if (m_CurrentFrameNum % 2 != 0) { lineStart = 1; } + if (m_CurrentFrameNum % 2 != 0) { + lineStart = 1; + } } if (isDelta) { - const unsigned char *lineAddr = m_PixelLineBuffer; + const unsigned char* lineAddr = m_PixelLineBuffer; for (int y = lineStart; y < maxHeight; y += lineStep) { for (int x = 0; x < maxWidth; x++) { *(bmp->line[bpy + y] + bpx + x) += lineAddr[x]; @@ -407,7 +420,7 @@ namespace RTE { } } else { // Copy box to bitmap line by line - const unsigned char *lineAddr = m_PixelLineBuffer; + const unsigned char* lineAddr = m_PixelLineBuffer; for (int y = lineStart; y < maxHeight; y += lineStep) { #ifdef _WIN32 memcpy_s(bmp->line[bpy + y] + bpx, maxWidth, lineAddr, maxWidth); @@ -433,19 +446,19 @@ namespace RTE { release_bitmap(bmp); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::SendSceneAcceptedMsg() { MsgRegister msg = {}; msg.Id = ID_CLT_SCENE_ACCEPTED; - m_Client->Send((const char *)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); + m_Client->Send((const char*)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); g_ConsoleMan.PrintString("CLIENT: Scene ACK Sent"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveSceneMsg(RakNet::Packet *packet) { - const MsgSceneLine *frameData = (MsgSceneLine *)packet->data; + void NetworkClient::ReceiveSceneMsg(RakNet::Packet* packet) { + const MsgSceneLine* frameData = (MsgSceneLine*)packet->data; if (frameData->SceneId != m_SceneID) { return; } @@ -453,7 +466,7 @@ namespace RTE { int linex = frameData->X; int liney = frameData->Y; - const BITMAP *bmp = nullptr; + const BITMAP* bmp = nullptr; if (frameData->Layer == 0) { bmp = m_SceneBackgroundBitmap; @@ -477,31 +490,35 @@ namespace RTE { memcpy(bmp->line[liney] + linex, packet->data + sizeof(MsgSceneLine), pixels); #endif } else { - LZ4_decompress_safe((char *)(packet->data + sizeof(MsgSceneLine)), (char *)(bmp->line[liney] + linex), frameData->DataSize, width); + LZ4_decompress_safe((char*)(packet->data + sizeof(MsgSceneLine)), (char*)(bmp->line[liney] + linex), frameData->DataSize, width); } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::ReceiveSceneEndMsg() { g_ConsoleMan.PrintString("CLIENT: Scene received."); SendSceneAcceptedMsg(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveSceneSetupMsg(RakNet::Packet *packet) { + void NetworkClient::ReceiveSceneSetupMsg(RakNet::Packet* packet) { clear_to_color(g_FrameMan.GetNetworkBackBufferIntermediateGUI8Ready(0), g_MaskColor); clear_to_color(g_FrameMan.GetNetworkBackBufferGUI8Ready(0), g_MaskColor); - const MsgSceneSetup *frameData = (MsgSceneSetup *)packet->data; + const MsgSceneSetup* frameData = (MsgSceneSetup*)packet->data; m_SceneID = frameData->SceneId; - if (m_SceneBackgroundBitmap) { destroy_bitmap(m_SceneBackgroundBitmap); } - if (m_SceneForegroundBitmap) { destroy_bitmap(m_SceneForegroundBitmap); } + if (m_SceneBackgroundBitmap) { + destroy_bitmap(m_SceneBackgroundBitmap); + } + if (m_SceneForegroundBitmap) { + destroy_bitmap(m_SceneForegroundBitmap); + } m_SceneBackgroundBitmap = create_bitmap_ex(8, frameData->Width, frameData->Height); m_SceneForegroundBitmap = create_bitmap_ex(8, frameData->Width, frameData->Height); @@ -551,8 +568,8 @@ namespace RTE { } } // Reset network framebuffers - BITMAP *net_bmp = g_FrameMan.GetNetworkBackBufferIntermediate8Ready(0); - BITMAP *net_gui_bmp = g_FrameMan.GetNetworkBackBufferIntermediateGUI8Ready(0); + BITMAP* net_bmp = g_FrameMan.GetNetworkBackBufferIntermediate8Ready(0); + BITMAP* net_gui_bmp = g_FrameMan.GetNetworkBackBufferIntermediateGUI8Ready(0); clear_to_color(net_bmp, ColorKeys::g_MaskColor); clear_to_color(net_gui_bmp, ColorKeys::g_MaskColor); @@ -561,25 +578,25 @@ namespace RTE { g_ConsoleMan.PrintString("CLIENT: Scene setup accepted"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::SendSceneSetupAcceptedMsg() { MsgRegister msg; msg.Id = ID_CLT_SCENE_SETUP_ACCEPTED; - m_Client->Send((const char *)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); + m_Client->Send((const char*)&msg, sizeof(msg), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ServerID, false); g_ConsoleMan.PrintString("CLIENT: Scene setup ACK Sent"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveTerrainChangeMsg(RakNet::Packet *packet) { - const MsgTerrainChange *frameData = (MsgTerrainChange *)packet->data; + void NetworkClient::ReceiveTerrainChangeMsg(RakNet::Packet* packet) { + const MsgTerrainChange* frameData = (MsgTerrainChange*)packet->data; if (frameData->SceneId != m_SceneID) { return; } if (frameData->W == 1 && frameData->H == 1) { - BITMAP *bmp = 0; + BITMAP* bmp = 0; bmp = frameData->Back ? m_SceneBackgroundBitmap : m_SceneForegroundBitmap; putpixel(bmp, frameData->X, frameData->Y, frameData->Color); } else { @@ -592,14 +609,14 @@ namespace RTE { memcpy(m_PixelLineBuffer, packet->data + sizeof(MsgTerrainChange), size); #endif } else { - LZ4_decompress_safe((char *)(packet->data + sizeof(MsgTerrainChange)), (char *)m_PixelLineBuffer, frameData->DataSize, size); + LZ4_decompress_safe((char*)(packet->data + sizeof(MsgTerrainChange)), (char*)m_PixelLineBuffer, frameData->DataSize, size); } // Copy bitmap data to scene bitmap - const BITMAP *bmp = 0; + const BITMAP* bmp = 0; bmp = (frameData->Back) ? m_SceneBackgroundBitmap : m_SceneForegroundBitmap; - const unsigned char *src = m_PixelLineBuffer; + const unsigned char* src = m_PixelLineBuffer; for (int y = 0; y < frameData->H && frameData->Y + y < bmp->h; y++) { memcpy(bmp->line[frameData->Y + y] + frameData->X, src, frameData->W); src += frameData->W; @@ -607,42 +624,44 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceivePostEffectsMsg(RakNet::Packet *packet) { - MsgPostEffects *msg = (MsgPostEffects *)packet->data; - const PostEffectNetworkData *effDataPtr = (PostEffectNetworkData *)((char *)msg + sizeof(MsgPostEffects)); + void NetworkClient::ReceivePostEffectsMsg(RakNet::Packet* packet) { + MsgPostEffects* msg = (MsgPostEffects*)packet->data; + const PostEffectNetworkData* effDataPtr = (PostEffectNetworkData*)((char*)msg + sizeof(MsgPostEffects)); for (int i = 0; i < msg->PostEffectsCount; i++) { - BITMAP *bmp = nullptr; + BITMAP* bmp = nullptr; std::string bitmapPath = ContentFile::GetPathFromHash(effDataPtr->BitmapHash); if (!bitmapPath.empty()) { ContentFile fl(bitmapPath.c_str()); bmp = fl.GetAsBitmap(); } - if (bmp) { m_PostEffects[msg->FrameNumber].push_back(PostEffect(Vector(effDataPtr->X, effDataPtr->Y), bmp, 0, effDataPtr->Strength, effDataPtr->Angle)); } + if (bmp) { + m_PostEffects[msg->FrameNumber].push_back(PostEffect(Vector(effDataPtr->X, effDataPtr->Y), bmp, 0, effDataPtr->Strength, effDataPtr->Angle)); + } effDataPtr++; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveSoundEventsMsg(RakNet::Packet *packet) { - MsgSoundEvents *msg = (MsgSoundEvents *)packet->data; - const AudioMan::NetworkSoundData *soundDataPointer = (AudioMan::NetworkSoundData *)((char *)msg + sizeof(MsgSoundEvents)); - std::unordered_multimap alreadyHandledSoundContainers; + void NetworkClient::ReceiveSoundEventsMsg(RakNet::Packet* packet) { + MsgSoundEvents* msg = (MsgSoundEvents*)packet->data; + const AudioMan::NetworkSoundData* soundDataPointer = (AudioMan::NetworkSoundData*)((char*)msg + sizeof(MsgSoundEvents)); + std::unordered_multimap alreadyHandledSoundContainers; for (int msgIndex = 0; msgIndex < msg->SoundEventsCount; msgIndex++) { if (soundDataPointer->State == AudioMan::SOUND_SET_GLOBAL_PITCH) { g_AudioMan.SetGlobalPitch(soundDataPointer->Pitch); } else { int serverSoundChannelIndex = soundDataPointer->Channel; - std::unordered_map::iterator serverSoundEntryForChannel = m_ServerSounds.find(serverSoundChannelIndex); + std::unordered_map::iterator serverSoundEntryForChannel = m_ServerSounds.find(serverSoundChannelIndex); if (soundDataPointer->State == AudioMan::SOUND_PLAY || serverSoundEntryForChannel != m_ServerSounds.end()) { - SoundContainer *soundContainerToHandle = (serverSoundEntryForChannel == m_ServerSounds.end()) ? nullptr : m_ServerSounds.at(serverSoundChannelIndex); + SoundContainer* soundContainerToHandle = (serverSoundEntryForChannel == m_ServerSounds.end()) ? nullptr : m_ServerSounds.at(serverSoundChannelIndex); auto alreadyHandledSoundStates = alreadyHandledSoundContainers.equal_range(soundContainerToHandle); - bool alreadyHandled = soundDataPointer->State != AudioMan::SOUND_PLAY && std::any_of(alreadyHandledSoundStates.first, alreadyHandledSoundStates.second, [&soundDataPointer](const std::pair &alreadyHandledSoundStateEntry) { return static_cast(alreadyHandledSoundStateEntry.second) == soundDataPointer->State; }); + bool alreadyHandled = soundDataPointer->State != AudioMan::SOUND_PLAY && std::any_of(alreadyHandledSoundStates.first, alreadyHandledSoundStates.second, [&soundDataPointer](const std::pair& alreadyHandledSoundStateEntry) { return static_cast(alreadyHandledSoundStateEntry.second) == soundDataPointer->State; }); if (!alreadyHandled) { switch (soundDataPointer->State) { case AudioMan::SOUND_PLAY: @@ -695,18 +714,20 @@ namespace RTE { } alreadyHandledSoundContainers.insert({soundContainerToHandle, soundDataPointer->State}); } - if (soundDataPointer->State == AudioMan::SOUND_PLAY) { m_ServerSounds.insert({ serverSoundChannelIndex, soundContainerToHandle }); } + if (soundDataPointer->State == AudioMan::SOUND_PLAY) { + m_ServerSounds.insert({serverSoundChannelIndex, soundContainerToHandle}); + } } } soundDataPointer++; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::ReceiveMusicEventsMsg(RakNet::Packet *packet) { - MsgMusicEvents *msg = (MsgMusicEvents *)packet->data; - const AudioMan::NetworkMusicData *musicDataPointer = (AudioMan::NetworkMusicData *)((char *)msg + sizeof(MsgMusicEvents)); + void NetworkClient::ReceiveMusicEventsMsg(RakNet::Packet* packet) { + MsgMusicEvents* msg = (MsgMusicEvents*)packet->data; + const AudioMan::NetworkMusicData* musicDataPointer = (AudioMan::NetworkMusicData*)((char*)msg + sizeof(MsgMusicEvents)); for (int i = 0; i < msg->MusicEventsCount; i++) { switch (musicDataPointer->State) { @@ -720,7 +741,9 @@ namespace RTE { std::snprintf(buf, sizeof(buf), "MUSIC %s %d", path, musicDataPointer->LoopsOrSilence); g_AudioMan.PlayMusic(path, musicDataPointer->LoopsOrSilence); - if (musicDataPointer->Position > 0) { g_AudioMan.SetMusicPosition(musicDataPointer->Position); } + if (musicDataPointer->Position > 0) { + g_AudioMan.SetMusicPosition(musicDataPointer->Position); + } break; case AudioMan::MUSIC_STOP: g_AudioMan.StopMusic(); @@ -739,12 +762,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkClient::DrawBackgrounds(BITMAP *targetBitmap) { + void NetworkClient::DrawBackgrounds(BITMAP* targetBitmap) { for (int i = m_ActiveBackgroundLayers - 1; i >= 0; i--) { if (m_BackgroundBitmaps[i] != 0) { - //masked_blit(m_BackgroundBitmaps[i], targetBitmap, 0, 0, 0, 0, m_BackgroundBitmaps[i]->w, m_BackgroundBitmaps[i]->h); + // masked_blit(m_BackgroundBitmaps[i], targetBitmap, 0, 0, 0, 0, m_BackgroundBitmaps[i]->w, m_BackgroundBitmaps[i]->h); Vector scrollOverride(0, 0); bool scrollOverridden = false; @@ -819,7 +842,7 @@ namespace RTE { set_clip_rect(targetBitmap, targetBox.GetCorner().m_X, targetBox.GetCorner().m_Y, targetBox.GetCorner().m_X + targetBox.GetWidth() - 1, targetBox.GetCorner().m_Y + targetBox.GetHeight() - 1); // Choose the correct blitting function based on transparency setting - void(*pfBlit)(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) = m_BackgroundLayers[frame][i].DrawTrans ? &masked_blit : &blit; + void (*pfBlit)(BITMAP* source, BITMAP* dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) = m_BackgroundLayers[frame][i].DrawTrans ? &masked_blit : &blit; // See if this SceneLayer is wider AND higher than the target bitmap; then use simple wrapping logic - otherwise need to tile if (m_BackgroundBitmaps[i]->w >= targetBitmap->w && m_BackgroundBitmaps[i]->h >= targetBitmap->h) { @@ -921,20 +944,20 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::DrawPostEffects(int frame) { g_PostProcessMan.SetNetworkPostEffectsList(0, m_PostEffects[frame]); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::DrawFrame(int frameNumber, bool useInterlacing, bool clearFramebuffer) { - BITMAP *src_bmp = g_FrameMan.GetNetworkBackBufferIntermediate8Ready(0); - BITMAP *dst_bmp = g_FrameMan.GetNetworkBackBuffer8Ready(0); + BITMAP* src_bmp = g_FrameMan.GetNetworkBackBufferIntermediate8Ready(0); + BITMAP* dst_bmp = g_FrameMan.GetNetworkBackBuffer8Ready(0); - BITMAP *src_gui_bmp = g_FrameMan.GetNetworkBackBufferIntermediateGUI8Ready(0); - BITMAP *dst_gui_bmp = g_FrameMan.GetNetworkBackBufferGUI8Ready(0); + BITMAP* src_gui_bmp = g_FrameMan.GetNetworkBackBufferIntermediateGUI8Ready(0); + BITMAP* dst_gui_bmp = g_FrameMan.GetNetworkBackBufferGUI8Ready(0); // Have to clear to color to fallback if there's no skybox on client clear_to_color(dst_bmp, g_BlackColor); @@ -962,7 +985,7 @@ namespace RTE { masked_blit(m_SceneBackgroundBitmap, dst_bmp, 0, sourceY, newDestX, destY, width, src_bmp->h); } - //Draw received bitmap + // Draw received bitmap masked_blit(src_bmp, dst_bmp, 0, 0, 0, 0, src_bmp->w, src_bmp->h); masked_blit(src_gui_bmp, dst_gui_bmp, 0, 0, 0, 0, src_bmp->w, src_bmp->h); masked_blit(m_SceneForegroundBitmap, dst_bmp, sourceX, sourceY, destX, destY, src_bmp->w, src_bmp->h); @@ -993,10 +1016,14 @@ namespace RTE { int boxedWidth = src_bmp->w / m_CurrentBoxWidth; int boxedHeight = src_bmp->h / m_CurrentBoxHeight; - if (src_bmp->w % m_CurrentBoxWidth != 0) { boxedWidth = boxedWidth + 1; } + if (src_bmp->w % m_CurrentBoxWidth != 0) { + boxedWidth = boxedWidth + 1; + } int lineStart = 0; - if (clearEven) { lineStart = 1; } + if (clearEven) { + lineStart = 1; + } for (int by = 0; by <= boxedHeight; by++) { for (int bx = 0; bx <= boxedWidth; bx++) { @@ -1008,10 +1035,14 @@ namespace RTE { } int maxWidth = m_CurrentBoxWidth; - if (bpx + m_CurrentBoxWidth >= src_bmp->w) { maxWidth = src_bmp->w - bpx; } + if (bpx + m_CurrentBoxWidth >= src_bmp->w) { + maxWidth = src_bmp->w - bpx; + } int maxHeight = m_CurrentBoxHeight; - if (bpy + m_CurrentBoxHeight >= src_bmp->h) { maxHeight = src_bmp->h - bpy; } + if (bpy + m_CurrentBoxHeight >= src_bmp->h) { + maxHeight = src_bmp->h - bpy; + } } } } else { @@ -1021,14 +1052,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::Update() { HandleNetworkPackets(); // Draw level loading animation if (m_CurrentSceneLayerReceived != -1) { - BITMAP * bmp = nullptr; + BITMAP* bmp = nullptr; if (m_CurrentSceneLayerReceived == -1) { bmp = m_SceneBackgroundBitmap; @@ -1038,7 +1069,7 @@ namespace RTE { bmp = m_SceneForegroundBitmap; } - BITMAP *dst_bmp = g_FrameMan.GetNetworkBackBuffer8Ready(0); + BITMAP* dst_bmp = g_FrameMan.GetNetworkBackBuffer8Ready(0); clear_to_color(dst_bmp, g_BlackColor); @@ -1048,7 +1079,9 @@ namespace RTE { int x = 0; int y = g_WindowMan.GetResY() / 2 - h / 2; - if (h >= g_WindowMan.GetResY()) { y = 0; } + if (h >= g_WindowMan.GetResY()) { + y = 0; + } // Recalculate everything for tall maps if (static_cast(bmp->h) / static_cast(bmp->w) > 1) { @@ -1058,23 +1091,39 @@ namespace RTE { x = g_WindowMan.GetResX() / 2 - w / 2; y = 0; - if (w >= g_WindowMan.GetResX()) { x = 0; } + if (w >= g_WindowMan.GetResX()) { + x = 0; + } } // Draw previous layer - if (m_CurrentSceneLayerReceived == 1) { masked_stretch_blit(m_SceneBackgroundBitmap, dst_bmp, 0, 0, bmp->w, bmp->h, x, y, w, h); } + if (m_CurrentSceneLayerReceived == 1) { + masked_stretch_blit(m_SceneBackgroundBitmap, dst_bmp, 0, 0, bmp->w, bmp->h, x, y, w, h); + } masked_stretch_blit(bmp, dst_bmp, 0, 0, bmp->w, bmp->h, x, y, w, h); } // Detect short mouse events like presses and releases. Holds are detected during input send - if (m_MouseButtonPressedState[MOUSE_LEFT] < 1) { m_MouseButtonPressedState[MOUSE_LEFT] = g_UInputMan.MouseButtonPressed(MOUSE_LEFT, -1) ? 1 : 0; } - if (m_MouseButtonPressedState[MOUSE_RIGHT] < 1) { m_MouseButtonPressedState[MOUSE_RIGHT] = g_UInputMan.MouseButtonPressed(MOUSE_RIGHT, -1) ? 1 : 0; } - if (m_MouseButtonPressedState[MOUSE_MIDDLE] < 1) { m_MouseButtonPressedState[MOUSE_MIDDLE] = g_UInputMan.MouseButtonPressed(MOUSE_MIDDLE, -1) ? 1 : 0; } + if (m_MouseButtonPressedState[MOUSE_LEFT] < 1) { + m_MouseButtonPressedState[MOUSE_LEFT] = g_UInputMan.MouseButtonPressed(MOUSE_LEFT, -1) ? 1 : 0; + } + if (m_MouseButtonPressedState[MOUSE_RIGHT] < 1) { + m_MouseButtonPressedState[MOUSE_RIGHT] = g_UInputMan.MouseButtonPressed(MOUSE_RIGHT, -1) ? 1 : 0; + } + if (m_MouseButtonPressedState[MOUSE_MIDDLE] < 1) { + m_MouseButtonPressedState[MOUSE_MIDDLE] = g_UInputMan.MouseButtonPressed(MOUSE_MIDDLE, -1) ? 1 : 0; + } - if (m_MouseButtonReleasedState[MOUSE_LEFT] < 1) { m_MouseButtonReleasedState[MOUSE_LEFT] = g_UInputMan.MouseButtonReleased(MOUSE_LEFT, -1) ? 1 : 0; } - if (m_MouseButtonReleasedState[MOUSE_RIGHT] < 1) { m_MouseButtonReleasedState[MOUSE_RIGHT] = g_UInputMan.MouseButtonReleased(MOUSE_RIGHT, -1) ? 1 : 0; } - if (m_MouseButtonReleasedState[MOUSE_MIDDLE] < 1) { m_MouseButtonReleasedState[MOUSE_MIDDLE] = g_UInputMan.MouseButtonReleased(MOUSE_MIDDLE, -1) ? 1 : 0; } + if (m_MouseButtonReleasedState[MOUSE_LEFT] < 1) { + m_MouseButtonReleasedState[MOUSE_LEFT] = g_UInputMan.MouseButtonReleased(MOUSE_LEFT, -1) ? 1 : 0; + } + if (m_MouseButtonReleasedState[MOUSE_RIGHT] < 1) { + m_MouseButtonReleasedState[MOUSE_RIGHT] = g_UInputMan.MouseButtonReleased(MOUSE_RIGHT, -1) ? 1 : 0; + } + if (m_MouseButtonReleasedState[MOUSE_MIDDLE] < 1) { + m_MouseButtonReleasedState[MOUSE_MIDDLE] = g_UInputMan.MouseButtonReleased(MOUSE_MIDDLE, -1) ? 1 : 0; + } if (g_UInputMan.MouseWheelMoved() != 0) { m_MouseWheelMoved = g_UInputMan.MouseWheelMoved(); @@ -1089,12 +1138,16 @@ namespace RTE { #endif long long currentTicks = g_TimerMan.GetRealTickCount(); - if (currentTicks - m_LastInputSentTime < 0) { m_LastInputSentTime = currentTicks; } + if (currentTicks - m_LastInputSentTime < 0) { + m_LastInputSentTime = currentTicks; + } if (static_cast((currentTicks - m_LastInputSentTime)) / static_cast(g_TimerMan.GetTicksPerSecond()) > 1.0 / inputSend) { m_LastInputSentTime = g_TimerMan.GetRealTickCount(); if (IsConnectedAndRegistered()) { - if (g_SettingsMan.UseExperimentalMultiplayerSpeedBoosts()) { DrawFrame(m_CurrentFrameNum, m_CurrentFrameInterlaced, !m_CurrentFrameDeltaCompressed); } + if (g_SettingsMan.UseExperimentalMultiplayerSpeedBoosts()) { + DrawFrame(m_CurrentFrameNum, m_CurrentFrameInterlaced, !m_CurrentFrameDeltaCompressed); + } SendInputMsg(); } } @@ -1104,12 +1157,12 @@ namespace RTE { #endif } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkClient::HandleNetworkPackets() { std::string msg; - for (RakNet::Packet *packet = m_Client->Receive(); packet; m_Client->DeallocatePacket(packet), packet = m_Client->Receive()) { + for (RakNet::Packet* packet = m_Client->Receive(); packet; m_Client->DeallocatePacket(packet), packet = m_Client->Receive()) { // We got a packet, get the identifier with our handy function unsigned char packetIdentifier = GetPacketIdentifier(packet); @@ -1263,4 +1316,4 @@ namespace RTE { } } } -} +} // namespace RTE diff --git a/Source/Managers/NetworkClient.h b/Source/Managers/NetworkClient.h index febe121c0..91504c3f5 100644 --- a/Source/Managers/NetworkClient.h +++ b/Source/Managers/NetworkClient.h @@ -30,12 +30,14 @@ namespace RTE { friend class SettingsMan; public: - #pragma region Creation /// /// Constructor method used to instantiate a NetworkClient object in system memory. Create() should be called before using the object. /// - NetworkClient() { Clear(); Initialize(); } + NetworkClient() { + Clear(); + Initialize(); + } /// /// Makes the NetworkClient object ready for use. @@ -85,7 +87,7 @@ namespace RTE { /// Get the coordinates of the center of the current frame. /// /// A vector containing the X/Y coordinates of the frame target. - const Vector & GetFrameTarget() const { return m_TargetPos[m_CurrentFrameNum]; } + const Vector& GetFrameTarget() const { return m_TargetPos[m_CurrentFrameNum]; } #pragma endregion @@ -133,16 +135,15 @@ namespace RTE { /// /// /// - RakNet::SystemAddress ConnectBlocking(RakNet::RakPeerInterface *rakPeer, const char *address, unsigned short port); + RakNet::SystemAddress ConnectBlocking(RakNet::RakPeerInterface* rakPeer, const char* address, unsigned short port); #pragma endregion protected: - static constexpr unsigned short c_PlayerNameCharLimit = 15; //!< Maximum length of the player name. std::string m_PlayerName; //!< The player name the will be used by the client in network games. - RakNet::RakPeerInterface *m_Client; //!< The client RakPeerInterface. + RakNet::RakPeerInterface* m_Client; //!< The client RakPeerInterface. RakNet::SystemAddress m_ClientID; //!< The client's identifier. RakNet::SystemAddress m_ServerID; //!< The server's identifier. @@ -176,15 +177,15 @@ namespace RTE { Vector m_TargetPos[c_FramesToRemember]; //!< std::list m_PostEffects[c_FramesToRemember]; //!< List of post-effects received from server. - std::unordered_map m_ServerSounds; //!< Unordered map of SoundContainers received from server. OWNED!!! + std::unordered_map m_ServerSounds; //!< Unordered map of SoundContainers received from server. OWNED!!! unsigned char m_SceneID; //!< int m_CurrentSceneLayerReceived; //!< - BITMAP *m_SceneBackgroundBitmap; //!< - BITMAP *m_SceneForegroundBitmap; //!< + BITMAP* m_SceneBackgroundBitmap; //!< + BITMAP* m_SceneForegroundBitmap; //!< - BITMAP *m_BackgroundBitmaps[c_MaxLayersStoredForNetwork]; //!< + BITMAP* m_BackgroundBitmaps[c_MaxLayersStoredForNetwork]; //!< LightweightSceneLayer m_BackgroundLayers[c_FramesToRemember][c_MaxLayersStoredForNetwork]; //!< int m_ActiveBackgroundLayers; //!< bool m_SceneWrapsX; //!< @@ -196,7 +197,6 @@ namespace RTE { int m_MouseWheelMoved; //!< Whether the mouse wheel was moved this Update. Used to make mouse wheel detection better. private: - #pragma region Update Breakdown /// /// @@ -210,7 +210,7 @@ namespace RTE { /// /// /// - unsigned char GetPacketIdentifier(RakNet::Packet *packet) const; + unsigned char GetPacketIdentifier(RakNet::Packet* packet) const; /// /// @@ -239,7 +239,7 @@ namespace RTE { /// /// /// - void ReceiveServerGUIDAnswer(RakNet::Packet *packet); + void ReceiveServerGUIDAnswer(RakNet::Packet* packet); /// /// @@ -250,19 +250,19 @@ namespace RTE { /// /// /// - void ReceiveFrameSetupMsg(RakNet::Packet *packet); + void ReceiveFrameSetupMsg(RakNet::Packet* packet); /// /// /// /// - void ReceiveFrameLineMsg(RakNet::Packet *packet); + void ReceiveFrameLineMsg(RakNet::Packet* packet); /// /// /// /// - void ReceiveFrameBoxMsg(RakNet::Packet *packet); + void ReceiveFrameBoxMsg(RakNet::Packet* packet); /// /// @@ -273,7 +273,7 @@ namespace RTE { /// /// /// - void ReceiveSceneMsg(RakNet::Packet *packet); + void ReceiveSceneMsg(RakNet::Packet* packet); /// /// @@ -284,7 +284,7 @@ namespace RTE { /// /// /// - void ReceiveSceneSetupMsg(RakNet::Packet *packet); + void ReceiveSceneSetupMsg(RakNet::Packet* packet); /// /// @@ -295,25 +295,25 @@ namespace RTE { /// Receive and handle a packet of terrain change data. /// /// The packet to handle. - void ReceiveTerrainChangeMsg(RakNet::Packet *packet); + void ReceiveTerrainChangeMsg(RakNet::Packet* packet); /// /// Receive and handle a packet of post-effect data. /// /// The packet to handle. - void ReceivePostEffectsMsg(RakNet::Packet *packet); + void ReceivePostEffectsMsg(RakNet::Packet* packet); /// /// Receive and handle a packet of sound event data. /// /// The packet to handle. - void ReceiveSoundEventsMsg(RakNet::Packet *packet); + void ReceiveSoundEventsMsg(RakNet::Packet* packet); /// /// Receive and handle a packet of music event data. /// /// The packet to handle. - void ReceiveMusicEventsMsg(RakNet::Packet *packet); + void ReceiveMusicEventsMsg(RakNet::Packet* packet); #pragma endregion #pragma region Drawing @@ -321,7 +321,7 @@ namespace RTE { /// /// /// - void DrawBackgrounds(BITMAP *targetBitmap); + void DrawBackgrounds(BITMAP* targetBitmap); /// /// @@ -350,8 +350,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - NetworkClient(const NetworkClient &reference) = delete; - NetworkClient & operator=(const NetworkClient &rhs) = delete; + NetworkClient(const NetworkClient& reference) = delete; + NetworkClient& operator=(const NetworkClient& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Managers/NetworkServer.cpp b/Source/Managers/NetworkServer.cpp index 8370f51a1..c004e4426 100644 --- a/Source/Managers/NetworkServer.cpp +++ b/Source/Managers/NetworkServer.cpp @@ -25,9 +25,9 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::BackgroundSendThreadFunction(NetworkServer *server, short player) { + void NetworkServer::BackgroundSendThreadFunction(NetworkServer* server, short player) { const int sleepTime = 1000000 / server->m_EncodingFps; while (server->IsServerModeEnabled() && server->IsPlayerConnected(player)) { if (server->NeedToSendSceneSetupData(player) && server->IsSceneAvailable(player)) { @@ -44,10 +44,9 @@ namespace RTE { server->UpdateStats(player); } server->SetThreadExitReason(player, NetworkServer::THREAD_FINISH); - } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::Clear() { m_SleepWhenIdle = false; @@ -148,7 +147,7 @@ namespace RTE { m_LastPackedReceived = nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int NetworkServer::Initialize() { m_IsInServerMode = false; @@ -157,7 +156,7 @@ namespace RTE { m_LastPackedReceived = std::make_unique(); - for (std::unique_ptr &pingTimer : m_PingTimer) { + for (std::unique_ptr& pingTimer: m_PingTimer) { pingTimer = std::make_unique(); } @@ -174,7 +173,9 @@ namespace RTE { if (m_BoxHeight % 2 != 0) { g_ConsoleMan.PrintString("SERVER: Box height must be divisible by 2! Box height will be adjusted!"); m_BoxHeight -= 1; - if (m_BoxHeight == 0) { m_BoxHeight = 2; } + if (m_BoxHeight == 0) { + m_BoxHeight = 2; + } } for (int i = 0; i < c_MaxClients; i++) { @@ -190,10 +191,10 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::Destroy() { - //Send a signal that server is going to shutdown + // Send a signal that server is going to shutdown m_IsInServerMode = false; // Wait for thread to shut down RakSleep(250); @@ -204,34 +205,42 @@ namespace RTE { for (short i = 0; i < c_MaxClients; i++) { DestroyBackBuffer(i); - if (m_LZ4CompressionState[i]) { free(m_LZ4CompressionState[i]); } + if (m_LZ4CompressionState[i]) { + free(m_LZ4CompressionState[i]); + } m_LZ4CompressionState[i] = 0; - if (m_LZ4FastCompressionState[i]) { free(m_LZ4FastCompressionState[i]); } + if (m_LZ4FastCompressionState[i]) { + free(m_LZ4FastCompressionState[i]); + } m_LZ4FastCompressionState[i] = 0; } Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool NetworkServer::ReadyForSimulation() { short playersReady = 0; short playersTotal = 0; for (short player = 0; player < c_MaxClients; player++) { - if (IsPlayerConnected(player)) { playersTotal++; } - if (SendFrameData(player)) { playersReady++; } + if (IsPlayerConnected(player)) { + playersTotal++; + } + if (SendFrameData(player)) { + playersReady++; + } } return playersReady >= playersTotal; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::SetServerPort(const std::string &newPort) { + void NetworkServer::SetServerPort(const std::string& newPort) { bool useDefault = false; - for (const char &stringChar : newPort) { + for (const char& stringChar: newPort) { if (!std::isdigit(stringChar)) { g_ConsoleMan.PrintString("ERROR: Invalid port passed into \"-server\" argument, using default (8000) instead!"); useDefault = true; @@ -241,7 +250,7 @@ namespace RTE { m_ServerPort = useDefault ? "8000" : newPort; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::Start() { RakNet::SocketDescriptor socketDescriptors[1]; @@ -271,7 +280,9 @@ namespace RTE { serverName = g_SettingsMan.GetNATServiceAddress().substr(0, portPos); std::string portStr = g_SettingsMan.GetNATServiceAddress().substr(portPos + 1, g_SettingsMan.GetNATServiceAddress().length() - 2); port = atoi(portStr.c_str()); - if (port == 0) { port = 61111; } + if (port == 0) { + port = 61111; + } } else { serverName = g_SettingsMan.GetNATServiceAddress(); port = 61111; @@ -288,7 +299,7 @@ namespace RTE { m_Server->SetUnreliableTimeout(50); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::LockScene(bool isLocked) { for (int i = 0; i < c_MaxClients; i++) { @@ -300,7 +311,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::ResetScene() { m_SceneID++; @@ -312,7 +323,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::RegisterTerrainChange(NetworkTerrainChange terrainChange) { if (m_IsInServerMode) { @@ -326,9 +337,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - unsigned char NetworkServer::GetPacketIdentifier(RakNet::Packet *packet) const { + unsigned char NetworkServer::GetPacketIdentifier(RakNet::Packet* packet) const { if (packet == 0) { return 255; } @@ -340,9 +351,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::ReceiveNewIncomingConnection(RakNet::Packet *packet) { + void NetworkServer::ReceiveNewIncomingConnection(RakNet::Packet* packet) { std::string msg; RakNet::SystemAddress clientID; char buf[256]; @@ -357,11 +368,11 @@ namespace RTE { RakNet::SystemAddress internalId = RakNet::UNASSIGNED_SYSTEM_ADDRESS; - //g_ConsoleMan.PrintString("SERVER: Remote internal IDs:\n"); + // g_ConsoleMan.PrintString("SERVER: Remote internal IDs:\n"); for (int index = 0; index < MAXIMUM_NUMBER_OF_INTERNAL_IDS; index++) { internalId = m_Server->GetInternalID(packet->systemAddress, index); if (internalId != RakNet::UNASSIGNED_SYSTEM_ADDRESS) { - //g_ConsoleMan.PrintString(internalId.ToString(true)); + // g_ConsoleMan.PrintString(internalId.ToString(true)); } } @@ -383,20 +394,22 @@ namespace RTE { break; } } - if (!connected) { g_ConsoleMan.PrintString("SERVER: Could not accept connection"); } + if (!connected) { + g_ConsoleMan.PrintString("SERVER: Could not accept connection"); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendAcceptedMsg(short player) { MsgAccepted msg; msg.Id = ID_SRV_ACCEPTED; - m_Server->Send((const char *)&msg, sizeof(MsgAccepted), HIGH_PRIORITY, RELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)&msg, sizeof(MsgAccepted), HIGH_PRIORITY, RELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::ReceiveDisconnection(RakNet::Packet *packet) { + void NetworkServer::ReceiveDisconnection(RakNet::Packet* packet) { std::string msg = "ID_CONNECTION_LOST from"; msg += packet->systemAddress.ToString(true); g_ConsoleMan.PrintString(msg); @@ -407,7 +420,7 @@ namespace RTE { m_ClientConnections[index].ClientId = RakNet::UNASSIGNED_SYSTEM_ADDRESS; m_ClientConnections[index].InternalId = RakNet::UNASSIGNED_SYSTEM_ADDRESS; - //delete m_ClientConnections[index].SendThread; + // delete m_ClientConnections[index].SendThread; m_ClientConnections[index].SendThread = 0; m_SendSceneSetupData[index] = true; @@ -417,11 +430,11 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::ReceiveRegisterMsg(RakNet::Packet *packet) { + void NetworkServer::ReceiveRegisterMsg(RakNet::Packet* packet) { std::string msg; - const MsgRegister *msgReg = (MsgRegister *)packet->data; + const MsgRegister* msgReg = (MsgRegister*)packet->data; char buf[32]; msg = "SERVER: CLIENT REGISTRATION: RES "; @@ -448,8 +461,8 @@ namespace RTE { m_SendFrameData[index] = false; // Get backbuffer bitmap for this player - BITMAP *frameManBmp = g_FrameMan.GetNetworkBackBuffer8Ready(index); - BITMAP *frameManGUIBmp = g_FrameMan.GetNetworkBackBufferGUI8Ready(index); + BITMAP* frameManBmp = g_FrameMan.GetNetworkBackBuffer8Ready(index); + BITMAP* frameManGUIBmp = g_FrameMan.GetNetworkBackBufferGUI8Ready(index); if (!m_BackBuffer8[index]) { CreateBackBuffer(index, frameManBmp->w, frameManBmp->h); @@ -465,7 +478,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendNATServerRegistrationMsg(RakNet::SystemAddress address) { MsgRegisterServer msg = {}; @@ -478,18 +491,20 @@ namespace RTE { int payloadSize = sizeof(MsgSceneSetup); - m_Server->Send((const char *)&msg, payloadSize, IMMEDIATE_PRIORITY, RELIABLE, 0, address, false); + m_Server->Send((const char*)&msg, payloadSize, IMMEDIATE_PRIORITY, RELIABLE, 0, address, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::ReceiveInputMsg(RakNet::Packet *packet) { - const MsgInput *m = (MsgInput *)packet->data; + void NetworkServer::ReceiveInputMsg(RakNet::Packet* packet) { + const MsgInput* m = (MsgInput*)packet->data; int player = -1; for (int index = 0; index < c_MaxClients; index++) { - if (m_ClientConnections[index].ClientId == packet->systemAddress) { player = index; } + if (m_ClientConnections[index].ClientId == packet->systemAddress) { + player = index; + } } if (player >= 0 && player < c_MaxClients) { @@ -515,27 +530,43 @@ namespace RTE { if (!m_InputMessages[player].empty()) { MsgInput lastmsg = m_InputMessages[player].back(); - if (msg.MouseX != lastmsg.MouseX) { skip = false; } - if (msg.MouseY != lastmsg.MouseY) { skip = false; } + if (msg.MouseX != lastmsg.MouseX) { + skip = false; + } + if (msg.MouseY != lastmsg.MouseY) { + skip = false; + } for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) { - if (msg.MouseButtonState[i] != lastmsg.MouseButtonState[i]) { skip = false; } + if (msg.MouseButtonState[i] != lastmsg.MouseButtonState[i]) { + skip = false; + } + } + if (msg.ResetActivityVote != lastmsg.ResetActivityVote) { + skip = false; + } + if (msg.RestartActivityVote != lastmsg.RestartActivityVote) { + skip = false; } - if (msg.ResetActivityVote != lastmsg.ResetActivityVote) { skip = false; } - if (msg.RestartActivityVote != lastmsg.RestartActivityVote) { skip = false; } - if (msg.MouseWheelMoved != lastmsg.MouseWheelMoved) { skip = false; } + if (msg.MouseWheelMoved != lastmsg.MouseWheelMoved) { + skip = false; + } - if (msg.InputElementState != lastmsg.InputElementState) { skip = false; } + if (msg.InputElementState != lastmsg.InputElementState) { + skip = false; + } } else { skip = false; } - if (!skip) { m_InputMessages[player].push_back(msg); } + if (!skip) { + m_InputMessages[player].push_back(msg); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::ProcessInputMsg(short player, MsgInput msg) { if (player >= 0 && player < c_MaxClients) { @@ -573,11 +604,11 @@ namespace RTE { // We need to replace mouse input obtained from the allegro with mouse input obtained from network clients GUIInput::SetNetworkMouseMovement(player, msg.MouseX, msg.MouseY); } else { - //g_ConsoleMan.PrintString("SERVER: Input for unknown client. Ignored."); + // g_ConsoleMan.PrintString("SERVER: Input for unknown client. Ignored."); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::ClearInputMessages(short player) { if (player >= 0 && player < c_MaxClients) { @@ -585,7 +616,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendSoundData(short player) { std::list events; @@ -595,13 +626,13 @@ namespace RTE { return; } - MsgSoundEvents *msg = (MsgSoundEvents *)m_CompressedLineBuffer[player]; - AudioMan::NetworkSoundData *soundDataPointer = (AudioMan::NetworkSoundData *)((char *)msg + sizeof(MsgSoundEvents)); + MsgSoundEvents* msg = (MsgSoundEvents*)m_CompressedLineBuffer[player]; + AudioMan::NetworkSoundData* soundDataPointer = (AudioMan::NetworkSoundData*)((char*)msg + sizeof(MsgSoundEvents)); msg->Id = ID_SRV_SOUND_EVENTS; msg->FrameNumber = m_FrameNumbers[player]; msg->SoundEventsCount = 0; - for (const AudioMan::NetworkSoundData &soundEvent : events) { + for (const AudioMan::NetworkSoundData& soundEvent: events) { if (sizeof(MsgSoundEvents) + (msg->SoundEventsCount * sizeof(AudioMan::NetworkSoundData)) <= c_MaxPixelLineBufferSize) { soundDataPointer->State = soundEvent.State; soundDataPointer->SoundFileHash = soundEvent.SoundFileHash; @@ -621,20 +652,20 @@ namespace RTE { soundDataPointer++; } else { int payloadSize = sizeof(MsgSoundEvents) + (msg->SoundEventsCount * sizeof(AudioMan::NetworkSoundData)); - m_Server->Send((const char *)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); m_SoundDataSentCurrent[player][STAT_CURRENT] += payloadSize; m_SoundDataSentTotal[player] += payloadSize; m_DataSentTotal[player] += payloadSize; - soundDataPointer = (AudioMan::NetworkSoundData *)((char *)msg + sizeof(MsgSoundEvents)); + soundDataPointer = (AudioMan::NetworkSoundData*)((char*)msg + sizeof(MsgSoundEvents)); msg->SoundEventsCount = 0; } } if (msg->SoundEventsCount > 0) { int payloadSize = sizeof(MsgSoundEvents) + (msg->SoundEventsCount * sizeof(AudioMan::NetworkSoundData)); - m_Server->Send((const char *)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); m_SoundDataSentCurrent[player][STAT_CURRENT] += payloadSize; m_SoundDataSentTotal[player] += payloadSize; @@ -642,7 +673,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendMusicData(short player) { std::list events; @@ -652,14 +683,14 @@ namespace RTE { return; } - MsgMusicEvents *msg = (MsgMusicEvents *)m_CompressedLineBuffer[player]; - AudioMan::NetworkMusicData *musicDataPointer = (AudioMan::NetworkMusicData *)((char *)msg + sizeof(MsgMusicEvents)); + MsgMusicEvents* msg = (MsgMusicEvents*)m_CompressedLineBuffer[player]; + AudioMan::NetworkMusicData* musicDataPointer = (AudioMan::NetworkMusicData*)((char*)msg + sizeof(MsgMusicEvents)); msg->Id = ID_SRV_MUSIC_EVENTS; msg->FrameNumber = m_FrameNumbers[player]; msg->MusicEventsCount = 0; - for (const AudioMan::NetworkMusicData &musicEvent : events) { + for (const AudioMan::NetworkMusicData& musicEvent: events) { musicDataPointer->State = musicEvent.State; musicDataPointer->LoopsOrSilence = musicEvent.LoopsOrSilence; musicDataPointer->Pitch = musicEvent.Pitch; @@ -671,21 +702,20 @@ namespace RTE { if (msg->MusicEventsCount >= 4) { int payloadSize = sizeof(MsgMusicEvents) + sizeof(AudioMan::NetworkMusicData) * msg->MusicEventsCount; - m_Server->Send((const char *)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); msg->MusicEventsCount = 0; - musicDataPointer = (AudioMan::NetworkMusicData *)((char *)msg + sizeof(MsgMusicEvents)); + musicDataPointer = (AudioMan::NetworkMusicData*)((char*)msg + sizeof(MsgMusicEvents)); m_SoundDataSentCurrent[player][STAT_CURRENT] += payloadSize; m_SoundDataSentTotal[player] += payloadSize; m_DataSentTotal[player] += payloadSize; - } } if (msg->MusicEventsCount > 0) { int payloadSize = sizeof(MsgMusicEvents) + sizeof(AudioMan::NetworkMusicData) * msg->MusicEventsCount; - m_Server->Send((const char *)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); m_SoundDataSentCurrent[player][STAT_CURRENT] += payloadSize; m_SoundDataSentTotal[player] += payloadSize; @@ -694,7 +724,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendSceneSetupData(short player) { MsgSceneSetup msgSceneSetup = {}; @@ -704,12 +734,12 @@ namespace RTE { msgSceneSetup.Height = static_cast(g_SceneMan.GetSceneHeight()); msgSceneSetup.SceneWrapsX = g_SceneMan.SceneWrapsX(); - Scene *scene = g_SceneMan.GetScene(); + Scene* scene = g_SceneMan.GetScene(); - std::list sceneLayers = scene->GetBackLayers(); + std::list sceneLayers = scene->GetBackLayers(); short index = 0; - for (SLBackground * &layer : sceneLayers) { + for (SLBackground*& layer: sceneLayers) { // Recalculate layers internal values for this player layer->InitScrollRatios(true, player); msgSceneSetup.BackgroundLayers[index].BitmapHash = layer->m_BitmapFile.GetHash(); @@ -743,7 +773,7 @@ namespace RTE { int payloadSize = sizeof(MsgSceneSetup); - m_Server->Send((const char *)&msgSceneSetup, payloadSize, HIGH_PRIORITY, RELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)&msgSceneSetup, payloadSize, HIGH_PRIORITY, RELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); m_DataSentCurrent[player][STAT_CURRENT] += payloadSize; m_DataSentTotal[player] += payloadSize; @@ -761,17 +791,21 @@ namespace RTE { // While we're on the same thread with freshly connected player, send current music being played if (g_AudioMan.IsMusicPlaying()) { std::string currentMusic = g_AudioMan.GetMusicPath(); - if (!currentMusic.empty()) { g_AudioMan.RegisterMusicEvent(player, AudioMan::MUSIC_PLAY, currentMusic.c_str(), -1, g_AudioMan.GetMusicPosition(), 1.0F); } + if (!currentMusic.empty()) { + g_AudioMan.RegisterMusicEvent(player, AudioMan::MUSIC_PLAY, currentMusic.c_str(), -1, g_AudioMan.GetMusicPosition(), 1.0F); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::ReceiveSceneSetupDataAccepted(RakNet::Packet *packet) { + void NetworkServer::ReceiveSceneSetupDataAccepted(RakNet::Packet* packet) { short player = -1; for (short index = 0; index < c_MaxClients; index++) { - if (m_ClientConnections[index].ClientId == packet->systemAddress) { player = index; } + if (m_ClientConnections[index].ClientId == packet->systemAddress) { + player = index; + } } if (player > -1) { @@ -781,13 +815,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendSceneData(short player) { // Check for congestion RakNet::RakNetStatistics rns; - MsgSceneLine *sceneData = (MsgSceneLine *)m_CompressedLineBuffer[player]; + MsgSceneLine* sceneData = (MsgSceneLine*)m_CompressedLineBuffer[player]; // Save message ID sceneData->Id = ID_SRV_SCENE; @@ -796,8 +830,8 @@ namespace RTE { int lineY = 0; int lineWidth = 1280; - Scene *scene = g_SceneMan.GetScene(); - SLTerrain *terrain = 0; + Scene* scene = g_SceneMan.GetScene(); + SLTerrain* terrain = 0; if (scene) { terrain = scene->GetTerrain(); @@ -812,7 +846,7 @@ namespace RTE { m_SceneLock[player].lock(); for (int layer = 0; layer < 2; layer++) { - BITMAP *bmp = 0; + BITMAP* bmp = 0; if (layer == 0) { bmp = terrain->GetBGColorBitmap(); } else if (layer == 1) { @@ -821,9 +855,11 @@ namespace RTE { lock_bitmap(bmp); - for (lineX = 0; ; lineX += lineWidth) { + for (lineX = 0;; lineX += lineWidth) { int width = lineWidth; - if (lineX + width >= g_SceneMan.GetSceneWidth()) { width = g_SceneMan.GetSceneWidth() - lineX; } + if (lineX + width >= g_SceneMan.GetSceneWidth()) { + width = g_SceneMan.GetSceneWidth() - lineX; + } for (lineY = 0; lineY < g_SceneMan.GetSceneHeight(); lineY++) { // Save scene fragment data @@ -836,9 +872,9 @@ namespace RTE { // Compression section int result = 0; - //bool lineIsEmpty = false; + // bool lineIsEmpty = false; - result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char *)bmp->line[lineY] + lineX, (char *)(m_CompressedLineBuffer[player] + sizeof(MsgSceneLine)), width, width, LZ4HC_CLEVEL_MAX); + result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char*)bmp->line[lineY] + lineX, (char*)(m_CompressedLineBuffer[player] + sizeof(MsgSceneLine)), width, width, LZ4HC_CLEVEL_MAX); // Compression failed or ineffective, send as is if (result == 0 || result == width) { @@ -853,7 +889,7 @@ namespace RTE { int payloadSize = sceneData->DataSize + sizeof(MsgSceneLine); - m_Server->Send((const char *)sceneData, payloadSize, HIGH_PRIORITY, RELIABLE, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)sceneData, payloadSize, HIGH_PRIORITY, RELIABLE, 0, m_ClientConnections[player].ClientId, false); m_DataSentCurrent[player][STAT_CURRENT] += payloadSize; m_DataSentTotal[player] += payloadSize; @@ -896,7 +932,7 @@ namespace RTE { SendSceneEndMsg(player); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::ClearTerrainChangeQueue(short player) { m_Mutex[player].lock(); @@ -909,7 +945,7 @@ namespace RTE { m_Mutex[player].unlock(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool NetworkServer::NeedToProcessTerrainChanges(short player) { bool result; @@ -921,7 +957,7 @@ namespace RTE { return result; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::ProcessTerrainChanges(short player) { m_Mutex[player].lock(); @@ -970,7 +1006,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendTerrainChangeMsg(short player, NetworkTerrainChange terrainChange) { if (terrainChange.w == 1 && terrainChange.h == 1) { @@ -988,7 +1024,7 @@ namespace RTE { int payloadSize = sizeof(MsgTerrainChange); - m_Server->Send((const char *)&msg, payloadSize, MEDIUM_PRIORITY, RELIABLE, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)&msg, payloadSize, MEDIUM_PRIORITY, RELIABLE, 0, m_ClientConnections[player].ClientId, false); m_DataSentCurrent[player][STAT_CURRENT] += payloadSize; m_DataSentTotal[player] += payloadSize; @@ -999,7 +1035,7 @@ namespace RTE { m_DataUncompressedCurrent[player][STAT_CURRENT] += payloadSize; m_DataUncompressedTotal[player] += payloadSize; } else { - MsgTerrainChange *msg = (MsgTerrainChange *)m_CompressedLineBuffer[player]; + MsgTerrainChange* msg = (MsgTerrainChange*)m_CompressedLineBuffer[player]; msg->Id = ID_SRV_TERRAIN; msg->X = terrainChange.x; msg->Y = terrainChange.y; @@ -1012,13 +1048,13 @@ namespace RTE { msg->Color = terrainChange.color; msg->Back = terrainChange.back; - Scene * scene = g_SceneMan.GetScene(); - SLTerrain * terrain = scene->GetTerrain(); + Scene* scene = g_SceneMan.GetScene(); + SLTerrain* terrain = scene->GetTerrain(); - const BITMAP *bmp = 0; + const BITMAP* bmp = 0; bmp = msg->Back ? terrain->GetBGColorBitmap() : terrain->GetFGColorBitmap(); - unsigned char *dest = (unsigned char *)(m_PixelLineBuffer[player]); + unsigned char* dest = (unsigned char*)(m_PixelLineBuffer[player]); // Copy bitmap data for (int y = 0; y < msg->H && msg->Y + y < bmp->h; y++) { @@ -1028,7 +1064,7 @@ namespace RTE { int result = 0; - result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char *)m_PixelLineBuffer[player], (char *)(m_CompressedLineBuffer[player] + sizeof(MsgTerrainChange)), size, size, LZ4HC_CLEVEL_OPT_MIN); + result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char*)m_PixelLineBuffer[player], (char*)(m_CompressedLineBuffer[player] + sizeof(MsgTerrainChange)), size, size, LZ4HC_CLEVEL_OPT_MIN); // Compression failed or ineffective, send as is if (result == 0 || result == size) { @@ -1043,7 +1079,7 @@ namespace RTE { int payloadSize = sizeof(MsgTerrainChange) + msg->DataSize; - m_Server->Send((const char *)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE, 0, m_ClientConnections[player].ClientId, false); m_DataSentCurrent[player][STAT_CURRENT] += payloadSize; m_DataSentTotal[player] += payloadSize; @@ -1056,23 +1092,25 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void NetworkServer::ReceiveSceneAcceptedMsg(RakNet::Packet *packet) { + void NetworkServer::ReceiveSceneAcceptedMsg(RakNet::Packet* packet) { for (short player = 0; player < c_MaxClients; player++) { - if (m_ClientConnections[player].ClientId == packet->systemAddress) { m_SendFrameData[player] = true; } + if (m_ClientConnections[player].ClientId == packet->systemAddress) { + m_SendFrameData[player] = true; + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendSceneEndMsg(short player) { MsgSceneEnd msg = {}; msg.Id = ID_SRV_SCENE_END; - m_Server->Send((const char *)&msg, sizeof(MsgSceneSetup), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)&msg, sizeof(MsgSceneSetup), HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::CreateBackBuffer(short player, int w, int h) { m_BackBuffer8[player] = create_bitmap_ex(8, w, h); @@ -1090,7 +1128,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::ClearBackBuffer(int player, int w, int h) { clear_to_color(m_BackBuffer8[player], ColorKeys::g_MaskColor); @@ -1105,7 +1143,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::DestroyBackBuffer(short player) { if (m_BackBuffer8) { @@ -1127,7 +1165,7 @@ namespace RTE { m_PixelLineBuffersGUIPrev[player] = nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendFrameSetupMsg(short player) { MsgFrameSetup msgFrameSetup; @@ -1147,7 +1185,7 @@ namespace RTE { int payloadSize = sizeof(MsgFrameSetup); - m_Server->Send((const char *)&msgFrameSetup, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)&msgFrameSetup, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); m_DataSentCurrent[player][STAT_CURRENT] += payloadSize; m_DataSentTotal[player] += payloadSize; @@ -1161,7 +1199,7 @@ namespace RTE { m_SendSceneData[player] = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::SendPostEffectData(short player) { std::list effects; @@ -1171,14 +1209,14 @@ namespace RTE { return; } - MsgPostEffects *msg = (MsgPostEffects *)m_CompressedLineBuffer[player]; - PostEffectNetworkData *effDataPtr = (PostEffectNetworkData *)((char *)msg + sizeof(MsgPostEffects)); + MsgPostEffects* msg = (MsgPostEffects*)m_CompressedLineBuffer[player]; + PostEffectNetworkData* effDataPtr = (PostEffectNetworkData*)((char*)msg + sizeof(MsgPostEffects)); msg->Id = ID_SRV_POST_EFFECTS; msg->FrameNumber = m_FrameNumbers[player]; msg->PostEffectsCount = 0; - for (const PostEffect postEffectEvent : effects) { + for (const PostEffect postEffectEvent: effects) { effDataPtr->X = postEffectEvent.m_Pos.GetX(); effDataPtr->Y = postEffectEvent.m_Pos.GetY(); effDataPtr->BitmapHash = postEffectEvent.m_BitmapHash; @@ -1190,9 +1228,9 @@ namespace RTE { if (msg->PostEffectsCount >= 75) { int payloadSize = sizeof(MsgPostEffects) + sizeof(PostEffectNetworkData) * msg->PostEffectsCount; - m_Server->Send((const char *)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); msg->PostEffectsCount = 0; - effDataPtr = (PostEffectNetworkData *)((char *)msg + sizeof(MsgPostEffects)); + effDataPtr = (PostEffectNetworkData*)((char*)msg + sizeof(MsgPostEffects)); m_PostEffectDataSentCurrent[player][STAT_CURRENT] += payloadSize; m_PostEffectDataSentTotal[player] += payloadSize; @@ -1202,13 +1240,13 @@ namespace RTE { } if (msg->PostEffectsCount > 0) { - //int header = sizeof(MsgPostEffects); - //int data = sizeof(PostEffectNetworkData); - //int total = header + data * msg->PostEffectsCount; - //int sz = sizeof(size_t); + // int header = sizeof(MsgPostEffects); + // int data = sizeof(PostEffectNetworkData); + // int total = header + data * msg->PostEffectsCount; + // int sz = sizeof(size_t); int payloadSize = sizeof(MsgPostEffects) + sizeof(PostEffectNetworkData) * msg->PostEffectsCount; - m_Server->Send((const char *)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)msg, payloadSize, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, m_ClientConnections[player].ClientId, false); m_PostEffectDataSentCurrent[player][STAT_CURRENT] += payloadSize; m_PostEffectDataSentTotal[player] += payloadSize; @@ -1217,7 +1255,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int NetworkServer::SendFrame(short player) { long long currentTicks = g_TimerMan.GetRealTickCount(); @@ -1229,7 +1267,9 @@ namespace RTE { double secsSinceLastFrame = static_cast(currentTicks - m_LastFrameSentTime[player]) / static_cast(g_TimerMan.GetTicksPerSecond()); // Fix for an overflow which may happen if server lags for a few seconds when loading activities - if (secsSinceLastFrame < 0) { secsSinceLastFrame = secsPerFrame; } + if (secsSinceLastFrame < 0) { + secsSinceLastFrame = secsPerFrame; + } m_MsecPerFrame[player] = static_cast(secsSinceLastFrame * 1000.0); @@ -1241,8 +1281,8 @@ namespace RTE { SetThreadExitReason(player, NetworkServer::NORMAL); // Get backbuffer bitmap for this player - BITMAP *frameManBmp = g_FrameMan.GetNetworkBackBuffer8Ready(player); - BITMAP *frameManGUIBmp = g_FrameMan.GetNetworkBackBufferGUI8Ready(player); + BITMAP* frameManBmp = g_FrameMan.GetNetworkBackBuffer8Ready(player); + BITMAP* frameManGUIBmp = g_FrameMan.GetNetworkBackBufferGUI8Ready(player); if (!m_BackBuffer8[player]) { CreateBackBuffer(player, frameManBmp->w, frameManBmp->h); @@ -1251,12 +1291,14 @@ namespace RTE { if (m_BackBuffer8[player]->w != frameManBmp->w || m_BackBuffer8[player]->h != frameManBmp->h) { DestroyBackBuffer(player); CreateBackBuffer(player, frameManBmp->w, frameManBmp->h); - //g_ConsoleMan.PrintString("SERVER: Backbuffer recreated"); + // g_ConsoleMan.PrintString("SERVER: Backbuffer recreated"); } } m_FrameNumbers[player]++; - if (m_FrameNumbers[player] >= c_FramesToRemember) { m_FrameNumbers[player] = 0; } + if (m_FrameNumbers[player] >= c_FramesToRemember) { + m_FrameNumbers[player] = 0; + } // Save a copy of buffer to avoid tearing when the original is updated by frame man blit(frameManBmp, m_BackBuffer8[player], 0, 0, 0, 0, frameManBmp->w, frameManBmp->h); @@ -1276,17 +1318,19 @@ namespace RTE { m_SendEven[player] = !m_SendEven[player]; if (m_TransmitAsBoxes) { - MsgFrameBox *frameData = (MsgFrameBox *)m_CompressedLineBuffer[player]; + MsgFrameBox* frameData = (MsgFrameBox*)m_CompressedLineBuffer[player]; int boxedWidth = m_BackBuffer8[player]->w / m_BoxWidth; int boxedHeight = m_BackBuffer8[player]->h / m_BoxHeight; int boxMaxSize = m_BoxWidth * m_BoxHeight; - if (m_BackBuffer8[player]->w % m_BoxWidth != 0) { boxedWidth += 1; } + if (m_BackBuffer8[player]->w % m_BoxWidth != 0) { + boxedWidth += 1; + } for (unsigned char layer = 0; layer < 2; layer++) { - const BITMAP *backBuffer = nullptr; - unsigned char *prevLineBuffers = 0; + const BITMAP* backBuffer = nullptr; + unsigned char* prevLineBuffers = 0; if (layer == 0) { backBuffer = m_BackBuffer8[player]; @@ -1309,10 +1353,14 @@ namespace RTE { frameData->BoxY = by; int maxWidth = m_BoxWidth; - if (bpx + m_BoxWidth >= m_BackBuffer8[player]->w) { maxWidth = m_BackBuffer8[player]->w - bpx; } + if (bpx + m_BoxWidth >= m_BackBuffer8[player]->w) { + maxWidth = m_BackBuffer8[player]->w - bpx; + } int maxHeight = m_BoxHeight; - if (bpy + m_BoxHeight >= m_BackBuffer8[player]->h) { maxHeight = m_BackBuffer8[player]->h - bpy; } + if (bpy + m_BoxHeight >= m_BackBuffer8[player]->h) { + maxHeight = m_BackBuffer8[player]->h - bpy; + } int lineStart = 0; int lineStep = 1; @@ -1320,7 +1368,9 @@ namespace RTE { if (m_UseInterlacing) { lineStep = 2; - if (m_SendEven[player]) { lineStart = 1; } + if (m_SendEven[player]) { + lineStart = 1; + } maxHeight /= 2; } int thisBoxSize = maxWidth * maxHeight; @@ -1329,7 +1379,7 @@ namespace RTE { bool boxIsDelta = false; bool sendEmptyBox = false; - unsigned char *dest = (unsigned char *)(m_PixelLineBuffer[player]); + unsigned char* dest = (unsigned char*)(m_PixelLineBuffer[player]); // Copy block line by line to linear buffer for (int line = lineStart; line < lineCount; line += lineStep) { @@ -1348,21 +1398,29 @@ namespace RTE { // Previous line to delta against int interlacedOffset = 0; - if (m_UseInterlacing) { interlacedOffset = m_SendEven[player] ? thisBoxSize : 0; } + if (m_UseInterlacing) { + interlacedOffset = m_SendEven[player] ? thisBoxSize : 0; + } - unsigned char *prevLineBufferStart = prevLineBuffers + by * boxedWidth * boxMaxSize + bx * boxMaxSize; - unsigned char *prevLineBufferWithOffset = prevLineBufferStart + interlacedOffset; + unsigned char* prevLineBufferStart = prevLineBuffers + by * boxedWidth * boxMaxSize + bx * boxMaxSize; + unsigned char* prevLineBufferWithOffset = prevLineBufferStart + interlacedOffset; // Currently processed box line buffer and delta storage - unsigned char *currLineBuffer = (unsigned char*)(m_PixelLineBufferDelta[player]); + unsigned char* currLineBuffer = (unsigned char*)(m_PixelLineBufferDelta[player]); // Calculate delta and decide whether we use it for (int i = 0; i < thisBoxSize; i++) { - if (currLineBuffer[i] > 0) { bytesNeededPlain++; } - if (prevLineBufferWithOffset[i] > 0) { bytesNeededPrev++; } + if (currLineBuffer[i] > 0) { + bytesNeededPlain++; + } + if (prevLineBufferWithOffset[i] > 0) { + bytesNeededPrev++; + } currLineBuffer[i] = currLineBuffer[i] - prevLineBufferWithOffset[i]; - if (currLineBuffer[i] > 0) { bytesNeededDelta++; } + if (currLineBuffer[i] > 0) { + bytesNeededDelta++; + } } // Store current line for delta check in the next frame @@ -1384,11 +1442,13 @@ namespace RTE { } } else { // Previous non empty block is now empty, clear it - if (bytesNeededPrev > 0 && bytesNeededPlain == 0) { sendEmptyBox = true; } + if (bytesNeededPrev > 0 && bytesNeededPlain == 0) { + sendEmptyBox = true; + } } } else { // Check if block is empty by evaluating by 64-bit ints - unsigned long *pixelInt = (unsigned long *)m_PixelLineBuffer[player]; + unsigned long* pixelInt = (unsigned long*)m_PixelLineBuffer[player]; int counter = 0; for (counter = 0; counter < thisBoxSize; counter += sizeof(unsigned long)) { @@ -1403,7 +1463,7 @@ namespace RTE { pixelInt--; counter -= sizeof(unsigned long); - const unsigned char *pixelChr = (unsigned char*)pixelInt; + const unsigned char* pixelChr = (unsigned char*)pixelInt; for (; counter < thisBoxSize; counter++) { if (*pixelChr > 0) { boxIsEmpty = false; @@ -1424,14 +1484,16 @@ namespace RTE { if (boxIsEmpty) { frameData->DataSize = 0; - if (!sendEmptyBox) { m_EmptyBlocks[player]++; } + if (!sendEmptyBox) { + m_EmptyBlocks[player]++; + } } else { int result = 0; if (m_UseHighCompression) { - result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char *)m_PixelLineBuffer[player], (char *)(m_CompressedLineBuffer[player] + sizeof(MsgFrameBox)), thisBoxSize, thisBoxSize, compressionMethod); + result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char*)m_PixelLineBuffer[player], (char*)(m_CompressedLineBuffer[player] + sizeof(MsgFrameBox)), thisBoxSize, thisBoxSize, compressionMethod); } else if (m_UseFastCompression) { - result = LZ4_compress_fast_extState(m_LZ4FastCompressionState[player], (char *)m_PixelLineBuffer[player], (char *)(m_CompressedLineBuffer[player] + sizeof(MsgFrameBox)), thisBoxSize, thisBoxSize, accelerationFactor); + result = LZ4_compress_fast_extState(m_LZ4FastCompressionState[player], (char*)m_PixelLineBuffer[player], (char*)(m_CompressedLineBuffer[player] + sizeof(MsgFrameBox)), thisBoxSize, thisBoxSize, accelerationFactor); } // Compression failed or ineffective, send as is @@ -1451,7 +1513,7 @@ namespace RTE { int payloadSize = frameData->DataSize + sizeof(MsgFrameBox); if (!boxIsEmpty || sendEmptyBox) { - m_Server->Send((const char *)frameData, payloadSize, MEDIUM_PRIORITY, UNRELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)frameData, payloadSize, MEDIUM_PRIORITY, UNRELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); } else { payloadSize = 0; } @@ -1476,7 +1538,7 @@ namespace RTE { } } } else { - MsgFrameLine *frameData = (MsgFrameLine *)m_CompressedLineBuffer[player]; + MsgFrameLine* frameData = (MsgFrameLine*)m_CompressedLineBuffer[player]; frameData->FrameNumber = m_FrameNumbers[player]; // Save message ID @@ -1493,7 +1555,7 @@ namespace RTE { for (int m_CurrentFrameLine = startLine; m_CurrentFrameLine < m_BackBuffer8[player]->h; m_CurrentFrameLine += step) { for (int layer = 0; layer < 2; layer++) { - const BITMAP *backBuffer = 0; + const BITMAP* backBuffer = 0; if (layer == 0) { backBuffer = m_BackBuffer8[player]; @@ -1515,7 +1577,7 @@ namespace RTE { // Check if line is empty { - unsigned long *pixelInt = (unsigned long *)backBuffer->line[m_CurrentFrameLine]; + unsigned long* pixelInt = (unsigned long*)backBuffer->line[m_CurrentFrameLine]; int counter = 0; for (counter = 0; counter < backBuffer->w; counter += sizeof(unsigned long)) { if (*pixelInt > 0) { @@ -1528,7 +1590,7 @@ namespace RTE { pixelInt--; counter -= sizeof(unsigned long); - const unsigned char *pixelChr = (unsigned char *)pixelInt; + const unsigned char* pixelChr = (unsigned char*)pixelInt; for (; counter < backBuffer->w; counter++) { if (*pixelChr > 0) { lineIsEmpty = false; @@ -1541,9 +1603,9 @@ namespace RTE { if (!lineIsEmpty) { if (m_UseHighCompression) { - result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char *)backBuffer->line[m_CurrentFrameLine], (char *)(m_CompressedLineBuffer[player] + sizeof(MsgFrameLine)), backBuffer->w, backBuffer->w, compressionMethod); + result = LZ4_compress_HC_extStateHC(m_LZ4CompressionState[player], (char*)backBuffer->line[m_CurrentFrameLine], (char*)(m_CompressedLineBuffer[player] + sizeof(MsgFrameLine)), backBuffer->w, backBuffer->w, compressionMethod); } else if (m_UseFastCompression) { - result = LZ4_compress_fast_extState(m_LZ4FastCompressionState[player], (char *)backBuffer->line[m_CurrentFrameLine], (char *)(m_CompressedLineBuffer[player] + sizeof(MsgFrameLine)), backBuffer->w, backBuffer->w, accelerationFactor); + result = LZ4_compress_fast_extState(m_LZ4FastCompressionState[player], (char*)backBuffer->line[m_CurrentFrameLine], (char*)(m_CompressedLineBuffer[player] + sizeof(MsgFrameLine)), backBuffer->w, backBuffer->w, accelerationFactor); } // Compression failed or ineffective, send as is @@ -1565,7 +1627,7 @@ namespace RTE { int payloadSize = frameData->DataSize + sizeof(MsgFrameLine); - m_Server->Send((const char *)frameData, payloadSize, MEDIUM_PRIORITY, UNRELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); + m_Server->Send((const char*)frameData, payloadSize, MEDIUM_PRIORITY, UNRELIABLE_SEQUENCED, 0, m_ClientConnections[player].ClientId, false); m_DataSentCurrent[player][STAT_CURRENT] += payloadSize; m_DataSentTotal[player] += payloadSize; @@ -1589,7 +1651,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::UpdateStats(short player) { long long currentTicks = g_TimerMan.GetRealTickCount(); @@ -1628,12 +1690,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::DrawStatisticsData() { int midX = g_WindowMan.GetResX() / 2; - BITMAP *bmp = g_FrameMan.GetBackBuffer8(); + BITMAP* bmp = g_FrameMan.GetBackBuffer8(); AllegroBitmap guiBMP(bmp); clear_to_color(bmp, g_BlackColor); @@ -1652,7 +1714,7 @@ namespace RTE { } if (g_ActivityMan.IsInActivity()) { - const GameActivity *gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); + const GameActivity* gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); if (gameActivity) { std::snprintf(buf, sizeof(buf), "Activity: %s Players: %d", gameActivity->GetPresetName().c_str(), gameActivity->GetPlayerCount()); g_FrameMan.GetLargeFont()->DrawAligned(&guiBMP, midX, 50, buf, GUIFont::Centre); @@ -1687,7 +1749,6 @@ namespace RTE { m_FullBlocks[c_MaxClients] = 0; m_EmptyBlocks[c_MaxClients] = 0; - for (short i = 0; i < MAX_STAT_RECORDS; i++) { // Update sum if (i < c_MaxClients) { @@ -1729,47 +1790,46 @@ namespace RTE { // Jesus christ std::snprintf(buf, sizeof(buf), - "%s\nPing %u\n" - "Cmp Mbit : % .1f\n" - "Unc Mbit : % .1f\n" - "R : % .2f\n" - "Full Blck %lu (%.1f Kb)\n" - "Empty Blck %lu (%.1f Kb)\n" - "Frame Kb : %lu\n" - "Glow Kb : %lu\n" - "Sound Kb : %lu\n" - "Scene Kb : %lu\n" - "Frames sent : %uK\n" - "Frame skipped : %uK\n" - "Blocks full : %uK\n" - "Blocks empty : %uK\n" - "Blk Ratio : % .2f\n" - "Frames ms : % d\n" - "Send ms % d\n" - "Total Data %lu MB", - - (i == c_MaxClients) ? "- TOTALS - " : playerName.c_str(), - (i < c_MaxClients) ? m_Ping[i] : 0, - static_cast(m_DataSentCurrent[i][STAT_SHOWN]) / 125000, - static_cast(m_DataUncompressedCurrent[i][STAT_SHOWN]) / 125000, - compressionRatio, - m_FullBlocksSentCurrent[i][STAT_SHOWN], - static_cast(m_FullBlocksDataSentCurrent[i][STAT_SHOWN]) / (125), - m_EmptyBlocksSentCurrent[i][STAT_SHOWN], - static_cast(m_EmptyBlocksDataSentCurrent[i][STAT_SHOWN]) / (125), - m_FrameDataSentCurrent[i][STAT_SHOWN] / 125, - m_PostEffectDataSentCurrent[i][STAT_SHOWN] / 125, - m_SoundDataSentCurrent[i][STAT_SHOWN] / 125, - m_TerrainDataSentCurrent[i][STAT_SHOWN] / 125, - m_FramesSent[i] / 1000, - m_FramesSkipped[i], - m_FullBlocks[i] / 1000, - m_EmptyBlocks[i] / 1000, - emptyRatio, - (i < c_MaxClients) ? m_MsecPerFrame[i] : 0, - (i < c_MaxClients) ? m_MsecPerSendCall[i] : 0, - m_DataSentTotal[i] / (1024 * 1024) - ); + "%s\nPing %u\n" + "Cmp Mbit : % .1f\n" + "Unc Mbit : % .1f\n" + "R : % .2f\n" + "Full Blck %lu (%.1f Kb)\n" + "Empty Blck %lu (%.1f Kb)\n" + "Frame Kb : %lu\n" + "Glow Kb : %lu\n" + "Sound Kb : %lu\n" + "Scene Kb : %lu\n" + "Frames sent : %uK\n" + "Frame skipped : %uK\n" + "Blocks full : %uK\n" + "Blocks empty : %uK\n" + "Blk Ratio : % .2f\n" + "Frames ms : % d\n" + "Send ms % d\n" + "Total Data %lu MB", + + (i == c_MaxClients) ? "- TOTALS - " : playerName.c_str(), + (i < c_MaxClients) ? m_Ping[i] : 0, + static_cast(m_DataSentCurrent[i][STAT_SHOWN]) / 125000, + static_cast(m_DataUncompressedCurrent[i][STAT_SHOWN]) / 125000, + compressionRatio, + m_FullBlocksSentCurrent[i][STAT_SHOWN], + static_cast(m_FullBlocksDataSentCurrent[i][STAT_SHOWN]) / (125), + m_EmptyBlocksSentCurrent[i][STAT_SHOWN], + static_cast(m_EmptyBlocksDataSentCurrent[i][STAT_SHOWN]) / (125), + m_FrameDataSentCurrent[i][STAT_SHOWN] / 125, + m_PostEffectDataSentCurrent[i][STAT_SHOWN] / 125, + m_SoundDataSentCurrent[i][STAT_SHOWN] / 125, + m_TerrainDataSentCurrent[i][STAT_SHOWN] / 125, + m_FramesSent[i] / 1000, + m_FramesSkipped[i], + m_FullBlocks[i] / 1000, + m_EmptyBlocks[i] / 1000, + emptyRatio, + (i < c_MaxClients) ? m_MsecPerFrame[i] : 0, + (i < c_MaxClients) ? m_MsecPerSendCall[i] : 0, + m_DataSentTotal[i] / (1024 * 1024)); g_FrameMan.GetLargeFont()->DrawAligned(&guiBMP, 10 + i * g_WindowMan.GetResX() / 5, 75, buf, GUIFont::Left); @@ -1781,14 +1841,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - RakNet::SystemAddress NetworkServer::ConnectBlocking(RakNet::RakPeerInterface *rakPeer, const char *address, unsigned short port) { + RakNet::SystemAddress NetworkServer::ConnectBlocking(RakNet::RakPeerInterface* rakPeer, const char* address, unsigned short port) { if (rakPeer->Connect(address, port, 0, 0) != RakNet::CONNECTION_ATTEMPT_STARTED) { return RakNet::UNASSIGNED_SYSTEM_ADDRESS; } - RakNet::Packet *packet; + RakNet::Packet* packet; while (true) { for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive()) { if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) { @@ -1803,7 +1863,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::Update(bool processInput) { HandleNetworkPackets(); @@ -1811,7 +1871,7 @@ namespace RTE { if (processInput) { for (short player = 0; player < c_MaxClients; player++) { if (!m_InputMessages[player].empty()) { - for (const MsgInput &msg: m_InputMessages[player]) { + for (const MsgInput& msg: m_InputMessages[player]) { ProcessInputMsg(player, msg); } m_InputMessages[player].clear(); @@ -1846,7 +1906,9 @@ namespace RTE { displayMsg = "Voting to end activity: " + std::to_string(endActivityVotes) + " of " + std::to_string(votesNeeded); } if (restartVotes > 0) { - if (!displayMsg.empty()) { displayMsg += "\n"; } + if (!displayMsg.empty()) { + displayMsg += "\n"; + } displayMsg += "Voting to restart activity: " + std::to_string(restartVotes) + " of " + std::to_string(votesNeeded); } @@ -1866,11 +1928,15 @@ namespace RTE { g_ActivityMan.EndActivity(); g_ActivityMan.SetRestartActivity(); g_ActivityMan.SetInActivity(false); - for (short player = 0; player < c_MaxClients; player++) { ClearInputMessages(player); } + for (short player = 0; player < c_MaxClients; player++) { + ClearInputMessages(player); + } } else if (restartVotes >= votesNeeded) { m_LatestRestartTime = currentTicks; g_ActivityMan.RestartActivity(); - for (short player = 0; player < c_MaxClients; player++) { ClearInputMessages(player); } + for (short player = 0; player < c_MaxClients; player++) { + ClearInputMessages(player); + } } } } @@ -1895,14 +1961,16 @@ namespace RTE { break; } - if (playersConnected == 0) { RakSleep(250); } + if (playersConnected == 0) { + RakSleep(250); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void NetworkServer::HandleNetworkPackets() { - for (RakNet::Packet *packet = m_Server->Receive(); packet; m_Server->DeallocatePacket(packet), packet = m_Server->Receive()) { + for (RakNet::Packet* packet = m_Server->Receive(); packet; m_Server->DeallocatePacket(packet), packet = m_Server->Receive()) { m_LastPackedReceived->Reset(); // We got a packet, get the identifier with our handy function @@ -1972,4 +2040,4 @@ namespace RTE { } } } -} +} // namespace RTE diff --git a/Source/Managers/NetworkServer.h b/Source/Managers/NetworkServer.h index d5bf687cb..8a14d3111 100644 --- a/Source/Managers/NetworkServer.h +++ b/Source/Managers/NetworkServer.h @@ -28,7 +28,6 @@ namespace RTE { friend class SettingsMan; public: - /// /// /// @@ -66,7 +65,10 @@ namespace RTE { /// /// Constructor method used to instantiate a NetworkServer object in system memory. This will call Create() so it shouldn't be called after. /// - NetworkServer() { Clear(); Initialize(); } + NetworkServer() { + Clear(); + Initialize(); + } /// /// Makes the NetworkServer object ready for use. @@ -110,7 +112,7 @@ namespace RTE { /// /// The player to check for. /// A string with the network player's name. - std::string & GetPlayerName(short player) { return m_ClientConnections[player].PlayerName; } + std::string& GetPlayerName(short player) { return m_ClientConnections[player].PlayerName; } /// /// Gets whether the specified player is connected to the server or not. @@ -123,7 +125,7 @@ namespace RTE { /// Sets the port this server will be using. /// /// The new port to set. - void SetServerPort(const std::string &newPort); + void SetServerPort(const std::string& newPort); /// /// Sets whether interlacing is used to reduce bandwidth usage or not. @@ -191,7 +193,6 @@ namespace RTE { #pragma endregion protected: - /// /// /// @@ -201,7 +202,7 @@ namespace RTE { RakNet::SystemAddress InternalId; //!< int ResX; //!< int ResY; //!< - std::thread *SendThread; //!< + std::thread* SendThread; //!< std::string PlayerName; //!< }; @@ -215,7 +216,7 @@ namespace RTE { long m_MSecsSinceLastUpdate[c_MaxClients]; //!< long m_MSecsToSleep[c_MaxClients]; //!< - RakNet::RakPeerInterface *m_Server; //!< + RakNet::RakPeerInterface* m_Server; //!< std::string m_ServerPort; //!< @@ -226,11 +227,11 @@ namespace RTE { RakNet::SystemAddress m_NATServiceServerID; //!< bool m_NatServerConnected; //!< - BITMAP *m_BackBuffer8[c_MaxClients]; //!< Buffers to store client screens before compression. - BITMAP *m_BackBufferGUI8[c_MaxClients]; //!< Buffers to store client GUI screens before compression. + BITMAP* m_BackBuffer8[c_MaxClients]; //!< Buffers to store client screens before compression. + BITMAP* m_BackBufferGUI8[c_MaxClients]; //!< Buffers to store client GUI screens before compression. - void *m_LZ4CompressionState[c_MaxClients]; //!< - void *m_LZ4FastCompressionState[c_MaxClients]; //!< + void* m_LZ4CompressionState[c_MaxClients]; //!< + void* m_LZ4FastCompressionState[c_MaxClients]; //!< int m_MouseState1[c_MaxClients]; //!< int m_MouseState2[c_MaxClients]; //!< @@ -268,8 +269,8 @@ namespace RTE { unsigned char m_PixelLineBufferDelta[c_MaxClients][c_MaxPixelLineBufferSize]; //!< Buffer to store currently transferred pixel data line. unsigned char m_CompressedLineBuffer[c_MaxClients][c_MaxPixelLineBufferSize]; //!< Buffer to store compressed pixel data line. - unsigned char *m_PixelLineBuffersPrev[c_MaxClients]; //!< - unsigned char *m_PixelLineBuffersGUIPrev[c_MaxClients]; //!< + unsigned char* m_PixelLineBuffersPrev[c_MaxClients]; //!< + unsigned char* m_PixelLineBuffersGUIPrev[c_MaxClients]; //!< std::queue m_PendingTerrainChanges[c_MaxClients]; //!< std::queue m_CurrentTerrainChanges[c_MaxClients]; //!< @@ -329,27 +330,26 @@ namespace RTE { unsigned long m_FrameDataSentCurrent[MAX_STAT_RECORDS][2]; //!< unsigned long m_FrameDataSentTotal[MAX_STAT_RECORDS]; //!< - unsigned long m_PostEffectDataSentCurrent[MAX_STAT_RECORDS][2]; //!< - unsigned long m_PostEffectDataSentTotal[MAX_STAT_RECORDS]; //!< + unsigned long m_PostEffectDataSentCurrent[MAX_STAT_RECORDS][2]; //!< + unsigned long m_PostEffectDataSentTotal[MAX_STAT_RECORDS]; //!< - unsigned long m_SoundDataSentCurrent[MAX_STAT_RECORDS][2]; //!< - unsigned long m_SoundDataSentTotal[MAX_STAT_RECORDS]; //!< + unsigned long m_SoundDataSentCurrent[MAX_STAT_RECORDS][2]; //!< + unsigned long m_SoundDataSentTotal[MAX_STAT_RECORDS]; //!< - unsigned long m_TerrainDataSentCurrent[MAX_STAT_RECORDS][2]; //!< - unsigned long m_TerrainDataSentTotal[MAX_STAT_RECORDS]; //!< + unsigned long m_TerrainDataSentCurrent[MAX_STAT_RECORDS][2]; //!< + unsigned long m_TerrainDataSentTotal[MAX_STAT_RECORDS]; //!< unsigned long m_OtherDataSentCurrent[MAX_STAT_RECORDS][2]; //!< unsigned long m_OtherDataSentTotal[MAX_STAT_RECORDS]; //!< private: - #pragma region Thread Handling /// /// /// /// /// - static void BackgroundSendThreadFunction(NetworkServer *server, short player); + static void BackgroundSendThreadFunction(NetworkServer* server, short player); /// /// @@ -365,13 +365,13 @@ namespace RTE { /// /// /// - unsigned char GetPacketIdentifier(RakNet::Packet *packet) const; + unsigned char GetPacketIdentifier(RakNet::Packet* packet) const; /// /// /// /// - void ReceiveNewIncomingConnection(RakNet::Packet *packet); + void ReceiveNewIncomingConnection(RakNet::Packet* packet); /// /// @@ -383,13 +383,13 @@ namespace RTE { /// /// /// - void ReceiveDisconnection(RakNet::Packet *packet); + void ReceiveDisconnection(RakNet::Packet* packet); /// /// /// /// - void ReceiveRegisterMsg(RakNet::Packet *packet); + void ReceiveRegisterMsg(RakNet::Packet* packet); /// /// @@ -401,7 +401,7 @@ namespace RTE { /// /// /// - void ReceiveInputMsg(RakNet::Packet *packet); + void ReceiveInputMsg(RakNet::Packet* packet); /// /// @@ -454,7 +454,7 @@ namespace RTE { /// /// /// - void ReceiveSceneSetupDataAccepted(RakNet::Packet *packet); + void ReceiveSceneSetupDataAccepted(RakNet::Packet* packet); /// /// @@ -499,7 +499,7 @@ namespace RTE { /// /// /// - void ReceiveSceneAcceptedMsg(RakNet::Packet *packet); + void ReceiveSceneAcceptedMsg(RakNet::Packet* packet); /// /// @@ -591,7 +591,7 @@ namespace RTE { /// /// /// - RakNet::SystemAddress ConnectBlocking(RakNet::RakPeerInterface *rakPeer, const char *address, unsigned short port); + RakNet::SystemAddress ConnectBlocking(RakNet::RakPeerInterface* rakPeer, const char* address, unsigned short port); /// /// Clears all the member variables of this NetworkServer, effectively resetting the members of this abstraction level only. @@ -599,8 +599,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - NetworkServer(const NetworkServer &reference) = delete; - NetworkServer & operator=(const NetworkServer &rhs) = delete; + NetworkServer(const NetworkServer& reference) = delete; + NetworkServer& operator=(const NetworkServer& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Managers/PerformanceMan.cpp b/Source/Managers/PerformanceMan.cpp index 42bde776f..a0e20ea45 100644 --- a/Source/Managers/PerformanceMan.cpp +++ b/Source/Managers/PerformanceMan.cpp @@ -8,12 +8,12 @@ namespace RTE { - const std::array PerformanceMan::m_PerfCounterNames = { "Total", "Act AI", "Act Travel", "Act Update", "Prt Travel", "Prt Update", "Activity", "Scripts"}; + const std::array PerformanceMan::m_PerfCounterNames = {"Total", "Act AI", "Act Travel", "Act Update", "Prt Travel", "Prt Update", "Activity", "Scripts"}; thread_local std::array s_PerfMeasureStart; //!< Current measurement start time in microseconds. thread_local std::array s_PerfMeasureStop; //!< Current measurement stop time in microseconds. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::Clear() { m_ShowPerfStats = false; @@ -31,7 +31,7 @@ namespace RTE { m_CurrentPing = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::Initialize() { m_SimUpdateTimer = std::make_unique(); @@ -44,24 +44,26 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::StartPerformanceMeasurement(PerformanceCounters counter) { s_PerfMeasureStart[counter] = g_TimerMan.GetAbsoluteTime(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::StopPerformanceMeasurement(PerformanceCounters counter) { s_PerfMeasureStop[counter] = g_TimerMan.GetAbsoluteTime(); AddPerformanceSample(counter, s_PerfMeasureStop[counter] - s_PerfMeasureStart[counter]); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::NewPerformanceSample() { m_Sample++; - if (m_Sample >= c_MaxSamples) { m_Sample = 0; } + if (m_Sample >= c_MaxSamples) { + m_Sample = 0; + } for (int counter = 0; counter < PerformanceCounters::PerfCounterCount; ++counter) { m_PerfData[counter][m_Sample] = 0; @@ -69,7 +71,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::CalculateSamplePercentages() { for (int counter = 0; counter < PerformanceCounters::PerfCounterCount; ++counter) { @@ -78,7 +80,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// uint64_t PerformanceMan::GetPerformanceCounterAverage(PerformanceCounters counter) const { uint64_t totalPerformanceMeasurement = 0; @@ -86,26 +88,28 @@ namespace RTE { for (int i = 0; i < c_Average; ++i) { totalPerformanceMeasurement += m_PerfData[counter][sample]; sample--; - if (sample < 0) { sample = c_MaxSamples - 1; } + if (sample < 0) { + sample = c_MaxSamples - 1; + } } return totalPerformanceMeasurement / c_Average; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PerformanceMan::CalculateTimeAverage(std::deque &timeMeasurements, float &avgResult, float newTimeMeasurement) const { + void PerformanceMan::CalculateTimeAverage(std::deque& timeMeasurements, float& avgResult, float newTimeMeasurement) const { timeMeasurements.emplace_back(newTimeMeasurement); while (timeMeasurements.size() > c_MSPAverageSampleSize) { timeMeasurements.pop_front(); } avgResult = 0; - for (const float &timeMeasurement : timeMeasurements) { + for (const float& timeMeasurement: timeMeasurements) { avgResult += timeMeasurement; } avgResult /= static_cast(timeMeasurements.size()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::UpdateMSPF(long long measuredUpdateTime, long long measuredDrawTime) { CalculateTimeAverage(m_MSPUs, m_MSPUAverage, static_cast(measuredUpdateTime / 1000)); @@ -113,13 +117,13 @@ namespace RTE { CalculateTimeAverage(m_MSPFs, m_MSPFAverage, static_cast((measuredUpdateTime + measuredDrawTime) / 1000)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PerformanceMan::Draw(BITMAP *bitmapToDrawTo) { + void PerformanceMan::Draw(BITMAP* bitmapToDrawTo) { if (m_ShowPerfStats) { AllegroBitmap drawBitmap(bitmapToDrawTo); - GUIFont *guiFont = g_FrameMan.GetLargeFont(true); + GUIFont* guiFont = g_FrameMan.GetLargeFont(true); char str[128]; float fps = 1.0F / (m_MSPFAverage / 1000.0F); @@ -158,8 +162,7 @@ namespace RTE { std::snprintf(str, sizeof(str), "Lua scripts taking the most time to call Update() this frame:"); guiFont->DrawAligned(&drawBitmap, c_StatsOffsetX, c_StatsHeight + 100, str, GUIFont::Left); - for (int i = 0; i < std::min((size_t)3, m_SortedScriptTimings.size()); i++) - { + for (int i = 0; i < std::min((size_t)3, m_SortedScriptTimings.size()); i++) { std::pair scriptTiming = m_SortedScriptTimings.at(i); std::snprintf(str, sizeof(str), "%.1fms total with %i calls in %s", scriptTiming.second.m_Time / 1000.0, scriptTiming.second.m_CallCount, scriptTiming.first.c_str()); @@ -173,12 +176,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PerformanceMan::DrawPeformanceGraphs(AllegroBitmap &bitmapToDrawTo) { + void PerformanceMan::DrawPeformanceGraphs(AllegroBitmap& bitmapToDrawTo) { CalculateSamplePercentages(); - GUIFont *guiFont = g_FrameMan.GetLargeFont(true); + GUIFont* guiFont = g_FrameMan.GetLargeFont(true); char str[128]; for (int pc = 0; pc < PerformanceCounters::PerfCounterCount; ++pc) { @@ -210,9 +213,13 @@ namespace RTE { bitmapToDrawTo.SetPixel(c_StatsOffsetX - 1 + c_MaxSamples - i, graphStart + c_GraphHeight - dotHeight, makecol32(234, 21, 7)); // Palette index 13. - if (peak < m_PerfData[pc][sample]) { peak = static_cast(m_PerfData[pc][sample]); } + if (peak < m_PerfData[pc][sample]) { + peak = static_cast(m_PerfData[pc][sample]); + } - if (sample == 0) { sample = c_MaxSamples; } + if (sample == 0) { + sample = c_MaxSamples; + } sample--; } @@ -221,16 +228,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PerformanceMan::DrawCurrentPing() const { AllegroBitmap allegroBitmap(g_FrameMan.GetBackBuffer8()); g_FrameMan.GetLargeFont()->DrawAligned(&allegroBitmap, g_FrameMan.GetBackBuffer8()->w - 25, g_FrameMan.GetBackBuffer8()->h - 14, "PING: " + std::to_string(m_CurrentPing), GUIFont::Right); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PerformanceMan::UpdateSortedScriptTimings(const std::unordered_map &scriptTimings) { + void PerformanceMan::UpdateSortedScriptTimings(const std::unordered_map& scriptTimings) { std::vector> sortedScriptTimings; for (auto it = scriptTimings.begin(); it != scriptTimings.end(); it++) { sortedScriptTimings.push_back(*it); @@ -240,4 +247,4 @@ namespace RTE { g_PerformanceMan.m_SortedScriptTimings = sortedScriptTimings; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/PerformanceMan.h b/Source/Managers/PerformanceMan.h index 5e6d009af..2fd695c19 100644 --- a/Source/Managers/PerformanceMan.h +++ b/Source/Managers/PerformanceMan.h @@ -19,7 +19,6 @@ namespace RTE { friend class SettingsMan; public: - /// /// Enumeration of all available performance counters. /// @@ -134,7 +133,12 @@ namespace RTE { /// /// Clears current performance timings. /// - void ResetPerformanceTimings() { m_MSPSUs.clear(); m_MSPFs.clear(); m_MSPUs.clear(); m_MSPDs.clear(); } + void ResetPerformanceTimings() { + m_MSPSUs.clear(); + m_MSPFs.clear(); + m_MSPUs.clear(); + m_MSPDs.clear(); + } /// /// Resets the sim update timer. @@ -151,13 +155,16 @@ namespace RTE { /// /// Updates the individual sim update time measurements and recalculates the average. Supposed to be done every sim update. /// - void UpdateMSPSU() { CalculateTimeAverage(m_MSPSUs, m_MSPSUAverage, static_cast(m_SimUpdateTimer->GetElapsedRealTimeMS())); m_SimUpdateTimer->Reset(); } + void UpdateMSPSU() { + CalculateTimeAverage(m_MSPSUs, m_MSPSUAverage, static_cast(m_SimUpdateTimer->GetElapsedRealTimeMS())); + m_SimUpdateTimer->Reset(); + } /// /// Draws the performance stats to the screen. /// /// The BITMAP to draw the performance stats to. - void Draw(BITMAP *bitmapToDrawTo); + void Draw(BITMAP* bitmapToDrawTo); /// /// Draws the current ping value to the screen. @@ -168,10 +175,9 @@ namespace RTE { /// /// Updates m_SortedScriptTimings so PerformanceMan::Draw() can list how long scripts took. /// - void UpdateSortedScriptTimings(const std::unordered_map &scriptTimings); + void UpdateSortedScriptTimings(const std::unordered_map& scriptTimings); protected: - static constexpr int c_MSPAverageSampleSize = 10; //!< How many samples to use to calculate average milliseconds-per-something value. static constexpr int c_MaxSamples = 120; //!< How many performance samples to store, directly affects graph size. static constexpr int c_Average = 10; //!< How many samples to use to calculate average value displayed on screen. @@ -209,7 +215,6 @@ namespace RTE { std::vector> m_SortedScriptTimings; //!< Sorted vector storing how long scripts took to execute. private: - #pragma region Performance Counter Handling /// /// Adds provided value to current sample of specified performance counter. @@ -237,12 +242,12 @@ namespace RTE { /// The deque of time measurements to store the new measurement in and to recalculate the average with. /// The variable the recalculated average should be stored in. /// The new time measurement to store. - void CalculateTimeAverage(std::deque &timeMeasurements, float &avgResult, float newTimeMeasurement) const; + void CalculateTimeAverage(std::deque& timeMeasurements, float& avgResult, float newTimeMeasurement) const; /// /// Draws the performance graphs to the screen. This will be called by Draw() if advanced performance stats are enabled. /// - void DrawPeformanceGraphs(AllegroBitmap &bitmapToDrawTo); + void DrawPeformanceGraphs(AllegroBitmap& bitmapToDrawTo); /// /// Clears all the member variables of this PerformanceMan, effectively resetting the members of this abstraction level only. @@ -250,8 +255,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - PerformanceMan(const PerformanceMan &reference) = delete; - PerformanceMan & operator=(const PerformanceMan &rhs) = delete; + PerformanceMan(const PerformanceMan& reference) = delete; + PerformanceMan& operator=(const PerformanceMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/PostProcessMan.cpp b/Source/Managers/PostProcessMan.cpp index 89ca5aefb..cb6eb649c 100644 --- a/Source/Managers/PostProcessMan.cpp +++ b/Source/Managers/PostProcessMan.cpp @@ -16,7 +16,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::Clear() { m_PostScreenEffects.clear(); @@ -41,7 +41,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int PostProcessMan::Initialize() { InitializeGLPointers(); @@ -72,7 +72,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::InitializeGLPointers() { glGenTextures(1, &m_BackBuffer8); @@ -89,19 +89,19 @@ namespace RTE { glBufferData(GL_ARRAY_BUFFER, sizeof(c_Quad), c_Quad.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); glEnableVertexAttribArray(1); glBindVertexArray(0); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::DestroyGLPointers() { glDeleteTextures(1, &m_BackBuffer8); glDeleteTextures(1, &m_BackBuffer32); glDeleteTextures(1, &m_Palette8Texture); glDeleteFramebuffers(1, &m_BlitFramebuffer); - for (auto &bitmapTexture : m_BitmapTextures) { + for (auto& bitmapTexture: m_BitmapTextures) { glDeleteTextures(1, &bitmapTexture->m_Texture); } glDeleteFramebuffers(1, &m_PostProcessFramebuffer); @@ -110,7 +110,7 @@ namespace RTE { glDeleteBuffers(1, &m_VertexBuffer); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::CreateGLBackBuffers() { glBindTexture(GL_TEXTURE_2D, m_BackBuffer8); @@ -131,7 +131,7 @@ namespace RTE { m_ProjectionMatrix = glm::ortho(0.0F, static_cast(g_FrameMan.GetBackBuffer8()->w), 0.0F, static_cast(g_FrameMan.GetBackBuffer8()->h), -1.0F, 1.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::UpdatePalette() { glBindTexture(GL_TEXTURE_1D, m_Palette8Texture); @@ -148,12 +148,12 @@ namespace RTE { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PostProcessMan::LazyInitBitmap(BITMAP *bitmap) { + void PostProcessMan::LazyInitBitmap(BITMAP* bitmap) { m_BitmapTextures.emplace_back(new GLBitmapInfo); glGenTextures(1, &m_BitmapTextures.back()->m_Texture); - bitmap->extra = reinterpret_cast(m_BitmapTextures.back().get()); + bitmap->extra = reinterpret_cast(m_BitmapTextures.back().get()); glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap_color_depth(bitmap) == 8 ? 1 : 4); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, reinterpret_cast(bitmap->extra)->m_Texture); @@ -163,10 +163,10 @@ namespace RTE { glGenerateMipmap(GL_TEXTURE_2D); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::Destroy() { - for (std::pair tempBitmapEntry : m_TempEffectBitmaps) { + for (std::pair tempBitmapEntry: m_TempEffectBitmaps) { destroy_bitmap(tempBitmapEntry.second); } DestroyGLPointers(); @@ -175,9 +175,9 @@ namespace RTE { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PostProcessMan::AdjustEffectsPosToPlayerScreen(int playerScreen, BITMAP *targetBitmap, const Vector &targetBitmapOffset, std::list &screenRelativeEffectsList, std::list &screenRelativeGlowBoxesList) { + void PostProcessMan::AdjustEffectsPosToPlayerScreen(int playerScreen, BITMAP* targetBitmap, const Vector& targetBitmapOffset, std::list& screenRelativeEffectsList, std::list& screenRelativeGlowBoxesList) { int screenOcclusionOffsetX = g_CameraMan.GetScreenOcclusion(playerScreen).GetFloorIntX(); int screenOcclusionOffsetY = g_CameraMan.GetScreenOcclusion(playerScreen).GetFloorIntY(); int occludedOffsetX = targetBitmap->w + screenOcclusionOffsetX; @@ -189,34 +189,34 @@ namespace RTE { } // Adjust for the player screen's position on the final buffer - for (const PostEffect &postEffect : screenRelativeEffectsList) { + for (const PostEffect& postEffect: screenRelativeEffectsList) { // Make sure we won't be adding any effects to a part of the screen that is occluded by menus and such if (postEffect.m_Pos.GetFloorIntX() > screenOcclusionOffsetX && postEffect.m_Pos.GetFloorIntY() > screenOcclusionOffsetY && postEffect.m_Pos.GetFloorIntX() < occludedOffsetX && postEffect.m_Pos.GetFloorIntY() < occludedOffsetY) { m_PostScreenEffects.emplace_back(postEffect.m_Pos + targetBitmapOffset, postEffect.m_Bitmap, postEffect.m_BitmapHash, postEffect.m_Strength, postEffect.m_Angle); } } // Adjust glow areas for the player screen's position on the final buffer - for (const Box &glowBox : screenRelativeGlowBoxesList) { + for (const Box& glowBox: screenRelativeGlowBoxesList) { m_PostScreenGlowBoxes.push_back(glowBox); // Adjust each added glow area for the player screen's position on the final buffer m_PostScreenGlowBoxes.back().m_Corner += targetBitmapOffset; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PostProcessMan::RegisterPostEffect(const Vector &effectPos, BITMAP *effect, size_t hash, int strength, float angle) { + void PostProcessMan::RegisterPostEffect(const Vector& effectPos, BITMAP* effect, size_t hash, int strength, float angle) { // These effects get applied when there's a drawn frame that followed one or more sim updates. // They are not only registered on drawn sim updates; flashes and stuff could be missed otherwise if they occur on undrawn sim updates. - + if (effect && g_TimerMan.SimUpdatesSinceDrawn() >= 0) { m_PostSceneEffects.push_back(PostEffect(effectPos, effect, hash, strength, angle)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PostProcessMan::GetPostScreenEffectsWrapped(const Vector &boxPos, int boxWidth, int boxHeight, std::list &effectsList, int team) { + bool PostProcessMan::GetPostScreenEffectsWrapped(const Vector& boxPos, int boxWidth, int boxHeight, std::list& effectsList, int team) { bool found = false; // Do the first unwrapped rect @@ -248,12 +248,12 @@ namespace RTE { return found; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BITMAP *PostProcessMan::GetTempEffectBitmap(BITMAP *bitmap) const { + BITMAP* PostProcessMan::GetTempEffectBitmap(BITMAP* bitmap) const { // Get the largest dimension of the bitmap and convert it to a multiple of 16, i.e. 16, 32, etc int bitmapSizeNeeded = static_cast(std::ceil(static_cast(std::max(bitmap->w, bitmap->h)) / 16.0F)) * 16; - std::unordered_map::const_iterator correspondingBitmapSizeEntry = m_TempEffectBitmaps.find(bitmapSizeNeeded); + std::unordered_map::const_iterator correspondingBitmapSizeEntry = m_TempEffectBitmaps.find(bitmapSizeNeeded); // If we didn't find a match then the bitmap size is greater than 512 but that's the biggest we've got, so return it if (correspondingBitmapSizeEntry == m_TempEffectBitmaps.end()) { @@ -263,33 +263,33 @@ namespace RTE { return correspondingBitmapSizeEntry->second; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PostProcessMan::RegisterGlowDotEffect(const Vector &effectPos, DotGlowColor color, int strength) { + void PostProcessMan::RegisterGlowDotEffect(const Vector& effectPos, DotGlowColor color, int strength) { // These effects only apply only once per drawn sim update, and only on the first frame drawn after one or more sim updates if (color != NoDot && g_TimerMan.DrawnSimUpdate() && g_TimerMan.SimUpdatesSinceDrawn() >= 0) { RegisterPostEffect(effectPos, GetDotGlowEffect(color), GetDotGlowEffectHash(color), strength); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PostProcessMan::GetGlowAreasWrapped(const Vector &boxPos, int boxWidth, int boxHeight, std::list &areaList) const { + bool PostProcessMan::GetGlowAreasWrapped(const Vector& boxPos, int boxWidth, int boxHeight, std::list& areaList) const { bool foundAny = false; Vector intRectPosRelativeToBox; // Account for wrapping in any registered glow IntRects, as well as on the box we're testing against std::list wrappedGlowRects; - for (const IntRect &glowArea : m_GlowAreas) { + for (const IntRect& glowArea: m_GlowAreas) { g_SceneMan.WrapRect(glowArea, wrappedGlowRects); } std::list wrappedTestRects; g_SceneMan.WrapRect(IntRect(boxPos.GetFloorIntX(), boxPos.GetFloorIntY(), boxPos.GetFloorIntX() + boxWidth, boxPos.GetFloorIntY() + boxHeight), wrappedTestRects); // Check for intersections. If any are found, cut down the intersecting IntRect to the bounds of the IntRect we're testing against, then make and store a Box out of it - for (IntRect &wrappedTestRect : wrappedTestRects) { - for (const IntRect &wrappedGlowRect : wrappedGlowRects) { + for (IntRect& wrappedTestRect: wrappedTestRects) { + for (const IntRect& wrappedGlowRect: wrappedGlowRects) { if (wrappedTestRect.Intersects(wrappedGlowRect)) { IntRect cutRect(wrappedGlowRect); cutRect.IntersectionCut(wrappedTestRect); @@ -302,38 +302,40 @@ namespace RTE { return foundAny; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PostProcessMan::GetNetworkPostEffectsList(int whichScreen, std::list &outputList) { + void PostProcessMan::GetNetworkPostEffectsList(int whichScreen, std::list& outputList) { ScreenRelativeEffectsMutex.at(whichScreen).lock(); outputList.clear(); - for (const PostEffect &postEffect : m_ScreenRelativeEffects.at(whichScreen)) { + for (const PostEffect& postEffect: m_ScreenRelativeEffects.at(whichScreen)) { outputList.push_back(PostEffect(postEffect.m_Pos, postEffect.m_Bitmap, postEffect.m_BitmapHash, postEffect.m_Strength, postEffect.m_Angle)); } ScreenRelativeEffectsMutex.at(whichScreen).unlock(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PostProcessMan::SetNetworkPostEffectsList(int whichScreen, std::list &inputList) { + void PostProcessMan::SetNetworkPostEffectsList(int whichScreen, std::list& inputList) { ScreenRelativeEffectsMutex.at(whichScreen).lock(); m_ScreenRelativeEffects.at(whichScreen).clear(); - for (const PostEffect &postEffect : inputList) { + for (const PostEffect& postEffect: inputList) { m_ScreenRelativeEffects.at(whichScreen).push_back(PostEffect(postEffect.m_Pos, postEffect.m_Bitmap, postEffect.m_BitmapHash, postEffect.m_Strength, postEffect.m_Angle)); } ScreenRelativeEffectsMutex.at(whichScreen).unlock(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PostProcessMan::GetPostScreenEffects(Vector boxPos, int boxWidth, int boxHeight, std::list &effectsList, int team) { + bool PostProcessMan::GetPostScreenEffects(Vector boxPos, int boxWidth, int boxHeight, std::list& effectsList, int team) { bool found = false; bool unseen = false; Vector postEffectPosRelativeToBox; if (g_SceneMan.GetScene()) { - for (PostEffect &scenePostEffect : m_PostSceneEffects) { - if (team != Activity::NoTeam) { unseen = g_SceneMan.IsUnseen(scenePostEffect.m_Pos.GetFloorIntX(), scenePostEffect.m_Pos.GetFloorIntY(), team); } + for (PostEffect& scenePostEffect: m_PostSceneEffects) { + if (team != Activity::NoTeam) { + unseen = g_SceneMan.IsUnseen(scenePostEffect.m_Pos.GetFloorIntX(), scenePostEffect.m_Pos.GetFloorIntY(), team); + } if (WithinBox(scenePostEffect.m_Pos, boxPos, static_cast(boxWidth), static_cast(boxHeight)) && !unseen) { found = true; @@ -345,14 +347,14 @@ namespace RTE { return found; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PostProcessMan::GetPostScreenEffects(int left, int top, int right, int bottom, std::list &effectsList, int team) { + bool PostProcessMan::GetPostScreenEffects(int left, int top, int right, int bottom, std::list& effectsList, int team) { bool found = false; bool unseen = false; Vector postEffectPosRelativeToBox; - for (PostEffect &scenePostEffect : m_PostSceneEffects) { + for (PostEffect& scenePostEffect: m_PostSceneEffects) { if (team != Activity::NoTeam) { unseen = g_SceneMan.IsUnseen(scenePostEffect.m_Pos.GetFloorIntX(), scenePostEffect.m_Pos.GetFloorIntY(), team); } @@ -366,9 +368,9 @@ namespace RTE { return found; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BITMAP * PostProcessMan::GetDotGlowEffect(DotGlowColor whichColor) const { + BITMAP* PostProcessMan::GetDotGlowEffect(DotGlowColor whichColor) const { switch (whichColor) { case NoDot: return nullptr; @@ -384,7 +386,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// size_t PostProcessMan::GetDotGlowEffectHash(DotGlowColor whichColor) const { switch (whichColor) { @@ -402,7 +404,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::PostProcess() { UpdatePalette(); @@ -447,7 +449,7 @@ namespace RTE { m_PostScreenEffects.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::DrawDotGlowEffects() { int startX = 0; @@ -455,7 +457,7 @@ namespace RTE { int endX = 0; int endY = 0; int testpixel = 0; - if(!m_YellowGlow->extra) { + if (!m_YellowGlow->extra) { LazyInitBitmap(m_YellowGlow); } @@ -464,7 +466,7 @@ namespace RTE { GL_CHECK(glBindTexture(GL_TEXTURE_2D, reinterpret_cast(m_YellowGlow->extra)->m_Texture)); // Randomly sample the entire backbuffer, looking for pixels to put a glow on. - for (const Box &glowBox : m_PostScreenGlowBoxes) { + for (const Box& glowBox: m_PostScreenGlowBoxes) { startX = glowBox.m_Corner.GetFloorIntX(); startY = glowBox.m_Corner.GetFloorIntY(); endX = startX + static_cast(glowBox.m_Width); @@ -472,7 +474,7 @@ namespace RTE { // Sanity check a little at least if (startX < 0 || startX >= g_FrameMan.GetBackBuffer8()->w || startY < 0 || startY >= g_FrameMan.GetBackBuffer8()->h || - endX < 0 || endX >= g_FrameMan.GetBackBuffer8()->w || endY < 0 || endY >= g_FrameMan.GetBackBuffer8()->h) { + endX < 0 || endX >= g_FrameMan.GetBackBuffer8()->w || endY < 0 || endY >= g_FrameMan.GetBackBuffer8()->h) { continue; } @@ -499,11 +501,11 @@ namespace RTE { // RED /* if (testpixel == 13) { - draw_trans_sprite(m_BackBuffer32, m_RedGlow, x - 2, y - 2); + draw_trans_sprite(m_BackBuffer32, m_RedGlow, x - 2, y - 2); } // BLUE if (testpixel == 166) { - draw_trans_sprite(g_FrameMan.GetBackBuffer32(), m_BlueGlow, x - 2, y - 2); + draw_trans_sprite(g_FrameMan.GetBackBuffer32(), m_BlueGlow, x - 2, y - 2); } */ } @@ -511,10 +513,10 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PostProcessMan::DrawPostScreenEffects() { - BITMAP *effectBitmap = nullptr; + BITMAP* effectBitmap = nullptr; float effectPosX = 0; float effectPosY = 0; float effectStrength = 0; @@ -525,7 +527,7 @@ namespace RTE { m_PostProcessShader->SetInt(m_PostProcessShader->GetTextureUniform(), 0); m_PostProcessShader->SetMatrix4f(m_PostProcessShader->GetProjectionUniform(), m_ProjectionMatrix); - for (const PostEffect &postEffect : m_PostScreenEffects) { + for (const PostEffect& postEffect: m_PostScreenEffects) { if (postEffect.m_Bitmap) { if (!postEffect.m_Bitmap->extra) { LazyInitBitmap(postEffect.m_Bitmap); diff --git a/Source/Managers/PostProcessMan.h b/Source/Managers/PostProcessMan.h index 7fa4a8e89..a2dc7a87d 100644 --- a/Source/Managers/PostProcessMan.h +++ b/Source/Managers/PostProcessMan.h @@ -22,7 +22,7 @@ namespace RTE { /// Structure for storing a post-process screen effect to be applied at the last stage of 32bpp rendering. /// struct PostEffect { - BITMAP *m_Bitmap = nullptr; //!< The bitmap to blend, not owned. + BITMAP* m_Bitmap = nullptr; //!< The bitmap to blend, not owned. size_t m_BitmapHash = 0; //!< Hash used to transmit glow events over the network. float m_Angle = 0.0F; // Post effect angle in radians. int m_Strength = 128; //!< Scalar float for how hard to blend it in, 0 - 255. @@ -31,7 +31,8 @@ namespace RTE { /// /// Constructor method used to instantiate a PostEffect object in system memory. /// - PostEffect(const Vector &pos, BITMAP *bitmap, size_t bitmapHash, int strength, float angle) : m_Bitmap(bitmap), m_BitmapHash(bitmapHash), m_Angle(angle), m_Strength(strength), m_Pos(pos) {} + PostEffect(const Vector& pos, BITMAP* bitmap, size_t bitmapHash, int strength, float angle) : + m_Bitmap(bitmap), m_BitmapHash(bitmapHash), m_Angle(angle), m_Strength(strength), m_Pos(pos) {} }; /// @@ -40,7 +41,6 @@ namespace RTE { class PostProcessMan : public Singleton { public: - #pragma region Creation /// /// Constructor method used to instantiate a PostProcessMan object in system memory. Create() should be called before using the object. @@ -73,12 +73,18 @@ namespace RTE { /// /// Clears the list of registered post-processing screen effects and glow boxes. /// - void ClearScreenPostEffects() { m_PostScreenEffects.clear(); m_PostScreenGlowBoxes.clear(); } + void ClearScreenPostEffects() { + m_PostScreenEffects.clear(); + m_PostScreenGlowBoxes.clear(); + } /// /// Clears the list of registered post-processing scene effects and glow areas. /// - void ClearScenePostEffects() { m_PostSceneEffects.clear(); m_GlowAreas.clear(); } + void ClearScenePostEffects() { + m_PostSceneEffects.clear(); + m_GlowAreas.clear(); + } #pragma endregion #pragma region Concrete Methods @@ -95,7 +101,7 @@ namespace RTE { /// The position of the specified player's draw screen on the backbuffer. /// List of the specified player's accumulated post effects for this frame. /// List of the specified player's accumulated glow boxes for this frame. - void AdjustEffectsPosToPlayerScreen(int playerScreen, BITMAP *targetBitmap, const Vector &targetBitmapOffset, std::list &screenRelativeEffectsList, std::list &screenRelativeGlowBoxesList); + void AdjustEffectsPosToPlayerScreen(int playerScreen, BITMAP* targetBitmap, const Vector& targetBitmapOffset, std::list& screenRelativeEffectsList, std::list& screenRelativeGlowBoxesList); #pragma endregion #pragma region Post Effect Handling @@ -107,7 +113,7 @@ namespace RTE { /// Hash value of the effect for transmitting over the network. /// The intensity level this effect should have when blended in post. 0 - 255. /// The angle this effect should be rotated at in radians. - void RegisterPostEffect(const Vector &effectPos, BITMAP *effect, size_t hash, int strength = 255, float angle = 0); + void RegisterPostEffect(const Vector& effectPos, BITMAP* effect, size_t hash, int strength = 255, float angle = 0); /// /// Gets all screen effects that are located within a box in the scene. @@ -119,14 +125,14 @@ namespace RTE { /// The list to add the screen effects that fall within the box to. The coordinates of the effects returned here will be relative to the boxPos passed in above. /// The team whose unseen layer should obscure the screen effects here. /// Whether any active post effects were found in that box. - bool GetPostScreenEffectsWrapped(const Vector &boxPos, int boxWidth, int boxHeight, std::list &effectsList, int team = -1); + bool GetPostScreenEffectsWrapped(const Vector& boxPos, int boxWidth, int boxHeight, std::list& effectsList, int team = -1); /// /// Gets a temporary bitmap of specified size to rotate post effects in. /// /// Size of bitmap to get. /// Pointer to the temporary bitmap. - BITMAP * GetTempEffectBitmap(BITMAP *bitmap) const; + BITMAP* GetTempEffectBitmap(BITMAP* bitmap) const; #pragma endregion #pragma region Post Pixel Glow Handling @@ -135,14 +141,18 @@ namespace RTE { /// Registers a specific IntRect to be post-processed and have special pixel colors lit up by glow effects in it. /// /// The IntRect to have special color pixels glow in, in scene coordinates. - void RegisterGlowArea(const IntRect &glowArea) { if (g_TimerMan.DrawnSimUpdate() && g_TimerMan.SimUpdatesSinceDrawn() >= 0) { m_GlowAreas.push_back(glowArea); } } + void RegisterGlowArea(const IntRect& glowArea) { + if (g_TimerMan.DrawnSimUpdate() && g_TimerMan.SimUpdatesSinceDrawn() >= 0) { + m_GlowAreas.push_back(glowArea); + } + } /// /// Creates an IntRect and registers it to be post-processed and have special pixel colors lit up by glow effects in it. /// /// The center of the IntRect. /// The radius around it to add as an area. - void RegisterGlowArea(const Vector ¢er, float radius) { + void RegisterGlowArea(const Vector& center, float radius) { RegisterGlowArea(IntRect(static_cast(center.m_X - radius), static_cast(center.m_Y - radius), static_cast(center.m_X + radius), static_cast(center.m_Y + radius))); } @@ -152,7 +162,7 @@ namespace RTE { /// The absolute scene coordinates of the center of the effect. /// Which glow dot color to register, see the DotGlowColor enumerator. /// The intensity level this effect should have when blended in post. 0 - 255. - void RegisterGlowDotEffect(const Vector &effectPos, DotGlowColor color, int strength = 255); + void RegisterGlowDotEffect(const Vector& effectPos, DotGlowColor color, int strength = 255); /// /// Gets all glow areas that affect anything within a box in the scene. @@ -163,7 +173,7 @@ namespace RTE { /// The height of the box. /// The list to add the glow Boxes that intersect to. The coordinates of the Boxes returned here will be relative to the boxPos passed in above. /// Whether any active post effects were found in that box. - bool GetGlowAreasWrapped(const Vector &boxPos, int boxWidth, int boxHeight, std::list &areaList) const; + bool GetGlowAreasWrapped(const Vector& boxPos, int boxWidth, int boxHeight, std::list& areaList) const; #pragma endregion #pragma region Network Post Effect Handling @@ -172,14 +182,14 @@ namespace RTE { /// /// Which player screen to get list for. /// Reference to the list of post effects to copy into. - void GetNetworkPostEffectsList(int whichScreen, std::list &outputList); + void GetNetworkPostEffectsList(int whichScreen, std::list& outputList); /// /// Copies the player's screen relative post effects from the referenced list to the list of this PostProcessMan. Used for receiving post effect data over the network. /// /// Which player screen to set list for. /// Reference to the list of post effects to copy from. - void SetNetworkPostEffectsList(int whichScreen, std::list &inputList); + void SetNetworkPostEffectsList(int whichScreen, std::list& inputList); #pragma endregion /// @@ -189,7 +199,6 @@ namespace RTE { GLuint GetPostProcessColorBuffer() { return m_BackBuffer32; } protected: - std::list m_PostScreenEffects; //!< List of effects to apply at the end of each frame. This list gets cleared out and re-filled each frame. std::list m_PostSceneEffects; //!< All post-processing effects registered for this draw frame in the scene. @@ -199,15 +208,15 @@ namespace RTE { std::array, c_MaxScreenCount> m_ScreenRelativeEffects; //!< List of screen relative effects for each player in online multiplayer. std::array ScreenRelativeEffectsMutex; //!< Mutex for the ScreenRelativeEffects list when accessed by multiple threads in online multiplayer. - BITMAP *m_YellowGlow; //!< Bitmap for the yellow dot glow effect. - BITMAP *m_RedGlow; //!< Bitmap for the red dot glow effect. - BITMAP *m_BlueGlow; //!< Bitmap for the blue dot glow effect. + BITMAP* m_YellowGlow; //!< Bitmap for the yellow dot glow effect. + BITMAP* m_RedGlow; //!< Bitmap for the red dot glow effect. + BITMAP* m_BlueGlow; //!< Bitmap for the blue dot glow effect. size_t m_YellowGlowHash; //!< Hash value for the yellow dot glow effect bitmap. size_t m_RedGlowHash; //!< Hash value for the red dot glow effect bitmap. size_t m_BlueGlowHash; //!< Hash value for the blue dot glow effect bitmap. - std::unordered_map m_TempEffectBitmaps; //!< Stores temporary bitmaps to rotate post effects in for quick access. + std::unordered_map m_TempEffectBitmaps; //!< Stores temporary bitmaps to rotate post effects in for quick access. private: GLuint m_BackBuffer8; //!< Backbuffer texture for incoming indexed drawings. @@ -233,7 +242,7 @@ namespace RTE { /// The list to add the screen effects that fall within the box to. The coordinates of the effects returned here will be relative to the boxPos passed in above. /// The team whose unseen area should block the glows. /// Whether any active post effects were found in that box. - bool GetPostScreenEffects(Vector boxPos, int boxWidth, int boxHeight, std::list &effectsList, int team = -1); + bool GetPostScreenEffects(Vector boxPos, int boxWidth, int boxHeight, std::list& effectsList, int team = -1); /// /// Gets all screen effects that are located within a box in the scene. Their coordinates will be returned relative to the upper left corner of the box passed in here. @@ -245,7 +254,7 @@ namespace RTE { /// The list to add the screen effects that fall within the box to. The coordinates of the effects returned here will be relative to the boxPos passed in above. /// The team whose unseen area should block the glows. /// Whether any active post effects were found in that box. - bool GetPostScreenEffects(int left, int top, int right, int bottom, std::list &effectsList, int team = -1); + bool GetPostScreenEffects(int left, int top, int right, int bottom, std::list& effectsList, int team = -1); #pragma endregion #pragma region Post Pixel Glow Handling @@ -254,7 +263,7 @@ namespace RTE { /// /// Which of the dot glow colors to get, see the DotGlowColor enumerator. /// The requested glow dot BITMAP. - BITMAP * GetDotGlowEffect(DotGlowColor whichColor) const; + BITMAP* GetDotGlowEffect(DotGlowColor whichColor) const; /// /// Gets the hash value of a specific standard dot glow effect for making pixels glow. @@ -285,7 +294,7 @@ namespace RTE { /// Initializes all the GL pointers used by this PostProcessMan. /// void InitializeGLPointers(); - + /// /// Destroys all the GL pointers used by this PostProcessMan. /// @@ -300,11 +309,11 @@ namespace RTE { /// Creates and upload a new GL texture. The texture pointer is stored in the BITMAP->extra field. /// /// The bitmap to create a texture for. - void LazyInitBitmap(BITMAP *bitmap); + void LazyInitBitmap(BITMAP* bitmap); // Disallow the use of some implicit methods. - PostProcessMan(const PostProcessMan &reference) = delete; - PostProcessMan & operator=(const PostProcessMan &rhs) = delete; + PostProcessMan(const PostProcessMan& reference) = delete; + PostProcessMan& operator=(const PostProcessMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/PresetMan.cpp b/Source/Managers/PresetMan.cpp index e788bb2ae..0ea1bc1a7 100644 --- a/Source/Managers/PresetMan.cpp +++ b/Source/Managers/PresetMan.cpp @@ -8,8 +8,7 @@ // http://www.datarealms.com // Suppress compiler warning about unrecognized escape sequence on line 183 -#pragma warning( disable : 4129 ) - +#pragma warning(disable : 4129) ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -31,1150 +30,1058 @@ namespace RTE { - const std::array PresetMan::c_OfficialModules = { "Base.rte", "Coalition.rte", "Imperatus.rte", "Techion.rte", "Dummy.rte", "Ronin.rte", "Browncoats.rte", "Uzira.rte", "MuIlaak.rte", "Missions.rte" }; - const std::array, 3> PresetMan::c_UserdataModules = {{ - {c_UserScenesModuleName, "User Scenes"}, - {c_UserConquestSavesModuleName, "Conquest Saves"}, - {c_UserScriptedSavesModuleName, "Scripted Activity Saves" } - }}; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this PresetMan, effectively -// resetting the members of this abstraction level only. - -void PresetMan::Clear() -{ - m_pDataModules.clear(); - m_DataModuleIDs.clear(); - m_OfficialModuleCount = 0; - m_TotalGroupRegister.clear(); - m_LastReloadedEntityPresetInfo.fill(""); - m_ReloadEntityPresetCalledThisUpdate = false; -} - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Save -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the complete state of this PresetMan with a Writer for -// later recreation with Create(Reader &reader); - -int PresetMan::Save(Writer &writer) const -{ - writer << m_Actors.size(); - for (list::const_iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) - writer << **itr; + const std::array PresetMan::c_OfficialModules = {"Base.rte", "Coalition.rte", "Imperatus.rte", "Techion.rte", "Dummy.rte", "Ronin.rte", "Browncoats.rte", "Uzira.rte", "MuIlaak.rte", "Missions.rte"}; + const std::array, 3> PresetMan::c_UserdataModules = {{{c_UserScenesModuleName, "User Scenes"}, + {c_UserConquestSavesModuleName, "Conquest Saves"}, + {c_UserScriptedSavesModuleName, "Scripted Activity Saves"}}}; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this PresetMan, effectively + // resetting the members of this abstraction level only. + + void PresetMan::Clear() { + m_pDataModules.clear(); + m_DataModuleIDs.clear(); + m_OfficialModuleCount = 0; + m_TotalGroupRegister.clear(); + m_LastReloadedEntityPresetInfo.fill(""); + m_ReloadEntityPresetCalledThisUpdate = false; + } - writer << m_Particles.size(); - for (list::const_iterator itr2 = m_Particles.begin(); itr2 != m_Particles.end(); ++itr2) - writer << **itr2; + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Save + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the complete state of this PresetMan with a Writer for + // later recreation with Create(Reader &reader); - return 0; -} -*/ + int PresetMan::Save(Writer &writer) const + { + writer << m_Actors.size(); + for (list::const_iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) + writer << **itr; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the PresetMan entity. + writer << m_Particles.size(); + for (list::const_iterator itr2 = m_Particles.begin(); itr2 != m_Particles.end(); ++itr2) + writer << **itr2; -void PresetMan::Destroy() -{ - for (std::vector::iterator dmItr = m_pDataModules.begin(); dmItr != m_pDataModules.end(); ++dmItr) - { - delete (*dmItr); - } + return 0; + } + */ - Clear(); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the PresetMan entity. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void PresetMan::Destroy() { + for (std::vector::iterator dmItr = m_pDataModules.begin(); dmItr != m_pDataModules.end(); ++dmItr) { + delete (*dmItr); + } -bool PresetMan::LoadDataModule(const std::string &moduleName, bool official, bool userdata, const ProgressCallback &progressCallback) { - if (moduleName.empty()) { - return false; + Clear(); } - // Make a lowercase-version of the module name so it makes it easier to compare to and find case-agnostically. - std::string lowercaseName = moduleName; - std::transform(lowercaseName.begin(), lowercaseName.end(), lowercaseName.begin(), ::tolower); - // Make sure we don't add the same module twice. - for (const DataModule *dataModule : m_pDataModules) { - if (dataModule->GetFileName() == moduleName) { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool PresetMan::LoadDataModule(const std::string& moduleName, bool official, bool userdata, const ProgressCallback& progressCallback) { + if (moduleName.empty()) { return false; } - } + // Make a lowercase-version of the module name so it makes it easier to compare to and find case-agnostically. + std::string lowercaseName = moduleName; + std::transform(lowercaseName.begin(), lowercaseName.end(), lowercaseName.begin(), ::tolower); - // Only instantiate it here, because it needs to be in the lists of this before being created. - DataModule *newModule = new DataModule(); + // Make sure we don't add the same module twice. + for (const DataModule* dataModule: m_pDataModules) { + if (dataModule->GetFileName() == moduleName) { + return false; + } + } - // Official modules are stacked in the beginning of the vector. - if (official && !userdata) { - // Halt if an official module is being loaded after any non-official ones! - //RTEAssert(m_pDataModules.size() == m_OfficialModuleCount, "Trying to load an official module after a non-official one has been loaded!"); + // Only instantiate it here, because it needs to be in the lists of this before being created. + DataModule* newModule = new DataModule(); - // Find where the official modules end in the vector. - std::vector::iterator moduleItr = m_pDataModules.begin(); - size_t newModuleID = 0; - for (; newModuleID < m_OfficialModuleCount; ++newModuleID) { - moduleItr++; + // Official modules are stacked in the beginning of the vector. + if (official && !userdata) { + // Halt if an official module is being loaded after any non-official ones! + // RTEAssert(m_pDataModules.size() == m_OfficialModuleCount, "Trying to load an official module after a non-official one has been loaded!"); + + // Find where the official modules end in the vector. + std::vector::iterator moduleItr = m_pDataModules.begin(); + size_t newModuleID = 0; + for (; newModuleID < m_OfficialModuleCount; ++newModuleID) { + moduleItr++; + } + // Insert into after the last official one. + m_pDataModules.emplace(moduleItr, newModule); + m_DataModuleIDs.try_emplace(lowercaseName, newModuleID); + m_OfficialModuleCount++; + } else { + if (userdata) { + newModule->SetAsUserdata(); + } + m_pDataModules.emplace_back(newModule); + m_DataModuleIDs.try_emplace(lowercaseName, m_pDataModules.size() - 1); } - // Insert into after the last official one. - m_pDataModules.emplace(moduleItr, newModule); - m_DataModuleIDs.try_emplace(lowercaseName, newModuleID); - m_OfficialModuleCount++; - } else { - if (userdata) { newModule->SetAsUserdata(); } - m_pDataModules.emplace_back(newModule); - m_DataModuleIDs.try_emplace(lowercaseName, m_pDataModules.size() - 1); - } - if (newModule->Create(moduleName, progressCallback) < 0) { - RTEAbort("Failed to find the " + moduleName + " Data Module!"); - return false; + if (newModule->Create(moduleName, progressCallback) < 0) { + RTEAbort("Failed to find the " + moduleName + " Data Module!"); + return false; + } + newModule = nullptr; + return true; } - newModule = nullptr; - return true; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool PresetMan::LoadAllDataModules() { - auto moduleLoadTimerStart = std::chrono::steady_clock::now(); + bool PresetMan::LoadAllDataModules() { + auto moduleLoadTimerStart = std::chrono::steady_clock::now(); - // Destroy any possible loaded modules - Destroy(); + // Destroy any possible loaded modules + Destroy(); - FindAndExtractZippedModules(); + FindAndExtractZippedModules(); - // Load all the official modules first! - for (const std::string &officialModule : c_OfficialModules) { - if (!LoadDataModule(officialModule, true, false, LoadingScreen::LoadingSplashProgressReport)) { - return false; + // Load all the official modules first! + for (const std::string& officialModule: c_OfficialModules) { + if (!LoadDataModule(officialModule, true, false, LoadingScreen::LoadingSplashProgressReport)) { + return false; + } } - } - // If a single module is specified, skip loading all other unofficial modules and load specified module only. - if (!m_SingleModuleToLoad.empty() && !IsModuleOfficial(m_SingleModuleToLoad)) { - if (!LoadDataModule(m_SingleModuleToLoad, false, false, LoadingScreen::LoadingSplashProgressReport)) { - g_ConsoleMan.PrintString("ERROR: Failed to load DataModule \"" + m_SingleModuleToLoad + "\"! Only official modules were loaded!"); - return false; - } - } else { - std::vector modDirectoryFolders; - const std::string modDirectory = System::GetWorkingDirectory() + System::GetModDirectory(); - std::copy_if(std::filesystem::directory_iterator(modDirectory), std::filesystem::directory_iterator(), std::back_inserter(modDirectoryFolders), - [](auto dirEntry){ return std::filesystem::is_directory(dirEntry); } - ); - std::sort(modDirectoryFolders.begin(), modDirectoryFolders.end()); - - for (const std::filesystem::directory_entry &directoryEntry : modDirectoryFolders) { - std::string directoryEntryPath = directoryEntry.path().generic_string(); - if (std::regex_match(directoryEntryPath, std::regex(".*\.rte"))) { - std::string moduleName = directoryEntryPath.substr(directoryEntryPath.find_last_of('/') + 1, std::string::npos); - if (!g_SettingsMan.IsModDisabled(moduleName) && !IsModuleOfficial(moduleName) && !IsModuleUserdata(moduleName)) { - int moduleID = GetModuleID(moduleName); - // NOTE: LoadDataModule can return false (especially since it may try to load already loaded modules, which is okay) and shouldn't cause stop, so we can ignore its return value here. - if (moduleID < 0 || moduleID >= GetOfficialModuleCount()) { LoadDataModule(moduleName, false, false, LoadingScreen::LoadingSplashProgressReport); } + // If a single module is specified, skip loading all other unofficial modules and load specified module only. + if (!m_SingleModuleToLoad.empty() && !IsModuleOfficial(m_SingleModuleToLoad)) { + if (!LoadDataModule(m_SingleModuleToLoad, false, false, LoadingScreen::LoadingSplashProgressReport)) { + g_ConsoleMan.PrintString("ERROR: Failed to load DataModule \"" + m_SingleModuleToLoad + "\"! Only official modules were loaded!"); + return false; + } + } else { + std::vector modDirectoryFolders; + const std::string modDirectory = System::GetWorkingDirectory() + System::GetModDirectory(); + std::copy_if(std::filesystem::directory_iterator(modDirectory), std::filesystem::directory_iterator(), std::back_inserter(modDirectoryFolders), + [](auto dirEntry) { return std::filesystem::is_directory(dirEntry); }); + std::sort(modDirectoryFolders.begin(), modDirectoryFolders.end()); + + for (const std::filesystem::directory_entry& directoryEntry: modDirectoryFolders) { + std::string directoryEntryPath = directoryEntry.path().generic_string(); + if (std::regex_match(directoryEntryPath, std::regex(".*\.rte"))) { + std::string moduleName = directoryEntryPath.substr(directoryEntryPath.find_last_of('/') + 1, std::string::npos); + if (!g_SettingsMan.IsModDisabled(moduleName) && !IsModuleOfficial(moduleName) && !IsModuleUserdata(moduleName)) { + int moduleID = GetModuleID(moduleName); + // NOTE: LoadDataModule can return false (especially since it may try to load already loaded modules, which is okay) and shouldn't cause stop, so we can ignore its return value here. + if (moduleID < 0 || moduleID >= GetOfficialModuleCount()) { + LoadDataModule(moduleName, false, false, LoadingScreen::LoadingSplashProgressReport); + } + } } } - } - // Load userdata modules AFTER all other techs etc are loaded; might be referring to stuff in user mods. - for (const auto &[userdataModuleName, userdataModuleFriendlyName] : c_UserdataModules) { - if (!std::filesystem::exists(System::GetWorkingDirectory() + System::GetUserdataDirectory() + userdataModuleName)) { - bool scanContentsAndIgnoreMissing = userdataModuleName == c_UserScenesModuleName; - DataModule::CreateOnDiskAsUserdata(userdataModuleName, userdataModuleFriendlyName, scanContentsAndIgnoreMissing, scanContentsAndIgnoreMissing); - } - if (!LoadDataModule(userdataModuleName, false, true, LoadingScreen::LoadingSplashProgressReport)) { - return false; + // Load userdata modules AFTER all other techs etc are loaded; might be referring to stuff in user mods. + for (const auto& [userdataModuleName, userdataModuleFriendlyName]: c_UserdataModules) { + if (!std::filesystem::exists(System::GetWorkingDirectory() + System::GetUserdataDirectory() + userdataModuleName)) { + bool scanContentsAndIgnoreMissing = userdataModuleName == c_UserScenesModuleName; + DataModule::CreateOnDiskAsUserdata(userdataModuleName, userdataModuleFriendlyName, scanContentsAndIgnoreMissing, scanContentsAndIgnoreMissing); + } + if (!LoadDataModule(userdataModuleName, false, true, LoadingScreen::LoadingSplashProgressReport)) { + return false; + } } } + + if (g_SettingsMan.IsMeasuringModuleLoadTime()) { + std::chrono::milliseconds moduleLoadElapsedTime = std::chrono::duration_cast(std::chrono::steady_clock::now() - moduleLoadTimerStart); + g_ConsoleMan.PrintString("Module load duration is: " + std::to_string(moduleLoadElapsedTime.count()) + "ms"); + } + return true; } - if (g_SettingsMan.IsMeasuringModuleLoadTime()) { - std::chrono::milliseconds moduleLoadElapsedTime = std::chrono::duration_cast(std::chrono::steady_clock::now() - moduleLoadTimerStart); - g_ConsoleMan.PrintString("Module load duration is: " + std::to_string(moduleLoadElapsedTime.count()) + "ms"); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDataModule + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a specific loaded DataModule + + const DataModule* PresetMan::GetDataModule(int whichModule) { + RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); + return m_pDataModules[whichModule]; } - return true; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDataModuleName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a name specific loaded DataModule -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDataModule -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a specific loaded DataModule + const std::string PresetMan::GetDataModuleName(int whichModule) { + RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); + return m_pDataModules[whichModule]->GetFileName(); + } -const DataModule * PresetMan::GetDataModule(int whichModule) -{ - RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - return m_pDataModules[whichModule]; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetModuleID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ID of a loaded DataModule. + + int PresetMan::GetModuleID(std::string moduleName) { + // Lower-case search name so we can match up against the already-lowercase names in m_DataModuleIDs + std::transform(moduleName.begin(), moduleName.end(), moduleName.begin(), ::tolower); + + // First pass + std::map::iterator itr = m_DataModuleIDs.find(moduleName); + if (itr != m_DataModuleIDs.end()) + return (*itr).second; + + // Try with or without the .rte on the end before giving up + int dotPos = moduleName.find_last_of('.'); + // Wasnt, so try adding it + if (dotPos == std::string::npos) + moduleName = moduleName + System::GetModulePackageExtension(); + // There was ".rte", so try to shave it off the name + else + moduleName = moduleName.substr(0, dotPos); + + // Try to find the module again! + itr = m_DataModuleIDs.find(moduleName); + if (itr != m_DataModuleIDs.end()) + return (*itr).second; + + /* No need to do this second pass now; we immediately do the case-agnostic search + // Add .rte and try to find the module in case-agnostic fashion + moduleName += ".rte"; + std::transform(moduleName.begin(), moduleName.end(), moduleName.begin(), ::tolower); + + itr = m_DataModuleIDs.find(moduleName); + if (itr != m_DataModuleIDs.end()) + return (*itr).second; + + // Try with or without the .rte on the end before giving up + dotPos = moduleName.find_last_of('.'); + // Wasnt, so try adding it + if (dotPos == string::npos) + moduleName = moduleName + System::GetModulePackageExtension(); + // There was ".rte", so try to shave it off the name + else + moduleName = moduleName.substr(0, dotPos); + + // Try to find the module again! + itr = m_DataModuleIDs.find(moduleName); + if (itr != m_DataModuleIDs.end()) + return (*itr).second; + */ + return -1; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDataModuleName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a name specific loaded DataModule + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const std::string PresetMan::GetDataModuleName(int whichModule) -{ - RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - return m_pDataModules[whichModule]->GetFileName(); -} + std::string PresetMan::GetModuleNameFromPath(const std::string& dataPath) const { + if (dataPath.empty()) { + return ""; + } + size_t slashPos = dataPath.find_first_of("/\\"); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetModuleID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ID of a loaded DataModule. - -int PresetMan::GetModuleID(std::string moduleName) -{ - // Lower-case search name so we can match up against the already-lowercase names in m_DataModuleIDs - std::transform(moduleName.begin(), moduleName.end(), moduleName.begin(), ::tolower); - - // First pass - std::map::iterator itr = m_DataModuleIDs.find(moduleName); - if (itr != m_DataModuleIDs.end()) - return (*itr).second; - - // Try with or without the .rte on the end before giving up - int dotPos = moduleName.find_last_of('.'); - // Wasnt, so try adding it - if (dotPos == std::string::npos) - moduleName = moduleName + System::GetModulePackageExtension(); - // There was ".rte", so try to shave it off the name - else - moduleName = moduleName.substr(0, dotPos); - - // Try to find the module again! - itr = m_DataModuleIDs.find(moduleName); - if (itr != m_DataModuleIDs.end()) - return (*itr).second; - -/* No need to do this second pass now; we immediately do the case-agnostic search - // Add .rte and try to find the module in case-agnostic fashion - moduleName += ".rte"; - std::transform(moduleName.begin(), moduleName.end(), moduleName.begin(), ::tolower); - - itr = m_DataModuleIDs.find(moduleName); - if (itr != m_DataModuleIDs.end()) - return (*itr).second; - - // Try with or without the .rte on the end before giving up - dotPos = moduleName.find_last_of('.'); - // Wasnt, so try adding it - if (dotPos == string::npos) - moduleName = moduleName + System::GetModulePackageExtension(); - // There was ".rte", so try to shave it off the name - else - moduleName = moduleName.substr(0, dotPos); - - // Try to find the module again! - itr = m_DataModuleIDs.find(moduleName); - if (itr != m_DataModuleIDs.end()) - return (*itr).second; -*/ - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -std::string PresetMan::GetModuleNameFromPath(const std::string &dataPath) const { - if (dataPath.empty()) { - return ""; - } - size_t slashPos = dataPath.find_first_of("/\\"); + // Include trailing slash in the substring range in case we need to match against the Data/Mods/Userdata directory. + std::string moduleName = (slashPos != std::string::npos) ? dataPath.substr(0, slashPos + 1) : dataPath; - // Include trailing slash in the substring range in case we need to match against the Data/Mods/Userdata directory. - std::string moduleName = (slashPos != std::string::npos) ? dataPath.substr(0, slashPos + 1) : dataPath; + // Check if path starts with Data/ or the Mods/Userdata dir names and remove that part to get to the actual module name. + if (moduleName == System::GetDataDirectory() || moduleName == System::GetModDirectory() || moduleName == System::GetUserdataDirectory()) { + std::string shortenPath = dataPath.substr(slashPos + 1); + slashPos = shortenPath.find_first_of("/\\"); + moduleName = shortenPath.substr(0, slashPos + 1); + } - // Check if path starts with Data/ or the Mods/Userdata dir names and remove that part to get to the actual module name. - if (moduleName == System::GetDataDirectory() || moduleName == System::GetModDirectory() || moduleName == System::GetUserdataDirectory()) { - std::string shortenPath = dataPath.substr(slashPos + 1); - slashPos = shortenPath.find_first_of("/\\"); - moduleName = shortenPath.substr(0, slashPos + 1); + if (!moduleName.empty() && moduleName.back() == '/') { + moduleName.pop_back(); + } + return moduleName; } - if (!moduleName.empty() && moduleName.back() == '/') { - moduleName.pop_back(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int PresetMan::GetModuleIDFromPath(const std::string& dataPath) { + if (dataPath.empty()) { + return -1; + } + return GetModuleID(GetModuleNameFromPath(dataPath)); } - return moduleName; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int PresetMan::GetModuleIDFromPath(const std::string &dataPath) { - if (dataPath.empty()) { - return -1; + bool PresetMan::IsModuleOfficial(const std::string& moduleName) const { + return std::find(c_OfficialModules.begin(), c_OfficialModules.end(), moduleName) != c_OfficialModules.end(); } - return GetModuleID(GetModuleNameFromPath(dataPath)); -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool PresetMan::IsModuleOfficial(const std::string &moduleName) const { - return std::find(c_OfficialModules.begin(), c_OfficialModules.end(), moduleName) != c_OfficialModules.end(); -} + bool PresetMan::IsModuleUserdata(const std::string& moduleName) const { + auto userdataModuleItr = std::find_if(c_UserdataModules.begin(), c_UserdataModules.end(), + [&moduleName](const auto& userdataModulesEntry) { + return userdataModulesEntry.first == moduleName; + }); + return userdataModuleItr != c_UserdataModules.end(); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool PresetMan::IsModuleUserdata(const std::string &moduleName) const { - auto userdataModuleItr = std::find_if(c_UserdataModules.begin(), c_UserdataModules.end(), - [&moduleName](const auto &userdataModulesEntry) { - return userdataModulesEntry.first == moduleName; - } - ); - return userdataModuleItr != c_UserdataModules.end(); -} + std::string PresetMan::GetFullModulePath(const std::string& modulePath) const { + // Note: Mods may use mixed path separators, which aren't supported on non Windows systems. + // Since Windows supports both forward and backslash separators it's safe to replace all backslashes with forward slashes. + std::string modulePathGeneric = std::filesystem::path(modulePath).generic_string(); + std::replace(modulePathGeneric.begin(), modulePathGeneric.end(), '\\', '/'); + + const std::string pathTopDir = modulePathGeneric.substr(0, modulePathGeneric.find_first_of("/") + 1); + const std::string moduleName = GetModuleNameFromPath(modulePathGeneric); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::string moduleTopDir = System::GetModDirectory(); -std::string PresetMan::GetFullModulePath(const std::string &modulePath) const { - // Note: Mods may use mixed path separators, which aren't supported on non Windows systems. - // Since Windows supports both forward and backslash separators it's safe to replace all backslashes with forward slashes. - std::string modulePathGeneric = std::filesystem::path(modulePath).generic_string(); - std::replace(modulePathGeneric.begin(), modulePathGeneric.end(), '\\', '/'); + if (IsModuleOfficial(moduleName)) { + moduleTopDir = System::GetDataDirectory(); + } else if (IsModuleUserdata(moduleName)) { + moduleTopDir = System::GetUserdataDirectory(); + } + return (pathTopDir == moduleTopDir) ? modulePathGeneric : moduleTopDir + modulePathGeneric; + } - const std::string pathTopDir = modulePathGeneric.substr(0, modulePathGeneric.find_first_of("/") + 1); - const std::string moduleName = GetModuleNameFromPath(modulePathGeneric); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddEntityPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an Entity instance's pointer and name associations to the + // internal list of already read in Entity:s. Ownership is NOT transferred! + // If there already is an instance defined, nothing happens. If there + // is not, a clone is made of the passed-in Entity and added to the library. - std::string moduleTopDir = System::GetModDirectory(); + bool PresetMan::AddEntityPreset(Entity* pEntToAdd, int whichModule, bool overwriteSame, std::string readFromFile) { + RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - if (IsModuleOfficial(moduleName)) { - moduleTopDir = System::GetDataDirectory(); - } else if (IsModuleUserdata(moduleName)) { - moduleTopDir = System::GetUserdataDirectory(); + return m_pDataModules[whichModule]->AddEntityPreset(pEntToAdd, overwriteSame, readFromFile); } - return (pathTopDir == moduleTopDir) ? modulePathGeneric : moduleTopDir + modulePathGeneric; -} -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddEntityPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an Entity instance's pointer and name associations to the -// internal list of already read in Entity:s. Ownership is NOT transferred! -// If there already is an instance defined, nothing happens. If there -// is not, a clone is made of the passed-in Entity and added to the library. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEntityPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a previously read in (defined) Entity, by type and instance name. -bool PresetMan::AddEntityPreset(Entity *pEntToAdd, int whichModule, bool overwriteSame, std::string readFromFile) -{ - RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); + const Entity* PresetMan::GetEntityPreset(std::string type, std::string preset, int whichModule) { + RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - return m_pDataModules[whichModule]->AddEntityPreset(pEntToAdd, overwriteSame, readFromFile); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEntityPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a previously read in (defined) Entity, by type and instance name. - -const Entity * PresetMan::GetEntityPreset(std::string type, std::string preset, int whichModule) -{ - RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - - const Entity *pRetEntity = 0; - - // Preset name might have "[ModuleName]/" preceding it, detect it here and select proper module! - int slashPos = preset.find_first_of('/'); - if (slashPos != std::string::npos) - { - // Get the module ID and cut off the module specifier in the string - whichModule = GetModuleID(preset.substr(0, slashPos)); - preset = preset.substr(slashPos + 1); - } - - // All modules - if (whichModule < 0) - { - // Search all modules - for (int i = 0; i < m_pDataModules.size() && !pRetEntity; ++i) - pRetEntity = m_pDataModules[i]->GetEntityPreset(type, preset); - } - // Specific module - else - { - // Try to get it from the asked for module - pRetEntity = m_pDataModules[whichModule]->GetEntityPreset(type, preset); - - // If couldn't find it in there, then try all the official modules! - if (!pRetEntity) - { - RTEAssert(m_OfficialModuleCount <= m_pDataModules.size(), "More official modules than modules loaded?!"); - for (int i = 0; i < m_OfficialModuleCount && !pRetEntity; ++i) - { - pRetEntity = m_pDataModules[i]->GetEntityPreset(type, preset); - } - } - } - - return pRetEntity; -} + const Entity* pRetEntity = 0; + // Preset name might have "[ModuleName]/" preceding it, detect it here and select proper module! + int slashPos = preset.find_first_of('/'); + if (slashPos != std::string::npos) { + // Get the module ID and cut off the module specifier in the string + whichModule = GetModuleID(preset.substr(0, slashPos)); + preset = preset.substr(slashPos + 1); + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEntityPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads an instance of an Entity that will be used as preset -// to later on be used to generate more instances of the same state. -// Will check if there was already one of the same class and instance -// name read in previously, and will return that one if found, or -// add the newly read in one to this PresetMan's list if not found to -// exist there previously. Ownership is NOT transferred! - -const Entity * PresetMan::GetEntityPreset(Reader &reader) -{ - // The reader is aware of which DataModule it is reading within - int whichModule = reader.GetReadModuleID(); - RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Reader has an out of bounds module number!"); - - std::string ClassName; - const Entity::ClassInfo *pClass = 0; - Entity *pNewInstance = 0; - const Entity *pReturnPreset = 0; - // Load class name and then preset instance - reader >> ClassName; - pClass = Entity::ClassInfo::GetClass(ClassName); - - if (pClass && pClass->IsConcrete()) - { - // Instantiate - pNewInstance = pClass->NewInstance(); - - // Get this before reading entity, since if it's the last one in its datafile, the stream will show the parent file instead - std::string entityFilePath = reader.GetCurrentFilePath(); - - // Try to read in the preset instance's data from the reader - if (pNewInstance && pNewInstance->Create(reader, false) < 0) - { - // Abort loading if we can't create entity and it's not in a module that allows ignoring missing items. - if (!g_PresetMan.GetDataModule(whichModule)->GetIgnoreMissingItems()) - RTEAbort("Reading of a preset instance \"" + pNewInstance->GetPresetName() + "\" of class " + pNewInstance->GetClassName() + " failed in file " + reader.GetCurrentFilePath() + ", shortly before line #" + reader.GetCurrentFileLine()); + // All modules + if (whichModule < 0) { + // Search all modules + for (int i = 0; i < m_pDataModules.size() && !pRetEntity; ++i) + pRetEntity = m_pDataModules[i]->GetEntityPreset(type, preset); } - else if (pNewInstance) - { - // Try to add the instance to the collection - m_pDataModules[whichModule]->AddEntityPreset(pNewInstance, reader.GetPresetOverwriting(), entityFilePath); - - // Regardless of whether there was a collision or not, use whatever now exists in the instance map of that class and name - pReturnPreset = m_pDataModules[whichModule]->GetEntityPreset(pNewInstance->GetClassName(), pNewInstance->GetPresetName()); - // If the instance wasn't found in the specific DataModule, try to find it in all the official ones instead - if (!pReturnPreset) - { + // Specific module + else { + // Try to get it from the asked for module + pRetEntity = m_pDataModules[whichModule]->GetEntityPreset(type, preset); + + // If couldn't find it in there, then try all the official modules! + if (!pRetEntity) { RTEAssert(m_OfficialModuleCount <= m_pDataModules.size(), "More official modules than modules loaded?!"); - for (int i = 0; i < m_OfficialModuleCount && !pReturnPreset; ++i) - pReturnPreset = m_pDataModules[i]->GetEntityPreset(pNewInstance->GetClassName(), pNewInstance->GetPresetName()); + for (int i = 0; i < m_OfficialModuleCount && !pRetEntity; ++i) { + pRetEntity = m_pDataModules[i]->GetEntityPreset(type, preset); + } } } - // Get rid of the read-in instance as its copy is now either added to the map, or discarded as there already was somehting in there of the same name. - delete pNewInstance; pNewInstance = 0; - } - else - pReturnPreset = 0; - return pReturnPreset; -} + return pRetEntity; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEntityPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads an instance of an Entity that will be used as preset + // to later on be used to generate more instances of the same state. + // Will check if there was already one of the same class and instance + // name read in previously, and will return that one if found, or + // add the newly read in one to this PresetMan's list if not found to + // exist there previously. Ownership is NOT transferred! + + const Entity* PresetMan::GetEntityPreset(Reader& reader) { + // The reader is aware of which DataModule it is reading within + int whichModule = reader.GetReadModuleID(); + RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Reader has an out of bounds module number!"); + + std::string ClassName; + const Entity::ClassInfo* pClass = 0; + Entity* pNewInstance = 0; + const Entity* pReturnPreset = 0; + // Load class name and then preset instance + reader >> ClassName; + pClass = Entity::ClassInfo::GetClass(ClassName); + + if (pClass && pClass->IsConcrete()) { + // Instantiate + pNewInstance = pClass->NewInstance(); + + // Get this before reading entity, since if it's the last one in its datafile, the stream will show the parent file instead + std::string entityFilePath = reader.GetCurrentFilePath(); + + // Try to read in the preset instance's data from the reader + if (pNewInstance && pNewInstance->Create(reader, false) < 0) { + // Abort loading if we can't create entity and it's not in a module that allows ignoring missing items. + if (!g_PresetMan.GetDataModule(whichModule)->GetIgnoreMissingItems()) + RTEAbort("Reading of a preset instance \"" + pNewInstance->GetPresetName() + "\" of class " + pNewInstance->GetClassName() + " failed in file " + reader.GetCurrentFilePath() + ", shortly before line #" + reader.GetCurrentFileLine()); + } else if (pNewInstance) { + // Try to add the instance to the collection + m_pDataModules[whichModule]->AddEntityPreset(pNewInstance, reader.GetPresetOverwriting(), entityFilePath); + + // Regardless of whether there was a collision or not, use whatever now exists in the instance map of that class and name + pReturnPreset = m_pDataModules[whichModule]->GetEntityPreset(pNewInstance->GetClassName(), pNewInstance->GetPresetName()); + // If the instance wasn't found in the specific DataModule, try to find it in all the official ones instead + if (!pReturnPreset) { + RTEAssert(m_OfficialModuleCount <= m_pDataModules.size(), "More official modules than modules loaded?!"); + for (int i = 0; i < m_OfficialModuleCount && !pReturnPreset; ++i) + pReturnPreset = m_pDataModules[i]->GetEntityPreset(pNewInstance->GetClassName(), pNewInstance->GetPresetName()); + } + } + // Get rid of the read-in instance as its copy is now either added to the map, or discarded as there already was somehting in there of the same name. + delete pNewInstance; + pNewInstance = 0; + } else + pReturnPreset = 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReadReflectedPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads an preset of an Entity and tries to add it to the list of -// read-in presets. Regardless of whether there is a name collision, -// the read-in preset will be returned, ownership TRANSFERRED! - -Entity * PresetMan::ReadReflectedPreset(Reader &reader) -{ - // The reader is aware of which DataModule it's reading within - int whichModule = reader.GetReadModuleID(); - RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Reader has an out of bounds module number!"); - - std::string ClassName; - const Entity::ClassInfo *pClass = 0; - Entity *pNewInstance = 0; - // Load class name and then preset instance - reader >> ClassName; - pClass = Entity::ClassInfo::GetClass(ClassName); - - if (pClass && pClass->IsConcrete()) - { - // Instantiate - pNewInstance = pClass->NewInstance(); - - // Get this before reading entity, since if it's the last one in its datafile, the stream will show the parent file instead - std::string entityFilePath = reader.GetCurrentFilePath(); - - // Try to read in the preset instance's data from the reader - if (pNewInstance && pNewInstance->Create(reader, false) < 0) - { - if (!g_PresetMan.GetDataModule(whichModule)->GetIgnoreMissingItems()) - RTEAbort("Reading of a preset instance \"" + pNewInstance->GetPresetName() + "\" of class " + pNewInstance->GetClassName() + " failed in file " + reader.GetCurrentFilePath() + ", shortly before line #" + reader.GetCurrentFileLine()); - } - else - { - // Try to add the instance to the collection. - // Note that we'll return this instance regardless of whether the adding was succesful or not - m_pDataModules[whichModule]->AddEntityPreset(pNewInstance, reader.GetPresetOverwriting(), entityFilePath); - return pNewInstance; + return pReturnPreset; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReadReflectedPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads an preset of an Entity and tries to add it to the list of + // read-in presets. Regardless of whether there is a name collision, + // the read-in preset will be returned, ownership TRANSFERRED! + + Entity* PresetMan::ReadReflectedPreset(Reader& reader) { + // The reader is aware of which DataModule it's reading within + int whichModule = reader.GetReadModuleID(); + RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Reader has an out of bounds module number!"); + + std::string ClassName; + const Entity::ClassInfo* pClass = 0; + Entity* pNewInstance = 0; + // Load class name and then preset instance + reader >> ClassName; + pClass = Entity::ClassInfo::GetClass(ClassName); + + if (pClass && pClass->IsConcrete()) { + // Instantiate + pNewInstance = pClass->NewInstance(); + + // Get this before reading entity, since if it's the last one in its datafile, the stream will show the parent file instead + std::string entityFilePath = reader.GetCurrentFilePath(); + + // Try to read in the preset instance's data from the reader + if (pNewInstance && pNewInstance->Create(reader, false) < 0) { + if (!g_PresetMan.GetDataModule(whichModule)->GetIgnoreMissingItems()) + RTEAbort("Reading of a preset instance \"" + pNewInstance->GetPresetName() + "\" of class " + pNewInstance->GetClassName() + " failed in file " + reader.GetCurrentFilePath() + ", shortly before line #" + reader.GetCurrentFileLine()); + } else { + // Try to add the instance to the collection. + // Note that we'll return this instance regardless of whether the adding was succesful or not + m_pDataModules[whichModule]->AddEntityPreset(pNewInstance, reader.GetPresetOverwriting(), entityFilePath); + return pNewInstance; + } } - } - return 0; -} + return 0; + } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAllOfType + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds to a list all previously read in (defined) Entitys, by type. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAllOfType -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds to a list all previously read in (defined) Entitys, by type. + bool PresetMan::GetAllOfType(std::list& entityList, std::string type, int whichModule) { + if (type.empty()) + return false; -bool PresetMan::GetAllOfType(std::list &entityList, std::string type, int whichModule) -{ - if (type.empty()) - return false; + bool foundAny = false; - bool foundAny = false; + // All modules + if (whichModule < 0) { + // Send the list to each module + for (int i = 0; i < m_pDataModules.size(); ++i) + foundAny = m_pDataModules[i]->GetAllOfType(entityList, type) || foundAny; + } + // Specific module + else { + RTEAssert(whichModule < (int)m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID!"); + foundAny = m_pDataModules[whichModule]->GetAllOfType(entityList, type); + } - // All modules - if (whichModule < 0) - { - // Send the list to each module - for (int i = 0; i < m_pDataModules.size(); ++i) - foundAny = m_pDataModules[i]->GetAllOfType(entityList, type) || foundAny; - } - // Specific module - else - { - RTEAssert(whichModule < (int)m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID!"); - foundAny = m_pDataModules[whichModule]->GetAllOfType(entityList, type); - } + return foundAny; + } - return foundAny; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAllOfTypeInModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds to a list all previously read in (defined) Entitys which are + // of a specific type, and only exist in a specific module space. + bool PresetMan::GetAllOfTypeInModuleSpace(std::list& entityList, std::string type, int whichModuleSpace) { + if (type.empty()) + return false; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAllOfTypeInModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds to a list all previously read in (defined) Entitys which are -// of a specific type, and only exist in a specific module space. - -bool PresetMan::GetAllOfTypeInModuleSpace(std::list &entityList, std::string type, int whichModuleSpace) -{ - if (type.empty()) - return false; - - bool foundAny = false; - - // All modules - if (whichModuleSpace < 0) - foundAny = GetAllOfType(entityList, type, whichModuleSpace); - // Specific module space - else - { - // Get all entitys of the specific type in the official modules loaded before the specified one - for (int module = 0; module < m_OfficialModuleCount && module < whichModuleSpace; ++module) - foundAny = GetAllOfType(entityList, type, module) || foundAny; - - // Now get the groups of the specified module (official or not) - foundAny = GetAllOfType(entityList, type, whichModuleSpace) || foundAny; - } - - return foundAny; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool PresetMan::GetAllOfGroups(std::list &entityList, const std::vector &groups, const std::string &type, int whichModule) { - RTEAssert(!groups.empty(), "Looking for empty groups in PresetMan::GetAllOfGroups!"); - bool foundAny = false; - - if (whichModule < 0) { - for (DataModule *dataModule : m_pDataModules) { - foundAny = dataModule->GetAllOfGroups(entityList, groups, type) || foundAny; + bool foundAny = false; + + // All modules + if (whichModuleSpace < 0) + foundAny = GetAllOfType(entityList, type, whichModuleSpace); + // Specific module space + else { + // Get all entitys of the specific type in the official modules loaded before the specified one + for (int module = 0; module < m_OfficialModuleCount && module < whichModuleSpace; ++module) + foundAny = GetAllOfType(entityList, type, module) || foundAny; + + // Now get the groups of the specified module (official or not) + foundAny = GetAllOfType(entityList, type, whichModuleSpace) || foundAny; } - } else { - RTEAssert(whichModule < (int)m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID in PresetMan::GetAllOfGroups!"); - foundAny = m_pDataModules[whichModule]->GetAllOfGroups(entityList, groups, type); + + return foundAny; } - return foundAny; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool PresetMan::GetAllNotOfGroups(std::list &entityList, const std::vector &groups, const std::string &type, int whichModule) { - if (groups.empty()) { - RTEAbort("Looking for empty groups in PresetMan::GetAllNotOfGroups!"); - } else if (std::find(groups.begin(), groups.end(), "All") != groups.end()) { - RTEAbort("Trying to exclude all groups while looking for presets in PresetMan::GetAllNotOfGroups!"); + bool PresetMan::GetAllOfGroups(std::list& entityList, const std::vector& groups, const std::string& type, int whichModule) { + RTEAssert(!groups.empty(), "Looking for empty groups in PresetMan::GetAllOfGroups!"); + bool foundAny = false; + + if (whichModule < 0) { + for (DataModule* dataModule: m_pDataModules) { + foundAny = dataModule->GetAllOfGroups(entityList, groups, type) || foundAny; + } + } else { + RTEAssert(whichModule < (int)m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID in PresetMan::GetAllOfGroups!"); + foundAny = m_pDataModules[whichModule]->GetAllOfGroups(entityList, groups, type); + } + return foundAny; } - bool foundAny = false; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (whichModule < 0) { - for (DataModule *dataModule : m_pDataModules) { - foundAny = dataModule->GetAllNotOfGroups(entityList, groups, type) || foundAny; + bool PresetMan::GetAllNotOfGroups(std::list& entityList, const std::vector& groups, const std::string& type, int whichModule) { + if (groups.empty()) { + RTEAbort("Looking for empty groups in PresetMan::GetAllNotOfGroups!"); + } else if (std::find(groups.begin(), groups.end(), "All") != groups.end()) { + RTEAbort("Trying to exclude all groups while looking for presets in PresetMan::GetAllNotOfGroups!"); } - } else { - RTEAssert(whichModule < (int)m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID in PresetMan::GetAllNotOfGroups!"); - foundAny = m_pDataModules[whichModule]->GetAllNotOfGroups(entityList, groups, type); - } - return foundAny; -} + bool foundAny = false; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRandomOfGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a previously read in (defined) Entity which is randomly -// selected from a specific group. - -Entity * PresetMan::GetRandomOfGroup(std::string group, std::string type, int whichModule) -{ - RTEAssert(!group.empty(), "Looking for empty group!"); - - bool foundAny = false; - // The total list we'll select a random one from - std::list entityList; - - // All modules - if (whichModule < 0) - { - // Get from all modules - for (int i = 0; i < m_pDataModules.size(); ++i) - // Send the list to each module, let them add - foundAny = m_pDataModules[i]->GetAllOfGroups(entityList, { group }, type) || foundAny; - } - // Specific one - else - { - RTEAssert(whichModule < m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID!"); - foundAny = m_pDataModules[whichModule]->GetAllOfGroups(entityList, { group }, type); - } - - // Didn't find any of that group in those module(s) - if (!foundAny) - return 0; - - // Pick one and return it - int current = 0; - int selection = RandomNum(0, entityList.size() - 1); - for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) - { - if (current == selection) - return (*itr); - current++; - } - - RTEAssert(0, "Tried selecting randomly but didn't?"); - return 0; -} + if (whichModule < 0) { + for (DataModule* dataModule: m_pDataModules) { + foundAny = dataModule->GetAllNotOfGroups(entityList, groups, type) || foundAny; + } + } else { + RTEAssert(whichModule < (int)m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID in PresetMan::GetAllNotOfGroups!"); + foundAny = m_pDataModules[whichModule]->GetAllNotOfGroups(entityList, groups, type); + } + return foundAny; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRandomOfGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a previously read in (defined) Entity which is randomly + // selected from a specific group. + + Entity* PresetMan::GetRandomOfGroup(std::string group, std::string type, int whichModule) { + RTEAssert(!group.empty(), "Looking for empty group!"); + + bool foundAny = false; + // The total list we'll select a random one from + std::list entityList; + + // All modules + if (whichModule < 0) { + // Get from all modules + for (int i = 0; i < m_pDataModules.size(); ++i) + // Send the list to each module, let them add + foundAny = m_pDataModules[i]->GetAllOfGroups(entityList, {group}, type) || foundAny; + } + // Specific one + else { + RTEAssert(whichModule < m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID!"); + foundAny = m_pDataModules[whichModule]->GetAllOfGroups(entityList, {group}, type); + } + // Didn't find any of that group in those module(s) + if (!foundAny) + return 0; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRandomOfGroupFromTech -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a previously read in (defined) Entity which is randomly -// selected from a specific group. - -Entity * PresetMan::GetRandomBuyableOfGroupFromTech(std::string group, std::string type, int whichModule) -{ - RTEAssert(!group.empty(), "Looking for empty group!"); - - bool foundAny = false; - // The total list we'll select a random one from - std::list entityList; - std::list tempList; - - // All modules - if (whichModule < 0) { - for (DataModule *dataModule : m_pDataModules) { - if (dataModule->IsFaction()) { foundAny = dataModule->GetAllOfGroups(tempList, { group }, type) || foundAny; } + // Pick one and return it + int current = 0; + int selection = RandomNum(0, entityList.size() - 1); + for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) { + if (current == selection) + return (*itr); + current++; } - } else { - RTEAssert(whichModule < m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID!"); - foundAny = m_pDataModules[whichModule]->GetAllOfGroups(tempList, { group }, type); + + RTEAssert(0, "Tried selecting randomly but didn't?"); + return 0; } - //Filter found entities, we need only buyables - if (foundAny) - { - //Do not filter anything if we're looking for brains - if (group == "Brains") - { - foundAny = false; - for (std::list::iterator oItr = tempList.begin(); oItr != tempList.end(); ++oItr) - { - entityList.push_back(*oItr); - foundAny = true; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRandomOfGroupFromTech + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a previously read in (defined) Entity which is randomly + // selected from a specific group. + + Entity* PresetMan::GetRandomBuyableOfGroupFromTech(std::string group, std::string type, int whichModule) { + RTEAssert(!group.empty(), "Looking for empty group!"); + + bool foundAny = false; + // The total list we'll select a random one from + std::list entityList; + std::list tempList; + + // All modules + if (whichModule < 0) { + for (DataModule* dataModule: m_pDataModules) { + if (dataModule->IsFaction()) { + foundAny = dataModule->GetAllOfGroups(tempList, {group}, type) || foundAny; + } } + } else { + RTEAssert(whichModule < m_pDataModules.size(), "Trying to get from an out of bounds DataModule ID!"); + foundAny = m_pDataModules[whichModule]->GetAllOfGroups(tempList, {group}, type); } - else - { - foundAny = false; - for (std::list::iterator oItr = tempList.begin(); oItr != tempList.end(); ++oItr) - { - SceneObject * pSObject = dynamic_cast(*oItr); - // Buyable and not brain? - if (pSObject && pSObject->IsBuyable() && !pSObject->IsBuyableInObjectPickerOnly() && !pSObject->IsInGroup("Brains")) - { + + // Filter found entities, we need only buyables + if (foundAny) { + // Do not filter anything if we're looking for brains + if (group == "Brains") { + foundAny = false; + for (std::list::iterator oItr = tempList.begin(); oItr != tempList.end(); ++oItr) { entityList.push_back(*oItr); foundAny = true; } + } else { + foundAny = false; + for (std::list::iterator oItr = tempList.begin(); oItr != tempList.end(); ++oItr) { + SceneObject* pSObject = dynamic_cast(*oItr); + // Buyable and not brain? + if (pSObject && pSObject->IsBuyable() && !pSObject->IsBuyableInObjectPickerOnly() && !pSObject->IsInGroup("Brains")) { + entityList.push_back(*oItr); + foundAny = true; + } + } } } - } - // Didn't find any of that group in those module(s) - if (!foundAny) - return 0; + // Didn't find any of that group in those module(s) + if (!foundAny) + return 0; - // Pick one and return it - int current = 0; - int selection = RandomNum(0, entityList.size() - 1); + // Pick one and return it + int current = 0; + int selection = RandomNum(0, entityList.size() - 1); - int totalWeight = 0; - for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) - totalWeight += (*itr)->GetRandomWeight(); + int totalWeight = 0; + for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) + totalWeight += (*itr)->GetRandomWeight(); - // Use random weights if looking in specific modules - if (whichModule >= 0) - { - if (totalWeight == 0) - return 0; + // Use random weights if looking in specific modules + if (whichModule >= 0) { + if (totalWeight == 0) + return 0; - selection = RandomNum(0, totalWeight - 1); - - for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) - { - bool found = false; - int bucketCounter = 0; - - if ((*itr)->GetRandomWeight() > 0) - { - while (bucketCounter < (*itr)->GetRandomWeight()) - { - if (current == selection) - { - found = true; - break; - } + selection = RandomNum(0, totalWeight - 1); + + for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) { + bool found = false; + int bucketCounter = 0; + + if ((*itr)->GetRandomWeight() > 0) { + while (bucketCounter < (*itr)->GetRandomWeight()) { + if (current == selection) { + found = true; + break; + } - current++; - bucketCounter++; + current++; + bucketCounter++; + } } + + if (found) + return (*itr); } + } else { + for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) { + if (current == selection) + return (*itr); - if (found) - return (*itr); + current++; + } } + + RTEAssert(0, "Tried selecting randomly but didn't?"); + return 0; } - else - { - for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) - { - if (current == selection) - return (*itr); - current++; + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAllOfGroupInModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds to a list all previously read in (defined) Entitys which are + // associated with a specific group, and only exist in a specific module + // space. + + bool PresetMan::GetAllOfGroupInModuleSpace(std::list& entityList, std::string group, std::string type, int whichModuleSpace) { + RTEAssert(!group.empty(), "Looking for empty group!"); + + bool foundAny = false; + + // All modules + if (whichModuleSpace < 0) + foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace); + // Specific module space + else { + // Get all entitys of the specific group the official modules loaded before the specified one + for (int module = 0; module < m_OfficialModuleCount && module < whichModuleSpace; ++module) + foundAny = GetAllOfGroup(entityList, group, type, module) || foundAny; + + // Now get the groups of the specified module (official or not) + foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace) || foundAny; } - } - RTEAssert(0, "Tried selecting randomly but didn't?"); - return 0; -} + return foundAny; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAllOfGroupInModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds to a list all previously read in (defined) Entitys which are -// associated with a specific group, and only exist in a specific module -// space. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRandomOfGroupInModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a previously read in (defined) Entity which is associated with + // a specific group, randomly selected and only exist in a specific module + // space. + + Entity* PresetMan::GetRandomOfGroupInModuleSpace(std::string group, std::string type, int whichModuleSpace) { + RTEAssert(!group.empty(), "Looking for empty group!"); + + bool foundAny = false; + // The total list we'll select a random one from + std::list entityList; + + // All modules + if (whichModuleSpace < 0) + foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace); + // Specific module space + else { + // Get all entitys of the specific group the official modules loaded before the specified one + for (int module = 0; module < m_OfficialModuleCount && module < whichModuleSpace; ++module) + foundAny = GetAllOfGroup(entityList, group, type, module) || foundAny; + + // Now get the groups of the specified module (official or not) + foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace) || foundAny; + } -bool PresetMan::GetAllOfGroupInModuleSpace(std::list &entityList, std::string group, std::string type, int whichModuleSpace) -{ - RTEAssert(!group.empty(), "Looking for empty group!"); + // Didn't find any of that group in those module(s) + if (!foundAny) + return 0; - bool foundAny = false; + // Pick one and return it + int current = 0; + int selection = RandomNum(0, entityList.size() - 1); + for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) { + if (current == selection) + return (*itr); + current++; + } - // All modules - if (whichModuleSpace < 0) - foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace); - // Specific module space - else - { - // Get all entitys of the specific group the official modules loaded before the specified one - for (int module = 0; module < m_OfficialModuleCount && module < whichModuleSpace; ++module) - foundAny = GetAllOfGroup(entityList, group, type, module) || foundAny; + RTEAssert(0, "Tried selecting randomly but didn't?"); + return 0; + } - // Now get the groups of the specified module (official or not) - foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace) || foundAny; - } + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEntityDataLocation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the data file path of a previously read in (defined) Entity. - return foundAny; -} + std::string PresetMan::GetEntityDataLocation(std::string type, std::string preset, int whichModule) { + RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); + std::string pRetPath = ""; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRandomOfGroupInModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a previously read in (defined) Entity which is associated with -// a specific group, randomly selected and only exist in a specific module -// space. - -Entity * PresetMan::GetRandomOfGroupInModuleSpace(std::string group, std::string type, int whichModuleSpace) -{ - RTEAssert(!group.empty(), "Looking for empty group!"); - - bool foundAny = false; - // The total list we'll select a random one from - std::list entityList; - - // All modules - if (whichModuleSpace < 0) - foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace); - // Specific module space - else - { - // Get all entitys of the specific group the official modules loaded before the specified one - for (int module = 0; module < m_OfficialModuleCount && module < whichModuleSpace; ++module) - foundAny = GetAllOfGroup(entityList, group, type, module) || foundAny; - - // Now get the groups of the specified module (official or not) - foundAny = GetAllOfGroup(entityList, group, type, whichModuleSpace) || foundAny; - } - - // Didn't find any of that group in those module(s) - if (!foundAny) - return 0; - - // Pick one and return it - int current = 0; - int selection = RandomNum(0, entityList.size() - 1); - for (std::list::iterator itr = entityList.begin(); itr != entityList.end(); ++itr) - { - if (current == selection) - return (*itr); - current++; - } - - RTEAssert(0, "Tried selecting randomly but didn't?"); - return 0; -} + // All modules + if (whichModule < 0) { + // Search all modules + for (int i = 0; i < m_pDataModules.size() && pRetPath.empty(); ++i) + pRetPath = m_pDataModules[i]->GetEntityDataLocation(type, preset); + } + // Specific module + else { + // Try to get it from the asked for module + pRetPath = m_pDataModules[whichModule]->GetEntityDataLocation(type, preset); + // If couldn't find it in there, then try all the official modules! + if (pRetPath.empty()) { + RTEAssert(m_OfficialModuleCount <= m_pDataModules.size(), "More official modules than modules loaded?!"); + for (int i = 0; i < m_OfficialModuleCount && pRetPath.empty(); ++i) { + pRetPath = m_pDataModules[i]->GetEntityDataLocation(type, preset); + } + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEntityDataLocation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the data file path of a previously read in (defined) Entity. - -std::string PresetMan::GetEntityDataLocation(std::string type, std::string preset, int whichModule) -{ - RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - - std::string pRetPath = ""; - - // All modules - if (whichModule < 0) - { - // Search all modules - for (int i = 0; i < m_pDataModules.size() && pRetPath.empty(); ++i) - pRetPath = m_pDataModules[i]->GetEntityDataLocation(type, preset); - } - // Specific module - else - { - // Try to get it from the asked for module - pRetPath = m_pDataModules[whichModule]->GetEntityDataLocation(type, preset); - - // If couldn't find it in there, then try all the official modules! - if (pRetPath.empty()) - { - RTEAssert(m_OfficialModuleCount <= m_pDataModules.size(), "More official modules than modules loaded?!"); - for (int i = 0; i < m_OfficialModuleCount && pRetPath.empty(); ++i) - { - pRetPath = m_pDataModules[i]->GetEntityDataLocation(type, preset); - } - } - } - - return pRetPath; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void PresetMan::ReloadAllScripts() const { - g_LuaMan.ClearUserModuleCache(); - for (const DataModule *dataModule : m_pDataModules) { - dataModule->ReloadAllScripts(); + return pRetPath; } - g_MovableMan.ReloadLuaScripts(); - g_ConsoleMan.PrintString("SYSTEM: Scripts reloaded!"); -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool PresetMan::ReloadEntityPreset(const std::string &presetName, const std::string &className, const std::string &moduleName, bool storeReloadedPresetDataForQuickReloading) { - if (className.empty() || presetName.empty()) { - g_ConsoleMan.PrintString("ERROR: Trying to reload Entity preset without specifying preset name or type!"); - return false; + void PresetMan::ReloadAllScripts() const { + g_LuaMan.ClearUserModuleCache(); + for (const DataModule* dataModule: m_pDataModules) { + dataModule->ReloadAllScripts(); + } + g_MovableMan.ReloadLuaScripts(); + g_ConsoleMan.PrintString("SYSTEM: Scripts reloaded!"); } - int moduleId = -1; - if (moduleName != "") { - moduleId = GetModuleID(moduleName); - if (moduleId < 0) { - g_ConsoleMan.PrintString("ERROR: Failed to find data module with name \"" + moduleName + "\" while attempting to reload an Entity preset with name \"" + presetName + "\" of type \"" + className + "\"!"); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool PresetMan::ReloadEntityPreset(const std::string& presetName, const std::string& className, const std::string& moduleName, bool storeReloadedPresetDataForQuickReloading) { + if (className.empty() || presetName.empty()) { + g_ConsoleMan.PrintString("ERROR: Trying to reload Entity preset without specifying preset name or type!"); return false; } - } - std::string actualDataModuleOfPreset = moduleName; - - std::string presetDataLocation = GetEntityDataLocation(className, presetName, moduleId); - if (presetDataLocation.empty()) { - g_ConsoleMan.PrintString("ERROR: Failed to locate data of Entity preset with name \"" + presetName + "\" of type \"" + className + "\" in \"" + moduleName + "\" or any official module! The preset might not exist!"); - return false; - } - // GetEntityDataLocation will attempt to locate the preset in the official modules if it fails to locate it in the specified module. Warn and correct the result string. - if (std::string presetDataLocationModuleName = presetDataLocation.substr(0, presetDataLocation.find_first_of("/\\")); presetDataLocationModuleName != actualDataModuleOfPreset) { - actualDataModuleOfPreset = presetDataLocationModuleName; + int moduleId = -1; if (moduleName != "") { - g_ConsoleMan.PrintString("WARNING: Failed to locate data of Entity preset with name \"" + presetName + "\" of type \"" + className + "\" in \"" + moduleName + "\"! Entity preset data matching the name and type was found in \"" + actualDataModuleOfPreset + "\"!"); + moduleId = GetModuleID(moduleName); + if (moduleId < 0) { + g_ConsoleMan.PrintString("ERROR: Failed to find data module with name \"" + moduleName + "\" while attempting to reload an Entity preset with name \"" + presetName + "\" of type \"" + className + "\"!"); + return false; + } } - } + std::string actualDataModuleOfPreset = moduleName; - m_ReloadEntityPresetCalledThisUpdate = true; + std::string presetDataLocation = GetEntityDataLocation(className, presetName, moduleId); + if (presetDataLocation.empty()) { + g_ConsoleMan.PrintString("ERROR: Failed to locate data of Entity preset with name \"" + presetName + "\" of type \"" + className + "\" in \"" + moduleName + "\" or any official module! The preset might not exist!"); + return false; + } - Reader reader(presetDataLocation.c_str(), true); - while (reader.NextProperty()) { - reader.ReadPropName(); - g_PresetMan.GetEntityPreset(reader); - } - g_ConsoleMan.PrintString("SYSTEM: Entity preset with name \"" + presetName + "\" of type \"" + className + "\" defined in \"" + actualDataModuleOfPreset + "\" was successfully reloaded"); + // GetEntityDataLocation will attempt to locate the preset in the official modules if it fails to locate it in the specified module. Warn and correct the result string. + if (std::string presetDataLocationModuleName = presetDataLocation.substr(0, presetDataLocation.find_first_of("/\\")); presetDataLocationModuleName != actualDataModuleOfPreset) { + actualDataModuleOfPreset = presetDataLocationModuleName; + if (moduleName != "") { + g_ConsoleMan.PrintString("WARNING: Failed to locate data of Entity preset with name \"" + presetName + "\" of type \"" + className + "\" in \"" + moduleName + "\"! Entity preset data matching the name and type was found in \"" + actualDataModuleOfPreset + "\"!"); + } + } - if (storeReloadedPresetDataForQuickReloading) { - m_LastReloadedEntityPresetInfo[0] = presetName; - m_LastReloadedEntityPresetInfo[1] = className; - m_LastReloadedEntityPresetInfo[2] = moduleName == "" ? actualDataModuleOfPreset : moduleName; // If there was a module name, store it as-is so that if there's a data location warning, it persists on every quick reload. + m_ReloadEntityPresetCalledThisUpdate = true; + + Reader reader(presetDataLocation.c_str(), true); + while (reader.NextProperty()) { + reader.ReadPropName(); + g_PresetMan.GetEntityPreset(reader); + } + g_ConsoleMan.PrintString("SYSTEM: Entity preset with name \"" + presetName + "\" of type \"" + className + "\" defined in \"" + actualDataModuleOfPreset + "\" was successfully reloaded"); + + if (storeReloadedPresetDataForQuickReloading) { + m_LastReloadedEntityPresetInfo[0] = presetName; + m_LastReloadedEntityPresetInfo[1] = className; + m_LastReloadedEntityPresetInfo[2] = moduleName == "" ? actualDataModuleOfPreset : moduleName; // If there was a module name, store it as-is so that if there's a data location warning, it persists on every quick reload. + } + return true; } - return true; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool PresetMan::QuickReloadEntityPreset() { - for (const std::string &entityPresetInfoEntry : m_LastReloadedEntityPresetInfo) { - if (entityPresetInfoEntry.empty()) { - g_ConsoleMan.PrintString("ERROR: Trying to quick reload Entity preset when there is nothing set to reload!"); - return false; + bool PresetMan::QuickReloadEntityPreset() { + for (const std::string& entityPresetInfoEntry: m_LastReloadedEntityPresetInfo) { + if (entityPresetInfoEntry.empty()) { + g_ConsoleMan.PrintString("ERROR: Trying to quick reload Entity preset when there is nothing set to reload!"); + return false; + } } + return ReloadEntityPreset(m_LastReloadedEntityPresetInfo[0], m_LastReloadedEntityPresetInfo[1], m_LastReloadedEntityPresetInfo[2]); } - return ReloadEntityPreset(m_LastReloadedEntityPresetInfo[0], m_LastReloadedEntityPresetInfo[1], m_LastReloadedEntityPresetInfo[2]); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddMaterialMapping + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a Material mapping local to a DataModule. This is used for when + // multiple DataModule:s are loading conflicting Material:s, and need to + // resolve the conflicts by mapping their materials to ID's different than + // those specified in the data files. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddMaterialMapping -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a Material mapping local to a DataModule. This is used for when -// multiple DataModule:s are loading conflicting Material:s, and need to -// resolve the conflicts by mapping their materials to ID's different than -// those specified in the data files. + bool PresetMan::AddMaterialMapping(int fromID, int toID, int whichModule) { + RTEAssert(whichModule >= m_OfficialModuleCount && whichModule < m_pDataModules.size(), "Tried to make a material mapping in an offical or out-of-bounds DataModule!"); -bool PresetMan::AddMaterialMapping(int fromID, int toID, int whichModule) -{ - RTEAssert(whichModule >= m_OfficialModuleCount && whichModule < m_pDataModules.size(), "Tried to make a material mapping in an offical or out-of-bounds DataModule!"); + return m_pDataModules[whichModule]->AddMaterialMapping(fromID, toID); + } - return m_pDataModules[whichModule]->AddMaterialMapping(fromID, toID); -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RegisterGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers the existence of an Entity group, and in which module. + void PresetMan::RegisterGroup(std::string newGroup, int whichModule) { + RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RegisterGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registers the existence of an Entity group, and in which module. + // Register in the handy total list + m_TotalGroupRegister.push_back(newGroup); + m_TotalGroupRegister.sort(); + m_TotalGroupRegister.unique(); -void PresetMan::RegisterGroup(std::string newGroup, int whichModule) -{ - RTEAssert(whichModule >= 0 && whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); + // Register in the specified module too + m_pDataModules[whichModule]->RegisterGroup(newGroup); + } - // Register in the handy total list - m_TotalGroupRegister.push_back(newGroup); - m_TotalGroupRegister.sort(); - m_TotalGroupRegister.unique(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGroups + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of all groups registered in a specific module. - // Register in the specified module too - m_pDataModules[whichModule]->RegisterGroup(newGroup); -} + bool PresetMan::GetGroups(std::list& groupList, int whichModule, std::string withType) const { + RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); + bool foundAny = false; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGroups -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of all groups registered in a specific module. - -bool PresetMan::GetGroups(std::list &groupList, int whichModule, std::string withType) const -{ - RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - - bool foundAny = false; - - // Asked for ALL groups ever registered - if (whichModule < 0) - { - // Get all applicable groups - if (withType == "All" || withType.empty()) - { - for (std::list::const_iterator gItr = m_TotalGroupRegister.begin(); gItr != m_TotalGroupRegister.end(); ++gItr) - groupList.push_back(*gItr); - - foundAny = !m_TotalGroupRegister.empty(); - } - // Filter out groups without any entitys of the specified type - else - { - for (int module = 0; module < (int)m_pDataModules.size(); ++module) - foundAny = m_pDataModules[module]->GetGroupsWithType(groupList, withType) || foundAny; - } - } - // Asked for specific DataModule's groups - else if (!m_pDataModules[whichModule]->GetGroupRegister()->empty()) - { - // Get ALL groups of that module - if (withType == "All" || withType.empty()) - { - const std::list *pGroupList = m_pDataModules[whichModule]->GetGroupRegister(); - for (std::list::const_iterator gItr = pGroupList->begin(); gItr != pGroupList->end(); ++gItr) - groupList.push_back(*gItr); - - foundAny = !pGroupList->empty(); - } - // Get only modules that contain an entity of valid type - else - foundAny = m_pDataModules[whichModule]->GetGroupsWithType(groupList, withType) || foundAny; - } - - return foundAny; -} + // Asked for ALL groups ever registered + if (whichModule < 0) { + // Get all applicable groups + if (withType == "All" || withType.empty()) { + for (std::list::const_iterator gItr = m_TotalGroupRegister.begin(); gItr != m_TotalGroupRegister.end(); ++gItr) + groupList.push_back(*gItr); + + foundAny = !m_TotalGroupRegister.empty(); + } + // Filter out groups without any entitys of the specified type + else { + for (int module = 0; module < (int)m_pDataModules.size(); ++module) + foundAny = m_pDataModules[module]->GetGroupsWithType(groupList, withType) || foundAny; + } + } + // Asked for specific DataModule's groups + else if (!m_pDataModules[whichModule]->GetGroupRegister()->empty()) { + // Get ALL groups of that module + if (withType == "All" || withType.empty()) { + const std::list* pGroupList = m_pDataModules[whichModule]->GetGroupRegister(); + for (std::list::const_iterator gItr = pGroupList->begin(); gItr != pGroupList->end(); ++gItr) + groupList.push_back(*gItr); + + foundAny = !pGroupList->empty(); + } + // Get only modules that contain an entity of valid type + else + foundAny = m_pDataModules[whichModule]->GetGroupsWithType(groupList, withType) || foundAny; + } + return foundAny; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetModuleSpaceGroups -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Fills out a list with all groups registered in all official, PLUS a -// a specific non-official module as well. - -bool PresetMan::GetModuleSpaceGroups(std::list &groupList, int whichModule, std::string withType) const -{ - RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); - - bool foundAny = false; - - // If all, then just copy the total register - if (whichModule < 0) - { - // Just get all groups ever registered - if (withType == "All" || withType.empty()) - { - for (std::list::const_iterator gItr = m_TotalGroupRegister.begin(); gItr != m_TotalGroupRegister.end(); ++gItr) - groupList.push_back(*gItr); - - foundAny = !m_TotalGroupRegister.empty(); - } - // Get type filtered groups from ALL data modules - else - { - for (int module = 0; module < (int)m_pDataModules.size(); ++module) - foundAny = GetGroups(groupList, module, withType) || foundAny; - } - } - // Getting modulespace of specific module - else - { - // Get all groups of the official modules that are loaded before the specified one - for (int module = 0; module < m_OfficialModuleCount && module < whichModule; ++module) - foundAny = GetGroups(groupList, module, withType) || foundAny; - - // Now get the groups of the specified module (official or not) - foundAny = GetGroups(groupList, whichModule, withType) || foundAny; - - // Make sure there are no dupe groups in the list - groupList.sort(); - groupList.unique(); - } - - return foundAny; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetModuleSpaceGroups + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Fills out a list with all groups registered in all official, PLUS a + // a specific non-official module as well. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLoadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns actor defined in the specified loadout. + bool PresetMan::GetModuleSpaceGroups(std::list& groupList, int whichModule, std::string withType) const { + RTEAssert(whichModule < (int)m_pDataModules.size(), "Tried to access an out of bounds data module number!"); -Actor * PresetMan::GetLoadout(std::string loadoutName, std::string module, bool spawnDropShip) -{ - return GetLoadout(loadoutName, GetModuleID(module), spawnDropShip); -} + bool foundAny = false; -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLoadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns actor defined in the specified loadout. + // If all, then just copy the total register + if (whichModule < 0) { + // Just get all groups ever registered + if (withType == "All" || withType.empty()) { + for (std::list::const_iterator gItr = m_TotalGroupRegister.begin(); gItr != m_TotalGroupRegister.end(); ++gItr) + groupList.push_back(*gItr); -Actor * PresetMan::GetLoadout(std::string loadoutName, int moduleNumber, bool spawnDropShip) -{ - if (spawnDropShip) - { - // Find the Loadout that this Deployment is referring to - const Loadout *pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", loadoutName, moduleNumber)); - if (pLoadout) - { - const ACraft * pCraftPreset = pLoadout->GetDeliveryCraft(); - if (pCraftPreset) - { - ACraft * pCraft = dynamic_cast(pCraftPreset->Clone()); - if (pCraft) - { - float tally = 0; - // Create and pass along the first Actor and his inventory defined in the Loadout - Actor * pActor = pLoadout->CreateFirstActor(moduleNumber, 1, 1, tally); - // Set the position and team etc for the Actor we are prepping to spawn - if (pActor) - pCraft->AddInventoryItem(pActor); - } - return pCraft; + foundAny = !m_TotalGroupRegister.empty(); + } + // Get type filtered groups from ALL data modules + else { + for (int module = 0; module < (int)m_pDataModules.size(); ++module) + foundAny = GetGroups(groupList, module, withType) || foundAny; } } - } - else - { - // Find the Loadout that this Deployment is referring to - const Loadout *pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", loadoutName, moduleNumber)); - if (pLoadout) - { - float tally = 0; - // Create and pass along the first Actor and his inventory defined in the Loadout - Actor * pReturnActor = pLoadout->CreateFirstActor(moduleNumber, 1, 1, tally); - // Set the position and team etc for the Actor we are prepping to spawn - return pReturnActor; + // Getting modulespace of specific module + else { + // Get all groups of the official modules that are loaded before the specified one + for (int module = 0; module < m_OfficialModuleCount && module < whichModule; ++module) + foundAny = GetGroups(groupList, module, withType) || foundAny; + + // Now get the groups of the specified module (official or not) + foundAny = GetGroups(groupList, whichModule, withType) || foundAny; + + // Make sure there are no dupe groups in the list + groupList.sort(); + groupList.unique(); } + + return foundAny; } - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLoadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns actor defined in the specified loadout. -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Actor* PresetMan::GetLoadout(std::string loadoutName, std::string module, bool spawnDropShip) { + return GetLoadout(loadoutName, GetModuleID(module), spawnDropShip); + } -void PresetMan::FindAndExtractZippedModules() const { - for (const std::filesystem::directory_entry &directoryEntry : std::filesystem::directory_iterator(System::GetWorkingDirectory() + System::GetModDirectory())) { - std::string zippedModulePath = std::filesystem::path(directoryEntry).generic_string(); - if (zippedModulePath.ends_with(System::GetZippedModulePackageExtension())) { - LoadingScreen::LoadingSplashProgressReport("Extracting Data Module from: " + directoryEntry.path().filename().generic_string(), true); - LoadingScreen::LoadingSplashProgressReport(System::ExtractZippedDataModule(zippedModulePath), true); + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLoadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns actor defined in the specified loadout. + + Actor* PresetMan::GetLoadout(std::string loadoutName, int moduleNumber, bool spawnDropShip) { + if (spawnDropShip) { + // Find the Loadout that this Deployment is referring to + const Loadout* pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", loadoutName, moduleNumber)); + if (pLoadout) { + const ACraft* pCraftPreset = pLoadout->GetDeliveryCraft(); + if (pCraftPreset) { + ACraft* pCraft = dynamic_cast(pCraftPreset->Clone()); + if (pCraft) { + float tally = 0; + // Create and pass along the first Actor and his inventory defined in the Loadout + Actor* pActor = pLoadout->CreateFirstActor(moduleNumber, 1, 1, tally); + // Set the position and team etc for the Actor we are prepping to spawn + if (pActor) + pCraft->AddInventoryItem(pActor); + } + return pCraft; + } + } + } else { + // Find the Loadout that this Deployment is referring to + const Loadout* pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", loadoutName, moduleNumber)); + if (pLoadout) { + float tally = 0; + // Create and pass along the first Actor and his inventory defined in the Loadout + Actor* pReturnActor = pLoadout->CreateFirstActor(moduleNumber, 1, 1, tally); + // Set the position and team etc for the Actor we are prepping to spawn + return pReturnActor; + } + } + + return 0; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void PresetMan::FindAndExtractZippedModules() const { + for (const std::filesystem::directory_entry& directoryEntry: std::filesystem::directory_iterator(System::GetWorkingDirectory() + System::GetModDirectory())) { + std::string zippedModulePath = std::filesystem::path(directoryEntry).generic_string(); + if (zippedModulePath.ends_with(System::GetZippedModulePackageExtension())) { + LoadingScreen::LoadingSplashProgressReport("Extracting Data Module from: " + directoryEntry.path().filename().generic_string(), true); + LoadingScreen::LoadingSplashProgressReport(System::ExtractZippedDataModule(zippedModulePath), true); + } } } -} } // namespace RTE diff --git a/Source/Managers/PresetMan.h b/Source/Managers/PresetMan.h index b06811cd0..b58bc08c8 100644 --- a/Source/Managers/PresetMan.h +++ b/Source/Managers/PresetMan.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,585 +18,550 @@ #define g_PresetMan PresetMan::Instance() -namespace RTE -{ - -class Actor; -class DataModule; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: PresetMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The singleton manager of all presets of Entity:s in the RTE. -// The presets serve as a respository of Entity instances with specific -// and unique and initial runtime data. -// Parent(s): Singleton, Serializable. -// Class history: 12/25/2001 PresetMan created. -// Class history: 05/30/2008 Changed name to PresetMan. - -class PresetMan : public Singleton { - friend struct ManagerLuaBindings; - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: PresetMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a PresetMan entity in system -// memory. Create() should be called before using the entity. -// Arguments: None. - - PresetMan() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~PresetMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a PresetMan entity before deletion -// from system memory. -// Arguments: None. - - ~PresetMan() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the PresetMan entity ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Initialize() { return 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire PresetMan, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the PresetMan entity. -// Arguments: None. -// Return value: None. - - void Destroy(); - - - /// - /// Reads an entire DataModule and adds it to this. NOTE that official modules can't be loaded after any non-official ones! - /// - /// The module name to read, e.g. "Base.rte". - /// Whether this module is 'official' or third party. If official, it has to not have any name conflicts with any other official module. - /// Whether this module is a userdata module. If true, will be treated as an unofficial module. - /// A function pointer to a function that will be called and sent a string with information about the progress of this DataModule's creation. - /// Whether the DataModule was read and added correctly. - bool LoadDataModule(const std::string &moduleName, bool official, bool userdata = false, const ProgressCallback &progressCallback = nullptr); - - /// - /// Reads an entire DataModule and adds it to this. NOTE that official modules can't be loaded after any non-official ones! - /// - /// The module name to read, e.g. "Base.rte". - /// Whether the DataModule was read and added correctly. - bool LoadDataModule(const std::string &moduleName) { return LoadDataModule(moduleName, false); } - - /// - /// Loads all the official data modules individually with LoadDataModule, then proceeds to look for any non-official modules and loads them as well. - /// - /// - bool LoadAllDataModules(); - - /// - /// Sets the single module to be loaded after the official modules. This will be the ONLY non-official module to be loaded. - /// - /// Name of the module to load. - void SetSingleModuleToLoad(std::string moduleName) { m_SingleModuleToLoad = moduleName; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDataModule -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a specific loaded DataModule -// Arguments: The ID of the module to get. -// Return value: The requested DataModule. Ownership is NOT transferred! - - const DataModule * GetDataModule(int whichModule = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDataModuleName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a name specific loaded DataModule -// Arguments: The ID of the module to get. -// Return value: The requested DataModule name. - - const std::string GetDataModuleName(int whichModule = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetModuleID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the ID of a loaded DataModule. -// Arguments: The name of the DataModule to get the ID from, including the ".rte" -// Return value: The requested ID. If no module of the name was found, -1 will be returned. - - int GetModuleID(std::string moduleName); - - /// - /// Gets the Name of a loaded DataModule, from a full data file path. - /// - /// The full path to a data file inside the data module id you want to get. - /// The requested Name. If no module of the name was found, "" will be returned. - std::string GetModuleNameFromPath(const std::string &dataPath) const; - - /// - /// Gets the ID of a loaded DataModule from a full data file path. - /// - /// The full path to a data file inside the data module ID you want to get. - /// The requested ID. If no module of the name was found, -1 will be returned. - int GetModuleIDFromPath(const std::string &dataPath); - - /// - /// Returns whether or not the module is vanilla. - /// - /// The name of the module to check, in the form "[moduleName].rte" - /// True if the module is an official data module, otherwise false. - bool IsModuleOfficial(const std::string &moduleName) const; - - /// - /// Returns whether or not the module is vanilla. - /// - /// The name of the module to check, in the form "[moduleName].rte" - /// True if the module is a listed user data module, otherwise false. - bool IsModuleUserdata(const std::string &moduleName) const; - - /// - /// Returns the Full path to the module including Data/, Userdata/ or Mods/. - /// - /// The Path to be completed. - /// The complete path to the file, including Data/, Userdata/ or Mods/ based on whether or not it's part of an official module or userdata. - std::string GetFullModulePath(const std::string &modulePath) const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalModuleCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of modules loaded so far, official or not. -// Arguments: None. -// Return value: The number of modules loaded so far, both official and non. - - int GetTotalModuleCount() { return m_pDataModules.size(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOfficialModuleCount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total number of OFFICIAL modules loaded so far. -// Arguments: None. -// Return value: The number of official modules loaded so far. - - int GetOfficialModuleCount() { return m_OfficialModuleCount; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddEntityPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an Entity instance's pointer and name associations to the -// internal list of already read in Entity:s. Ownership is NOT transferred! -// If there already is an instance defined, nothing happens. If there -// is not, a clone is made of the passed-in Entity and added to the library. -// Arguments: A pointer to the Entity derived instance to add. It should be created -// from a Reader. Ownership is NOT transferred! -// Which module to add the entity to. -// Whether to overwrite if an instance of the EXACT same TYPE and name -// was found. If one of the same name but not the exact type, false -// is returned regardless and nothing will have been added. -// The file this instance was read from, or where it should be written. -// If "Same" is passed as the file path read from, an overwritten instance -// will keep the old one's file location entry. -// Return value: Whether or not a copy of the passed-in instance was successfully inserted -// into the module. False will be returned if there already was an instance -// of that class and instance name inserted previously, unless overwritten. - - bool AddEntityPreset(Entity *pEntToAdd, int whichModule = 0, bool overwriteSame = false, std::string readFromFile = "Same"); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEntityPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a previously read in (defined) Entity, by type and instance name. -// Arguments: The type name of the derived Entity. Ownership is NOT transferred! -// The instance name of the derived Entity instance. -// Which module to try to get the entity from. If it's not found there, -// the official modules will be searched also. -1 means search ALL modules! -// Return value: A pointer to the requested Entity instance. 0 if no Entity with that -// derived type or instance name was found. Ownership is NOT transferred! - - const Entity * GetEntityPreset(std::string type, std::string preset, int whichModule = -1); - // Helper for passing in string module name instead of ID - const Entity * GetEntityPreset(std::string type, std::string preset, std::string module) { return GetEntityPreset(type, preset, GetModuleID(module)); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEntityPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads an instance of an Entity that will be used as preset -// to later on be used to generate more instances of the same state. -// Will check if there was already one of the same class and instance -// name read in previously, and will return that one if found, or -// add the newly read in one to this PresetMan's list if not found to -// exist there previously. Ownership is NOT transferred! -// Arguments: The Reader which is about to read in an instance reference. It'll make -// this look in the same module as it's reading from. -// Return value: A const pointer to the Entity instance read in. 0 if there was an -// error, or the instance name was 'None'. Ownership is NOT transferred! - - const Entity * GetEntityPreset(Reader &reader); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ReadReflectedPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reads a preset of an Entity and tries to add it to the list of -// read-in instances. Regardless of whether there is a name collision, -// the read-in preset will be returned, ownership TRANSFERRED! -// Arguments: The Reader which is about to read in a preset. -// Return value: A pointer to the Entity preset read in. 0 if there was an -// error, or the instance name was 'None'. Ownership IS transferred! - - Entity * ReadReflectedPreset(Reader &reader); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAllOfType -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds to a list all previously read in (defined) Entitys, by type. -// Arguments: Reference to a list which will get all matching Entity:s added to it. -// Ownership of the list or the Entitys placed in it are NOT transferred! -// The type name of the Entitys you want. -// Whether to only get those of one specific DataModule (0-n), or all (-1). -// Return value: Whether any Entity:s were found and added to the list. - - bool GetAllOfType(std::list &entityList, std::string type, int whichModule = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAllOfTypeInModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds to a list all previously read in (defined) Entitys which are -// of a specific type, and only exist in a specific module space. -// Arguments: Reference to a list which will get all matching Entity:s added to it. -// Ownership of the list or the Entitys placed in it are NOT transferred! -// The type name of the Entitys you want. -// Which module to get the instances for, in addition to all groups in -// official modules loaded earlier than the one specified here. -1 means -// get ALL groups ever reg'd. -// Return value: Whether any Entity:s were found and added to the list. - - bool GetAllOfTypeInModuleSpace(std::list &entityList, std::string type, int whichModuleSpace); - - - /// - /// Adds to a list all previously read in (defined) Entities which are associated with a specific group. - /// - /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! - /// The group to look for. "All" will look in all. - /// The name of the least common denominator type of the Entities you want. "All" will look at all types. - /// Whether to only get those of one specific DataModule (0-n), or all (-1). - /// Whether any Entities were found and added to the list. - bool GetAllOfGroup(std::list &entityList, const std::string &group, const std::string &type = "All", int whichModule = -1) { return GetAllOfGroups(entityList, { group }, type, whichModule); } - - /// - /// Adds to a list all previously read in (defined) Entities which are associated with several specific groups. - /// - /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! - /// The groups to look for. "All" will look in all. - /// The name of the least common denominator type of the Entities you want. "All" will look at all types. - /// Whether to only get those of one specific DataModule (0-n), or all (-1). - /// Whether any Entities were found and added to the list. - bool GetAllOfGroups(std::list &entityList, const std::vector &groups, const std::string &type = "All", int whichModule = -1); - - /// - /// Adds to a list all previously read in (defined) Entities which are not associated with a specific group. - /// - /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! - /// The group to exclude. - /// The name of the least common denominator type of the Entities you want. "All" will look at all types. - /// Whether to only get those of one specific DataModule (0-n), or all (-1). - /// Whether any Entities were found and added to the list. - bool GetAllNotOfGroup(std::list &entityList, const std::string &group, const std::string &type = "All", int whichModule = -1) { return GetAllNotOfGroups(entityList, { group }, type, whichModule); } - - /// - /// Adds to a list all previously read in (defined) Entities which are not associated with several specific groups. - /// - /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! - /// The groups to exclude. - /// The name of the least common denominator type of the Entities you want. "All" will look at all types. - /// Whether to only get those of one specific DataModule (0-n), or all (-1). - /// Whether any Entities were found and added to the list. - bool GetAllNotOfGroups(std::list &entityList, const std::vector &groups, const std::string &type = "All", int whichModule = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRandomOfGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a previously read in (defined) Entity which is randomly -// selected from a specific group. -// Arguments: The group to randomly select an Entity from. "All" will look in all. -// The name of the least common denominator type of the Entitys you want. -// "All" will look at all types. -// Whether to only get those of one specific DataModule (0-n), or all (-1). -// Return value: The Entity preset that was randomly selected. Ownership is NOT transferred! - - Entity * GetRandomOfGroup(std::string group, std::string type = "All", int whichModule = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRandomOfGroupFromTech -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a previously read in (defined) Entity which is randomly -// selected from a specific group only if it belongs to some tech. -// Arguments: The group to randomly select an Entity from. "All" will look in all. -// The name of the least common denominator type of the Entitys you want. -// "All" will look at all types. -// Whether to only get those of one specific DataModule (0-n), or all (-1) -// or all modules uncluding non-tech ones. -// Return value: The Entity preset that was randomly selected. Ownership is NOT transferred! - - Entity * GetRandomBuyableOfGroupFromTech(std::string group, std::string type = "All", int whichModule = -1); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetAllOfGroupInModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds to a list all previously read in (defined) Entitys which are -// associated with a specific group, and only exist in a specific module -// space. -// Arguments: Reference to a list which will get all matching Entity:s added to it. -// Ownership of the list or the Entitys placed in it are NOT transferred! -// The group to look for. "All" will look in all. -// The name of the least common denominator type of the Entitys you want. -// "All" will look at all types. -// Which module to get the instances for, in addition to all groups in -// official modules loaded earlier than the one specified here. -1 means -// get ALL groups ever reg'd. -// Return value: Whether any Entity:s were found and added to the list. - - bool GetAllOfGroupInModuleSpace(std::list &entityList, std::string group, std::string type, int whichModuleSpace); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRandomOfGroupInModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a previously read in (defined) Entity which is associated with -// a specific group, randomly selected and only exist in a specific module -// space. -// Arguments: Ownership of the list or the Entitys placed in it are NOT transferred! -// The group to randomly select from. "All" will look in all. -// The name of the least common denominator type of the Entity:s you want. -// "All" will look at all types. -// Which module to get the instances for, in addition to all groups in -// official modules loaded earlier than the one specified here. -1 means -// get ALL groups ever reg'd. -// Return value: The randomly select preset, if any was found with thse search params. -// Ownership is NOT transferred! - - Entity * GetRandomOfGroupInModuleSpace(std::string group, std::string type, int whichModuleSpace); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEntityDataLocation -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the data file path of a previously read in (defined) Entity. -// Arguments: The type name of the derived Entity. Ownership is NOT transferred! -// The preset name of the derived Entity preset. -// Which module to try to get the entity from. If it's not found there, -// the official modules will be searched also. -// Return value: The file path of the data file that the specified Entity was read from. -// If no Entity of that description was found, "" is returned. - - std::string GetEntityDataLocation(std::string type, std::string preset, int whichModule); - - - /// - /// Reloads all scripted Entity Presets with the latest version of their respective script files. - /// - void ReloadAllScripts() const; - - /// - /// Reloads an Entity preset and all related presets with the latest version of their respective files. - /// Stores the passed in Entity preset info for later re-use in PresetMan::QuickReloadEntityPreset. - /// - /// The name of the preset to reload. - /// The type of the preset to reload, to avoid any ambiguity. - /// The DataModule the preset to reload is defined in. - /// Whether or not to store the reloaded entity preset data for quick reloading. - /// Whether reloading the preset was successful. - bool ReloadEntityPreset(const std::string &presetName, const std::string &className, const std::string &dataModule, bool storeReloadedPresetDataForQuickReloading = true); - - /// - /// Reloads the previously reloaded Entity preset and all related presets with the latest version of their respective files. - /// - /// Whether reloading the preset was successful. - bool QuickReloadEntityPreset(); - - /// - /// Gets whether or not ReloadEntityPreset was called this update. - /// - /// Whether or not ReloadEntityPreset was called this update. - bool GetReloadEntityPresetCalledThisUpdate() const { return m_ReloadEntityPresetCalledThisUpdate; } - - /// - /// Resets whether or not ReloadEntityPreset was called this update. - /// - void ClearReloadEntityPresetCalledThisUpdate() { m_ReloadEntityPresetCalledThisUpdate = false; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddMaterialMapping -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a Material mapping local to a DataModule. This is used for when -// multiple DataModule:s are loading conflicting Material:s, and need to -// resolve the conflicts by mapping their materials to ID's different than -// those specified in the data files. -// Arguments: The material ID to map from. -// The material ID to map to. -// The ID of the DataModule we are making the mapping for. This should be -// a non-official module as mapping shouldn't be needed in the official -// modules. -// Return value: Whether this created a new mapping which didn't override a previous -// material mapping. - - bool AddMaterialMapping(int fromID, int toID, int whichModule); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RegisterGroup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registers the existence of an Entity group, and in which module. -// Arguments: The group to register. -// The ID of the module in which at least one entity of this group can be -// found. -// global register. -// Return value: None. - - void RegisterGroup(std::string newGroup, int whichModule); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGroups -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Fills out a list with all groups registered in a specific module. -// Arguments: The list that all found groups will be ADDED to. OWNERSHIP IS NOT TRANSFERRED! -// Which module to get the groups for. -1 means get ALL groups ever reg'd. -// Pass a type name here and only groups with entitys of that type will be -// be included. "All" means don't consider what types are in the groups. -// Return value: Whether any groups were found and thus added to the list. - - bool GetGroups(std::list &groupList, int whichModule = -1, std::string withType = "All") const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetModuleSpaceGroups -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Fills out a list with all groups registered in all official modules, -// PLUS a specific non-official module as well. -// Arguments: The list that all found groups will be ADDED to. OWNERSHIP IS NOT TRANSFERRED! -// Which module to get the groups for, in addition to all groups in -// official modules loaded earlier than the one specified here. -1 means -// get ALL groups ever reg'd. -// Pass a type name here and only groups with entitys of that type will be -// be included. "All" means don't consider what types are in the groups. -// Return value: Whether any groups were found and thus added to the list. - - bool GetModuleSpaceGroups(std::list &groupList, int whichModule, std::string withType = "All") const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLoadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns actor defined in the specified loadout. -// Arguments: Loadout preset name, module name, whether or not spawn delivery craft defined for that loadout -// Return value: Created actor if matching loadout was found or 0. OWNERSHIP IS TRANSFERED. - - Actor * GetLoadout(std::string loadoutName, std::string module, bool spawnDropShip); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLoadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates and returns actor defined in the specified loadout. -// Arguments: Loadout preset name, module id, whether or not spawn delivery craft defined for that loadout -// Return value: Created actor if matching loadout was found or 0. OWNERSHIP IS TRANSFERED. - - Actor * GetLoadout(std::string loadoutName, int moduleNumber, bool spawnDropShip); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - // Owned and loaded DataModule:s - std::vector m_pDataModules; - - // Names of all DataModule:s mapped to indices into the m_pDataModules vector. - // The names are all lowercase name so we can more easily find them in case-agnostic fashion - std::map m_DataModuleIDs; - - // How many modules are 'official' and shipped with the game, and guaranteed to not have name conflicts among them - // All official modules are in the beginning of the m_TypeMap, so this count shows how many into that vector they represent - int m_OfficialModuleCount; - - std::string m_SingleModuleToLoad; //!< Name of the single module to load after the official modules. - - // List of all Entity groups ever registered, all uniques - // This is just a handy total of all the groups registered in all the individual DataModule:s - std::list m_TotalGroupRegister; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - static const std::array c_OfficialModules; // Array storing the names of all the official modules. - static const std::array, 3> c_UserdataModules; // Array storing the names of all the userdata modules. - - std::array m_LastReloadedEntityPresetInfo; //!< Array storing the last reloaded Entity preset info (ClassName, PresetName and DataModule). Used for quick reloading via key combination. - bool m_ReloadEntityPresetCalledThisUpdate; //!< A flag for whether or not ReloadEntityPreset was called this update. - - /// - /// Iterates through the working directory to find any files matching the zipped module package extension (.rte.zip) and proceeds to extract them. - /// - void FindAndExtractZippedModules() const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this PresetMan, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - PresetMan(const PresetMan &reference) = delete; - PresetMan & operator=(const PresetMan &rhs) = delete; - -}; +namespace RTE { + + class Actor; + class DataModule; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: PresetMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The singleton manager of all presets of Entity:s in the RTE. + // The presets serve as a respository of Entity instances with specific + // and unique and initial runtime data. + // Parent(s): Singleton, Serializable. + // Class history: 12/25/2001 PresetMan created. + // Class history: 05/30/2008 Changed name to PresetMan. + + class PresetMan : public Singleton { + friend struct ManagerLuaBindings; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: PresetMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a PresetMan entity in system + // memory. Create() should be called before using the entity. + // Arguments: None. + + PresetMan() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~PresetMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a PresetMan entity before deletion + // from system memory. + // Arguments: None. + + ~PresetMan() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the PresetMan entity ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Initialize() { return 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire PresetMan, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the PresetMan entity. + // Arguments: None. + // Return value: None. + + void Destroy(); + + /// + /// Reads an entire DataModule and adds it to this. NOTE that official modules can't be loaded after any non-official ones! + /// + /// The module name to read, e.g. "Base.rte". + /// Whether this module is 'official' or third party. If official, it has to not have any name conflicts with any other official module. + /// Whether this module is a userdata module. If true, will be treated as an unofficial module. + /// A function pointer to a function that will be called and sent a string with information about the progress of this DataModule's creation. + /// Whether the DataModule was read and added correctly. + bool LoadDataModule(const std::string& moduleName, bool official, bool userdata = false, const ProgressCallback& progressCallback = nullptr); + + /// + /// Reads an entire DataModule and adds it to this. NOTE that official modules can't be loaded after any non-official ones! + /// + /// The module name to read, e.g. "Base.rte". + /// Whether the DataModule was read and added correctly. + bool LoadDataModule(const std::string& moduleName) { return LoadDataModule(moduleName, false); } + + /// + /// Loads all the official data modules individually with LoadDataModule, then proceeds to look for any non-official modules and loads them as well. + /// + /// + bool LoadAllDataModules(); + + /// + /// Sets the single module to be loaded after the official modules. This will be the ONLY non-official module to be loaded. + /// + /// Name of the module to load. + void SetSingleModuleToLoad(std::string moduleName) { m_SingleModuleToLoad = moduleName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDataModule + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a specific loaded DataModule + // Arguments: The ID of the module to get. + // Return value: The requested DataModule. Ownership is NOT transferred! + + const DataModule* GetDataModule(int whichModule = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDataModuleName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a name specific loaded DataModule + // Arguments: The ID of the module to get. + // Return value: The requested DataModule name. + + const std::string GetDataModuleName(int whichModule = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetModuleID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the ID of a loaded DataModule. + // Arguments: The name of the DataModule to get the ID from, including the ".rte" + // Return value: The requested ID. If no module of the name was found, -1 will be returned. + + int GetModuleID(std::string moduleName); + + /// + /// Gets the Name of a loaded DataModule, from a full data file path. + /// + /// The full path to a data file inside the data module id you want to get. + /// The requested Name. If no module of the name was found, "" will be returned. + std::string GetModuleNameFromPath(const std::string& dataPath) const; + + /// + /// Gets the ID of a loaded DataModule from a full data file path. + /// + /// The full path to a data file inside the data module ID you want to get. + /// The requested ID. If no module of the name was found, -1 will be returned. + int GetModuleIDFromPath(const std::string& dataPath); + + /// + /// Returns whether or not the module is vanilla. + /// + /// The name of the module to check, in the form "[moduleName].rte" + /// True if the module is an official data module, otherwise false. + bool IsModuleOfficial(const std::string& moduleName) const; + + /// + /// Returns whether or not the module is vanilla. + /// + /// The name of the module to check, in the form "[moduleName].rte" + /// True if the module is a listed user data module, otherwise false. + bool IsModuleUserdata(const std::string& moduleName) const; + + /// + /// Returns the Full path to the module including Data/, Userdata/ or Mods/. + /// + /// The Path to be completed. + /// The complete path to the file, including Data/, Userdata/ or Mods/ based on whether or not it's part of an official module or userdata. + std::string GetFullModulePath(const std::string& modulePath) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalModuleCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of modules loaded so far, official or not. + // Arguments: None. + // Return value: The number of modules loaded so far, both official and non. + + int GetTotalModuleCount() { return m_pDataModules.size(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOfficialModuleCount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total number of OFFICIAL modules loaded so far. + // Arguments: None. + // Return value: The number of official modules loaded so far. + + int GetOfficialModuleCount() { return m_OfficialModuleCount; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddEntityPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an Entity instance's pointer and name associations to the + // internal list of already read in Entity:s. Ownership is NOT transferred! + // If there already is an instance defined, nothing happens. If there + // is not, a clone is made of the passed-in Entity and added to the library. + // Arguments: A pointer to the Entity derived instance to add. It should be created + // from a Reader. Ownership is NOT transferred! + // Which module to add the entity to. + // Whether to overwrite if an instance of the EXACT same TYPE and name + // was found. If one of the same name but not the exact type, false + // is returned regardless and nothing will have been added. + // The file this instance was read from, or where it should be written. + // If "Same" is passed as the file path read from, an overwritten instance + // will keep the old one's file location entry. + // Return value: Whether or not a copy of the passed-in instance was successfully inserted + // into the module. False will be returned if there already was an instance + // of that class and instance name inserted previously, unless overwritten. + + bool AddEntityPreset(Entity* pEntToAdd, int whichModule = 0, bool overwriteSame = false, std::string readFromFile = "Same"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEntityPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a previously read in (defined) Entity, by type and instance name. + // Arguments: The type name of the derived Entity. Ownership is NOT transferred! + // The instance name of the derived Entity instance. + // Which module to try to get the entity from. If it's not found there, + // the official modules will be searched also. -1 means search ALL modules! + // Return value: A pointer to the requested Entity instance. 0 if no Entity with that + // derived type or instance name was found. Ownership is NOT transferred! + + const Entity* GetEntityPreset(std::string type, std::string preset, int whichModule = -1); + // Helper for passing in string module name instead of ID + const Entity* GetEntityPreset(std::string type, std::string preset, std::string module) { return GetEntityPreset(type, preset, GetModuleID(module)); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEntityPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads an instance of an Entity that will be used as preset + // to later on be used to generate more instances of the same state. + // Will check if there was already one of the same class and instance + // name read in previously, and will return that one if found, or + // add the newly read in one to this PresetMan's list if not found to + // exist there previously. Ownership is NOT transferred! + // Arguments: The Reader which is about to read in an instance reference. It'll make + // this look in the same module as it's reading from. + // Return value: A const pointer to the Entity instance read in. 0 if there was an + // error, or the instance name was 'None'. Ownership is NOT transferred! + + const Entity* GetEntityPreset(Reader& reader); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ReadReflectedPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reads a preset of an Entity and tries to add it to the list of + // read-in instances. Regardless of whether there is a name collision, + // the read-in preset will be returned, ownership TRANSFERRED! + // Arguments: The Reader which is about to read in a preset. + // Return value: A pointer to the Entity preset read in. 0 if there was an + // error, or the instance name was 'None'. Ownership IS transferred! + + Entity* ReadReflectedPreset(Reader& reader); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAllOfType + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds to a list all previously read in (defined) Entitys, by type. + // Arguments: Reference to a list which will get all matching Entity:s added to it. + // Ownership of the list or the Entitys placed in it are NOT transferred! + // The type name of the Entitys you want. + // Whether to only get those of one specific DataModule (0-n), or all (-1). + // Return value: Whether any Entity:s were found and added to the list. + + bool GetAllOfType(std::list& entityList, std::string type, int whichModule = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAllOfTypeInModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds to a list all previously read in (defined) Entitys which are + // of a specific type, and only exist in a specific module space. + // Arguments: Reference to a list which will get all matching Entity:s added to it. + // Ownership of the list or the Entitys placed in it are NOT transferred! + // The type name of the Entitys you want. + // Which module to get the instances for, in addition to all groups in + // official modules loaded earlier than the one specified here. -1 means + // get ALL groups ever reg'd. + // Return value: Whether any Entity:s were found and added to the list. + + bool GetAllOfTypeInModuleSpace(std::list& entityList, std::string type, int whichModuleSpace); + + /// + /// Adds to a list all previously read in (defined) Entities which are associated with a specific group. + /// + /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! + /// The group to look for. "All" will look in all. + /// The name of the least common denominator type of the Entities you want. "All" will look at all types. + /// Whether to only get those of one specific DataModule (0-n), or all (-1). + /// Whether any Entities were found and added to the list. + bool GetAllOfGroup(std::list& entityList, const std::string& group, const std::string& type = "All", int whichModule = -1) { return GetAllOfGroups(entityList, {group}, type, whichModule); } + + /// + /// Adds to a list all previously read in (defined) Entities which are associated with several specific groups. + /// + /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! + /// The groups to look for. "All" will look in all. + /// The name of the least common denominator type of the Entities you want. "All" will look at all types. + /// Whether to only get those of one specific DataModule (0-n), or all (-1). + /// Whether any Entities were found and added to the list. + bool GetAllOfGroups(std::list& entityList, const std::vector& groups, const std::string& type = "All", int whichModule = -1); + + /// + /// Adds to a list all previously read in (defined) Entities which are not associated with a specific group. + /// + /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! + /// The group to exclude. + /// The name of the least common denominator type of the Entities you want. "All" will look at all types. + /// Whether to only get those of one specific DataModule (0-n), or all (-1). + /// Whether any Entities were found and added to the list. + bool GetAllNotOfGroup(std::list& entityList, const std::string& group, const std::string& type = "All", int whichModule = -1) { return GetAllNotOfGroups(entityList, {group}, type, whichModule); } + + /// + /// Adds to a list all previously read in (defined) Entities which are not associated with several specific groups. + /// + /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! + /// The groups to exclude. + /// The name of the least common denominator type of the Entities you want. "All" will look at all types. + /// Whether to only get those of one specific DataModule (0-n), or all (-1). + /// Whether any Entities were found and added to the list. + bool GetAllNotOfGroups(std::list& entityList, const std::vector& groups, const std::string& type = "All", int whichModule = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRandomOfGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a previously read in (defined) Entity which is randomly + // selected from a specific group. + // Arguments: The group to randomly select an Entity from. "All" will look in all. + // The name of the least common denominator type of the Entitys you want. + // "All" will look at all types. + // Whether to only get those of one specific DataModule (0-n), or all (-1). + // Return value: The Entity preset that was randomly selected. Ownership is NOT transferred! + + Entity* GetRandomOfGroup(std::string group, std::string type = "All", int whichModule = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRandomOfGroupFromTech + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a previously read in (defined) Entity which is randomly + // selected from a specific group only if it belongs to some tech. + // Arguments: The group to randomly select an Entity from. "All" will look in all. + // The name of the least common denominator type of the Entitys you want. + // "All" will look at all types. + // Whether to only get those of one specific DataModule (0-n), or all (-1) + // or all modules uncluding non-tech ones. + // Return value: The Entity preset that was randomly selected. Ownership is NOT transferred! + + Entity* GetRandomBuyableOfGroupFromTech(std::string group, std::string type = "All", int whichModule = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetAllOfGroupInModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds to a list all previously read in (defined) Entitys which are + // associated with a specific group, and only exist in a specific module + // space. + // Arguments: Reference to a list which will get all matching Entity:s added to it. + // Ownership of the list or the Entitys placed in it are NOT transferred! + // The group to look for. "All" will look in all. + // The name of the least common denominator type of the Entitys you want. + // "All" will look at all types. + // Which module to get the instances for, in addition to all groups in + // official modules loaded earlier than the one specified here. -1 means + // get ALL groups ever reg'd. + // Return value: Whether any Entity:s were found and added to the list. + + bool GetAllOfGroupInModuleSpace(std::list& entityList, std::string group, std::string type, int whichModuleSpace); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRandomOfGroupInModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a previously read in (defined) Entity which is associated with + // a specific group, randomly selected and only exist in a specific module + // space. + // Arguments: Ownership of the list or the Entitys placed in it are NOT transferred! + // The group to randomly select from. "All" will look in all. + // The name of the least common denominator type of the Entity:s you want. + // "All" will look at all types. + // Which module to get the instances for, in addition to all groups in + // official modules loaded earlier than the one specified here. -1 means + // get ALL groups ever reg'd. + // Return value: The randomly select preset, if any was found with thse search params. + // Ownership is NOT transferred! + + Entity* GetRandomOfGroupInModuleSpace(std::string group, std::string type, int whichModuleSpace); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEntityDataLocation + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the data file path of a previously read in (defined) Entity. + // Arguments: The type name of the derived Entity. Ownership is NOT transferred! + // The preset name of the derived Entity preset. + // Which module to try to get the entity from. If it's not found there, + // the official modules will be searched also. + // Return value: The file path of the data file that the specified Entity was read from. + // If no Entity of that description was found, "" is returned. + + std::string GetEntityDataLocation(std::string type, std::string preset, int whichModule); + + /// + /// Reloads all scripted Entity Presets with the latest version of their respective script files. + /// + void ReloadAllScripts() const; + + /// + /// Reloads an Entity preset and all related presets with the latest version of their respective files. + /// Stores the passed in Entity preset info for later re-use in PresetMan::QuickReloadEntityPreset. + /// + /// The name of the preset to reload. + /// The type of the preset to reload, to avoid any ambiguity. + /// The DataModule the preset to reload is defined in. + /// Whether or not to store the reloaded entity preset data for quick reloading. + /// Whether reloading the preset was successful. + bool ReloadEntityPreset(const std::string& presetName, const std::string& className, const std::string& dataModule, bool storeReloadedPresetDataForQuickReloading = true); + + /// + /// Reloads the previously reloaded Entity preset and all related presets with the latest version of their respective files. + /// + /// Whether reloading the preset was successful. + bool QuickReloadEntityPreset(); + + /// + /// Gets whether or not ReloadEntityPreset was called this update. + /// + /// Whether or not ReloadEntityPreset was called this update. + bool GetReloadEntityPresetCalledThisUpdate() const { return m_ReloadEntityPresetCalledThisUpdate; } + + /// + /// Resets whether or not ReloadEntityPreset was called this update. + /// + void ClearReloadEntityPresetCalledThisUpdate() { m_ReloadEntityPresetCalledThisUpdate = false; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddMaterialMapping + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a Material mapping local to a DataModule. This is used for when + // multiple DataModule:s are loading conflicting Material:s, and need to + // resolve the conflicts by mapping their materials to ID's different than + // those specified in the data files. + // Arguments: The material ID to map from. + // The material ID to map to. + // The ID of the DataModule we are making the mapping for. This should be + // a non-official module as mapping shouldn't be needed in the official + // modules. + // Return value: Whether this created a new mapping which didn't override a previous + // material mapping. + + bool AddMaterialMapping(int fromID, int toID, int whichModule); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RegisterGroup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers the existence of an Entity group, and in which module. + // Arguments: The group to register. + // The ID of the module in which at least one entity of this group can be + // found. + // global register. + // Return value: None. + + void RegisterGroup(std::string newGroup, int whichModule); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGroups + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Fills out a list with all groups registered in a specific module. + // Arguments: The list that all found groups will be ADDED to. OWNERSHIP IS NOT TRANSFERRED! + // Which module to get the groups for. -1 means get ALL groups ever reg'd. + // Pass a type name here and only groups with entitys of that type will be + // be included. "All" means don't consider what types are in the groups. + // Return value: Whether any groups were found and thus added to the list. + + bool GetGroups(std::list& groupList, int whichModule = -1, std::string withType = "All") const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetModuleSpaceGroups + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Fills out a list with all groups registered in all official modules, + // PLUS a specific non-official module as well. + // Arguments: The list that all found groups will be ADDED to. OWNERSHIP IS NOT TRANSFERRED! + // Which module to get the groups for, in addition to all groups in + // official modules loaded earlier than the one specified here. -1 means + // get ALL groups ever reg'd. + // Pass a type name here and only groups with entitys of that type will be + // be included. "All" means don't consider what types are in the groups. + // Return value: Whether any groups were found and thus added to the list. + + bool GetModuleSpaceGroups(std::list& groupList, int whichModule, std::string withType = "All") const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLoadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns actor defined in the specified loadout. + // Arguments: Loadout preset name, module name, whether or not spawn delivery craft defined for that loadout + // Return value: Created actor if matching loadout was found or 0. OWNERSHIP IS TRANSFERED. + + Actor* GetLoadout(std::string loadoutName, std::string module, bool spawnDropShip); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLoadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates and returns actor defined in the specified loadout. + // Arguments: Loadout preset name, module id, whether or not spawn delivery craft defined for that loadout + // Return value: Created actor if matching loadout was found or 0. OWNERSHIP IS TRANSFERED. + + Actor* GetLoadout(std::string loadoutName, int moduleNumber, bool spawnDropShip); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + // Owned and loaded DataModule:s + std::vector m_pDataModules; + + // Names of all DataModule:s mapped to indices into the m_pDataModules vector. + // The names are all lowercase name so we can more easily find them in case-agnostic fashion + std::map m_DataModuleIDs; + + // How many modules are 'official' and shipped with the game, and guaranteed to not have name conflicts among them + // All official modules are in the beginning of the m_TypeMap, so this count shows how many into that vector they represent + int m_OfficialModuleCount; + + std::string m_SingleModuleToLoad; //!< Name of the single module to load after the official modules. + + // List of all Entity groups ever registered, all uniques + // This is just a handy total of all the groups registered in all the individual DataModule:s + std::list m_TotalGroupRegister; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::array c_OfficialModules; // Array storing the names of all the official modules. + static const std::array, 3> c_UserdataModules; // Array storing the names of all the userdata modules. + + std::array m_LastReloadedEntityPresetInfo; //!< Array storing the last reloaded Entity preset info (ClassName, PresetName and DataModule). Used for quick reloading via key combination. + bool m_ReloadEntityPresetCalledThisUpdate; //!< A flag for whether or not ReloadEntityPreset was called this update. + + /// + /// Iterates through the working directory to find any files matching the zipped module package extension (.rte.zip) and proceeds to extract them. + /// + void FindAndExtractZippedModules() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this PresetMan, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + PresetMan(const PresetMan& reference) = delete; + PresetMan& operator=(const PresetMan& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Managers/PrimitiveMan.cpp b/Source/Managers/PrimitiveMan.cpp index 6fe5b3f69..a29d08d63 100644 --- a/Source/Managers/PrimitiveMan.cpp +++ b/Source/Managers/PrimitiveMan.cpp @@ -9,55 +9,55 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::unique_ptr PrimitiveMan::MakeUniqueOfAppropriateTypeFromPrimitiveRawPtr(GraphicalPrimitive *primitive) { + std::unique_ptr PrimitiveMan::MakeUniqueOfAppropriateTypeFromPrimitiveRawPtr(GraphicalPrimitive* primitive) { switch (primitive->GetPrimitiveType()) { case GraphicalPrimitive::PrimitiveType::Line: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Arc: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Spline: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Box: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::BoxFill: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::RoundedBox: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::RoundedBoxFill: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Circle: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::CircleFill: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Ellipse: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::EllipseFill: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Triangle: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::TriangleFill: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Text: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); case GraphicalPrimitive::PrimitiveType::Bitmap: - return std::unique_ptr(static_cast(primitive)); + return std::unique_ptr(static_cast(primitive)); default: return nullptr; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PrimitiveMan::SchedulePrimitive(std::unique_ptr&& primitive) { std::lock_guard lock(m_Mutex); m_ScheduledPrimitives.emplace_back(std::move(primitive)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::SchedulePrimitivesForBlendedDrawing(DrawBlendMode blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const std::vector &primitives) { + void PrimitiveMan::SchedulePrimitivesForBlendedDrawing(DrawBlendMode blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const std::vector& primitives) { if (blendMode < DrawBlendMode::NoBlend || blendMode >= DrawBlendMode::BlendModeCount) { g_ConsoleMan.PrintString("ERROR: Encountered invalid blending mode when attempting to draw primitives! Drawing will be skipped! See the DrawBlendMode enumeration for valid modes."); return; @@ -67,16 +67,16 @@ namespace RTE { blendAmountB = std::clamp(blendAmountB, static_cast(BlendAmountLimits::MinBlend), static_cast(BlendAmountLimits::MaxBlend)); blendAmountA = std::clamp(blendAmountA, static_cast(BlendAmountLimits::MinBlend), static_cast(BlendAmountLimits::MaxBlend)); - for (GraphicalPrimitive *primitive : primitives) { + for (GraphicalPrimitive* primitive: primitives) { primitive->m_BlendMode = blendMode; - primitive->m_ColorChannelBlendAmounts = { blendAmountR, blendAmountG, blendAmountB, blendAmountA }; + primitive->m_ColorChannelBlendAmounts = {blendAmountR, blendAmountG, blendAmountB, blendAmountA}; SchedulePrimitive(MakeUniqueOfAppropriateTypeFromPrimitiveRawPtr(primitive)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawLinePrimitive(int player, const Vector &startPos, const Vector &endPos, unsigned char color, int thickness) { + void PrimitiveMan::DrawLinePrimitive(int player, const Vector& startPos, const Vector& endPos, unsigned char color, int thickness) { if (thickness > 1) { Vector dirVector = g_SceneMan.ShortestDistance(startPos, endPos, g_SceneMan.SceneWrapsX()).SetMagnitude(static_cast(thickness - 1) / 2.0F).Perpendicularize(); Vector pointA = startPos + dirVector; @@ -91,165 +91,165 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawArcPrimitive(const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color) { + void PrimitiveMan::DrawArcPrimitive(const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color) { SchedulePrimitive(std::make_unique(-1, centerPos, startAngle, endAngle, radius, 1, color)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawArcPrimitive(const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness) { + void PrimitiveMan::DrawArcPrimitive(const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness) { SchedulePrimitive(std::make_unique(-1, centerPos, startAngle, endAngle, radius, thickness, color)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawArcPrimitive(int player, const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color) { + void PrimitiveMan::DrawArcPrimitive(int player, const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color) { SchedulePrimitive(std::make_unique(player, centerPos, startAngle, endAngle, radius, 1, color)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawArcPrimitive(int player, const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness) { + void PrimitiveMan::DrawArcPrimitive(int player, const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness) { SchedulePrimitive(std::make_unique(player, centerPos, startAngle, endAngle, radius, thickness, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawSplinePrimitive(const Vector &startPos, const Vector &guideA, const Vector &guideB, const Vector &endPos, unsigned char color) { + void PrimitiveMan::DrawSplinePrimitive(const Vector& startPos, const Vector& guideA, const Vector& guideB, const Vector& endPos, unsigned char color) { SchedulePrimitive(std::make_unique(-1, startPos, guideA, guideB, endPos, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawSplinePrimitive(int player, const Vector &startPos, const Vector &guideA, const Vector &guideB, const Vector &endPos, unsigned char color) { + void PrimitiveMan::DrawSplinePrimitive(int player, const Vector& startPos, const Vector& guideA, const Vector& guideB, const Vector& endPos, unsigned char color) { SchedulePrimitive(std::make_unique(player, startPos, guideA, guideB, endPos, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawBoxPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color) { + void PrimitiveMan::DrawBoxPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color) { SchedulePrimitive(std::make_unique(-1, topLeftPos, bottomRightPos, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawBoxPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color) { + void PrimitiveMan::DrawBoxPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color) { SchedulePrimitive(std::make_unique(player, topLeftPos, bottomRightPos, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawBoxFillPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color) { + void PrimitiveMan::DrawBoxFillPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color) { SchedulePrimitive(std::make_unique(-1, topLeftPos, bottomRightPos, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawBoxFillPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color) { + void PrimitiveMan::DrawBoxFillPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color) { SchedulePrimitive(std::make_unique(player, topLeftPos, bottomRightPos, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawRoundedBoxPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color) { + void PrimitiveMan::DrawRoundedBoxPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color) { SchedulePrimitive(std::make_unique(-1, topLeftPos, bottomRightPos, cornerRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawRoundedBoxPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color) { + void PrimitiveMan::DrawRoundedBoxPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color) { SchedulePrimitive(std::make_unique(player, topLeftPos, bottomRightPos, cornerRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawRoundedBoxFillPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color) { + void PrimitiveMan::DrawRoundedBoxFillPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color) { SchedulePrimitive(std::make_unique(-1, topLeftPos, bottomRightPos, cornerRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawRoundedBoxFillPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color) { + void PrimitiveMan::DrawRoundedBoxFillPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color) { SchedulePrimitive(std::make_unique(player, topLeftPos, bottomRightPos, cornerRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawCirclePrimitive(const Vector ¢erPos, int radius, unsigned char color) { + void PrimitiveMan::DrawCirclePrimitive(const Vector& centerPos, int radius, unsigned char color) { SchedulePrimitive(std::make_unique(-1, centerPos, radius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawCirclePrimitive(int player, const Vector ¢erPos, int radius, unsigned char color) { + void PrimitiveMan::DrawCirclePrimitive(int player, const Vector& centerPos, int radius, unsigned char color) { SchedulePrimitive(std::make_unique(player, centerPos, radius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawCircleFillPrimitive(const Vector ¢erPos, int radius, unsigned char color) { + void PrimitiveMan::DrawCircleFillPrimitive(const Vector& centerPos, int radius, unsigned char color) { SchedulePrimitive(std::make_unique(-1, centerPos, radius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawCircleFillPrimitive(int player, const Vector ¢erPos, int radius, unsigned char color) { + void PrimitiveMan::DrawCircleFillPrimitive(int player, const Vector& centerPos, int radius, unsigned char color) { SchedulePrimitive(std::make_unique(player, centerPos, radius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawEllipsePrimitive(const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color) { + void PrimitiveMan::DrawEllipsePrimitive(const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color) { SchedulePrimitive(std::make_unique(-1, centerPos, horizRadius, vertRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawEllipsePrimitive(int player, const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color) { + void PrimitiveMan::DrawEllipsePrimitive(int player, const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color) { SchedulePrimitive(std::make_unique(player, centerPos, horizRadius, vertRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawEllipseFillPrimitive(const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color) { + void PrimitiveMan::DrawEllipseFillPrimitive(const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color) { SchedulePrimitive(std::make_unique(-1, centerPos, horizRadius, vertRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawEllipseFillPrimitive(int player, const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color) { + void PrimitiveMan::DrawEllipseFillPrimitive(int player, const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color) { SchedulePrimitive(std::make_unique(player, centerPos, horizRadius, vertRadius, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTrianglePrimitive(const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color) { + void PrimitiveMan::DrawTrianglePrimitive(const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color) { SchedulePrimitive(std::make_unique(-1, pointA, pointB, pointC, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTrianglePrimitive(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color) { + void PrimitiveMan::DrawTrianglePrimitive(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color) { SchedulePrimitive(std::make_unique(player, pointA, pointB, pointC, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTriangleFillPrimitive(const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color) { + void PrimitiveMan::DrawTriangleFillPrimitive(const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color) { SchedulePrimitive(std::make_unique(-1, pointA, pointB, pointC, color)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTriangleFillPrimitive(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color) { + void PrimitiveMan::DrawTriangleFillPrimitive(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color) { SchedulePrimitive(std::make_unique(player, pointA, pointB, pointC, color)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawPolygonOrPolygonFillPrimitive(int player, const Vector &startPos, unsigned char color, const std::vector &vertices, bool filled) { + void PrimitiveMan::DrawPolygonOrPolygonFillPrimitive(int player, const Vector& startPos, unsigned char color, const std::vector& vertices, bool filled) { if (vertices.size() < 2) { g_ConsoleMan.PrintString("ERROR: Polygon primitive should have at least 2 vertices! Drawing will be skipped!"); return; @@ -261,53 +261,53 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTextPrimitive(const Vector &start, const std::string &text, bool isSmall, int alignment) { + void PrimitiveMan::DrawTextPrimitive(const Vector& start, const std::string& text, bool isSmall, int alignment) { SchedulePrimitive(std::make_unique(-1, start, text, isSmall, alignment, 0)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTextPrimitive(const Vector &start, const std::string &text, bool isSmall, int alignment, float rotAngle) { + void PrimitiveMan::DrawTextPrimitive(const Vector& start, const std::string& text, bool isSmall, int alignment, float rotAngle) { SchedulePrimitive(std::make_unique(-1, start, text, isSmall, alignment, rotAngle)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTextPrimitive(int player, const Vector &start, const std::string &text, bool isSmall, int alignment) { + void PrimitiveMan::DrawTextPrimitive(int player, const Vector& start, const std::string& text, bool isSmall, int alignment) { SchedulePrimitive(std::make_unique(player, start, text, isSmall, alignment, 0)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawTextPrimitive(int player, const Vector &start, const std::string &text, bool isSmall, int alignment, float rotAngle) { + void PrimitiveMan::DrawTextPrimitive(int player, const Vector& start, const std::string& text, bool isSmall, int alignment, float rotAngle) { SchedulePrimitive(std::make_unique(player, start, text, isSmall, alignment, rotAngle)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawBitmapPrimitive(int player, const Vector ¢erPos, const MOSprite *moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped) { + void PrimitiveMan::DrawBitmapPrimitive(int player, const Vector& centerPos, const MOSprite* moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped) { SchedulePrimitive(std::make_unique(player, centerPos, moSprite, rotAngle, frame, hFlipped, vFlipped)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawBitmapPrimitive(int player, const Vector ¢erPos, const std::string &filePath, float rotAngle, bool hFlipped, bool vFlipped) { + void PrimitiveMan::DrawBitmapPrimitive(int player, const Vector& centerPos, const std::string& filePath, float rotAngle, bool hFlipped, bool vFlipped) { SchedulePrimitive(std::make_unique(player, centerPos, filePath, rotAngle, hFlipped, vFlipped)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawIconPrimitive(int player, const Vector ¢erPos, Entity *entity) { - if (const MOSprite *moSprite = dynamic_cast(entity)) { - SchedulePrimitive(std::make_unique(player, centerPos, moSprite->GetGraphicalIcon(), 0, false, false)); + void PrimitiveMan::DrawIconPrimitive(int player, const Vector& centerPos, Entity* entity) { + if (const MOSprite* moSprite = dynamic_cast(entity)) { + SchedulePrimitive(std::make_unique(player, centerPos, moSprite->GetGraphicalIcon(), 0, false, false)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveMan::DrawPrimitives(int player, BITMAP *targetBitmap, const Vector &targetPos) const { + void PrimitiveMan::DrawPrimitives(int player, BITMAP* targetBitmap, const Vector& targetPos) const { ZoneScoped; if (m_ScheduledPrimitives.empty()) { @@ -316,12 +316,12 @@ namespace RTE { int lastDrawMode = DRAW_MODE_SOLID; DrawBlendMode lastBlendMode = DrawBlendMode::NoBlend; - std::array lastBlendAmounts = { BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend }; + std::array lastBlendAmounts = {BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend}; - for (const std::unique_ptr &primitive : m_ScheduledPrimitives) { + for (const std::unique_ptr& primitive: m_ScheduledPrimitives) { if (int playerToDrawFor = primitive->m_Player; playerToDrawFor == player || playerToDrawFor == -1) { if (DrawBlendMode blendMode = primitive->m_BlendMode; blendMode > DrawBlendMode::NoBlend) { - if (const std::array &blendAmounts = primitive->m_ColorChannelBlendAmounts; blendMode != lastBlendMode || blendAmounts != lastBlendAmounts) { + if (const std::array& blendAmounts = primitive->m_ColorChannelBlendAmounts; blendMode != lastBlendMode || blendAmounts != lastBlendAmounts) { g_FrameMan.SetColorTable(blendMode, blendAmounts); lastBlendMode = blendMode; lastBlendAmounts = blendAmounts; @@ -343,4 +343,4 @@ namespace RTE { } drawing_mode(DRAW_MODE_SOLID, nullptr, 0, 0); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/PrimitiveMan.h b/Source/Managers/PrimitiveMan.h index 16a92e8a3..e8deb56db 100644 --- a/Source/Managers/PrimitiveMan.h +++ b/Source/Managers/PrimitiveMan.h @@ -16,7 +16,6 @@ namespace RTE { class PrimitiveMan : public Singleton { public: - #pragma region Creation /// /// Constructor method used to instantiate a PrimitiveMan object in system memory. @@ -38,7 +37,7 @@ namespace RTE { /// Player to draw for. /// Bitmap to draw on. /// Position to draw. - void DrawPrimitives(int player, BITMAP *targetBitmap, const Vector &targetPos) const; + void DrawPrimitives(int player, BITMAP* targetBitmap, const Vector& targetPos) const; #pragma endregion #pragma region Primitive Draw Scheduling @@ -51,7 +50,7 @@ namespace RTE { /// The blending amount for the Blue channel. 0-100. /// The blending amount for the Alpha channel. 0-100. /// A vector of primitives to schedule drawing for. - void SchedulePrimitivesForBlendedDrawing(DrawBlendMode blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const std::vector &primitives); + void SchedulePrimitivesForBlendedDrawing(DrawBlendMode blendMode, int blendAmountR, int blendAmountG, int blendAmountB, int blendAmountA, const std::vector& primitives); /// /// Schedule to draw a line primitive. @@ -59,7 +58,7 @@ namespace RTE { /// Start position of primitive in scene coordinates. /// End position of primitive in scene coordinates. /// Color to draw primitive with. - void DrawLinePrimitive(const Vector &startPos, const Vector &endPos, unsigned char color) { DrawLinePrimitive(-1, startPos, endPos, color, 1); } + void DrawLinePrimitive(const Vector& startPos, const Vector& endPos, unsigned char color) { DrawLinePrimitive(-1, startPos, endPos, color, 1); } /// /// Schedule to draw a line primitive with the option to change thickness. @@ -68,7 +67,7 @@ namespace RTE { /// End position of primitive in scene coordinates. /// Color to draw primitive with. /// Thickness of the line in pixels. - void DrawLinePrimitive(const Vector &startPos, const Vector &endPos, unsigned char color, int thickness) { DrawLinePrimitive(-1, startPos, endPos, color, thickness); } + void DrawLinePrimitive(const Vector& startPos, const Vector& endPos, unsigned char color, int thickness) { DrawLinePrimitive(-1, startPos, endPos, color, thickness); } /// /// Schedule to draw a line primitive visible only to a specified player. @@ -77,7 +76,7 @@ namespace RTE { /// Start position of primitive in scene coordinates. /// End position of primitive in scene coordinates. /// Color to draw primitive with. - void DrawLinePrimitive(int player, const Vector &startPos, const Vector &endPos, unsigned char color) { DrawLinePrimitive(player, startPos, endPos, color, 1); } + void DrawLinePrimitive(int player, const Vector& startPos, const Vector& endPos, unsigned char color) { DrawLinePrimitive(player, startPos, endPos, color, 1); } /// /// Schedule to draw a line primitive visible only to a specified player with the option to change thickness. @@ -87,7 +86,7 @@ namespace RTE { /// End position of primitive in scene coordinates. /// Color to draw primitive with. /// Thickness of the line in pixels. - void DrawLinePrimitive(int player, const Vector &startPos, const Vector &endPos, unsigned char color, int thickness); + void DrawLinePrimitive(int player, const Vector& startPos, const Vector& endPos, unsigned char color, int thickness); /// /// Schedule to draw an arc primitive. @@ -97,7 +96,7 @@ namespace RTE { /// The angle at which the arc drawing ends. /// Radius of the arc primitive. /// Color to draw primitive with. - void DrawArcPrimitive(const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color); + void DrawArcPrimitive(const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color); /// /// Schedule to draw an arc primitive with the option to change thickness. @@ -108,7 +107,7 @@ namespace RTE { /// Radius of the arc primitive. /// Color to draw primitive with. /// Thickness of the arc in pixels. - void DrawArcPrimitive(const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness); + void DrawArcPrimitive(const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness); /// /// Schedule to draw an arc primitive visible only to a specified player. @@ -119,7 +118,7 @@ namespace RTE { /// The angle at which the arc drawing ends. /// Radius of the arc primitive. /// Color to draw primitive with. - void DrawArcPrimitive(int player, const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color); + void DrawArcPrimitive(int player, const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color); /// /// Schedule to draw an arc primitive visible only to a specified player with the option to change thickness. @@ -131,7 +130,7 @@ namespace RTE { /// Radius of the arc primitive. /// Color to draw primitive with. /// Thickness of the arc in pixels. - void DrawArcPrimitive(int player, const Vector ¢erPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness); + void DrawArcPrimitive(int player, const Vector& centerPos, float startAngle, float endAngle, int radius, unsigned char color, int thickness); /// /// Schedule to draw a Bezier spline primitive. @@ -141,7 +140,7 @@ namespace RTE { /// The second guide point that controls the curve of the spline. The spline won't necessarily pass through this point, but it will affect it's shape. /// End position of primitive in scene coordinates. /// Color to draw primitive with. - void DrawSplinePrimitive(const Vector &startPos, const Vector &guideA, const Vector &guideB, const Vector &endPos, unsigned char color); + void DrawSplinePrimitive(const Vector& startPos, const Vector& guideA, const Vector& guideB, const Vector& endPos, unsigned char color); /// /// Schedule to draw a Bezier spline primitive visible only to a specified player. @@ -152,7 +151,7 @@ namespace RTE { /// The second guide point that controls the curve of the spline. The spline won't necessarily pass through this point, but it will affect it's shape. /// End position of primitive in scene coordinates. /// Color to draw primitive with. - void DrawSplinePrimitive(int player, const Vector &startPos, const Vector &guideA, const Vector &guideB, const Vector &endPos, unsigned char color); + void DrawSplinePrimitive(int player, const Vector& startPos, const Vector& guideA, const Vector& guideB, const Vector& endPos, unsigned char color); /// /// Schedule to draw a box primitive. @@ -160,7 +159,7 @@ namespace RTE { /// Start position of primitive in scene coordinates. Top left corner. /// End position of primitive in scene coordinates. Bottom right corner. /// Color to draw primitive with. - void DrawBoxPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color); + void DrawBoxPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color); /// /// Schedule to draw a box primitive visible only to a specified player. @@ -169,7 +168,7 @@ namespace RTE { /// Start position of primitive in scene coordinates. Top left corner. /// End position of primitive in scene coordinates. Bottom right corner. /// Color to draw primitive with. - void DrawBoxPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color); + void DrawBoxPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color); /// /// Schedule to draw a filled box primitive. @@ -177,7 +176,7 @@ namespace RTE { /// Start position of primitive in scene coordinates. Top left corner. /// End position of primitive in scene coordinates. Bottom right corner. /// Color to draw primitive with. - void DrawBoxFillPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color); + void DrawBoxFillPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color); /// /// Schedule to draw a filled box primitive visible only to a specified player. @@ -186,7 +185,7 @@ namespace RTE { /// Start position of primitive in scene coordinates. Top left corner. /// End position of primitive in scene coordinates. Bottom right corner. /// Color to draw primitive with. - void DrawBoxFillPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color); + void DrawBoxFillPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color); /// /// Schedule to draw a rounded box primitive. @@ -195,7 +194,7 @@ namespace RTE { /// End position of primitive in scene coordinates. Bottom right corner. /// The radius of the corners of the box. Smaller radius equals sharper corners. /// Color to draw primitive with. - void DrawRoundedBoxPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color); + void DrawRoundedBoxPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color); /// /// Schedule to draw a rounded box primitive visible only to a specified player. @@ -205,7 +204,7 @@ namespace RTE { /// End position of primitive in scene coordinates. Bottom right corner. /// The radius of the corners of the box. Smaller radius equals sharper corners. /// Color to draw primitive with. - void DrawRoundedBoxPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color); + void DrawRoundedBoxPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color); /// /// Schedule to draw a filled rounded box primitive. @@ -214,7 +213,7 @@ namespace RTE { /// End position of primitive in scene coordinates. Bottom right corner. /// The radius of the corners of the box. Smaller radius equals sharper corners. /// Color to draw primitive with. - void DrawRoundedBoxFillPrimitive(const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color); + void DrawRoundedBoxFillPrimitive(const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color); /// /// Schedule to draw a filled rounded box primitive visible only to a specified player. @@ -224,7 +223,7 @@ namespace RTE { /// End position of primitive in scene coordinates. Bottom right corner. /// The radius of the corners of the box. Smaller radius equals sharper corners. /// Color to draw primitive with. - void DrawRoundedBoxFillPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color); + void DrawRoundedBoxFillPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color); /// /// Schedule to draw a circle primitive. @@ -232,7 +231,7 @@ namespace RTE { /// Position of primitive's center in scene coordinates. /// Radius of circle primitive. /// Color to draw primitive with. - void DrawCirclePrimitive(const Vector ¢erPos, int radius, unsigned char color); + void DrawCirclePrimitive(const Vector& centerPos, int radius, unsigned char color); /// /// Schedule to draw a circle primitive visible only to a specified player. @@ -241,7 +240,7 @@ namespace RTE { /// Position of primitive's center in scene coordinates. /// Radius of circle primitive. /// Color to draw primitive with. - void DrawCirclePrimitive(int player, const Vector ¢erPos, int radius, unsigned char color); + void DrawCirclePrimitive(int player, const Vector& centerPos, int radius, unsigned char color); /// /// Schedule to draw a filled circle primitive. @@ -249,7 +248,7 @@ namespace RTE { /// Position of primitive's center in scene coordinates. /// Radius of circle primitive. /// Color to fill primitive with. - void DrawCircleFillPrimitive(const Vector ¢erPos, int radius, unsigned char color); + void DrawCircleFillPrimitive(const Vector& centerPos, int radius, unsigned char color); /// /// Schedule to draw a filled circle primitive visible only to a specified player. @@ -258,7 +257,7 @@ namespace RTE { /// Position of primitive's center in scene coordinates. /// Radius of circle primitive. /// Color to fill primitive with. - void DrawCircleFillPrimitive(int player, const Vector ¢erPos, int radius, unsigned char color); + void DrawCircleFillPrimitive(int player, const Vector& centerPos, int radius, unsigned char color); /// /// Schedule to draw an ellipse primitive. @@ -267,7 +266,7 @@ namespace RTE { /// Horizontal radius of the ellipse primitive. /// Vertical radius of the ellipse primitive. /// Color to draw primitive with. - void DrawEllipsePrimitive(const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color); + void DrawEllipsePrimitive(const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color); /// /// Schedule to draw an ellipse primitive visible only to a specified player. @@ -277,7 +276,7 @@ namespace RTE { /// Horizontal radius of the ellipse primitive. /// Vertical radius of the ellipse primitive. /// Color to draw primitive with. - void DrawEllipsePrimitive(int player, const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color); + void DrawEllipsePrimitive(int player, const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color); /// /// Schedule to draw a filled ellipse primitive. @@ -286,7 +285,7 @@ namespace RTE { /// Horizontal radius of the ellipse primitive. /// Vertical radius of the ellipse primitive. /// Color to fill primitive with. - void DrawEllipseFillPrimitive(const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color); + void DrawEllipseFillPrimitive(const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color); /// /// Schedule to draw a filled ellipse primitive visible only to a specified player. @@ -296,7 +295,7 @@ namespace RTE { /// Horizontal radius of the ellipse primitive. /// Vertical radius of the ellipse primitive. /// Color to fill primitive with. - void DrawEllipseFillPrimitive(int player, const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color); + void DrawEllipseFillPrimitive(int player, const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color); /// /// Schedule to draw a triangle primitive. @@ -305,7 +304,7 @@ namespace RTE { /// Position of the second point of the triangle in scene coordinates. /// Position of the third point of the triangle in scene coordinates. /// Color to fill primitive with. - void DrawTrianglePrimitive(const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color); + void DrawTrianglePrimitive(const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color); /// /// Schedule to draw a triangle primitive visible only to a specified player. @@ -315,7 +314,7 @@ namespace RTE { /// Position of the second point of the triangle in scene coordinates. /// Position of the third point of the triangle in scene coordinates. /// Color to fill primitive with. - void DrawTrianglePrimitive(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color); + void DrawTrianglePrimitive(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color); /// /// Schedule to draw a filled triangle primitive. @@ -324,7 +323,7 @@ namespace RTE { /// Position of the second point of the triangle in scene coordinates. /// Position of the third point of the triangle in scene coordinates. /// Color to fill primitive with. - void DrawTriangleFillPrimitive(const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color); + void DrawTriangleFillPrimitive(const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color); /// /// Schedule to draw a filled triangle primitive visible only to a specified player. @@ -334,7 +333,7 @@ namespace RTE { /// Position of the second point of the triangle in scene coordinates. /// Position of the third point of the triangle in scene coordinates. /// Color to fill primitive with. - void DrawTriangleFillPrimitive(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color); + void DrawTriangleFillPrimitive(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color); /// /// Schedule to draw a polygon primitive visible only to a specified player. @@ -344,7 +343,7 @@ namespace RTE { /// Color to draw primitive with. /// A vector containing the positions of the vertices of the polygon, relative to the center position. /// Whether a PolygonFillPrimitive should be scheduled instead of PolygonPrimitive. - void DrawPolygonOrPolygonFillPrimitive(int player, const Vector &startPos, unsigned char color, const std::vector &vertices, bool filled); + void DrawPolygonOrPolygonFillPrimitive(int player, const Vector& startPos, unsigned char color, const std::vector& vertices, bool filled); /// /// Schedule to draw a text primitive. @@ -353,7 +352,7 @@ namespace RTE { /// Text string to draw. /// Use small or large font. True for small font. /// Alignment of text. - void DrawTextPrimitive(const Vector &start, const std::string &text, bool isSmall, int alignment); + void DrawTextPrimitive(const Vector& start, const std::string& text, bool isSmall, int alignment); /// /// Schedule to draw a text primitive. @@ -363,7 +362,7 @@ namespace RTE { /// Use small or large font. True for small font. /// Alignment of text. /// Angle to rotate text in radians. - void DrawTextPrimitive(const Vector &start, const std::string &text, bool isSmall, int alignment, float rotAngle); + void DrawTextPrimitive(const Vector& start, const std::string& text, bool isSmall, int alignment, float rotAngle); /// /// Schedule to draw a text primitive visible only to a specified player. @@ -373,7 +372,7 @@ namespace RTE { /// Text string to draw. /// Use small or large font. True for small font. /// Alignment of text. - void DrawTextPrimitive(int player, const Vector &start, const std::string &text, bool isSmall, int alignment); + void DrawTextPrimitive(int player, const Vector& start, const std::string& text, bool isSmall, int alignment); /// /// Schedule to draw a text primitive visible only to a specified player. @@ -384,7 +383,7 @@ namespace RTE { /// Use small or large font. True for small font. /// Alignment of text. /// Angle to rotate text in radians. - void DrawTextPrimitive(int player, const Vector &start, const std::string &text, bool isSmall, int alignment, float rotAngle); + void DrawTextPrimitive(int player, const Vector& start, const std::string& text, bool isSmall, int alignment, float rotAngle); /// /// Schedule to draw a bitmap primitive. @@ -393,7 +392,7 @@ namespace RTE { /// A MOSprite to draw BITMAP from. /// Rotation angle in radians. /// Frame to draw. - void DrawBitmapPrimitive(const Vector ¢erPos, const MOSprite *moSprite, float rotAngle, int frame) { DrawBitmapPrimitive(-1, centerPos, moSprite, rotAngle, frame, false, false); } + void DrawBitmapPrimitive(const Vector& centerPos, const MOSprite* moSprite, float rotAngle, int frame) { DrawBitmapPrimitive(-1, centerPos, moSprite, rotAngle, frame, false, false); } /// /// Schedule to draw a bitmap primitive with the option to flip the primitive horizontally and vertically. @@ -404,7 +403,7 @@ namespace RTE { /// Frame to draw. /// Whether to flip the sprite horizontally. /// Whether to flip the sprite vertically. - void DrawBitmapPrimitive(const Vector ¢erPos, const MOSprite *moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped) { DrawBitmapPrimitive(-1, centerPos, moSprite, rotAngle, frame, hFlipped, vFlipped); } + void DrawBitmapPrimitive(const Vector& centerPos, const MOSprite* moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped) { DrawBitmapPrimitive(-1, centerPos, moSprite, rotAngle, frame, hFlipped, vFlipped); } /// /// Schedule to draw a bitmap primitive visible only to a specified player. @@ -414,7 +413,7 @@ namespace RTE { /// A MOSprite to draw BITMAP from. /// Rotation angle in radians. /// Frame to draw. - void DrawBitmapPrimitive(int player, const Vector ¢erPos, const MOSprite *moSprite, float rotAngle, int frame) { DrawBitmapPrimitive(player, centerPos, moSprite, rotAngle, frame, false, false); } + void DrawBitmapPrimitive(int player, const Vector& centerPos, const MOSprite* moSprite, float rotAngle, int frame) { DrawBitmapPrimitive(player, centerPos, moSprite, rotAngle, frame, false, false); } /// /// Schedule to draw a bitmap primitive visible only to a specified player with the option to flip the primitive horizontally or vertically. @@ -426,7 +425,7 @@ namespace RTE { /// Frame to draw. /// Whether to flip the sprite horizontally. /// Whether to flip the sprite vertically. - void DrawBitmapPrimitive(int player, const Vector ¢erPos, const MOSprite *moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped); + void DrawBitmapPrimitive(int player, const Vector& centerPos, const MOSprite* moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped); /// /// Schedule to draw a bitmap primitive. @@ -434,7 +433,7 @@ namespace RTE { /// Position of primitive's center in scene coordinates. /// Path to the bitmap to draw. /// Rotation angle in radians. - void DrawBitmapPrimitive(const Vector ¢erPos, const std::string &filePath, float rotAngle) { DrawBitmapPrimitive(-1, centerPos, filePath, rotAngle, false, false); } + void DrawBitmapPrimitive(const Vector& centerPos, const std::string& filePath, float rotAngle) { DrawBitmapPrimitive(-1, centerPos, filePath, rotAngle, false, false); } /// /// Schedule to draw a bitmap primitive with the option to flip the primitive horizontally and vertically. @@ -444,7 +443,7 @@ namespace RTE { /// Rotation angle in radians. /// Whether to flip the sprite horizontally. /// Whether to flip the sprite vertically. - void DrawBitmapPrimitive(const Vector ¢erPos, const std::string &filePath, float rotAngle, bool hFlipped, bool vFlipped) { DrawBitmapPrimitive(-1, centerPos, filePath, rotAngle, hFlipped, vFlipped); } + void DrawBitmapPrimitive(const Vector& centerPos, const std::string& filePath, float rotAngle, bool hFlipped, bool vFlipped) { DrawBitmapPrimitive(-1, centerPos, filePath, rotAngle, hFlipped, vFlipped); } /// /// Schedule to draw a bitmap primitive visible only to a specified player. @@ -453,7 +452,7 @@ namespace RTE { /// Position of primitive's center in scene coordinates. /// Path to the bitmap to draw. /// Rotation angle in radians. - void DrawBitmapPrimitive(int player, const Vector ¢erPos, const std::string &filePath, float rotAngle) { DrawBitmapPrimitive(player, centerPos, filePath, rotAngle, false, false); } + void DrawBitmapPrimitive(int player, const Vector& centerPos, const std::string& filePath, float rotAngle) { DrawBitmapPrimitive(player, centerPos, filePath, rotAngle, false, false); } /// /// Schedule to draw a bitmap primitive visible only to a specified player with the option to flip the primitive horizontally or vertically. @@ -464,14 +463,14 @@ namespace RTE { /// Rotation angle in radians. /// Whether to flip the sprite horizontally. /// Whether to flip the sprite vertically. - void DrawBitmapPrimitive(int player, const Vector ¢erPos, const std::string &filePath, float rotAngle, bool hFlipped, bool vFlipped); + void DrawBitmapPrimitive(int player, const Vector& centerPos, const std::string& filePath, float rotAngle, bool hFlipped, bool vFlipped); /// /// Schedule to draw the GUI icon of an object. /// /// Position of primitive's center in scene coordinates. /// An entity to draw sprite from. - void DrawIconPrimitive(const Vector ¢erPos, Entity *entity) { DrawIconPrimitive(-1, centerPos, entity); } + void DrawIconPrimitive(const Vector& centerPos, Entity* entity) { DrawIconPrimitive(-1, centerPos, entity); } /// /// Schedule to draw the GUI icon of an object, visible only to a specified player. @@ -479,11 +478,10 @@ namespace RTE { /// Player screen to draw primitive on. /// Position of primitive's center in scene coordinates. /// An entity to draw sprite from. - void DrawIconPrimitive(int player, const Vector ¢erPos, Entity *entity); + void DrawIconPrimitive(int player, const Vector& centerPos, Entity* entity); #pragma endregion protected: - std::mutex m_Mutex; //!< Mutex so that mutiple threads (i.e multithreaded scripts) can safely queue up draws std::deque> m_ScheduledPrimitives; //!< List of graphical primitives scheduled to draw this frame, cleared every frame during FrameMan::Draw(). @@ -494,7 +492,7 @@ namespace RTE { /// /// Raw pointer to the GraphicalPrimitive object to make unique. /// A unique_ptr of the appropriate derived GraphicalPrimitive type. Ownership is transferred! - std::unique_ptr MakeUniqueOfAppropriateTypeFromPrimitiveRawPtr(GraphicalPrimitive *primitive); + std::unique_ptr MakeUniqueOfAppropriateTypeFromPrimitiveRawPtr(GraphicalPrimitive* primitive); /// /// Safely schedules a primite to draw in a thread-safe manner. @@ -503,8 +501,8 @@ namespace RTE { void SchedulePrimitive(std::unique_ptr&& primitive); // Disallow the use of some implicit methods. - PrimitiveMan(const PrimitiveMan &reference) = delete; - PrimitiveMan & operator=(const PrimitiveMan &rhs) = delete; + PrimitiveMan(const PrimitiveMan& reference) = delete; + PrimitiveMan& operator=(const PrimitiveMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/SceneMan.cpp b/Source/Managers/SceneMan.cpp index 438bec041..a668f7953 100644 --- a/Source/Managers/SceneMan.cpp +++ b/Source/Managers/SceneMan.cpp @@ -7,7 +7,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files #include "NetworkServer.h" @@ -38,2899 +37,2680 @@ #include "tracy/Tracy.hpp" -namespace RTE -{ +namespace RTE { #define CLEANAIRINTERVAL 200000 -const std::string SceneMan::c_ClassName = "SceneMan"; -std::vector> SceneMan::m_IntermediateSettlingBitmaps; + const std::string SceneMan::c_ClassName = "SceneMan"; + std::vector> SceneMan::m_IntermediateSettlingBitmaps; -// Stored as a thread-local instead of in the class, because multithreaded Lua scripts will interfere otherwise -thread_local Vector s_LastRayHitPos; + // Stored as a thread-local instead of in the class, because multithreaded Lua scripts will interfere otherwise + thread_local Vector s_LastRayHitPos; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void SceneMan::Clear() -{ - m_DefaultSceneName = "Tutorial Bunker"; - m_pSceneToLoad = nullptr; - m_PlaceObjects = true; - m_PlaceUnits = true; - m_pCurrentScene = nullptr; - m_pMOColorLayer = nullptr; - m_pMOIDLayer = nullptr; - m_pDebugLayer = nullptr; + void SceneMan::Clear() { + m_DefaultSceneName = "Tutorial Bunker"; + m_pSceneToLoad = nullptr; + m_PlaceObjects = true; + m_PlaceUnits = true; + m_pCurrentScene = nullptr; + m_pMOColorLayer = nullptr; + m_pMOIDLayer = nullptr; + m_pDebugLayer = nullptr; - m_LayerDrawMode = g_LayerNormal; + m_LayerDrawMode = g_LayerNormal; - m_MatNameMap.clear(); - m_apMatPalette.fill(nullptr); - m_MaterialCount = 0; + m_MatNameMap.clear(); + m_apMatPalette.fill(nullptr); + m_MaterialCount = 0; - m_MaterialCopiesVector.clear(); + m_MaterialCopiesVector.clear(); - m_pUnseenRevealSound = nullptr; - m_DrawRayCastVisualizations = false; - m_DrawPixelCheckVisualizations = false; - m_LastUpdatedScreen = 0; - m_SecondStructPass = false; -// m_CalcTimer.Reset(); - m_CleanTimer.Reset(); + m_pUnseenRevealSound = nullptr; + m_DrawRayCastVisualizations = false; + m_DrawPixelCheckVisualizations = false; + m_LastUpdatedScreen = 0; + m_SecondStructPass = false; + // m_CalcTimer.Reset(); + m_CleanTimer.Reset(); - if (m_pOrphanSearchBitmap) - destroy_bitmap(m_pOrphanSearchBitmap); - m_pOrphanSearchBitmap = create_bitmap_ex(8, MAXORPHANRADIUS , MAXORPHANRADIUS); - - m_ScrapCompactingHeight = 25; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::Initialize() const { - // Can't create these earlier in the static declaration because allegro_init needs to be called before create_bitmap - m_IntermediateSettlingBitmaps = { - { 16, create_bitmap_ex(8, 16, 16) }, - { 32, create_bitmap_ex(8, 32, 32) }, - { 48, create_bitmap_ex(8, 48, 48) }, - { 64, create_bitmap_ex(8, 64, 64) }, - { 96, create_bitmap_ex(8, 96, 96) }, - { 128, create_bitmap_ex(8, 128, 128) }, - { 192, create_bitmap_ex(8, 192, 192) }, - { 256, create_bitmap_ex(8, 256, 256) }, - { 384, create_bitmap_ex(8, 384, 384) }, - { 512, create_bitmap_ex(8, 512, 512) } - }; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::Create(std::string readerFile) -{ - Reader *reader = new Reader(); - if (reader->Create(readerFile.c_str())) - g_ConsoleMan.PrintString("ERROR: Could not find Scene definition file!"); - - Serializable::Create(*reader); - delete reader; - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Material * SceneMan::AddMaterialCopy(Material *mat) -{ - Material * matCopy = dynamic_cast(mat->Clone()); - if (matCopy) - m_MaterialCopiesVector.push_back(matCopy); - - return matCopy; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::LoadScene(Scene *pNewScene, bool placeObjects, bool placeUnits) { - if (!pNewScene) { - return -1; + if (m_pOrphanSearchBitmap) + destroy_bitmap(m_pOrphanSearchBitmap); + m_pOrphanSearchBitmap = create_bitmap_ex(8, MAXORPHANRADIUS, MAXORPHANRADIUS); + + m_ScrapCompactingHeight = 25; } - g_MovableMan.PurgeAllMOs(); - g_PostProcessMan.ClearScenePostEffects(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::Initialize() const { + // Can't create these earlier in the static declaration because allegro_init needs to be called before create_bitmap + m_IntermediateSettlingBitmaps = { + {16, create_bitmap_ex(8, 16, 16)}, + {32, create_bitmap_ex(8, 32, 32)}, + {48, create_bitmap_ex(8, 48, 48)}, + {64, create_bitmap_ex(8, 64, 64)}, + {96, create_bitmap_ex(8, 96, 96)}, + {128, create_bitmap_ex(8, 128, 128)}, + {192, create_bitmap_ex(8, 192, 192)}, + {256, create_bitmap_ex(8, 256, 256)}, + {384, create_bitmap_ex(8, 384, 384)}, + {512, create_bitmap_ex(8, 512, 512)}}; + } - if (m_pCurrentScene) { - delete m_pCurrentScene; - m_pCurrentScene = nullptr; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::Create(std::string readerFile) { + Reader* reader = new Reader(); + if (reader->Create(readerFile.c_str())) + g_ConsoleMan.PrintString("ERROR: Could not find Scene definition file!"); + + Serializable::Create(*reader); + delete reader; + + return 0; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Material* SceneMan::AddMaterialCopy(Material* mat) { + Material* matCopy = dynamic_cast(mat->Clone()); + if (matCopy) + m_MaterialCopiesVector.push_back(matCopy); + + return matCopy; } - g_NetworkServer.LockScene(true); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::LoadScene(Scene* pNewScene, bool placeObjects, bool placeUnits) { + if (!pNewScene) { + return -1; + } + + g_MovableMan.PurgeAllMOs(); + g_PostProcessMan.ClearScenePostEffects(); + + if (m_pCurrentScene) { + delete m_pCurrentScene; + m_pCurrentScene = nullptr; + } + + g_NetworkServer.LockScene(true); + + m_pCurrentScene = pNewScene; + if (m_pCurrentScene->LoadData(placeObjects, true, placeUnits) < 0) { + g_ConsoleMan.PrintString("ERROR: Loading scene \'" + m_pCurrentScene->GetPresetName() + "\' failed! Has it been properly defined?"); + g_NetworkServer.LockScene(false); + return -1; + } + + // Report successful load to the console + g_ConsoleMan.PrintString("SYSTEM: Scene \"" + m_pCurrentScene->GetPresetName() + "\" was loaded"); + + // Set the proper scales of the unseen obscuring SceneLayers + SceneLayer* pUnseenLayer = 0; + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + if (!g_ActivityMan.GetActivity()->TeamActive(team)) + continue; + SceneLayer* pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); + if (pUnseenLayer && pUnseenLayer->GetBitmap()) { + // Calculate how many times smaller the unseen map is compared to the entire terrain's dimensions, and set it as the scale factor on the Unseen layer + pUnseenLayer->SetScaleFactor(Vector((float)m_pCurrentScene->GetTerrain()->GetBitmap()->w / (float)pUnseenLayer->GetBitmap()->w, (float)m_pCurrentScene->GetTerrain()->GetBitmap()->h / (float)pUnseenLayer->GetBitmap()->h)); + } + } + + // Get the unseen reveal sound + if (!m_pUnseenRevealSound) + m_pUnseenRevealSound = dynamic_cast(g_PresetMan.GetEntityPreset("SoundContainer", "Unseen Reveal Blip")->Clone()); + + // m_pCurrentScene->GetTerrain()->CleanAir(); + + // Re-create the MoveableObject:s color SceneLayer + delete m_pMOColorLayer; + BITMAP* pBitmap = create_bitmap_ex(8, GetSceneWidth(), GetSceneHeight()); + clear_to_color(pBitmap, g_MaskColor); + m_pMOColorLayer = new SceneLayerTracked(); + m_pMOColorLayer->Create(pBitmap, true, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)); + pBitmap = 0; + + // Re-create the MoveableObject:s ID SceneLayer + delete m_pMOIDLayer; + pBitmap = create_bitmap_ex(c_MOIDLayerBitDepth, GetSceneWidth(), GetSceneHeight()); + clear_to_color(pBitmap, g_NoMOID); + m_pMOIDLayer = new SceneLayerTracked(); + m_pMOIDLayer->Create(pBitmap, false, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)); + pBitmap = 0; + + const int cellSize = 20; + m_MOIDsGrid = SpatialPartitionGrid(GetSceneWidth(), GetSceneHeight(), cellSize); + + // Create the Debug SceneLayer + if (m_DrawRayCastVisualizations || m_DrawPixelCheckVisualizations) { + delete m_pDebugLayer; + pBitmap = create_bitmap_ex(8, GetSceneWidth(), GetSceneHeight()); + clear_to_color(pBitmap, g_MaskColor); + m_pDebugLayer = new SceneLayer(); + m_pDebugLayer->Create(pBitmap, true, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)); + pBitmap = nullptr; + } + + // Finally draw the ID:s of the MO:s to the MOID layers for the first time + g_MovableMan.UpdateDrawMOIDs(m_pMOIDLayer->GetBitmap()); - m_pCurrentScene = pNewScene; - if (m_pCurrentScene->LoadData(placeObjects, true, placeUnits) < 0) - { - g_ConsoleMan.PrintString("ERROR: Loading scene \'" + m_pCurrentScene->GetPresetName() + "\' failed! Has it been properly defined?"); g_NetworkServer.LockScene(false); - return -1; - } - - // Report successful load to the console - g_ConsoleMan.PrintString("SYSTEM: Scene \"" + m_pCurrentScene->GetPresetName() + "\" was loaded"); - - // Set the proper scales of the unseen obscuring SceneLayers - SceneLayer *pUnseenLayer = 0; - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - if (!g_ActivityMan.GetActivity()->TeamActive(team)) - continue; - SceneLayer *pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); - if (pUnseenLayer && pUnseenLayer->GetBitmap()) - { - // Calculate how many times smaller the unseen map is compared to the entire terrain's dimensions, and set it as the scale factor on the Unseen layer - pUnseenLayer->SetScaleFactor(Vector((float)m_pCurrentScene->GetTerrain()->GetBitmap()->w / (float)pUnseenLayer->GetBitmap()->w, (float)m_pCurrentScene->GetTerrain()->GetBitmap()->h / (float)pUnseenLayer->GetBitmap()->h)); - } - } - - // Get the unseen reveal sound - if (!m_pUnseenRevealSound) - m_pUnseenRevealSound = dynamic_cast(g_PresetMan.GetEntityPreset("SoundContainer", "Unseen Reveal Blip")->Clone()); - -// m_pCurrentScene->GetTerrain()->CleanAir(); - - // Re-create the MoveableObject:s color SceneLayer - delete m_pMOColorLayer; - BITMAP *pBitmap = create_bitmap_ex(8, GetSceneWidth(), GetSceneHeight()); - clear_to_color(pBitmap, g_MaskColor); - m_pMOColorLayer = new SceneLayerTracked(); - m_pMOColorLayer->Create(pBitmap, true, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)); - pBitmap = 0; - - // Re-create the MoveableObject:s ID SceneLayer - delete m_pMOIDLayer; - pBitmap = create_bitmap_ex(c_MOIDLayerBitDepth, GetSceneWidth(), GetSceneHeight()); - clear_to_color(pBitmap, g_NoMOID); - m_pMOIDLayer = new SceneLayerTracked(); - m_pMOIDLayer->Create(pBitmap, false, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)); - pBitmap = 0; - - const int cellSize = 20; - m_MOIDsGrid = SpatialPartitionGrid(GetSceneWidth(), GetSceneHeight(), cellSize); - - // Create the Debug SceneLayer - if (m_DrawRayCastVisualizations || m_DrawPixelCheckVisualizations) { - delete m_pDebugLayer; - pBitmap = create_bitmap_ex(8, GetSceneWidth(), GetSceneHeight()); - clear_to_color(pBitmap, g_MaskColor); - m_pDebugLayer = new SceneLayer(); - m_pDebugLayer->Create(pBitmap, true, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)); - pBitmap = nullptr; - } - - // Finally draw the ID:s of the MO:s to the MOID layers for the first time - g_MovableMan.UpdateDrawMOIDs(m_pMOIDLayer->GetBitmap()); - - g_NetworkServer.LockScene(false); - g_NetworkServer.ResetScene(); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::SetSceneToLoad(std::string sceneName, bool placeObjects, bool placeUnits) -{ - // Use the name passed in to load the preset requested - const Scene *pSceneRef = dynamic_cast(g_PresetMan.GetEntityPreset("Scene", sceneName)); - - if (!pSceneRef) - { - g_ConsoleMan.PrintString("ERROR: Finding Scene preset \'" + sceneName + "\' failed! Has it been properly defined?"); - return -1; - } - - // Store the scene reference to load later - SetSceneToLoad(pSceneRef, placeObjects, placeUnits); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::LoadScene() -{ - // In case we have no set Scene reference to load from, do something graceful about it - if (!m_pSceneToLoad) - { - // Try to use the Scene the current Activity is associated with - if (g_ActivityMan.GetActivity()) - SetSceneToLoad(g_ActivityMan.GetActivity()->GetSceneName()); - - // If that failed, then resort to the default scene name - if (SetSceneToLoad(m_DefaultSceneName) < 0) - { - g_ConsoleMan.PrintString("ERROR: Couldn't start because no Scene has been specified to load!"); - return -1; - } - } - - return LoadScene(dynamic_cast(m_pSceneToLoad->Clone()), m_PlaceObjects, m_PlaceUnits); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::LoadScene(std::string sceneName, bool placeObjects, bool placeUnits) -{ - // First retrieve and set up the preset reference - int error = SetSceneToLoad(sceneName, placeObjects, placeUnits); - if (error < 0) - return error; - // Now actually load and start it - error = LoadScene(); - return error; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::ReadProperty(const std::string_view &propName, Reader &reader) -{ - StartPropertyList(return Serializable::ReadProperty(propName, reader)); - - MatchProperty("AddMaterial", - { - // Get this before reading Object, since if it's the last one in its datafile, the stream will show the parent file instead - std::string objectFilePath = reader.GetCurrentFilePath(); - - // Don't use the << operator, because it adds the material to the PresetMan before we get a chance to set the proper ID! - Material *pNewMat = new Material; - ((Serializable *)(pNewMat))->Create(reader); - - // If the initially requested material slot is available, then put it there - // But if it's not available, then check if any subsequent one is, looping around the palette if necessary - for (int tryId = pNewMat->GetIndex(); tryId < c_PaletteEntriesNumber; ++tryId) - { - // We found an empty slot in the Material palette! - if (m_apMatPalette.at(tryId) == nullptr) - { - // If the final ID isn't the same as the one originally requested by the data file, then make the mapping so - // subsequent ID references to this within the same data module can be translated to the actual ID of this material - if (tryId != pNewMat->GetIndex()) - g_PresetMan.AddMaterialMapping(pNewMat->GetIndex(), tryId, reader.GetReadModuleID()); - - // Assign the final ID to the material and register it in the palette - pNewMat->SetIndex(tryId); - - // Ensure out-of-bounds material is unbreakable - if (tryId == MaterialColorKeys::g_MaterialOutOfBounds) { - RTEAssert(pNewMat->GetIntegrity() == std::numeric_limits::max(), "Material with index " + std::to_string(MaterialColorKeys::g_MaterialOutOfBounds) + " (i.e out-of-bounds material) has a finite integrity!\n This should be infinity (-1)."); - } - - m_apMatPalette.at(tryId) = pNewMat; - m_MatNameMap.insert(std::pair(std::string(pNewMat->GetPresetName()), pNewMat->GetIndex())); - // Now add the instance, when ID has been registered! - g_PresetMan.AddEntityPreset(pNewMat, reader.GetReadModuleID(), reader.GetPresetOverwriting(), objectFilePath); - ++m_MaterialCount; - break; - } - // We reached the end of the Material palette without finding any empty slots.. loop around to the start - else if (tryId >= c_PaletteEntriesNumber - 1) - tryId = 0; - // If we've looped around without finding anything, break and throw error - else if (tryId == pNewMat->GetIndex() - 1) - { -// TODO: find the closest matching mateiral and map to it? - RTEAbort("Tried to load material \"" + pNewMat->GetPresetName() + "\" but the material palette (256 max) is full! Try consolidating or removing some redundant materials, or removing some entire data modules."); - break; - } - } - }); - - EndPropertyList; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::Save(Writer &writer) const { - g_ConsoleMan.PrintString("ERROR: Tried to save SceneMan, screen does not make sense"); - - Serializable::Save(writer); - - for (int i = 0; i < m_MaterialCount; ++i) { - writer.NewPropertyWithValue("AddMaterial", *(m_apMatPalette.at(i))); - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::Destroy() -{ - for (int i = 0; i < c_PaletteEntriesNumber; ++i) - delete m_apMatPalette[i]; - - delete m_pCurrentScene; - delete m_pDebugLayer; - delete m_pMOIDLayer; - delete m_pMOColorLayer; - delete m_pUnseenRevealSound; - - destroy_bitmap(m_pOrphanSearchBitmap); - m_pOrphanSearchBitmap = 0; - - for (const auto &[bitmapSize, bitmapPtr] : m_IntermediateSettlingBitmaps) { - destroy_bitmap(bitmapPtr); - } - - Clear(); -} + g_NetworkServer.ResetScene(); + + return 0; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::SetSceneToLoad(std::string sceneName, bool placeObjects, bool placeUnits) { + // Use the name passed in to load the preset requested + const Scene* pSceneRef = dynamic_cast(g_PresetMan.GetEntityPreset("Scene", sceneName)); + + if (!pSceneRef) { + g_ConsoleMan.PrintString("ERROR: Finding Scene preset \'" + sceneName + "\' failed! Has it been properly defined?"); + return -1; + } + + // Store the scene reference to load later + SetSceneToLoad(pSceneRef, placeObjects, placeUnits); + + return 0; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::LoadScene() { + // In case we have no set Scene reference to load from, do something graceful about it + if (!m_pSceneToLoad) { + // Try to use the Scene the current Activity is associated with + if (g_ActivityMan.GetActivity()) + SetSceneToLoad(g_ActivityMan.GetActivity()->GetSceneName()); + + // If that failed, then resort to the default scene name + if (SetSceneToLoad(m_DefaultSceneName) < 0) { + g_ConsoleMan.PrintString("ERROR: Couldn't start because no Scene has been specified to load!"); + return -1; + } + } + + return LoadScene(dynamic_cast(m_pSceneToLoad->Clone()), m_PlaceObjects, m_PlaceUnits); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::LoadScene(std::string sceneName, bool placeObjects, bool placeUnits) { + // First retrieve and set up the preset reference + int error = SetSceneToLoad(sceneName, placeObjects, placeUnits); + if (error < 0) + return error; + // Now actually load and start it + error = LoadScene(); + return error; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::ReadProperty(const std::string_view& propName, Reader& reader) { + StartPropertyList(return Serializable::ReadProperty(propName, reader)); + + MatchProperty("AddMaterial", + { + // Get this before reading Object, since if it's the last one in its datafile, the stream will show the parent file instead + std::string objectFilePath = reader.GetCurrentFilePath(); + + // Don't use the << operator, because it adds the material to the PresetMan before we get a chance to set the proper ID! + Material* pNewMat = new Material; + ((Serializable*)(pNewMat))->Create(reader); + + // If the initially requested material slot is available, then put it there + // But if it's not available, then check if any subsequent one is, looping around the palette if necessary + for (int tryId = pNewMat->GetIndex(); tryId < c_PaletteEntriesNumber; ++tryId) { + // We found an empty slot in the Material palette! + if (m_apMatPalette.at(tryId) == nullptr) { + // If the final ID isn't the same as the one originally requested by the data file, then make the mapping so + // subsequent ID references to this within the same data module can be translated to the actual ID of this material + if (tryId != pNewMat->GetIndex()) + g_PresetMan.AddMaterialMapping(pNewMat->GetIndex(), tryId, reader.GetReadModuleID()); + + // Assign the final ID to the material and register it in the palette + pNewMat->SetIndex(tryId); + + // Ensure out-of-bounds material is unbreakable + if (tryId == MaterialColorKeys::g_MaterialOutOfBounds) { + RTEAssert(pNewMat->GetIntegrity() == std::numeric_limits::max(), "Material with index " + std::to_string(MaterialColorKeys::g_MaterialOutOfBounds) + " (i.e out-of-bounds material) has a finite integrity!\n This should be infinity (-1)."); + } + + m_apMatPalette.at(tryId) = pNewMat; + m_MatNameMap.insert(std::pair(std::string(pNewMat->GetPresetName()), pNewMat->GetIndex())); + // Now add the instance, when ID has been registered! + g_PresetMan.AddEntityPreset(pNewMat, reader.GetReadModuleID(), reader.GetPresetOverwriting(), objectFilePath); + ++m_MaterialCount; + break; + } + // We reached the end of the Material palette without finding any empty slots.. loop around to the start + else if (tryId >= c_PaletteEntriesNumber - 1) + tryId = 0; + // If we've looped around without finding anything, break and throw error + else if (tryId == pNewMat->GetIndex() - 1) { + // TODO: find the closest matching mateiral and map to it? + RTEAbort("Tried to load material \"" + pNewMat->GetPresetName() + "\" but the material palette (256 max) is full! Try consolidating or removing some redundant materials, or removing some entire data modules."); + break; + } + } + }); + + EndPropertyList; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::Save(Writer& writer) const { + g_ConsoleMan.PrintString("ERROR: Tried to save SceneMan, screen does not make sense"); + + Serializable::Save(writer); + + for (int i = 0; i < m_MaterialCount; ++i) { + writer.NewPropertyWithValue("AddMaterial", *(m_apMatPalette.at(i))); + } + + return 0; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SceneMan::Destroy() { + for (int i = 0; i < c_PaletteEntriesNumber; ++i) + delete m_apMatPalette[i]; -Vector SceneMan::GetSceneDim() const -{ - if (m_pCurrentScene) { - RTEAssert(m_pCurrentScene->GetTerrain() && m_pCurrentScene->GetTerrain()->GetBitmap(), "Trying to get terrain info before there is a scene or terrain!"); - return m_pCurrentScene->GetDimensions(); - } - return Vector(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::GetSceneWidth() const -{ - if (g_NetworkClient.IsConnectedAndRegistered()) { - return g_NetworkClient.GetSceneWidth(); - } - - if (m_pCurrentScene) - return m_pCurrentScene->GetWidth(); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::GetSceneHeight() const -{ -// RTEAssert(m_pCurrentScene, "Trying to get terrain info before there is a scene or terrain!"); - if (m_pCurrentScene) - return m_pCurrentScene->GetHeight(); - return 0; -} + delete m_pCurrentScene; + delete m_pDebugLayer; + delete m_pMOIDLayer; + delete m_pMOColorLayer; + delete m_pUnseenRevealSound; + + destroy_bitmap(m_pOrphanSearchBitmap); + m_pOrphanSearchBitmap = 0; + + for (const auto& [bitmapSize, bitmapPtr]: m_IntermediateSettlingBitmaps) { + destroy_bitmap(bitmapPtr); + } + + Clear(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::SceneWrapsX() const -{ - if (g_NetworkClient.IsConnectedAndRegistered()) { - return g_NetworkClient.SceneWrapsX(); + Vector SceneMan::GetSceneDim() const { + if (m_pCurrentScene) { + RTEAssert(m_pCurrentScene->GetTerrain() && m_pCurrentScene->GetTerrain()->GetBitmap(), "Trying to get terrain info before there is a scene or terrain!"); + return m_pCurrentScene->GetDimensions(); + } + return Vector(); } - if (m_pCurrentScene) - return m_pCurrentScene->WrapsX(); - return false; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::GetSceneWidth() const { + if (g_NetworkClient.IsConnectedAndRegistered()) { + return g_NetworkClient.GetSceneWidth(); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (m_pCurrentScene) + return m_pCurrentScene->GetWidth(); + return 0; + } -bool SceneMan::SceneWrapsY() const -{ - if (m_pCurrentScene) - return m_pCurrentScene->WrapsY(); - return false; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int SceneMan::GetSceneHeight() const { + // RTEAssert(m_pCurrentScene, "Trying to get terrain info before there is a scene or terrain!"); + if (m_pCurrentScene) + return m_pCurrentScene->GetHeight(); + return 0; + } -Directions SceneMan::GetSceneOrbitDirection() const { - if (m_pCurrentScene) { - SLTerrain *terrain = m_pCurrentScene->GetTerrain(); - if (terrain) { - return terrain->GetOrbitDirection(); - } - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return Directions::Up; -} + bool SceneMan::SceneWrapsX() const { + if (g_NetworkClient.IsConnectedAndRegistered()) { + return g_NetworkClient.SceneWrapsX(); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (m_pCurrentScene) + return m_pCurrentScene->WrapsX(); + return false; + } -SLTerrain * SceneMan::GetTerrain() -{ -// RTEAssert(m_pCurrentScene, "Trying to get terrain matter before there is a scene or terrain!"); - if (m_pCurrentScene) { - return m_pCurrentScene->GetTerrain(); - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return nullptr; -} + bool SceneMan::SceneWrapsY() const { + if (m_pCurrentScene) + return m_pCurrentScene->WrapsY(); + return false; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -BITMAP * SceneMan::GetMOColorBitmap() const { - return m_pMOColorLayer->GetBitmap(); -} + Directions SceneMan::GetSceneOrbitDirection() const { + if (m_pCurrentScene) { + SLTerrain* terrain = m_pCurrentScene->GetTerrain(); + if (terrain) { + return terrain->GetOrbitDirection(); + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return Directions::Up; + } -BITMAP *SceneMan::GetDebugBitmap() const { - RTEAssert(m_pDebugLayer, "Tried to get debug bitmap but debug layer doesn't exist. Note that the debug layer is only created under certain circumstances."); - return m_pDebugLayer->GetBitmap(); -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + SLTerrain* SceneMan::GetTerrain() { + // RTEAssert(m_pCurrentScene, "Trying to get terrain matter before there is a scene or terrain!"); + if (m_pCurrentScene) { + return m_pCurrentScene->GetTerrain(); + } -BITMAP * SceneMan::GetMOIDBitmap() const { - return m_pMOIDLayer->GetBitmap(); -} + return nullptr; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// TEMP! -bool SceneMan::MOIDClearCheck() -{ - BITMAP *pMOIDMap = m_pMOIDLayer->GetBitmap(); - int badMOID = g_NoMOID; - for (int y = 0; y < pMOIDMap->h; ++y) - { - for (int x = 0; x < pMOIDMap->w; ++x) - { - if ((badMOID = _getpixel(pMOIDMap, x, y)) != g_NoMOID) - { - g_FrameMan.SaveBitmapToPNG(pMOIDMap, "MOIDCheck"); - g_FrameMan.SaveBitmapToPNG(m_pMOColorLayer->GetBitmap(), "MOIDCheck"); - RTEAbort("Bad MOID of MO detected: " + g_MovableMan.GetMOFromID(badMOID)->GetPresetName()); - return false; - } - } - } - return true; -} + BITMAP* SceneMan::GetMOColorBitmap() const { + return m_pMOColorLayer->GetBitmap(); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -unsigned char SceneMan::GetTerrMatter(int pixelX, int pixelY) -{ - RTEAssert(m_pCurrentScene, "Trying to get terrain matter before there is a scene or terrain!"); + BITMAP* SceneMan::GetDebugBitmap() const { + RTEAssert(m_pDebugLayer, "Tried to get debug bitmap but debug layer doesn't exist. Note that the debug layer is only created under certain circumstances."); + return m_pDebugLayer->GetBitmap(); + } - WrapPosition(pixelX, pixelY); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (m_pDebugLayer && m_DrawPixelCheckVisualizations) { m_pDebugLayer->SetPixel(pixelX, pixelY, 5); } + BITMAP* SceneMan::GetMOIDBitmap() const { + return m_pMOIDLayer->GetBitmap(); + } - BITMAP *pTMatBitmap = m_pCurrentScene->GetTerrain()->GetMaterialBitmap(); - if (pTMatBitmap == nullptr) { - return g_MaterialAir; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // TEMP! + bool SceneMan::MOIDClearCheck() { + BITMAP* pMOIDMap = m_pMOIDLayer->GetBitmap(); + int badMOID = g_NoMOID; + for (int y = 0; y < pMOIDMap->h; ++y) { + for (int x = 0; x < pMOIDMap->w; ++x) { + if ((badMOID = _getpixel(pMOIDMap, x, y)) != g_NoMOID) { + g_FrameMan.SaveBitmapToPNG(pMOIDMap, "MOIDCheck"); + g_FrameMan.SaveBitmapToPNG(m_pMOColorLayer->GetBitmap(), "MOIDCheck"); + RTEAbort("Bad MOID of MO detected: " + g_MovableMan.GetMOFromID(badMOID)->GetPresetName()); + return false; + } + } + } + return true; } - // If it's still below or to the sides out of bounds after - // what is supposed to be wrapped, shit is out of bounds. - if (pixelX < 0 || pixelX >= pTMatBitmap->w || pixelY >= pTMatBitmap->h) - return g_MaterialAir; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // If above terrain bitmap, return air material. - if (pixelY < 0) - return g_MaterialAir; + unsigned char SceneMan::GetTerrMatter(int pixelX, int pixelY) { + RTEAssert(m_pCurrentScene, "Trying to get terrain matter before there is a scene or terrain!"); - return getpixel(pTMatBitmap, pixelX, pixelY); -} + WrapPosition(pixelX, pixelY); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if (m_pDebugLayer && m_DrawPixelCheckVisualizations) { + m_pDebugLayer->SetPixel(pixelX, pixelY, 5); + } + + BITMAP* pTMatBitmap = m_pCurrentScene->GetTerrain()->GetMaterialBitmap(); + if (pTMatBitmap == nullptr) { + return g_MaterialAir; + } + + // If it's still below or to the sides out of bounds after + // what is supposed to be wrapped, shit is out of bounds. + if (pixelX < 0 || pixelX >= pTMatBitmap->w || pixelY >= pTMatBitmap->h) + return g_MaterialAir; + + // If above terrain bitmap, return air material. + if (pixelY < 0) + return g_MaterialAir; + + return getpixel(pTMatBitmap, pixelX, pixelY); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -MOID SceneMan::GetMOIDPixel(int pixelX, int pixelY, int ignoreTeam) -{ - WrapPosition(pixelX, pixelY); + MOID SceneMan::GetMOIDPixel(int pixelX, int pixelY, int ignoreTeam) { + WrapPosition(pixelX, pixelY); - if (m_pDebugLayer && m_DrawPixelCheckVisualizations) { m_pDebugLayer->SetPixel(pixelX, pixelY, 5); } + if (m_pDebugLayer && m_DrawPixelCheckVisualizations) { + m_pDebugLayer->SetPixel(pixelX, pixelY, 5); + } - if (pixelX < 0 || pixelX >= m_pMOIDLayer->GetBitmap()->w || pixelY < 0 || pixelY >= m_pMOIDLayer->GetBitmap()->h) { - return g_NoMOID; - } + if (pixelX < 0 || pixelX >= m_pMOIDLayer->GetBitmap()->w || pixelY < 0 || pixelY >= m_pMOIDLayer->GetBitmap()->h) { + return g_NoMOID; + } #ifdef DRAW_MOID_LAYER - MOID moid = getpixel(m_pMOIDLayer->GetBitmap(), pixelX, pixelY); + MOID moid = getpixel(m_pMOIDLayer->GetBitmap(), pixelX, pixelY); #else - const std::vector &moidList = m_MOIDsGrid.GetMOIDsAtPosition(pixelX, pixelY, ignoreTeam, true); - MOID moid = g_MovableMan.GetMOIDPixel(pixelX, pixelY, moidList); + const std::vector& moidList = m_MOIDsGrid.GetMOIDsAtPosition(pixelX, pixelY, ignoreTeam, true); + MOID moid = g_MovableMan.GetMOIDPixel(pixelX, pixelY, moidList); #endif - if (g_SettingsMan.SimplifiedCollisionDetection()) { - if (moid != ColorKeys::g_NoMOID && moid != ColorKeys::g_MOIDMaskColor) { - const MOSprite *mo = dynamic_cast(g_MovableMan.GetMOFromID(moid)); - return (mo && !mo->GetTraveling()) ? moid : ColorKeys::g_NoMOID; - } else { - return ColorKeys::g_NoMOID; - } - } - - return moid; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Material const * SceneMan::GetMaterial(const std::string &matName) -{ - std::map::iterator itr = m_MatNameMap.find(matName); - if (itr == m_MatNameMap.end()) - { - g_ConsoleMan.PrintString("ERROR: Material of name: " + matName + " not found!"); - return 0; - } - else - return m_apMatPalette.at((*itr).second); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Vector SceneMan::GetGlobalAcc() const -{ - RTEAssert(m_pCurrentScene, "Trying to get terrain matter before there is a scene or terrain!"); - return m_pCurrentScene->GetGlobalAcc(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::LockScene() -{ -// RTEAssert(!m_pCurrentScene->IsLocked(), "Hey, locking already locked scene!"); - if (m_pCurrentScene && !m_pCurrentScene->IsLocked()) - { - m_pCurrentScene->Lock(); - m_pMOColorLayer->LockBitmaps(); - m_pMOIDLayer->LockBitmaps(); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::UnlockScene() -{ -// RTEAssert(m_pCurrentScene->IsLocked(), "Hey, unlocking already unlocked scene!"); - if (m_pCurrentScene && m_pCurrentScene->IsLocked()) - { - m_pCurrentScene->Unlock(); - m_pMOColorLayer->UnlockBitmaps(); - m_pMOIDLayer->UnlockBitmaps(); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::SceneIsLocked() const -{ - RTEAssert(m_pCurrentScene, "Trying to check if scene is locked before there is a scene or terrain!"); - return m_pCurrentScene->IsLocked(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::RegisterDrawing(const BITMAP *bitmap, int moid, int left, int top, int right, int bottom) { - if (m_pMOColorLayer && m_pMOColorLayer->GetBitmap() == bitmap) { - m_pMOColorLayer->RegisterDrawing(left, top, right, bottom); - } else if (m_pMOIDLayer && m_pMOIDLayer->GetBitmap() == bitmap) { + if (g_SettingsMan.SimplifiedCollisionDetection()) { + if (moid != ColorKeys::g_NoMOID && moid != ColorKeys::g_MOIDMaskColor) { + const MOSprite* mo = dynamic_cast(g_MovableMan.GetMOFromID(moid)); + return (mo && !mo->GetTraveling()) ? moid : ColorKeys::g_NoMOID; + } else { + return ColorKeys::g_NoMOID; + } + } + + return moid; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Material const* SceneMan::GetMaterial(const std::string& matName) { + std::map::iterator itr = m_MatNameMap.find(matName); + if (itr == m_MatNameMap.end()) { + g_ConsoleMan.PrintString("ERROR: Material of name: " + matName + " not found!"); + return 0; + } else + return m_apMatPalette.at((*itr).second); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Vector SceneMan::GetGlobalAcc() const { + RTEAssert(m_pCurrentScene, "Trying to get terrain matter before there is a scene or terrain!"); + return m_pCurrentScene->GetGlobalAcc(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::LockScene() { + // RTEAssert(!m_pCurrentScene->IsLocked(), "Hey, locking already locked scene!"); + if (m_pCurrentScene && !m_pCurrentScene->IsLocked()) { + m_pCurrentScene->Lock(); + m_pMOColorLayer->LockBitmaps(); + m_pMOIDLayer->LockBitmaps(); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::UnlockScene() { + // RTEAssert(m_pCurrentScene->IsLocked(), "Hey, unlocking already unlocked scene!"); + if (m_pCurrentScene && m_pCurrentScene->IsLocked()) { + m_pCurrentScene->Unlock(); + m_pMOColorLayer->UnlockBitmaps(); + m_pMOIDLayer->UnlockBitmaps(); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::SceneIsLocked() const { + RTEAssert(m_pCurrentScene, "Trying to check if scene is locked before there is a scene or terrain!"); + return m_pCurrentScene->IsLocked(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::RegisterDrawing(const BITMAP* bitmap, int moid, int left, int top, int right, int bottom) { + if (m_pMOColorLayer && m_pMOColorLayer->GetBitmap() == bitmap) { + m_pMOColorLayer->RegisterDrawing(left, top, right, bottom); + } else if (m_pMOIDLayer && m_pMOIDLayer->GetBitmap() == bitmap) { #ifdef DRAW_MOID_LAYER - m_pMOIDLayer->RegisterDrawing(left, top, right, bottom); + m_pMOIDLayer->RegisterDrawing(left, top, right, bottom); #else - const MovableObject *mo = g_MovableMan.GetMOFromID(moid); - if (mo) { - IntRect rect(left, top, right, bottom); - m_MOIDsGrid.Add(rect, *mo); - } + const MovableObject* mo = g_MovableMan.GetMOFromID(moid); + if (mo) { + IntRect rect(left, top, right, bottom); + m_MOIDsGrid.Add(rect, *mo); + } #endif - } -} + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void SceneMan::RegisterDrawing(const BITMAP *bitmap, int moid, const Vector ¢er, float radius) { - if (radius != 0.0F) { - RegisterDrawing(bitmap, moid, static_cast(std::floor(center.m_X - radius)), static_cast(std::floor(center.m_Y - radius)), static_cast(std::floor(center.m_X + radius)), static_cast(std::floor(center.m_Y + radius))); + void SceneMan::RegisterDrawing(const BITMAP* bitmap, int moid, const Vector& center, float radius) { + if (radius != 0.0F) { + RegisterDrawing(bitmap, moid, static_cast(std::floor(center.m_X - radius)), static_cast(std::floor(center.m_Y - radius)), static_cast(std::floor(center.m_X + radius)), static_cast(std::floor(center.m_Y + radius))); + } } -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void SceneMan::ClearAllMOIDDrawings() { + void SceneMan::ClearAllMOIDDrawings() { #ifdef DRAW_MOID_LAYER - m_pMOIDLayer->ClearBitmap(g_NoMOID); + m_pMOIDLayer->ClearBitmap(g_NoMOID); #else - m_MOIDsGrid.Reset(); + m_MOIDsGrid.Reset(); #endif -} + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool SceneMan::WillPenetrate(const int posX, - const int posY, - const Vector &impulse) -{ - RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); + bool SceneMan::WillPenetrate(const int posX, + const int posY, + const Vector& impulse) { + RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); - if (!m_pCurrentScene->GetTerrain()->IsWithinBounds(posX, posY)) - return false; + if (!m_pCurrentScene->GetTerrain()->IsWithinBounds(posX, posY)) + return false; - unsigned char materialID = getpixel(m_pCurrentScene->GetTerrain()->GetMaterialBitmap(), posX, posY); - float integrity = GetMaterialFromID(materialID)->GetIntegrity(); - return impulse.MagnitudeIsGreaterThan(integrity); -} + unsigned char materialID = getpixel(m_pCurrentScene->GetTerrain()->GetMaterialBitmap(), posX, posY); + float integrity = GetMaterialFromID(materialID)->GetIntegrity(); + return impulse.MagnitudeIsGreaterThan(integrity); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int SceneMan::RemoveOrphans(int posX, int posY, int radius, int maxArea, bool remove) -{ - if (radius > MAXORPHANRADIUS) - radius = MAXORPHANRADIUS; + int SceneMan::RemoveOrphans(int posX, int posY, int radius, int maxArea, bool remove) { + if (radius > MAXORPHANRADIUS) + radius = MAXORPHANRADIUS; - clear_to_color(m_pOrphanSearchBitmap, g_MaterialAir); - int area = RemoveOrphans(posX, posY, posX, posY, 0, radius, maxArea, false); - if (remove && area <= maxArea) - { clear_to_color(m_pOrphanSearchBitmap, g_MaterialAir); - RemoveOrphans(posX, posY, posX, posY, 0, radius, maxArea, true); + int area = RemoveOrphans(posX, posY, posX, posY, 0, radius, maxArea, false); + if (remove && area <= maxArea) { + clear_to_color(m_pOrphanSearchBitmap, g_MaterialAir); + RemoveOrphans(posX, posY, posX, posY, 0, radius, maxArea, true); + } + + return area; } - return area; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int SceneMan::RemoveOrphans(int posX, int posY, + int centerPosX, int centerPosY, + int accumulatedArea, int radius, int maxArea, bool remove) { + int area = 0; + int bmpX = 0; + int bmpY = 0; -int SceneMan::RemoveOrphans(int posX, int posY, - int centerPosX, int centerPosY, - int accumulatedArea, int radius, int maxArea, bool remove) -{ - int area = 0; - int bmpX = 0; - int bmpY = 0; + BITMAP* mat = m_pCurrentScene->GetTerrain()->GetMaterialBitmap(); - BITMAP * mat = m_pCurrentScene->GetTerrain()->GetMaterialBitmap(); + if (posX < 0 || posY < 0 || posX >= mat->w || posY >= mat->h) + return 0; - if (posX < 0 || posY < 0 || posX >= mat->w || posY >= mat->h) return 0; + unsigned char materialID = _getpixel(mat, posX, posY); + if (materialID == g_MaterialAir && (posX != centerPosX || posY != centerPosY)) + return 0; + else { + bmpX = posX - (centerPosX - radius / 2); + bmpY = posY - (centerPosY - radius / 2); - unsigned char materialID = _getpixel(mat, posX, posY); - if (materialID == g_MaterialAir && (posX != centerPosX || posY != centerPosY)) - return 0; - else - { - bmpX = posX - (centerPosX - radius / 2); - bmpY = posY - (centerPosY - radius / 2); - - // We reached the border of orphan-searching area and - // there are still material pixels there -> the area is not an orphaned teran piece, abort search - if (bmpX <= 0 || bmpY <= 0 || bmpX >= radius - 1 || bmpY >= radius - 1) - return MAXORPHANRADIUS * MAXORPHANRADIUS + 1; - else - // Check if pixel was already checked - { - if (_getpixel(m_pOrphanSearchBitmap, bmpX, bmpY) != g_MaterialAir) - return 0; - } - } - - _putpixel(m_pOrphanSearchBitmap, bmpX, bmpY, materialID); - area++; - - // We're clear to remove the pixel - if (remove) - { - Material const * sceneMat = GetMaterialFromID(materialID); - Material const * spawnMat; - spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; - float sprayScale = 0.1; - Color spawnColor; - if (spawnMat->UsesOwnColor()) - spawnColor = spawnMat->GetColor(); - else - spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, posY)); - - // No point generating a key-colored MOPixel - if (spawnColor.GetIndex() != g_MaskColor) - { - // TEST COLOR - // spawnColor = 5; - - // Get the new pixel from the pre-allocated pool, should be faster than dynamic allocation - // Density is used as the mass for the new MOPixel - float tempMax = 2.0F * sprayScale; - float tempMin = tempMax / 2.0F; - MOPixel *pixelMO = new MOPixel(spawnColor, - spawnMat->GetPixelDensity(), - Vector(posX, posY), - Vector(-RandomNum(tempMin, tempMax), - -RandomNum(tempMin, tempMax)), - new Atom(Vector(), spawnMat->GetIndex(), 0, spawnColor, 2), - 0); - - pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); - pixelMO->SetToGetHitByMOs(false); - g_MovableMan.AddParticle(pixelMO); - pixelMO = 0; - } - m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, g_MaskColor); - RegisterTerrainChange(posX, posY, 1, 1, g_MaskColor, false); - m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, g_MaterialAir); - } - - int xoff[8] = { -1, 0, 1, -1, 1, -1, 0, 1}; - int yoff[8] = { -1, -1, -1, 0, 0, 1, 1, 1}; - - for (int c = 0; c < 8; c++) - { - area += RemoveOrphans(posX + xoff[c], posY + yoff[c], centerPosX, centerPosY, area, radius, maxArea, remove); - if (accumulatedArea + area > maxArea) - break; - } - - return area; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::RegisterTerrainChange(int x, int y, int w, int h, unsigned char color, bool back) -{ - if (!g_NetworkServer.IsServerModeEnabled()) - return; - - // Crop if it's out of scene as both the client and server will not tolerate out of bitmap coords while packing/unpacking - if (y < 0) - y = 0; - - if (y + h >= GetSceneHeight()) - h = GetSceneHeight() - y - 1; - - if (y >= GetSceneHeight() || h <= 0) - return; - - if (w == 1) - { - if (x >= GetSceneWidth()) - { - if (!SceneWrapsX()) - return; - x = x - GetSceneWidth(); - } - if (x < 0) - { - if (!SceneWrapsX()) - return; - x = GetSceneWidth() + x; - } - } - else - { - // Divide region if crossing the seam - if (x + w >= GetSceneWidth() || x < 0) - { - // Crossing right part of the scene - if (x + w >= GetSceneWidth()) + // We reached the border of orphan-searching area and + // there are still material pixels there -> the area is not an orphaned teran piece, abort search + if (bmpX <= 0 || bmpY <= 0 || bmpX >= radius - 1 || bmpY >= radius - 1) + return MAXORPHANRADIUS * MAXORPHANRADIUS + 1; + else + // Check if pixel was already checked { - // Left part, on the scene - NetworkServer::NetworkTerrainChange tc1; - tc1.x = x; - tc1.y = y; - tc1.w = GetSceneWidth() - x; - tc1.h = h; - tc1.back = back; - tc1.color = color; - g_NetworkServer.RegisterTerrainChange(tc1); - - // Discard out of scene part if scene is not wrapped - if (!SceneWrapsX()) - return; + if (_getpixel(m_pOrphanSearchBitmap, bmpX, bmpY) != g_MaterialAir) + return 0; + } + } - // Right part, out of scene - NetworkServer::NetworkTerrainChange tc2; - tc2.x = 0; - tc2.y = y; - tc2.w = w - (GetSceneWidth() - x); - tc2.h = h; - tc2.back = back; - tc2.color = color; - - g_NetworkServer.RegisterTerrainChange(tc2); - return; + _putpixel(m_pOrphanSearchBitmap, bmpX, bmpY, materialID); + area++; + + // We're clear to remove the pixel + if (remove) { + Material const* sceneMat = GetMaterialFromID(materialID); + Material const* spawnMat; + spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; + float sprayScale = 0.1; + Color spawnColor; + if (spawnMat->UsesOwnColor()) + spawnColor = spawnMat->GetColor(); + else + spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, posY)); + + // No point generating a key-colored MOPixel + if (spawnColor.GetIndex() != g_MaskColor) { + // TEST COLOR + // spawnColor = 5; + + // Get the new pixel from the pre-allocated pool, should be faster than dynamic allocation + // Density is used as the mass for the new MOPixel + float tempMax = 2.0F * sprayScale; + float tempMin = tempMax / 2.0F; + MOPixel* pixelMO = new MOPixel(spawnColor, + spawnMat->GetPixelDensity(), + Vector(posX, posY), + Vector(-RandomNum(tempMin, tempMax), + -RandomNum(tempMin, tempMax)), + new Atom(Vector(), spawnMat->GetIndex(), 0, spawnColor, 2), + 0); + + pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); + pixelMO->SetToGetHitByMOs(false); + g_MovableMan.AddParticle(pixelMO); + pixelMO = 0; } + m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, g_MaskColor); + RegisterTerrainChange(posX, posY, 1, 1, g_MaskColor, false); + m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, g_MaterialAir); + } - if (x < 0) - { - // Right part, on the scene - NetworkServer::NetworkTerrainChange tc2; - tc2.x = 0; - tc2.y = y; - tc2.w = w + x; - tc2.h = h; - tc2.back = back; - tc2.color = color; - g_NetworkServer.RegisterTerrainChange(tc2); - - // Discard out of scene part if scene is not wrapped + int xoff[8] = {-1, 0, 1, -1, 1, -1, 0, 1}; + int yoff[8] = {-1, -1, -1, 0, 0, 1, 1, 1}; + + for (int c = 0; c < 8; c++) { + area += RemoveOrphans(posX + xoff[c], posY + yoff[c], centerPosX, centerPosY, area, radius, maxArea, remove); + if (accumulatedArea + area > maxArea) + break; + } + + return area; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::RegisterTerrainChange(int x, int y, int w, int h, unsigned char color, bool back) { + if (!g_NetworkServer.IsServerModeEnabled()) + return; + + // Crop if it's out of scene as both the client and server will not tolerate out of bitmap coords while packing/unpacking + if (y < 0) + y = 0; + + if (y + h >= GetSceneHeight()) + h = GetSceneHeight() - y - 1; + + if (y >= GetSceneHeight() || h <= 0) + return; + + if (w == 1) { + if (x >= GetSceneWidth()) { + if (!SceneWrapsX()) + return; + x = x - GetSceneWidth(); + } + if (x < 0) { if (!SceneWrapsX()) return; + x = GetSceneWidth() + x; + } + } else { + // Divide region if crossing the seam + if (x + w >= GetSceneWidth() || x < 0) { + // Crossing right part of the scene + if (x + w >= GetSceneWidth()) { + // Left part, on the scene + NetworkServer::NetworkTerrainChange tc1; + tc1.x = x; + tc1.y = y; + tc1.w = GetSceneWidth() - x; + tc1.h = h; + tc1.back = back; + tc1.color = color; + g_NetworkServer.RegisterTerrainChange(tc1); + + // Discard out of scene part if scene is not wrapped + if (!SceneWrapsX()) + return; + + // Right part, out of scene + NetworkServer::NetworkTerrainChange tc2; + tc2.x = 0; + tc2.y = y; + tc2.w = w - (GetSceneWidth() - x); + tc2.h = h; + tc2.back = back; + tc2.color = color; + + g_NetworkServer.RegisterTerrainChange(tc2); + return; + } - // Left part, out of the scene - NetworkServer::NetworkTerrainChange tc1; - tc1.x = GetSceneWidth() + x; - tc1.y = y; - tc1.w = -x; - tc1.h = h; - tc1.back = back; - tc1.color = color; - g_NetworkServer.RegisterTerrainChange(tc1); - return; + if (x < 0) { + // Right part, on the scene + NetworkServer::NetworkTerrainChange tc2; + tc2.x = 0; + tc2.y = y; + tc2.w = w + x; + tc2.h = h; + tc2.back = back; + tc2.color = color; + g_NetworkServer.RegisterTerrainChange(tc2); + + // Discard out of scene part if scene is not wrapped + if (!SceneWrapsX()) + return; + + // Left part, out of the scene + NetworkServer::NetworkTerrainChange tc1; + tc1.x = GetSceneWidth() + x; + tc1.y = y; + tc1.w = -x; + tc1.h = h; + tc1.back = back; + tc1.color = color; + g_NetworkServer.RegisterTerrainChange(tc1); + return; + } } } - } - NetworkServer::NetworkTerrainChange tc; - tc.x = x; - tc.y = y; - tc.w = w; - tc.h = h; - tc.back = back; - tc.color = color; - g_NetworkServer.RegisterTerrainChange(tc); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::TryPenetrate(int posX, - int posY, - const Vector &impulse, - const Vector &velocity, - float &retardation, - const float airRatio, - const int numPenetrations, - const int removeOrphansRadius, - const int removeOrphansMaxArea, - const float removeOrphansRate) -{ - RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); - - if (!m_pCurrentScene->GetTerrain()->IsWithinBounds(posX, posY)) - return false; - - WrapPosition(posX, posY); - unsigned char materialID = _getpixel(m_pCurrentScene->GetTerrain()->GetMaterialBitmap(), posX, posY); - if (materialID == g_MaterialAir) - { -// RTEAbort("Why are we penetrating air??"); - return true; - } - Material const * sceneMat = GetMaterialFromID(materialID); - Material const * spawnMat; - - float sprayScale = 0.1F; - float sqrImpMag = impulse.GetSqrMagnitude(); - - // Test if impulse force is enough to penetrate - if (sqrImpMag >= (sceneMat->GetIntegrity() * sceneMat->GetIntegrity())) - { - if (numPenetrations <= 3) - { - spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; - Color spawnColor; - if (spawnMat->UsesOwnColor()) - spawnColor = spawnMat->GetColor(); - else - spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, posY)); - - // No point generating a key-colored MOPixel - if (spawnColor.GetIndex() != g_MaskColor) - { - // Get the new pixel from the pre-allocated pool, should be faster than dynamic allocation - // Density is used as the mass for the new MOPixel -/* MOPixel *pixelMO = dynamic_cast(MOPixel::InstanceFromPool()); - pixelMO->Create(spawnColor, - spawnMat.pixelDensity, - Vector(posX, posY), - Vector(-RandomNum((velocity.m_X * sprayScale) / 2 , velocity.m_X * sprayScale), - -RandomNum((velocity.m_Y * sprayScale) / 2 , velocity.m_Y * sprayScale)), -// -(impulse * (sprayScale * RandomNum() / spawnMat.density)), - new Atom(Vector(), spawnMat, 0, spawnColor, 2), - 0); -*/ - float tempMaxX = velocity.m_X * sprayScale; - float tempMinX = tempMaxX / 2.0F; - float tempMaxY = velocity.m_Y * sprayScale; - float tempMinY = tempMaxY / 2.0F; - MOPixel *pixelMO = new MOPixel(spawnColor, - spawnMat->GetPixelDensity(), - Vector(posX, posY), - Vector(-RandomNum(tempMinX, tempMaxX), - -RandomNum(tempMinY, tempMaxY)), -// -(impulse * (sprayScale * RandomNum() / spawnMat.density)), - new Atom(Vector(), spawnMat->GetIndex(), 0, spawnColor, 2), - 0); - -// TODO: Make material IDs more robust!") - pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); - pixelMO->SetToGetHitByMOs(false); - g_MovableMan.AddParticle(pixelMO); - pixelMO = 0; - } - m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, g_MaskColor); - RegisterTerrainChange(posX, posY, 1, 1, g_MaskColor, false); + NetworkServer::NetworkTerrainChange tc; + tc.x = x; + tc.y = y; + tc.w = w; + tc.h = h; + tc.back = back; + tc.color = color; + g_NetworkServer.RegisterTerrainChange(tc); + } - m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, g_MaterialAir); - } -// TODO: Improve / tweak randomized pushing away of terrain") - else if (RandomNum() <= airRatio) - { - m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, g_MaskColor); - RegisterTerrainChange(posX, posY, 1, 1, g_MaskColor, false); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::TryPenetrate(int posX, + int posY, + const Vector& impulse, + const Vector& velocity, + float& retardation, + const float airRatio, + const int numPenetrations, + const int removeOrphansRadius, + const int removeOrphansMaxArea, + const float removeOrphansRate) { + RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); + + if (!m_pCurrentScene->GetTerrain()->IsWithinBounds(posX, posY)) + return false; + + WrapPosition(posX, posY); + unsigned char materialID = _getpixel(m_pCurrentScene->GetTerrain()->GetMaterialBitmap(), posX, posY); + if (materialID == g_MaterialAir) { + // RTEAbort("Why are we penetrating air??"); + return true; + } + Material const* sceneMat = GetMaterialFromID(materialID); + Material const* spawnMat; + + float sprayScale = 0.1F; + float sqrImpMag = impulse.GetSqrMagnitude(); + + // Test if impulse force is enough to penetrate + if (sqrImpMag >= (sceneMat->GetIntegrity() * sceneMat->GetIntegrity())) { + if (numPenetrations <= 3) { + spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; + Color spawnColor; + if (spawnMat->UsesOwnColor()) + spawnColor = spawnMat->GetColor(); + else + spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, posY)); + + // No point generating a key-colored MOPixel + if (spawnColor.GetIndex() != g_MaskColor) { + // Get the new pixel from the pre-allocated pool, should be faster than dynamic allocation + // Density is used as the mass for the new MOPixel + /* MOPixel *pixelMO = dynamic_cast(MOPixel::InstanceFromPool()); + pixelMO->Create(spawnColor, + spawnMat.pixelDensity, + Vector(posX, posY), + Vector(-RandomNum((velocity.m_X * sprayScale) / 2 , velocity.m_X * sprayScale), + -RandomNum((velocity.m_Y * sprayScale) / 2 , velocity.m_Y * sprayScale)), + // -(impulse * (sprayScale * RandomNum() / spawnMat.density)), + new Atom(Vector(), spawnMat, 0, spawnColor, 2), + 0); + */ + float tempMaxX = velocity.m_X * sprayScale; + float tempMinX = tempMaxX / 2.0F; + float tempMaxY = velocity.m_Y * sprayScale; + float tempMinY = tempMaxY / 2.0F; + MOPixel* pixelMO = new MOPixel(spawnColor, + spawnMat->GetPixelDensity(), + Vector(posX, posY), + Vector(-RandomNum(tempMinX, tempMaxX), + -RandomNum(tempMinY, tempMaxY)), + // -(impulse * (sprayScale * RandomNum() / spawnMat.density)), + new Atom(Vector(), spawnMat->GetIndex(), 0, spawnColor, 2), + 0); + + // TODO: Make material IDs more robust!") + pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); + pixelMO->SetToGetHitByMOs(false); + g_MovableMan.AddParticle(pixelMO); + pixelMO = 0; + } + m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, g_MaskColor); + RegisterTerrainChange(posX, posY, 1, 1, g_MaskColor, false); - m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, g_MaterialAir); - } - - // Save the impulse force effects of the penetrating particle. -// retardation = -sceneMat.density; - retardation = -(sceneMat->GetIntegrity() / std::sqrt(sqrImpMag)); - - // If this is a scrap pixel, or there is no background pixel 'supporting' the knocked-loose pixel, make the column above also turn into particles. - if (m_ScrapCompactingHeight > 0 && (sceneMat->IsScrap() || _getpixel(m_pCurrentScene->GetTerrain()->GetBGColorBitmap(), posX, posY) == g_MaskColor)) { - // Get quicker direct access to bitmaps - BITMAP *pFGColor = m_pCurrentScene->GetTerrain()->GetFGColorBitmap(); - BITMAP *pBGColor = m_pCurrentScene->GetTerrain()->GetBGColorBitmap(); - BITMAP *pMaterial = m_pCurrentScene->GetTerrain()->GetMaterialBitmap(); - - int testMaterialID = g_MaterialAir; - MOPixel *pixelMO = 0; - Color spawnColor; - float sprayMag = std::sqrt(velocity.GetMagnitude() * sprayScale); - Vector sprayVel; - - for (int testY = posY - 1; testY > posY - m_ScrapCompactingHeight && testY >= 0; --testY) { - if ((testMaterialID = _getpixel(pMaterial, posX, testY)) != g_MaterialAir) { - sceneMat = GetMaterialFromID(testMaterialID); - - if (sceneMat->IsScrap() || _getpixel(pBGColor, posX, testY) == g_MaskColor) { - if (RandomNum() < 0.7F) { - spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; - if (spawnMat->UsesOwnColor()) { - spawnColor = spawnMat->GetColor(); - } else { - spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, testY)); - } - if (spawnColor.GetIndex() != g_MaskColor) { - // Send terrain pixels flying at a diminishing rate the higher the column goes. - sprayVel.SetXY(0, -sprayMag * (1.0F - (static_cast(posY - testY) / static_cast(m_ScrapCompactingHeight)))); - sprayVel.RadRotate(RandomNum(-c_HalfPI, c_HalfPI)); + m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, g_MaterialAir); + } + // TODO: Improve / tweak randomized pushing away of terrain") + else if (RandomNum() <= airRatio) { + m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, g_MaskColor); + RegisterTerrainChange(posX, posY, 1, 1, g_MaskColor, false); - pixelMO = new MOPixel(spawnColor, spawnMat->GetPixelDensity(), Vector(posX, testY), sprayVel, new Atom(Vector(), spawnMat->GetIndex(), 0, spawnColor, 2), 0); + m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, g_MaterialAir); + } - pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); - pixelMO->SetToGetHitByMOs(false); - g_MovableMan.AddParticle(pixelMO); - pixelMO = 0; + // Save the impulse force effects of the penetrating particle. + // retardation = -sceneMat.density; + retardation = -(sceneMat->GetIntegrity() / std::sqrt(sqrImpMag)); + + // If this is a scrap pixel, or there is no background pixel 'supporting' the knocked-loose pixel, make the column above also turn into particles. + if (m_ScrapCompactingHeight > 0 && (sceneMat->IsScrap() || _getpixel(m_pCurrentScene->GetTerrain()->GetBGColorBitmap(), posX, posY) == g_MaskColor)) { + // Get quicker direct access to bitmaps + BITMAP* pFGColor = m_pCurrentScene->GetTerrain()->GetFGColorBitmap(); + BITMAP* pBGColor = m_pCurrentScene->GetTerrain()->GetBGColorBitmap(); + BITMAP* pMaterial = m_pCurrentScene->GetTerrain()->GetMaterialBitmap(); + + int testMaterialID = g_MaterialAir; + MOPixel* pixelMO = 0; + Color spawnColor; + float sprayMag = std::sqrt(velocity.GetMagnitude() * sprayScale); + Vector sprayVel; + + for (int testY = posY - 1; testY > posY - m_ScrapCompactingHeight && testY >= 0; --testY) { + if ((testMaterialID = _getpixel(pMaterial, posX, testY)) != g_MaterialAir) { + sceneMat = GetMaterialFromID(testMaterialID); + + if (sceneMat->IsScrap() || _getpixel(pBGColor, posX, testY) == g_MaskColor) { + if (RandomNum() < 0.7F) { + spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; + if (spawnMat->UsesOwnColor()) { + spawnColor = spawnMat->GetColor(); + } else { + spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, testY)); + } + if (spawnColor.GetIndex() != g_MaskColor) { + // Send terrain pixels flying at a diminishing rate the higher the column goes. + sprayVel.SetXY(0, -sprayMag * (1.0F - (static_cast(posY - testY) / static_cast(m_ScrapCompactingHeight)))); + sprayVel.RadRotate(RandomNum(-c_HalfPI, c_HalfPI)); + + pixelMO = new MOPixel(spawnColor, spawnMat->GetPixelDensity(), Vector(posX, testY), sprayVel, new Atom(Vector(), spawnMat->GetIndex(), 0, spawnColor, 2), 0); + + pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); + pixelMO->SetToGetHitByMOs(false); + g_MovableMan.AddParticle(pixelMO); + pixelMO = 0; + } + RemoveOrphans(posX + testY % 2 ? -1 : 1, testY, removeOrphansRadius + 5, removeOrphansMaxArea + 10, true); } - RemoveOrphans(posX + testY % 2 ? -1 : 1, testY, removeOrphansRadius + 5, removeOrphansMaxArea + 10, true); - } - RegisterTerrainChange(posX, testY, 1, 1, g_MaskColor, false); - _putpixel(pFGColor, posX, testY, g_MaskColor); - _putpixel(pMaterial, posX, testY, g_MaterialAir); - } else { - break; + RegisterTerrainChange(posX, testY, 1, 1, g_MaskColor, false); + _putpixel(pFGColor, posX, testY, g_MaskColor); + _putpixel(pMaterial, posX, testY, g_MaterialAir); + } else { + break; + } } - } - } - } + } + } + + // Remove orphaned regions if told to by parent MO who travelled an atom which tries to penetrate terrain + if (removeOrphansRadius && removeOrphansMaxArea && removeOrphansRate > 0 && RandomNum() < removeOrphansRate) { + RemoveOrphans(posX, posY, removeOrphansRadius, removeOrphansMaxArea, true); + /*PALETTE palette; + get_palette(palette); + save_bmp("Orphan.bmp", m_pOrphanSearchBitmap, palette);*/ + } - // Remove orphaned regions if told to by parent MO who travelled an atom which tries to penetrate terrain - if (removeOrphansRadius && removeOrphansMaxArea && removeOrphansRate > 0 && RandomNum() < removeOrphansRate) - { - RemoveOrphans(posX, posY, removeOrphansRadius, removeOrphansMaxArea, true); - /*PALETTE palette; - get_palette(palette); - save_bmp("Orphan.bmp", m_pOrphanSearchBitmap, palette);*/ + return true; } + return false; + } - return true; - } - return false; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + MovableObject* SceneMan::DislodgePixel(int posX, int posY) { + int materialID = getpixel(m_pCurrentScene->GetTerrain()->GetMaterialBitmap(), posX, posY); + if (materialID <= MaterialColorKeys::g_MaterialAir) { + return nullptr; + } + const Material* sceneMat = GetMaterialFromID(static_cast(materialID)); + const Material* spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; -MovableObject * SceneMan::DislodgePixel(int posX, int posY) { - int materialID = getpixel(m_pCurrentScene->GetTerrain()->GetMaterialBitmap(), posX, posY); - if (materialID <= MaterialColorKeys::g_MaterialAir) { - return nullptr; - } - const Material *sceneMat = GetMaterialFromID(static_cast(materialID)); - const Material *spawnMat = sceneMat->GetSpawnMaterial() ? GetMaterialFromID(sceneMat->GetSpawnMaterial()) : sceneMat; + Color spawnColor; + if (spawnMat->UsesOwnColor()) { + spawnColor = spawnMat->GetColor(); + } else { + spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, posY)); + } + // No point generating a key-colored MOPixel. + if (spawnColor.GetIndex() == ColorKeys::g_MaskColor) { + return nullptr; + } + Atom* pixelAtom = new Atom(Vector(), spawnMat->GetIndex(), nullptr, spawnColor, 2); + MOPixel* pixelMO = new MOPixel(spawnColor, spawnMat->GetPixelDensity(), Vector(static_cast(posX), static_cast(posY)), Vector(), pixelAtom, 0); + pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); + g_MovableMan.AddParticle(pixelMO); - Color spawnColor; - if (spawnMat->UsesOwnColor()) { - spawnColor = spawnMat->GetColor(); - } else { - spawnColor.SetRGBWithIndex(m_pCurrentScene->GetTerrain()->GetFGColorPixel(posX, posY)); - } - // No point generating a key-colored MOPixel. - if (spawnColor.GetIndex() == ColorKeys::g_MaskColor) { - return nullptr; + m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, ColorKeys::g_MaskColor); + RegisterTerrainChange(posX, posY, 1, 1, ColorKeys::g_MaskColor, false); + m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, MaterialColorKeys::g_MaterialAir); + + return pixelMO; } - Atom *pixelAtom = new Atom(Vector(), spawnMat->GetIndex(), nullptr, spawnColor, 2); - MOPixel *pixelMO = new MOPixel(spawnColor, spawnMat->GetPixelDensity(), Vector(static_cast(posX), static_cast(posY)), Vector(), pixelAtom, 0); - pixelMO->SetToHitMOs(spawnMat->GetIndex() == c_GoldMaterialID); - g_MovableMan.AddParticle(pixelMO); - m_pCurrentScene->GetTerrain()->SetFGColorPixel(posX, posY, ColorKeys::g_MaskColor); - RegisterTerrainChange(posX, posY, 1, 1, ColorKeys::g_MaskColor, false); - m_pCurrentScene->GetTerrain()->SetMaterialPixel(posX, posY, MaterialColorKeys::g_MaterialAir); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return pixelMO; -} + void SceneMan::MakeAllUnseen(Vector pixelSize, const int team) { + RTEAssert(m_pCurrentScene, "Messing with scene before the scene exists!"); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + return; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + m_pCurrentScene->FillUnseenLayer(pixelSize, team); + } -void SceneMan::MakeAllUnseen(Vector pixelSize, const int team) -{ - RTEAssert(m_pCurrentScene, "Messing with scene before the scene exists!"); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) - return; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - m_pCurrentScene->FillUnseenLayer(pixelSize, team); -} + bool SceneMan::LoadUnseenLayer(std::string bitmapPath, int team) { + ContentFile bitmapFile(bitmapPath.c_str()); + SceneLayer* pUnseenLayer = new SceneLayer(); + if (pUnseenLayer->Create(bitmapFile.GetAsBitmap(COLORCONV_NONE, false), true, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)) < 0) { + g_ConsoleMan.PrintString("ERROR: Loading background layer " + pUnseenLayer->GetPresetName() + "\'s data failed!"); + return false; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Pass in ownership here + m_pCurrentScene->SetUnseenLayer(pUnseenLayer, team); + return true; + } -bool SceneMan::LoadUnseenLayer(std::string bitmapPath, int team) -{ - ContentFile bitmapFile(bitmapPath.c_str()); - SceneLayer *pUnseenLayer = new SceneLayer(); - if (pUnseenLayer->Create(bitmapFile.GetAsBitmap(COLORCONV_NONE, false), true, Vector(), m_pCurrentScene->WrapsX(), m_pCurrentScene->WrapsY(), Vector(1.0, 1.0)) < 0) - { - g_ConsoleMan.PrintString("ERROR: Loading background layer " + pUnseenLayer->GetPresetName() + "\'s data failed!"); - return false; - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Pass in ownership here - m_pCurrentScene->SetUnseenLayer(pUnseenLayer, team); - return true; -} + bool SceneMan::AnythingUnseen(const int team) { + RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when checking if anything is unseen!"); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return m_pCurrentScene->GetUnseenLayer(team) != 0; + // TODO: Actually check all pixels on the map too? + } -bool SceneMan::AnythingUnseen(const int team) -{ - RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when checking if anything is unseen!"); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return m_pCurrentScene->GetUnseenLayer(team) != 0; -// TODO: Actually check all pixels on the map too? -} + Vector SceneMan::GetUnseenResolution(const int team) const { + RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when getting unseen resolution!"); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + return Vector(1, 1); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + SceneLayer* pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); + if (pUnseenLayer) + return pUnseenLayer->GetScaleFactor(); -Vector SceneMan::GetUnseenResolution(const int team) const -{ - RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when getting unseen resolution!"); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) return Vector(1, 1); + } - SceneLayer *pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); - if (pUnseenLayer) - return pUnseenLayer->GetScaleFactor(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - return Vector(1, 1); -} + bool SceneMan::IsUnseen(const int posX, const int posY, const int team) { + RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when checking if a position is unseen!"); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + return false; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + SceneLayer* pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); + if (pUnseenLayer) { + // Translate to the scaled unseen layer's coordinates + Vector scale = pUnseenLayer->GetScaleFactor(); + int scaledX = posX / scale.m_X; + int scaledY = posY / scale.m_Y; + return getpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY) != g_MaskColor; + } -bool SceneMan::IsUnseen(const int posX, const int posY, const int team) -{ - RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when checking if a position is unseen!"); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) return false; + } - SceneLayer *pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); - if (pUnseenLayer) - { - // Translate to the scaled unseen layer's coordinates - Vector scale = pUnseenLayer->GetScaleFactor(); - int scaledX = posX / scale.m_X; - int scaledY = posY / scale.m_Y; - return getpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY) != g_MaskColor; - } - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::RevealUnseen(const int posX, const int posY, const int team) -{ - RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when revealing an unseen position!"); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) - return false; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::RevealUnseen(const int posX, const int posY, const int team) { + RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when revealing an unseen position!"); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + return false; + + SceneLayer* pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); + if (pUnseenLayer) { + // Translate to the scaled unseen layer's coordinates + Vector scale = pUnseenLayer->GetScaleFactor(); + int scaledX = posX / scale.m_X; + int scaledY = posY / scale.m_Y; + + // Make sure we're actually revealing an unseen pixel that is ON the bitmap! + int pixel = getpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY); + if (pixel != g_MaskColor && pixel != -1) { + // Add the pixel to the list of now seen pixels so it can be visually flashed + m_pCurrentScene->GetSeenPixels(team).push_back(Vector(scaledX, scaledY)); + // Clear to key color that pixel on the map so it won't be detected as unseen again + putpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY, g_MaskColor); + // Play the reveal sound, if there's not too many already revealed this frame + if (g_SettingsMan.BlipOnRevealUnseen() && m_pUnseenRevealSound && m_pCurrentScene->GetSeenPixels(team).size() < 5) + m_pUnseenRevealSound->Play(Vector(posX, posY)); + // Show that we actually cleared an unseen pixel + return true; + } + } - SceneLayer *pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); - if (pUnseenLayer) - { - // Translate to the scaled unseen layer's coordinates - Vector scale = pUnseenLayer->GetScaleFactor(); - int scaledX = posX / scale.m_X; - int scaledY = posY / scale.m_Y; - - // Make sure we're actually revealing an unseen pixel that is ON the bitmap! - int pixel = getpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY); - if (pixel != g_MaskColor && pixel != -1) - { - // Add the pixel to the list of now seen pixels so it can be visually flashed - m_pCurrentScene->GetSeenPixels(team).push_back(Vector(scaledX, scaledY)); - // Clear to key color that pixel on the map so it won't be detected as unseen again - putpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY, g_MaskColor); - // Play the reveal sound, if there's not too many already revealed this frame - if (g_SettingsMan.BlipOnRevealUnseen() && m_pUnseenRevealSound && m_pCurrentScene->GetSeenPixels(team).size() < 5) - m_pUnseenRevealSound->Play(Vector(posX, posY)); - // Show that we actually cleared an unseen pixel - return true; - } - } - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::RestoreUnseen(const int posX, const int posY, const int team) -{ - RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when making a position unseen!"); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) return false; - - SceneLayer *pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); - if (pUnseenLayer) - { - // Translate to the scaled unseen layer's coordinates - Vector scale = pUnseenLayer->GetScaleFactor(); - int scaledX = posX / scale.m_X; - int scaledY = posY / scale.m_Y; - - // Make sure we're actually revealing an unseen pixel that is ON the bitmap! - int pixel = getpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY); - if (pixel != g_BlackColor && pixel != -1) - { - // Add the pixel to the list of now seen pixels so it can be visually flashed - m_pCurrentScene->GetSeenPixels(team).push_back(Vector(scaledX, scaledY)); - // Clear to key color that pixel on the map so it won't be detected as unseen again - putpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY, g_BlackColor); - // Play the reveal sound, if there's not too many already revealed this frame - //if (g_SettingsMan.BlipOnRevealUnseen() && m_pUnseenRevealSound && m_pCurrentScene->GetSeenPixels(team).size() < 5) - // m_pUnseenRevealSound->Play(g_SceneMan.TargetDistanceScalar(Vector(posX, posY))); - // Show that we actually cleared an unseen pixel - return true; - } - } - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::RevealUnseenBox(const int posX, const int posY, const int width, const int height, const int team) -{ - RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when revealing an unseen area!"); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) - return; - - SceneLayer *pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); - if (pUnseenLayer) - { - // Translate to the scaled unseen layer's coordinates - Vector scale = pUnseenLayer->GetScaleFactor(); - int scaledX = posX / scale.m_X; - int scaledY = posY / scale.m_Y; - int scaledW = width / scale.m_X; - int scaledH = height / scale.m_Y; - - // Fill the box - rectfill(pUnseenLayer->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_MaskColor); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void SceneMan::RestoreUnseenBox(const int posX, const int posY, const int width, const int height, const int team) -{ - RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when making an area unseen!"); - if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) - return; - - SceneLayer *pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); - if (pUnseenLayer) - { - // Translate to the scaled unseen layer's coordinates - Vector scale = pUnseenLayer->GetScaleFactor(); - int scaledX = posX / scale.m_X; - int scaledY = posY / scale.m_Y; - int scaledW = width / scale.m_X; - int scaledH = height / scale.m_Y; - - // Fill the box - rectfill(pUnseenLayer->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_BlackColor); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//TODO Every raycast should use some shared line drawing method (or maybe something more efficient if it exists, that needs looking into) instead of having a ton of duplicated code. -bool SceneMan::CastUnseenRay(int team, const Vector &start, const Vector &ray, Vector &endPos, int strengthLimit, int skip, bool reveal) -{ - if (!m_pCurrentScene->GetUnseenLayer(team)) - return false; - - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool affectedAny = false; - unsigned char materialID; - Material const * foundMaterial; - int totalStrength = 0; - // Save the projected end of the ray pos - endPos = start + ray; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return false; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - // Reveal if we can, save the result - if (reveal) - affectedAny = RevealUnseen(intPos[X], intPos[Y], team) || affectedAny; - else - affectedAny = RestoreUnseen(intPos[X], intPos[Y], team) || affectedAny; - - // Check the strength of the terrain to see if we can penetrate further - materialID = GetTerrMatter(intPos[X], intPos[Y]); - // Get the material object - foundMaterial = GetMaterialFromID(materialID); - // Add the encountered material's strength to the tally - totalStrength += foundMaterial->GetIntegrity(); - // See if we have hit the limits of our ray's strength - if (totalStrength >= strengthLimit) - { - // Save the position of the end of the ray where blocked - endPos.SetXY(intPos[X], intPos[Y]); - break; - } - // Reset skip counter - skipped = 0; - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - return affectedAny; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::CastSeeRay(int team, const Vector &start, const Vector &ray, Vector &endPos, int strengthLimit, int skip) -{ - return CastUnseenRay(team, start, ray, endPos, strengthLimit, skip, true); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::CastUnseeRay(int team, const Vector &start, const Vector &ray, Vector &endPos, int strengthLimit, int skip) -{ - return CastUnseenRay(team, start, ray, endPos, strengthLimit, skip, false); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::CastMaterialRay(const Vector &start, const Vector &ray, unsigned char material, Vector &result, int skip, bool wrap) -{ - - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool foundPixel = false; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return false; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - if (wrap) - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - // See if we found the looked-for pixel of the correct material - if (GetTerrMatter(intPos[X], intPos[Y]) == material) - { - // Save result and report success - foundPixel = true; - result.SetXY(intPos[X], intPos[Y]); - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - break; - } - - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - return foundPixel; -} - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::CastMaterialRay(const Vector &start, const Vector &ray, unsigned char material, int skip) -{ - Vector result; - if (CastMaterialRay(start, ray, material, result, skip)) - { - // Calculate the length between the start and the found material pixel coords - result -= start; - return result.GetMagnitude(); - } - - // Signal that we didn't hit anything - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::CastNotMaterialRay(const Vector &start, const Vector &ray, unsigned char material, Vector &result, int skip, bool checkMOs) -{ - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool foundPixel = false; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return false; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - // See if we found the looked-for pixel of the correct material, - // Or an MO is blocking the way - if (GetTerrMatter(intPos[X], intPos[Y]) != material || - (checkMOs && g_SceneMan.GetMOIDPixel(intPos[X], intPos[Y], Activity::NoTeam) != g_NoMOID)) - { - // Save result and report success - foundPixel = true; - result.SetXY(intPos[X], intPos[Y]); - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - break; - } - - skipped = 0; - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - return foundPixel; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::CastNotMaterialRay(const Vector &start, const Vector &ray, unsigned char material, int skip, bool checkMOs) -{ - Vector result; - if (CastNotMaterialRay(start, ray, material, result, skip, checkMOs)) - { - // Calculate the length between the start and the found material pixel coords - result -= start; - return result.GetMagnitude(); - } - - // Signal that we didn't hit anything - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::CastStrengthSumRay(const Vector &start, const Vector &end, int skip, unsigned char ignoreMaterial) -{ - Vector ray = g_SceneMan.ShortestDistance(start, end); - float strengthSum = 0; - - int error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool foundPixel = false; - unsigned char materialID; - Material foundMaterial; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return false; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else - { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - // Sum all strengths - materialID = GetTerrMatter(intPos[X], intPos[Y]); - if (materialID != g_MaterialAir && materialID != ignoreMaterial) { - strengthSum += GetMaterialFromID(materialID)->GetIntegrity(); - } - - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - return strengthSum; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::CastMaxStrengthRay(const Vector &start, const Vector &end, int skip, unsigned char ignoreMaterial) { - return CastMaxStrengthRayMaterial(start, end, skip, ignoreMaterial)->GetIntegrity(); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -const Material * SceneMan::CastMaxStrengthRayMaterial(const Vector &start, const Vector &end, int skip, unsigned char ignoreMaterial) { - Vector ray = g_SceneMan.ShortestDistance(start, end); - const Material *strongestMaterial = GetMaterialFromID(MaterialColorKeys::g_MaterialAir); - - int error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool foundPixel = false; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) { - return strongestMaterial; } - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else - { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - // Sum all strengths - unsigned char materialID = GetTerrMatter(intPos[X], intPos[Y]); - if (materialID != g_MaterialAir && materialID != ignoreMaterial) { - const Material *foundMaterial = GetMaterialFromID(materialID); - if (foundMaterial->GetIntegrity() > strongestMaterial->GetIntegrity()) { - strongestMaterial = foundMaterial; - } - } - - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - return strongestMaterial; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::CastStrengthRay(const Vector &start, const Vector &ray, float strength, Vector &result, int skip, unsigned char ignoreMaterial, bool wrap) -{ - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool foundPixel = false; - unsigned char materialID; - Material const * foundMaterial; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return false; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - if (wrap) - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - materialID = GetTerrMatter(intPos[X], intPos[Y]); - // Ignore the ignore material - if (materialID != ignoreMaterial) - { - // Get the material object - foundMaterial = GetMaterialFromID(materialID); - - // See if we found a pixel of equal or more strength than the threshold - if (foundMaterial->GetIntegrity() >= strength) - { - // Save result and report success - foundPixel = true; - result.SetXY(intPos[X], intPos[Y]); - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - break; - } - } - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - // If no pixel of sufficient strength was found, set the result to the final tried position - if (!foundPixel) - result.SetXY(intPos[X], intPos[Y]); - - return foundPixel; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::CastWeaknessRay(const Vector &start, const Vector &ray, float strength, Vector &result, int skip, bool wrap) -{ - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool foundPixel = false; - unsigned char materialID; - Material const *foundMaterial; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return false; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - if (wrap) - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - materialID = GetTerrMatter(intPos[X], intPos[Y]); - foundMaterial = GetMaterialFromID(materialID); - - // See if we found a pixel of equal or less strength than the threshold - if (foundMaterial->GetIntegrity() <= strength) - { - // Save result and report success - foundPixel = true; - result.SetXY(intPos[X], intPos[Y]); - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - break; - } - - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - // If no pixel of sufficient strength was found, set the result to the final tried position - if (!foundPixel) - result.SetXY(intPos[X], intPos[Y]); - - return foundPixel; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -MOID SceneMan::CastMORay(const Vector &start, const Vector &ray, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) -{ - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - MOID hitMOID = g_NoMOID; - unsigned char hitTerrain = 0; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return g_NoMOID; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - - // Scene wrapping, if necessary - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - // Detect MOIDs - hitMOID = GetMOIDPixel(intPos[X], intPos[Y], ignoreTeam); - if (hitMOID != g_NoMOID && hitMOID != ignoreMOID && g_MovableMan.GetRootMOID(hitMOID) != ignoreMOID) - { -#ifdef DRAW_MOID_LAYER // Unnecessary with non-drawn MOIDs - they'll be culled out at the spatial partition level. - // Check if we're supposed to ignore the team of what we hit - if (ignoreTeam != Activity::NoTeam) - { - const MovableObject *pHitMO = g_MovableMan.GetMOFromID(hitMOID); - pHitMO = pHitMO ? pHitMO->GetRootParent() : 0; - // Yup, we are supposed to ignore this! - if (pHitMO && pHitMO->IgnoresTeamHits() && pHitMO->GetTeam() == ignoreTeam) - { - ; - } - else - { - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - return hitMOID; - } - } - // Legit hit - else -#endif - { - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - return hitMOID; - } - } - - // Detect terrain hits - if (!ignoreAllTerrain) - { - hitTerrain = g_SceneMan.GetTerrMatter(intPos[X], intPos[Y]); - if (hitTerrain != g_MaterialAir && hitTerrain != ignoreMaterial) - { - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - return g_NoMOID; - } - } - - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - // Didn't hit anything but air - return g_NoMOID; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::CastFindMORay(const Vector &start, const Vector &ray, MOID targetMOID, Vector &resultPos, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) -{ - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - MOID hitMOID = g_NoMOID; - unsigned char hitTerrain = 0; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - - if (delta[X] == 0 && delta[Y] == 0) - return g_NoMOID; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) - { - increment[X] = -1; - delta[X] = -delta[X]; - } - else - increment[X] = 1; - - if (delta[Y] < 0) - { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } - else - increment[Y] = 1; - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] << 1; - delta2[Y] = delta[Y] << 1; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } - else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - // Detect MOIDs - hitMOID = GetMOIDPixel(intPos[X], intPos[Y], Activity::NoTeam); - if (hitMOID == targetMOID || g_MovableMan.GetRootMOID(hitMOID) == targetMOID) - { - // Found target MOID, so save result and report success - resultPos.SetXY(intPos[X], intPos[Y]); - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - return true; - } - - // Detect terrain hits - if (!ignoreAllTerrain) - { - hitTerrain = g_SceneMan.GetTerrMatter(intPos[X], intPos[Y]); - if (hitTerrain != g_MaterialAir && hitTerrain != ignoreMaterial) - { - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - return false; - } - } - - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } - } - - // Didn't hit the target - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::CastObstacleRay(const Vector &start, const Vector &ray, Vector &obstaclePos, Vector &freePos, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, int skip) -{ - int hitCount = 0, error, dom, sub, domSteps, skipped = skip; - int intPos[2], delta[2], delta2[2], increment[2]; - bool hitObstacle = false; - - intPos[X] = std::floor(start.m_X); - intPos[Y] = std::floor(start.m_Y); - delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; - delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - // The fraction of a pixel that we start from, to be added to the integer result positions for accuracy - Vector startFraction(start.m_X - intPos[X], start.m_Y - intPos[Y]); - - if (delta[X] == 0 && delta[Y] == 0) { - return -1.0f; - } - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm preparation - - if (delta[X] < 0) { - increment[X] = -1; - delta[X] = -delta[X]; - } else { - increment[X] = 1; - } - - if (delta[Y] < 0) { - increment[Y] = -1; - delta[Y] = -delta[Y]; - } else { - increment[Y] = 1; - } - - // Scale by 2, for better accuracy of the error at the first pixel - delta2[X] = delta[X] * 2; - delta2[Y] = delta[Y] * 2; - - // If X is dominant, Y is submissive, and vice versa. - if (delta[X] > delta[Y]) { - dom = X; - sub = Y; - } else { - dom = Y; - sub = X; - } - - error = delta2[sub] - delta[dom]; - - ///////////////////////////////////////////////////// - // Bresenham's line drawing algorithm execution - - for (domSteps = 0; domSteps < delta[dom]; ++domSteps) - { - intPos[dom] += increment[dom]; - if (error >= 0) - { - intPos[sub] += increment[sub]; - error -= delta2[dom]; - } - error += delta2[sub]; - - // Only check pixel if we're not due to skip any, or if this is the last pixel - if (++skipped > skip || domSteps + 1 == delta[dom]) - { - // Scene wrapping, if necessary - g_SceneMan.WrapPosition(intPos[X], intPos[Y]); - - unsigned char checkMat = GetTerrMatter(intPos[X], intPos[Y]); - MOID checkMOID = GetMOIDPixel(intPos[X], intPos[Y], ignoreTeam); - - // Translate any found MOID into the root MOID of that hit MO - if (checkMOID != g_NoMOID) - { - MovableObject *pHitMO = g_MovableMan.GetMOFromID(checkMOID); - if (pHitMO) - { - checkMOID = pHitMO->GetRootID(); -#ifdef DRAW_MOID_LAYER // Unnecessary with non-drawn MOIDs - they'll be culled out at the spatial partition level. - // Check if we're supposed to ignore the team of what we hit - if (ignoreTeam != Activity::NoTeam) - { - pHitMO = pHitMO->GetRootParent(); - // We are indeed supposed to ignore this object because of its ignoring of its specific team - if (pHitMO && pHitMO->IgnoresTeamHits() && pHitMO->GetTeam() == ignoreTeam) { - checkMOID = g_NoMOID; - } - } -#endif - } - } - - // See if we found the looked-for pixel of the correct material, - // Or an MO is blocking the way - if ((checkMat != g_MaterialAir && checkMat != ignoreMaterial) || (checkMOID != g_NoMOID && checkMOID != ignoreMOID)) { - hitObstacle = true; - obstaclePos.SetXY(intPos[X], intPos[Y]); - // Save last ray pos - s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); - break; - } else { - freePos.SetXY(intPos[X], intPos[Y]); - } - - skipped = 0; - - if (m_pDebugLayer && m_DrawRayCastVisualizations) { m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); } - } else { - freePos.SetXY(intPos[X], intPos[Y]); - } - } - - // Add the pixel fraction to the free position if there were any free pixels - if (domSteps != 0) { - freePos += startFraction; - } - - if (hitObstacle) - { - // Add the pixel fraction to the obstacle position, to acoid losing precision - obstaclePos += startFraction; - if (domSteps == 0) { - // If there was an obstacle on the start position, return 0 as the distance to obstacle - return 0.0F; - } else { - // Calculate the length between the start and the found material pixel coords - return g_SceneMan.ShortestDistance(obstaclePos, start).GetMagnitude(); - } - } - - // Didn't hit anything but air - return -1.0F; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -const Vector& SceneMan::GetLastRayHitPos() -{ - // The absolute end position of the last ray cast - return s_LastRayHitPos; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::FindAltitude(const Vector &from, int max, int accuracy, bool fromSceneOrbitDirection) -{ -// TODO: Also make this avoid doors - Vector temp(from); - ForceBounds(temp); - - Directions orbitDirection = Directions::Up; - if (fromSceneOrbitDirection && m_pCurrentScene) { - orbitDirection = m_pCurrentScene->GetTerrain()->GetOrbitDirection(); - } - - float yDir = max > 0 ? max : g_SceneMan.GetSceneHeight(); - yDir *= orbitDirection == Directions::Up ? 1.0 : -1.0f; - Vector direction = Vector(0, yDir); - - float result = g_SceneMan.CastNotMaterialRay(temp, direction, g_MaterialAir, accuracy); - // If we didn't find anything but air, then report max height - if (result < 0) { - result = max > 0 ? max : g_SceneMan.GetSceneHeight(); - } - - return orbitDirection == Directions::Up ? result : g_SceneMan.GetSceneHeight() - result; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::OverAltitude(const Vector &point, int threshold, int accuracy) -{ - Vector temp(point); - ForceBounds(temp); - return g_SceneMan.CastNotMaterialRay(temp, Vector(0, threshold), g_MaterialAir, accuracy) < 0; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Vector SceneMan::MovePointToGround(const Vector &from, int maxAltitude, int accuracy) -{ - // Todo, instead of a nograv area maybe best to tag certain areas as NoGrav. As otherwise it's tricky to keep track of when things are removed - if (m_pCurrentScene) { - Scene::Area* noGravArea = m_pCurrentScene->GetOptionalArea("NoGravityArea"); - if (noGravArea && noGravArea->IsInside(from)) { - return from; - } - } - - Vector temp(from); - ForceBounds(temp); - - float altitude = FindAltitude(temp, g_SceneMan.GetSceneHeight(), accuracy); - - // If there's no ground beneath us, do nothing - if (altitude == g_SceneMan.GetSceneHeight()) { - return temp; - } - - // Only move down if we're above the maxAltitude over the ground - Vector groundPoint(temp.m_X, temp.m_Y + (altitude > maxAltitude ? altitude - maxAltitude : 0)); - return groundPoint; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::IsWithinBounds(const int pixelX, const int pixelY, const int margin) -{ - if (m_pCurrentScene) - return m_pCurrentScene->GetTerrain()->IsWithinBounds(pixelX, pixelY, margin); - - return false; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::ForceBounds(int &posX, int &posY) -{ - RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); - return m_pCurrentScene->GetTerrain()->ForceBounds(posX, posY); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::ForceBounds(Vector &pos) -{ - RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); - - int posX = std::floor(pos.m_X); - int posY = std::floor(pos.m_Y); - - bool wrapped = m_pCurrentScene->GetTerrain()->ForceBounds(posX, posY); - - pos.m_X = posX + (pos.m_X - std::floor(pos.m_X)); - pos.m_Y = posY + (pos.m_Y - std::floor(pos.m_Y)); - - return wrapped; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::WrapPosition(int &posX, int &posY) -{ - RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); - return m_pCurrentScene->GetTerrain()->WrapPosition(posX, posY); -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::WrapPosition(Vector &pos) -{ - RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); - - int posX = std::floor(pos.m_X); - int posY = std::floor(pos.m_Y); - - bool wrapped = m_pCurrentScene->GetTerrain()->WrapPosition(posX, posY); - - pos.m_X = posX + (pos.m_X - std::floor(pos.m_X)); - pos.m_Y = posY + (pos.m_Y - std::floor(pos.m_Y)); - - return wrapped; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Vector SceneMan::SnapPosition(const Vector &pos, bool snap) -{ - Vector snappedPos = pos; - - if (snap) - { - snappedPos.m_X = std::floor((pos.m_X / SCENESNAPSIZE) + 0.5) * SCENESNAPSIZE; - snappedPos.m_Y = std::floor((pos.m_Y / SCENESNAPSIZE) + 0.5) * SCENESNAPSIZE; - } - - return snappedPos; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -Vector SceneMan::ShortestDistance(Vector pos1, Vector pos2, bool checkBounds) -{ - if (!m_pCurrentScene) - return Vector(); - - if (checkBounds) - { - WrapPosition(pos1); - WrapPosition(pos2); - } - - Vector distance = pos2 - pos1; - float sceneWidth = m_pCurrentScene->GetWidth(); - float sceneHeight = m_pCurrentScene->GetHeight(); - - if (m_pCurrentScene->GetTerrain()->WrapsX()) - { - if (distance.m_X > 0) - { - if (distance.m_X > (sceneWidth / 2)) - distance.m_X -= sceneWidth; - } - else - { - if (abs(distance.m_X) > (sceneWidth / 2)) - distance.m_X += sceneWidth; - } - } - - if (m_pCurrentScene->GetTerrain()->WrapsY()) - { - if (distance.m_Y > 0) - { - if (distance.m_Y > (sceneHeight / 2)) - distance.m_Y -= sceneHeight; - } - else - { - if (abs(distance.m_Y) > (sceneHeight / 2)) - distance.m_Y += sceneHeight; - } - } - - return distance; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::ShortestDistanceX(float val1, float val2, bool checkBounds, int direction) -{ - if (!m_pCurrentScene) - return 0; - - if (checkBounds) - { - int x1 = val1; - int x2 = val2; - int crap = 0; - WrapPosition(x1, crap); - WrapPosition(x2, crap); - val1 = x1; - val2 = x2; - } - - float distance = val2 - val1; - float sceneWidth = m_pCurrentScene->GetWidth(); - - if (m_pCurrentScene->GetTerrain()->WrapsX()) - { - if (distance > 0) - { - if (distance > (sceneWidth / 2)) - distance -= sceneWidth; - } - else - { - if (abs(distance) > (sceneWidth / 2)) - distance += sceneWidth; - } - - // Apply direction constraint if wrapped - if (direction > 0 && distance < 0) - distance += sceneWidth; - else if (direction < 0 && distance > 0) - distance -= sceneWidth; - } - - return distance; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -float SceneMan::ShortestDistanceY(float val1, float val2, bool checkBounds, int direction) -{ - if (!m_pCurrentScene) - return 0; - - if (checkBounds) - { - int y1 = val1; - int y2 = val2; - int crap = 0; - WrapPosition(crap, y1); - WrapPosition(crap, y2); - val1 = y1; - val2 = y2; - } - - float distance = val2 - val1; - float sceneHeight = m_pCurrentScene->GetHeight(); - - if (m_pCurrentScene->GetTerrain()->WrapsY()) - { - if (distance > 0) - { - if (distance > (sceneHeight / 2)) - distance -= sceneHeight; - } - else - { - if (abs(distance) > (sceneHeight / 2)) - distance += sceneHeight; - } - - // Apply direction constraint if wrapped - if (direction > 0 && distance < 0) - distance += sceneHeight; - else if (direction < 0 && distance > 0) - distance -= sceneHeight; - } - - return distance; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::ObscuredPoint(int x, int y, int team) -{ - bool obscured = m_pCurrentScene->GetTerrain()->GetPixel(x, y) != g_MaterialAir || GetMOIDPixel(x, y, Activity::NoTeam) != g_NoMOID; - - if (team != Activity::NoTeam) - obscured = obscured || IsUnseen(x, y, team); - - return obscured; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::WrapRect(const IntRect &wrapRect, std::list &outputList) -{ - // Always add at least one copy of the unwrapped rect - int addedTimes = 1; - outputList.push_back(wrapRect); - - // Only bother with wrap checking if the scene actually wraps around in X - if (SceneWrapsX()) - { - int sceneWidth = GetSceneWidth(); - - if (wrapRect.m_Left < 0) - { - outputList.push_back(wrapRect); - outputList.back().m_Left += sceneWidth; - outputList.back().m_Right += sceneWidth; - addedTimes++; - } - if (wrapRect.m_Right >= sceneWidth) - { - outputList.push_back(wrapRect); - outputList.back().m_Left -= sceneWidth; - outputList.back().m_Right -= sceneWidth; - addedTimes++; - } - } - - // Only bother with wrap checking if the scene actually wraps around in Y - if (SceneWrapsY()) - { - int sceneHeight = GetSceneHeight(); - - if (wrapRect.m_Top < 0) - { - outputList.push_back(wrapRect); - outputList.back().m_Top += sceneHeight; - outputList.back().m_Bottom += sceneHeight; - addedTimes++; - } - if (wrapRect.m_Bottom >= sceneHeight) - { - outputList.push_back(wrapRect); - outputList.back().m_Top -= sceneHeight; - outputList.back().m_Bottom -= sceneHeight; - addedTimes++; - } - } - - return addedTimes; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -int SceneMan::WrapBox(const Box &wrapBox, std::list &outputList) -{ - // Unflip the input box, or checking will be tedious - Box flipBox(wrapBox); - flipBox.Unflip(); - - // Always add at least one copy of the unwrapped rect - int addedTimes = 1; - outputList.push_back(flipBox); - - // Only bother with wrap checking if the scene actually wraps around in X - if (SceneWrapsX()) - { - int sceneWidth = GetSceneWidth(); - - if (flipBox.m_Corner.m_X < 0) - { - outputList.push_back(flipBox); - outputList.back().m_Corner.m_X += sceneWidth; - addedTimes++; - } - if (flipBox.m_Corner.m_X + flipBox.m_Width >= sceneWidth) - { - outputList.push_back(flipBox); - outputList.back().m_Corner.m_X -= sceneWidth; - addedTimes++; - } - } - - // Only bother with wrap checking if the scene actually wraps around in Y - if (SceneWrapsY()) - { - int sceneHeight = GetSceneHeight(); - - if (flipBox.m_Corner.m_Y < 0) - { - outputList.push_back(flipBox); - outputList.back().m_Corner.m_Y += sceneHeight; - addedTimes++; - } - if (flipBox.m_Corner.m_Y + flipBox.m_Height >= sceneHeight) - { - outputList.push_back(flipBox); - outputList.back().m_Corner.m_Y -= sceneHeight; - addedTimes++; - } - } - - return addedTimes; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -bool SceneMan::AddSceneObject(SceneObject *sceneObject) { - bool result = false; - if (sceneObject) { - if (MovableObject *sceneObjectAsMovableObject = dynamic_cast(sceneObject)) { - return g_MovableMan.AddMO(sceneObjectAsMovableObject); - } else if (TerrainObject *sceneObjectAsTerrainObject = dynamic_cast(sceneObject)) { - result = m_pCurrentScene && sceneObjectAsTerrainObject->PlaceOnTerrain(m_pCurrentScene->GetTerrain()); - if (result) { - Box airBox(sceneObjectAsTerrainObject->GetPos() + sceneObjectAsTerrainObject->GetBitmapOffset(), static_cast(sceneObjectAsTerrainObject->GetBitmapWidth()), static_cast(sceneObjectAsTerrainObject->GetBitmapHeight())); - m_pCurrentScene->GetTerrain()->CleanAirBox(airBox, GetScene()->WrapsX(), GetScene()->WrapsY()); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::RestoreUnseen(const int posX, const int posY, const int team) { + RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when making a position unseen!"); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + return false; + + SceneLayer* pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); + if (pUnseenLayer) { + // Translate to the scaled unseen layer's coordinates + Vector scale = pUnseenLayer->GetScaleFactor(); + int scaledX = posX / scale.m_X; + int scaledY = posY / scale.m_Y; + + // Make sure we're actually revealing an unseen pixel that is ON the bitmap! + int pixel = getpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY); + if (pixel != g_BlackColor && pixel != -1) { + // Add the pixel to the list of now seen pixels so it can be visually flashed + m_pCurrentScene->GetSeenPixels(team).push_back(Vector(scaledX, scaledY)); + // Clear to key color that pixel on the map so it won't be detected as unseen again + putpixel(pUnseenLayer->GetBitmap(), scaledX, scaledY, g_BlackColor); + // Play the reveal sound, if there's not too many already revealed this frame + // if (g_SettingsMan.BlipOnRevealUnseen() && m_pUnseenRevealSound && m_pCurrentScene->GetSeenPixels(team).size() < 5) + // m_pUnseenRevealSound->Play(g_SceneMan.TargetDistanceScalar(Vector(posX, posY))); + // Show that we actually cleared an unseen pixel + return true; } } + + return false; } - delete sceneObject; - return result; -} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::RevealUnseenBox(const int posX, const int posY, const int width, const int height, const int team) { + RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when revealing an unseen area!"); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + return; -void SceneMan::Update(int screenId) { - ZoneScoped; - - if (!m_pCurrentScene) { - return; + SceneLayer* pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); + if (pUnseenLayer) { + // Translate to the scaled unseen layer's coordinates + Vector scale = pUnseenLayer->GetScaleFactor(); + int scaledX = posX / scale.m_X; + int scaledY = posY / scale.m_Y; + int scaledW = width / scale.m_X; + int scaledH = height / scale.m_Y; + + // Fill the box + rectfill(pUnseenLayer->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_MaskColor); + } } - m_LastUpdatedScreen = screenId; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Vector &offset = g_CameraMan.GetOffset(screenId); - m_pMOColorLayer->SetOffset(offset); - m_pMOIDLayer->SetOffset(offset); - if (m_pDebugLayer) { - m_pDebugLayer->SetOffset(offset); - } + void SceneMan::RestoreUnseenBox(const int posX, const int posY, const int width, const int height, const int team) { + RTEAssert(m_pCurrentScene, "Checking scene before the scene exists when making an area unseen!"); + if (team < Activity::TeamOne || team >= Activity::MaxTeamCount) + return; - SLTerrain *terrain = m_pCurrentScene->GetTerrain(); - terrain->SetOffset(offset); - terrain->Update(); + SceneLayer* pUnseenLayer = m_pCurrentScene->GetUnseenLayer(team); + if (pUnseenLayer) { + // Translate to the scaled unseen layer's coordinates + Vector scale = pUnseenLayer->GetScaleFactor(); + int scaledX = posX / scale.m_X; + int scaledY = posY / scale.m_Y; + int scaledW = width / scale.m_X; + int scaledH = height / scale.m_Y; - // Background layers may scroll in fractions of the real offset and need special care to avoid jumping after having traversed wrapped edges, so they need the total offset without taking wrapping into account. - const Vector &unwrappedOffset = g_CameraMan.GetUnwrappedOffset(screenId); - for (SLBackground *backgroundLayer : m_pCurrentScene->GetBackLayers()) { - backgroundLayer->SetOffset(unwrappedOffset); - backgroundLayer->Update(); + // Fill the box + rectfill(pUnseenLayer->GetBitmap(), scaledX, scaledY, scaledX + scaledW, scaledY + scaledH, g_BlackColor); + } } - // Update the unseen obstruction layer for this team's screen view, if there is one. - const int teamId = g_CameraMan.GetScreenTeam(screenId); - if (SceneLayer *unseenLayer = (teamId != Activity::NoTeam) ? m_pCurrentScene->GetUnseenLayer(teamId) : nullptr) { - unseenLayer->SetOffset(offset); - } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // TODO Every raycast should use some shared line drawing method (or maybe something more efficient if it exists, that needs looking into) instead of having a ton of duplicated code. + bool SceneMan::CastUnseenRay(int team, const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip, bool reveal) { + if (!m_pCurrentScene->GetUnseenLayer(team)) + return false; + + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool affectedAny = false; + unsigned char materialID; + Material const* foundMaterial; + int totalStrength = 0; + // Save the projected end of the ray pos + endPos = start + ray; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return false; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; - if (m_CleanTimer.GetElapsedSimTimeMS() > CLEANAIRINTERVAL) { - terrain->CleanAir(); - m_CleanTimer.Reset(); - } -} + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + // Reveal if we can, save the result + if (reveal) + affectedAny = RevealUnseen(intPos[X], intPos[Y], team) || affectedAny; + else + affectedAny = RestoreUnseen(intPos[X], intPos[Y], team) || affectedAny; + + // Check the strength of the terrain to see if we can penetrate further + materialID = GetTerrMatter(intPos[X], intPos[Y]); + // Get the material object + foundMaterial = GetMaterialFromID(materialID); + // Add the encountered material's strength to the tally + totalStrength += foundMaterial->GetIntegrity(); + // See if we have hit the limits of our ray's strength + if (totalStrength >= strengthLimit) { + // Save the position of the end of the ray where blocked + endPos.SetXY(intPos[X], intPos[Y]); + break; + } + // Reset skip counter + skipped = 0; + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } -void SceneMan::Draw(BITMAP *targetBitmap, BITMAP *targetGUIBitmap, const Vector &targetPos, bool skipBackgroundLayers, bool skipTerrain) { - ZoneScoped; - - if (!m_pCurrentScene) { - return; + return affectedAny; } - SLTerrain *terrain = m_pCurrentScene->GetTerrain(); - // Set up the target box to draw to on the target bitmap, if it is larger than the scene in either dimension. - Box targetBox(Vector(), static_cast(targetBitmap->w), static_cast(targetBitmap->h)); - if (!terrain->WrapsX() && targetBitmap->w > GetSceneWidth()) { - targetBox.SetCorner(Vector(static_cast((targetBitmap->w - GetSceneWidth()) / 2), targetBox.GetCorner().GetY())); - targetBox.SetWidth(static_cast(GetSceneWidth())); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::CastSeeRay(int team, const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip) { + return CastUnseenRay(team, start, ray, endPos, strengthLimit, skip, true); } - if (!terrain->WrapsY() && targetBitmap->h > GetSceneHeight()) { - targetBox.SetCorner(Vector(targetBox.GetCorner().GetX(), static_cast((targetBitmap->h - GetSceneHeight()) / 2))); - targetBox.SetHeight(static_cast(GetSceneHeight())); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::CastUnseeRay(int team, const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip) { + return CastUnseenRay(team, start, ray, endPos, strengthLimit, skip, false); } - switch (m_LayerDrawMode) { - case LayerDrawMode::g_LayerTerrainMatter: - terrain->SetLayerToDraw(SLTerrain::LayerType::MaterialLayer); - terrain->Draw(targetBitmap, targetBox); - break; -#ifdef DRAW_MOID_LAYER - case LayerDrawMode::g_LayerMOID: - m_pMOIDLayer->Draw(targetBitmap, targetBox); - break; -#endif - default: - if (!skipBackgroundLayers) { - for (std::list::reverse_iterator backgroundLayer = m_pCurrentScene->GetBackLayers().rbegin(); backgroundLayer != m_pCurrentScene->GetBackLayers().rend(); ++backgroundLayer) { - (*backgroundLayer)->Draw(targetBitmap, targetBox); - } - } - if (!skipTerrain) { - terrain->SetLayerToDraw(SLTerrain::LayerType::BackgroundLayer); - terrain->Draw(targetBitmap, targetBox); - } - m_pMOColorLayer->Draw(targetBitmap, targetBox); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (!skipTerrain) { - terrain->SetLayerToDraw(SLTerrain::LayerType::ForegroundLayer); - terrain->Draw(targetBitmap, targetBox); - } - if (!g_FrameMan.IsInMultiplayerMode()) { - int teamId = g_CameraMan.GetScreenTeam(m_LastUpdatedScreen); - if (SceneLayer *unseenLayer = (teamId != Activity::NoTeam) ? m_pCurrentScene->GetUnseenLayer(teamId) : nullptr) { - unseenLayer->Draw(targetBitmap, targetBox); - } - } + bool SceneMan::CastMaterialRay(const Vector& start, const Vector& ray, unsigned char material, Vector& result, int skip, bool wrap) { - bool shouldDrawHUD = !g_FrameMan.IsHudDisabled(m_LastUpdatedScreen); - if (shouldDrawHUD) { - g_MovableMan.DrawHUD(targetGUIBitmap, targetPos, m_LastUpdatedScreen); - } + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool foundPixel = false; - g_PrimitiveMan.DrawPrimitives(m_LastUpdatedScreen, targetGUIBitmap, targetPos); + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; - if (shouldDrawHUD) { - g_ActivityMan.GetActivity()->DrawGUI(targetGUIBitmap, targetPos, m_LastUpdatedScreen); - } + if (delta[X] == 0 && delta[Y] == 0) + return false; -#ifdef DRAW_NOGRAV_BOXES - if (Scene::Area* noGravArea = m_pCurrentScene->GetArea("NoGravityArea")) { - const std::vector& boxList = noGravArea->GetBoxes(); - g_FrameMan.SetTransTableFromPreset(TransparencyPreset::MoreTrans); - drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); - - std::list wrappedBoxes; - for (std::vector::const_iterator bItr = boxList.begin(); bItr != boxList.end(); ++bItr) - { - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*bItr, wrappedBoxes); - - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - Vector adjCorner = (*wItr).GetCorner() - targetPos; - rectfill(targetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_RedColor); - } - } - } -#endif + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation - if (m_pDebugLayer) { - m_pDebugLayer->Draw(targetBitmap, targetBox); - } + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; - break; - } -} + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + error = delta2[sub] - delta[dom]; -void SceneMan::ClearMOColorLayer() -{ - m_pMOColorLayer->ClearBitmap(g_MaskColor); - if (m_pDebugLayer) { m_pDebugLayer->ClearBitmap(g_MaskColor); } -} + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + if (wrap) + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + // See if we found the looked-for pixel of the correct material + if (GetTerrMatter(intPos[X], intPos[Y]) == material) { + // Save result and report success + foundPixel = true; + result.SetXY(intPos[X], intPos[Y]); + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + break; + } -void SceneMan::ClearSeenPixels() -{ - if (!m_pCurrentScene) - return; + skipped = 0; - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - m_pCurrentScene->ClearSeenPixels(team); -} + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + return foundPixel; + } -void SceneMan::ClearCurrentScene() { - m_pCurrentScene = nullptr; -} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float SceneMan::CastMaterialRay(const Vector& start, const Vector& ray, unsigned char material, int skip) { + Vector result; + if (CastMaterialRay(start, ray, material, result, skip)) { + // Calculate the length between the start and the found material pixel coords + result -= start; + return result.GetMagnitude(); + } -BITMAP * SceneMan::GetIntermediateBitmapForSettlingIntoTerrain(int moDiameter) const { - int bitmapSizeNeeded = static_cast(std::ceil(static_cast(moDiameter) / 16.0F)) * 16; - for (const auto &[bitmapSize, bitmapPtr] : m_IntermediateSettlingBitmaps) { - if (std::min(bitmapSize, bitmapSizeNeeded) >= bitmapSizeNeeded) { - return bitmapPtr; + // Signal that we didn't hit anything + return -1; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::CastNotMaterialRay(const Vector& start, const Vector& ray, unsigned char material, Vector& result, int skip, bool checkMOs) { + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool foundPixel = false; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return false; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + // See if we found the looked-for pixel of the correct material, + // Or an MO is blocking the way + if (GetTerrMatter(intPos[X], intPos[Y]) != material || + (checkMOs && g_SceneMan.GetMOIDPixel(intPos[X], intPos[Y], Activity::NoTeam) != g_NoMOID)) { + // Save result and report success + foundPixel = true; + result.SetXY(intPos[X], intPos[Y]); + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + break; + } + + skipped = 0; + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + return foundPixel; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float SceneMan::CastNotMaterialRay(const Vector& start, const Vector& ray, unsigned char material, int skip, bool checkMOs) { + Vector result; + if (CastNotMaterialRay(start, ray, material, result, skip, checkMOs)) { + // Calculate the length between the start and the found material pixel coords + result -= start; + return result.GetMagnitude(); + } + + // Signal that we didn't hit anything + return -1; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float SceneMan::CastStrengthSumRay(const Vector& start, const Vector& end, int skip, unsigned char ignoreMaterial) { + Vector ray = g_SceneMan.ShortestDistance(start, end); + float strengthSum = 0; + + int error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool foundPixel = false; + unsigned char materialID; + Material foundMaterial; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return false; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + // Sum all strengths + materialID = GetTerrMatter(intPos[X], intPos[Y]); + if (materialID != g_MaterialAir && materialID != ignoreMaterial) { + strengthSum += GetMaterialFromID(materialID)->GetIntegrity(); + } + + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + return strengthSum; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float SceneMan::CastMaxStrengthRay(const Vector& start, const Vector& end, int skip, unsigned char ignoreMaterial) { + return CastMaxStrengthRayMaterial(start, end, skip, ignoreMaterial)->GetIntegrity(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + const Material* SceneMan::CastMaxStrengthRayMaterial(const Vector& start, const Vector& end, int skip, unsigned char ignoreMaterial) { + Vector ray = g_SceneMan.ShortestDistance(start, end); + const Material* strongestMaterial = GetMaterialFromID(MaterialColorKeys::g_MaterialAir); + + int error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool foundPixel = false; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) { + return strongestMaterial; + } + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + // Sum all strengths + unsigned char materialID = GetTerrMatter(intPos[X], intPos[Y]); + if (materialID != g_MaterialAir && materialID != ignoreMaterial) { + const Material* foundMaterial = GetMaterialFromID(materialID); + if (foundMaterial->GetIntegrity() > strongestMaterial->GetIntegrity()) { + strongestMaterial = foundMaterial; + } + } + + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + return strongestMaterial; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::CastStrengthRay(const Vector& start, const Vector& ray, float strength, Vector& result, int skip, unsigned char ignoreMaterial, bool wrap) { + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool foundPixel = false; + unsigned char materialID; + Material const* foundMaterial; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return false; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + if (wrap) + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + materialID = GetTerrMatter(intPos[X], intPos[Y]); + // Ignore the ignore material + if (materialID != ignoreMaterial) { + // Get the material object + foundMaterial = GetMaterialFromID(materialID); + + // See if we found a pixel of equal or more strength than the threshold + if (foundMaterial->GetIntegrity() >= strength) { + // Save result and report success + foundPixel = true; + result.SetXY(intPos[X], intPos[Y]); + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + break; + } + } + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + // If no pixel of sufficient strength was found, set the result to the final tried position + if (!foundPixel) + result.SetXY(intPos[X], intPos[Y]); + + return foundPixel; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::CastWeaknessRay(const Vector& start, const Vector& ray, float strength, Vector& result, int skip, bool wrap) { + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool foundPixel = false; + unsigned char materialID; + Material const* foundMaterial; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return false; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + if (wrap) + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + materialID = GetTerrMatter(intPos[X], intPos[Y]); + foundMaterial = GetMaterialFromID(materialID); + + // See if we found a pixel of equal or less strength than the threshold + if (foundMaterial->GetIntegrity() <= strength) { + // Save result and report success + foundPixel = true; + result.SetXY(intPos[X], intPos[Y]); + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + break; + } + + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + // If no pixel of sufficient strength was found, set the result to the final tried position + if (!foundPixel) + result.SetXY(intPos[X], intPos[Y]); + + return foundPixel; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + MOID SceneMan::CastMORay(const Vector& start, const Vector& ray, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + MOID hitMOID = g_NoMOID; + unsigned char hitTerrain = 0; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return g_NoMOID; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + + // Scene wrapping, if necessary + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + // Detect MOIDs + hitMOID = GetMOIDPixel(intPos[X], intPos[Y], ignoreTeam); + if (hitMOID != g_NoMOID && hitMOID != ignoreMOID && g_MovableMan.GetRootMOID(hitMOID) != ignoreMOID) { +#ifdef DRAW_MOID_LAYER // Unnecessary with non-drawn MOIDs - they'll be culled out at the spatial partition level. + // Check if we're supposed to ignore the team of what we hit + if (ignoreTeam != Activity::NoTeam) { + const MovableObject* pHitMO = g_MovableMan.GetMOFromID(hitMOID); + pHitMO = pHitMO ? pHitMO->GetRootParent() : 0; + // Yup, we are supposed to ignore this! + if (pHitMO && pHitMO->IgnoresTeamHits() && pHitMO->GetTeam() == ignoreTeam) { + ; + } else { + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + return hitMOID; + } + } + // Legit hit + else +#endif + { + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + return hitMOID; + } + } + + // Detect terrain hits + if (!ignoreAllTerrain) { + hitTerrain = g_SceneMan.GetTerrMatter(intPos[X], intPos[Y]); + if (hitTerrain != g_MaterialAir && hitTerrain != ignoreMaterial) { + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + return g_NoMOID; + } + } + + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + // Didn't hit anything but air + return g_NoMOID; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::CastFindMORay(const Vector& start, const Vector& ray, MOID targetMOID, Vector& resultPos, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + MOID hitMOID = g_NoMOID; + unsigned char hitTerrain = 0; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return g_NoMOID; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + // Detect MOIDs + hitMOID = GetMOIDPixel(intPos[X], intPos[Y], Activity::NoTeam); + if (hitMOID == targetMOID || g_MovableMan.GetRootMOID(hitMOID) == targetMOID) { + // Found target MOID, so save result and report success + resultPos.SetXY(intPos[X], intPos[Y]); + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + return true; + } + + // Detect terrain hits + if (!ignoreAllTerrain) { + hitTerrain = g_SceneMan.GetTerrMatter(intPos[X], intPos[Y]); + if (hitTerrain != g_MaterialAir && hitTerrain != ignoreMaterial) { + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + return false; + } + } + + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + // Didn't hit the target + return false; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float SceneMan::CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, int skip) { + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + bool hitObstacle = false; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + // The fraction of a pixel that we start from, to be added to the integer result positions for accuracy + Vector startFraction(start.m_X - intPos[X], start.m_Y - intPos[Y]); + + if (delta[X] == 0 && delta[Y] == 0) { + return -1.0f; + } + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else { + increment[X] = 1; + } + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else { + increment[Y] = 1; + } + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] * 2; + delta2[Y] = delta[Y] * 2; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + // Scene wrapping, if necessary + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + unsigned char checkMat = GetTerrMatter(intPos[X], intPos[Y]); + MOID checkMOID = GetMOIDPixel(intPos[X], intPos[Y], ignoreTeam); + + // Translate any found MOID into the root MOID of that hit MO + if (checkMOID != g_NoMOID) { + MovableObject* pHitMO = g_MovableMan.GetMOFromID(checkMOID); + if (pHitMO) { + checkMOID = pHitMO->GetRootID(); +#ifdef DRAW_MOID_LAYER // Unnecessary with non-drawn MOIDs - they'll be culled out at the spatial partition level. \ + // Check if we're supposed to ignore the team of what we hit + if (ignoreTeam != Activity::NoTeam) { + pHitMO = pHitMO->GetRootParent(); + // We are indeed supposed to ignore this object because of its ignoring of its specific team + if (pHitMO && pHitMO->IgnoresTeamHits() && pHitMO->GetTeam() == ignoreTeam) { + checkMOID = g_NoMOID; + } + } +#endif + } + } + + // See if we found the looked-for pixel of the correct material, + // Or an MO is blocking the way + if ((checkMat != g_MaterialAir && checkMat != ignoreMaterial) || (checkMOID != g_NoMOID && checkMOID != ignoreMOID)) { + hitObstacle = true; + obstaclePos.SetXY(intPos[X], intPos[Y]); + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + break; + } else { + freePos.SetXY(intPos[X], intPos[Y]); + } + + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } else { + freePos.SetXY(intPos[X], intPos[Y]); + } + } + + // Add the pixel fraction to the free position if there were any free pixels + if (domSteps != 0) { + freePos += startFraction; + } + + if (hitObstacle) { + // Add the pixel fraction to the obstacle position, to acoid losing precision + obstaclePos += startFraction; + if (domSteps == 0) { + // If there was an obstacle on the start position, return 0 as the distance to obstacle + return 0.0F; + } else { + // Calculate the length between the start and the found material pixel coords + return g_SceneMan.ShortestDistance(obstaclePos, start).GetMagnitude(); + } + } + + // Didn't hit anything but air + return -1.0F; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + const Vector& SceneMan::GetLastRayHitPos() { + // The absolute end position of the last ray cast + return s_LastRayHitPos; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float SceneMan::FindAltitude(const Vector& from, int max, int accuracy, bool fromSceneOrbitDirection) { + // TODO: Also make this avoid doors + Vector temp(from); + ForceBounds(temp); + + Directions orbitDirection = Directions::Up; + if (fromSceneOrbitDirection && m_pCurrentScene) { + orbitDirection = m_pCurrentScene->GetTerrain()->GetOrbitDirection(); + } + + float yDir = max > 0 ? max : g_SceneMan.GetSceneHeight(); + yDir *= orbitDirection == Directions::Up ? 1.0 : -1.0f; + Vector direction = Vector(0, yDir); + + float result = g_SceneMan.CastNotMaterialRay(temp, direction, g_MaterialAir, accuracy); + // If we didn't find anything but air, then report max height + if (result < 0) { + result = max > 0 ? max : g_SceneMan.GetSceneHeight(); + } + + return orbitDirection == Directions::Up ? result : g_SceneMan.GetSceneHeight() - result; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::OverAltitude(const Vector& point, int threshold, int accuracy) { + Vector temp(point); + ForceBounds(temp); + return g_SceneMan.CastNotMaterialRay(temp, Vector(0, threshold), g_MaterialAir, accuracy) < 0; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Vector SceneMan::MovePointToGround(const Vector& from, int maxAltitude, int accuracy) { + // Todo, instead of a nograv area maybe best to tag certain areas as NoGrav. As otherwise it's tricky to keep track of when things are removed + if (m_pCurrentScene) { + Scene::Area* noGravArea = m_pCurrentScene->GetOptionalArea("NoGravityArea"); + if (noGravArea && noGravArea->IsInside(from)) { + return from; + } + } + + Vector temp(from); + ForceBounds(temp); + + float altitude = FindAltitude(temp, g_SceneMan.GetSceneHeight(), accuracy); + + // If there's no ground beneath us, do nothing + if (altitude == g_SceneMan.GetSceneHeight()) { + return temp; + } + + // Only move down if we're above the maxAltitude over the ground + Vector groundPoint(temp.m_X, temp.m_Y + (altitude > maxAltitude ? altitude - maxAltitude : 0)); + return groundPoint; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::IsWithinBounds(const int pixelX, const int pixelY, const int margin) { + if (m_pCurrentScene) + return m_pCurrentScene->GetTerrain()->IsWithinBounds(pixelX, pixelY, margin); + + return false; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::ForceBounds(int& posX, int& posY) { + RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); + return m_pCurrentScene->GetTerrain()->ForceBounds(posX, posY); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::ForceBounds(Vector& pos) { + RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); + + int posX = std::floor(pos.m_X); + int posY = std::floor(pos.m_Y); + + bool wrapped = m_pCurrentScene->GetTerrain()->ForceBounds(posX, posY); + + pos.m_X = posX + (pos.m_X - std::floor(pos.m_X)); + pos.m_Y = posY + (pos.m_Y - std::floor(pos.m_Y)); + + return wrapped; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::WrapPosition(int& posX, int& posY) { + RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); + return m_pCurrentScene->GetTerrain()->WrapPosition(posX, posY); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::WrapPosition(Vector& pos) { + RTEAssert(m_pCurrentScene, "Trying to access scene before there is one!"); + + int posX = std::floor(pos.m_X); + int posY = std::floor(pos.m_Y); + + bool wrapped = m_pCurrentScene->GetTerrain()->WrapPosition(posX, posY); + + pos.m_X = posX + (pos.m_X - std::floor(pos.m_X)); + pos.m_Y = posY + (pos.m_Y - std::floor(pos.m_Y)); + + return wrapped; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Vector SceneMan::SnapPosition(const Vector& pos, bool snap) { + Vector snappedPos = pos; + + if (snap) { + snappedPos.m_X = std::floor((pos.m_X / SCENESNAPSIZE) + 0.5) * SCENESNAPSIZE; + snappedPos.m_Y = std::floor((pos.m_Y / SCENESNAPSIZE) + 0.5) * SCENESNAPSIZE; + } + + return snappedPos; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Vector SceneMan::ShortestDistance(Vector pos1, Vector pos2, bool checkBounds) { + if (!m_pCurrentScene) + return Vector(); + + if (checkBounds) { + WrapPosition(pos1); + WrapPosition(pos2); + } + + Vector distance = pos2 - pos1; + float sceneWidth = m_pCurrentScene->GetWidth(); + float sceneHeight = m_pCurrentScene->GetHeight(); + + if (m_pCurrentScene->GetTerrain()->WrapsX()) { + if (distance.m_X > 0) { + if (distance.m_X > (sceneWidth / 2)) + distance.m_X -= sceneWidth; + } else { + if (abs(distance.m_X) > (sceneWidth / 2)) + distance.m_X += sceneWidth; + } + } + + if (m_pCurrentScene->GetTerrain()->WrapsY()) { + if (distance.m_Y > 0) { + if (distance.m_Y > (sceneHeight / 2)) + distance.m_Y -= sceneHeight; + } else { + if (abs(distance.m_Y) > (sceneHeight / 2)) + distance.m_Y += sceneHeight; + } + } + + return distance; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float SceneMan::ShortestDistanceX(float val1, float val2, bool checkBounds, int direction) { + if (!m_pCurrentScene) + return 0; + + if (checkBounds) { + int x1 = val1; + int x2 = val2; + int crap = 0; + WrapPosition(x1, crap); + WrapPosition(x2, crap); + val1 = x1; + val2 = x2; + } + + float distance = val2 - val1; + float sceneWidth = m_pCurrentScene->GetWidth(); + + if (m_pCurrentScene->GetTerrain()->WrapsX()) { + if (distance > 0) { + if (distance > (sceneWidth / 2)) + distance -= sceneWidth; + } else { + if (abs(distance) > (sceneWidth / 2)) + distance += sceneWidth; + } + + // Apply direction constraint if wrapped + if (direction > 0 && distance < 0) + distance += sceneWidth; + else if (direction < 0 && distance > 0) + distance -= sceneWidth; + } + + return distance; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float SceneMan::ShortestDistanceY(float val1, float val2, bool checkBounds, int direction) { + if (!m_pCurrentScene) + return 0; + + if (checkBounds) { + int y1 = val1; + int y2 = val2; + int crap = 0; + WrapPosition(crap, y1); + WrapPosition(crap, y2); + val1 = y1; + val2 = y2; + } + + float distance = val2 - val1; + float sceneHeight = m_pCurrentScene->GetHeight(); + + if (m_pCurrentScene->GetTerrain()->WrapsY()) { + if (distance > 0) { + if (distance > (sceneHeight / 2)) + distance -= sceneHeight; + } else { + if (abs(distance) > (sceneHeight / 2)) + distance += sceneHeight; + } + + // Apply direction constraint if wrapped + if (direction > 0 && distance < 0) + distance += sceneHeight; + else if (direction < 0 && distance > 0) + distance -= sceneHeight; + } + + return distance; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::ObscuredPoint(int x, int y, int team) { + bool obscured = m_pCurrentScene->GetTerrain()->GetPixel(x, y) != g_MaterialAir || GetMOIDPixel(x, y, Activity::NoTeam) != g_NoMOID; + + if (team != Activity::NoTeam) + obscured = obscured || IsUnseen(x, y, team); + + return obscured; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::WrapRect(const IntRect& wrapRect, std::list& outputList) { + // Always add at least one copy of the unwrapped rect + int addedTimes = 1; + outputList.push_back(wrapRect); + + // Only bother with wrap checking if the scene actually wraps around in X + if (SceneWrapsX()) { + int sceneWidth = GetSceneWidth(); + + if (wrapRect.m_Left < 0) { + outputList.push_back(wrapRect); + outputList.back().m_Left += sceneWidth; + outputList.back().m_Right += sceneWidth; + addedTimes++; + } + if (wrapRect.m_Right >= sceneWidth) { + outputList.push_back(wrapRect); + outputList.back().m_Left -= sceneWidth; + outputList.back().m_Right -= sceneWidth; + addedTimes++; + } + } + + // Only bother with wrap checking if the scene actually wraps around in Y + if (SceneWrapsY()) { + int sceneHeight = GetSceneHeight(); + + if (wrapRect.m_Top < 0) { + outputList.push_back(wrapRect); + outputList.back().m_Top += sceneHeight; + outputList.back().m_Bottom += sceneHeight; + addedTimes++; + } + if (wrapRect.m_Bottom >= sceneHeight) { + outputList.push_back(wrapRect); + outputList.back().m_Top -= sceneHeight; + outputList.back().m_Bottom -= sceneHeight; + addedTimes++; + } + } + + return addedTimes; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + int SceneMan::WrapBox(const Box& wrapBox, std::list& outputList) { + // Unflip the input box, or checking will be tedious + Box flipBox(wrapBox); + flipBox.Unflip(); + + // Always add at least one copy of the unwrapped rect + int addedTimes = 1; + outputList.push_back(flipBox); + + // Only bother with wrap checking if the scene actually wraps around in X + if (SceneWrapsX()) { + int sceneWidth = GetSceneWidth(); + + if (flipBox.m_Corner.m_X < 0) { + outputList.push_back(flipBox); + outputList.back().m_Corner.m_X += sceneWidth; + addedTimes++; + } + if (flipBox.m_Corner.m_X + flipBox.m_Width >= sceneWidth) { + outputList.push_back(flipBox); + outputList.back().m_Corner.m_X -= sceneWidth; + addedTimes++; + } + } + + // Only bother with wrap checking if the scene actually wraps around in Y + if (SceneWrapsY()) { + int sceneHeight = GetSceneHeight(); + + if (flipBox.m_Corner.m_Y < 0) { + outputList.push_back(flipBox); + outputList.back().m_Corner.m_Y += sceneHeight; + addedTimes++; + } + if (flipBox.m_Corner.m_Y + flipBox.m_Height >= sceneHeight) { + outputList.push_back(flipBox); + outputList.back().m_Corner.m_Y -= sceneHeight; + addedTimes++; + } + } + + return addedTimes; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SceneMan::AddSceneObject(SceneObject* sceneObject) { + bool result = false; + if (sceneObject) { + if (MovableObject* sceneObjectAsMovableObject = dynamic_cast(sceneObject)) { + return g_MovableMan.AddMO(sceneObjectAsMovableObject); + } else if (TerrainObject* sceneObjectAsTerrainObject = dynamic_cast(sceneObject)) { + result = m_pCurrentScene && sceneObjectAsTerrainObject->PlaceOnTerrain(m_pCurrentScene->GetTerrain()); + if (result) { + Box airBox(sceneObjectAsTerrainObject->GetPos() + sceneObjectAsTerrainObject->GetBitmapOffset(), static_cast(sceneObjectAsTerrainObject->GetBitmapWidth()), static_cast(sceneObjectAsTerrainObject->GetBitmapHeight())); + m_pCurrentScene->GetTerrain()->CleanAirBox(airBox, GetScene()->WrapsX(), GetScene()->WrapsY()); + } + } + } + delete sceneObject; + return result; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::Update(int screenId) { + ZoneScoped; + + if (!m_pCurrentScene) { + return; + } + + m_LastUpdatedScreen = screenId; + + const Vector& offset = g_CameraMan.GetOffset(screenId); + m_pMOColorLayer->SetOffset(offset); + m_pMOIDLayer->SetOffset(offset); + if (m_pDebugLayer) { + m_pDebugLayer->SetOffset(offset); + } + + SLTerrain* terrain = m_pCurrentScene->GetTerrain(); + terrain->SetOffset(offset); + terrain->Update(); + + // Background layers may scroll in fractions of the real offset and need special care to avoid jumping after having traversed wrapped edges, so they need the total offset without taking wrapping into account. + const Vector& unwrappedOffset = g_CameraMan.GetUnwrappedOffset(screenId); + for (SLBackground* backgroundLayer: m_pCurrentScene->GetBackLayers()) { + backgroundLayer->SetOffset(unwrappedOffset); + backgroundLayer->Update(); + } + + // Update the unseen obstruction layer for this team's screen view, if there is one. + const int teamId = g_CameraMan.GetScreenTeam(screenId); + if (SceneLayer* unseenLayer = (teamId != Activity::NoTeam) ? m_pCurrentScene->GetUnseenLayer(teamId) : nullptr) { + unseenLayer->SetOffset(offset); + } + + if (m_CleanTimer.GetElapsedSimTimeMS() > CLEANAIRINTERVAL) { + terrain->CleanAir(); + m_CleanTimer.Reset(); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::Draw(BITMAP* targetBitmap, BITMAP* targetGUIBitmap, const Vector& targetPos, bool skipBackgroundLayers, bool skipTerrain) { + ZoneScoped; + + if (!m_pCurrentScene) { + return; + } + SLTerrain* terrain = m_pCurrentScene->GetTerrain(); + // Set up the target box to draw to on the target bitmap, if it is larger than the scene in either dimension. + Box targetBox(Vector(), static_cast(targetBitmap->w), static_cast(targetBitmap->h)); + + if (!terrain->WrapsX() && targetBitmap->w > GetSceneWidth()) { + targetBox.SetCorner(Vector(static_cast((targetBitmap->w - GetSceneWidth()) / 2), targetBox.GetCorner().GetY())); + targetBox.SetWidth(static_cast(GetSceneWidth())); + } + if (!terrain->WrapsY() && targetBitmap->h > GetSceneHeight()) { + targetBox.SetCorner(Vector(targetBox.GetCorner().GetX(), static_cast((targetBitmap->h - GetSceneHeight()) / 2))); + targetBox.SetHeight(static_cast(GetSceneHeight())); + } + + switch (m_LayerDrawMode) { + case LayerDrawMode::g_LayerTerrainMatter: + terrain->SetLayerToDraw(SLTerrain::LayerType::MaterialLayer); + terrain->Draw(targetBitmap, targetBox); + break; +#ifdef DRAW_MOID_LAYER + case LayerDrawMode::g_LayerMOID: + m_pMOIDLayer->Draw(targetBitmap, targetBox); + break; +#endif + default: + if (!skipBackgroundLayers) { + for (std::list::reverse_iterator backgroundLayer = m_pCurrentScene->GetBackLayers().rbegin(); backgroundLayer != m_pCurrentScene->GetBackLayers().rend(); ++backgroundLayer) { + (*backgroundLayer)->Draw(targetBitmap, targetBox); + } + } + if (!skipTerrain) { + terrain->SetLayerToDraw(SLTerrain::LayerType::BackgroundLayer); + terrain->Draw(targetBitmap, targetBox); + } + m_pMOColorLayer->Draw(targetBitmap, targetBox); + + if (!skipTerrain) { + terrain->SetLayerToDraw(SLTerrain::LayerType::ForegroundLayer); + terrain->Draw(targetBitmap, targetBox); + } + if (!g_FrameMan.IsInMultiplayerMode()) { + int teamId = g_CameraMan.GetScreenTeam(m_LastUpdatedScreen); + if (SceneLayer* unseenLayer = (teamId != Activity::NoTeam) ? m_pCurrentScene->GetUnseenLayer(teamId) : nullptr) { + unseenLayer->Draw(targetBitmap, targetBox); + } + } + + bool shouldDrawHUD = !g_FrameMan.IsHudDisabled(m_LastUpdatedScreen); + if (shouldDrawHUD) { + g_MovableMan.DrawHUD(targetGUIBitmap, targetPos, m_LastUpdatedScreen); + } + + g_PrimitiveMan.DrawPrimitives(m_LastUpdatedScreen, targetGUIBitmap, targetPos); + + if (shouldDrawHUD) { + g_ActivityMan.GetActivity()->DrawGUI(targetGUIBitmap, targetPos, m_LastUpdatedScreen); + } + +#ifdef DRAW_NOGRAV_BOXES + if (Scene::Area* noGravArea = m_pCurrentScene->GetArea("NoGravityArea")) { + const std::vector& boxList = noGravArea->GetBoxes(); + g_FrameMan.SetTransTableFromPreset(TransparencyPreset::MoreTrans); + drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); + + std::list wrappedBoxes; + for (std::vector::const_iterator bItr = boxList.begin(); bItr != boxList.end(); ++bItr) { + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*bItr, wrappedBoxes); + + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + Vector adjCorner = (*wItr).GetCorner() - targetPos; + rectfill(targetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_RedColor); + } + } + } +#endif + + if (m_pDebugLayer) { + m_pDebugLayer->Draw(targetBitmap, targetBox); + } + + break; + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::ClearMOColorLayer() { + m_pMOColorLayer->ClearBitmap(g_MaskColor); + if (m_pDebugLayer) { + m_pDebugLayer->ClearBitmap(g_MaskColor); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::ClearSeenPixels() { + if (!m_pCurrentScene) + return; + + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) + m_pCurrentScene->ClearSeenPixels(team); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SceneMan::ClearCurrentScene() { + m_pCurrentScene = nullptr; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + BITMAP* SceneMan::GetIntermediateBitmapForSettlingIntoTerrain(int moDiameter) const { + int bitmapSizeNeeded = static_cast(std::ceil(static_cast(moDiameter) / 16.0F)) * 16; + for (const auto& [bitmapSize, bitmapPtr]: m_IntermediateSettlingBitmaps) { + if (std::min(bitmapSize, bitmapSizeNeeded) >= bitmapSizeNeeded) { + return bitmapPtr; + } } + return m_IntermediateSettlingBitmaps.back().second; } - return m_IntermediateSettlingBitmaps.back().second; -} -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/SceneMan.h b/Source/Managers/SceneMan.h index 7873c254d..e4a781aee 100644 --- a/Source/Managers/SceneMan.h +++ b/Source/Managers/SceneMan.h @@ -10,7 +10,6 @@ // data@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -24,1496 +23,1405 @@ #define g_SceneMan SceneMan::Instance() -namespace RTE -{ - -class Scene; -class SceneLayer; -class SceneLayerTracked; -class SLTerrain; -class SceneObject; -class TerrainObject; -class MovableObject; -class Material; -class SoundContainer; -struct PostEffect; - -// Different modes to draw the SceneLayers in -enum LayerDrawMode -{ - g_LayerNormal = 0, - g_LayerTerrainMatter, +namespace RTE { + + class Scene; + class SceneLayer; + class SceneLayerTracked; + class SLTerrain; + class SceneObject; + class TerrainObject; + class MovableObject; + class Material; + class SoundContainer; + struct PostEffect; + + // Different modes to draw the SceneLayers in + enum LayerDrawMode { + g_LayerNormal = 0, + g_LayerTerrainMatter, #ifdef DRAW_MOID_LAYER - g_LayerMOID + g_LayerMOID #endif -}; + }; #define SCENEGRIDSIZE 24 #define SCENESNAPSIZE 12 #define MAXORPHANRADIUS 11 - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: SceneMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The singleton manager of all terrain and backgrounds in the RTE. -// Parent(s): Singleton, Serializable. -// Class history: 12/25/2001 SceneMan created. - -class SceneMan : public Singleton, public Serializable { - friend class SettingsMan; - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - SerializableClassNameGetter; - SerializableOverrideMethods; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: SceneMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a SceneMan object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - SceneMan() { m_pOrphanSearchBitmap = 0; Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~SceneMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a SceneMan object before deletion -// from system memory. -// Arguments: None. - - ~SceneMan() { Destroy(); } - - - /// - /// Makes the SceneMan object ready for use. - /// - void Initialize() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SceneMan object ready for use. -// Arguments: A string with the filepath to a Reader file from screen this SceneMan's -// data should be created. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(std::string readerFile); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetDefaultSceneName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the instance name of the default Scene to be loaded if nothing -// else is available. -// Arguments: The default scene instance name. -// Return value: None. - - void SetDefaultSceneName(std::string defaultSceneName) { m_DefaultSceneName = defaultSceneName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDefaultSceneName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the name of the default A to be loaded if nothing -// else is available. -// Arguments: None. -// Return value: The default Scene instance name. - - std::string GetDefaultSceneName() const { return m_DefaultSceneName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Actually loads a new Scene into memory. has to be done before using -// this object. -// Arguments: The instance of the Scene, ownership IS transferred! -// Whether the scene should actually apply all its SceneObject:s placed -// in its definition. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int LoadScene(Scene *pNewScene, bool placeObjects = true, bool placeUnits = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSceneToLoad -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Stores a Scene reference to be loaded later into the SceneMan. -// Arguments: The instance reference of the Scene, ownership IS NOT (!!) transferred! -// Whether the scene should actually apply all its SceneObject:s placed -// in its definition. -// Return value: None. - - void SetSceneToLoad(const Scene *pLoadScene, bool placeObjects = true, bool placeUnits = true) { m_pSceneToLoad = pLoadScene; m_PlaceObjects = placeObjects; m_PlaceUnits = placeUnits; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetSceneToLoad -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets a scene to load later, by preset name. -// Arguments: The name of the Scene preset instance to load. -// Whether the scene should actually apply all its SceneObject:s placed -// in its definition. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int SetSceneToLoad(std::string sceneName, bool placeObjects = true, bool placeUnits = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneToLoad -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the stored Scene reference to be loaded later into the SceneMan. -// Arguments: None. -// Return value: The instance reference of the Scene, ownership IS NOT (!!) transferred! - - const Scene * GetSceneToLoad() { return m_pSceneToLoad; } - - /// - /// Gets whether objects are placed when the Scene is initially started. Used for saving/loading games. - /// - /// Whether objects are placed when the Scene is initially started. - bool GetPlaceObjectsOnLoad() const { return m_PlaceObjects; } - - /// - /// Gets whether units are placed when the Scene is initially started. Used for saving/loading games. - /// - /// Whether units are placed when the Scene is initially started. - bool GetPlaceUnitsOnLoad() const { return m_PlaceUnits; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Actually loads the Scene set to be loaded in SetSceneToLoad. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int LoadScene(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads a Scene right now, by preset name. -// Arguments: The name of the Scene preset instance to load. -// Whether the scene should actually apply all its SceneObject:s placed -// in its definition. -// Whether the scene should actually deploy all units placed in its definition. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int LoadScene(std::string sceneName, bool placeObjects = true, bool placeUnits = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads a Scene right now, by preset name. -// Arguments: The name of the Scene preset instance to load. -// Whether the scene should actually apply all its SceneObject:s placed -// in its definition. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int LoadScene(std::string sceneName, bool placeObjects = true) { return LoadScene(sceneName, placeObjects, true); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire SceneMan, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneMan object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the currently loaded scene, if any. -// Arguments: None. -// Return value: The scene, ownership IS NOT TRANSFERRED! - - Scene * GetScene() const { return m_pCurrentScene; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneDim -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total dimensions (width and height) of the scene, in pixels. -// Arguments: None. -// Return value: A Vector describing the scene dimensions. - - Vector GetSceneDim() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneWidth -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total width of the scene, in pixels. -// Arguments: None. -// Return value: An int describing the scene width. - - int GetSceneWidth() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetSceneHeight -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total height of the scene, in pixels. -// Arguments: None. -// Return value: An int describing the scene width. - - int GetSceneHeight() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaterialPalette -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets access to the whole material palette array of 256 entries. -// Arguments: None. -// Return value: A const reference to the material palette array. - - const std::array & GetMaterialPalette() const { return m_apMatPalette; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaterial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a specific material by name. Ownership is NOT transferred! -// Arguments: The string name of the Material to get. -// Return value: A pointer to the requested material, or 0 if no material with that -// name was found. - - Material const * GetMaterial(const std::string &matName); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMaterialFromID -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a specific material from the material palette. Ownership is NOT -// transferred! -// Arguments: The unsigned char index specifying screen material to get (0-255). -// Return value: A reference to the requested material. OWNERSHIP IS NOT TRANSFERRED! - - Material const * GetMaterialFromID(unsigned char screen) { return screen >= 0 && screen < c_PaletteEntriesNumber && m_apMatPalette[screen] ? m_apMatPalette[screen] : m_apMatPalette[g_MaterialAir]; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SceneWrapsX -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the scene wraps its scrolling around the X axis. -// Arguments: None. -// Return value: Whether the scene wraps around the X axis or not. - - bool SceneWrapsX() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SceneWrapsY -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the scene wraps its scrolling around the Y axis. -// Arguments: None. -// Return value: Whether the scene wraps around the Y axis or not. - - bool SceneWrapsY() const; - - /// - /// Gets the orbit direction for the current scene. - /// - /// The orbit direction for the current scene. - Directions GetSceneOrbitDirection() const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTerrain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the SLTerrain, or 0 if no scene is loaded. -// Arguments: None. -// Return value: A pointer to the SLTerrain. Ownership is NOT transferred! - - SLTerrain * GetTerrain(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMOColorBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bitmap of the intermediary collection SceneLayer that all -// MovableObject:s draw themselves onto before it itself gets drawn onto -// the screen back buffer. -// Arguments: None. -// Return value: A BITMAP pointer to the MO bitmap. Ownership is NOT transferred! - - BITMAP * GetMOColorBitmap() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDebugBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bitmap of the SceneLayer that debug graphics is drawn onto. -// Will only return valid BITMAP if building with DEBUG_BUILD. -// Arguments: None. -// Return value: A BITMAP pointer to the debug bitmap. Ownership is NOT transferred! - - BITMAP * GetDebugBitmap() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMOIDBitmap -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the bitmap of the SceneLayer that all MovableObject:s draw thir -// current (for the frame only!) MOID's onto. -// Arguments: None. -// Return value: A BITMAP pointer to the MO bitmap. Ownership is NOT transferred! - - BITMAP * GetMOIDBitmap() const; - -// TEMP! -////////////////////////////////////////////////////////////////////////////////////////// -// Method: MOIDClearCheck -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes sure the MOID bitmap layer is completely of NoMOID color. -// If found to be not, dumps MOID layer and the FG actor color layer for -// debugging. -// Arguments: None. -// Return value: Was it clear? - - bool MOIDClearCheck(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLayerDrawMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current drawing mode of the SceneMan. -// Arguments: None. -// Return value: The current layer draw mode, see the LayerDrawMode enumeration for the -// different possible mode settings. - - int GetLayerDrawMode() const { return m_LayerDrawMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTerrMatter -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets a specific pixel from the total material representation of -// this Scene. LockScene() must be called before using this method. -// Arguments: The X and Y coordinates of screen material pixel to get. -// Return value: An unsigned char specifying the requested pixel's material index. - - unsigned char GetTerrMatter(int pixelX, int pixelY); - - - /// - /// Gets a MOID from pixel coordinates in the Scene. LockScene() must be called before using this method. - /// - /// The X coordinate of the Scene pixel to test. - /// The Y coordinate of the Scene pixel to test. - /// The team to ignore. - /// The MOID currently at the specified pixel coordinates. - MOID GetMOIDPixel(int pixelX, int pixelY, int ignoreTeam); - - /// - /// Gets a MOID from pixel coordinates in the Scene. LockScene() must be called before using this method. - /// - /// The X coordinate of the Scene pixel to test. - /// The Y coordinate of the Scene pixel to test. - /// The MOID currently at the specified pixel coordinates. - MOID GetMOIDPixel(int pixelX, int pixelY) { return GetMOIDPixel(pixelX, pixelY, Activity::NoTeam); } - - /// - /// Gets this Scene's MOID SpatialPartitionGrid. - /// - /// This Scene's MOID SpatialPartitionGrid. - const SpatialPartitionGrid & GetMOIDGrid() const { return m_MOIDsGrid; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGlobalAcc -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the global acceleration (in m/s^2) that is applied to all movable -// objects' velocities during every frame. Typically models gravity. -// Arguments: None. -// Return value: A Vector describing the global acceleration. - - Vector GetGlobalAcc() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOzPerKg -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how many Ounces there are in a metric Kilogram -// Arguments: None. -// Return value: A float describing the Oz/Kg ratio. - - float GetOzPerKg() const { return 35.27396; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetKgPerOz -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets how many metric Kilograms there are in an Ounce. -// Arguments: None. -// Return value: A float describing the Kg/Oz ratio. - - float GetKgPerOz() const { return 0.02834952; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetLayerDrawMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the drawing mode of the SceneMan, to easily view what's going on -// in the different internal SceneLayer:s. -// Arguments: The layer mode to draw in, see the LayerDrawMode enumeration for the -// different possible settings. -// Return value: None. - - void SetLayerDrawMode(int mode) { m_LayerDrawMode = mode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LockScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Locks all dynamic internal scene bitmaps so that manipulaitons of the -// scene's color and matter representations can take place. -// Doing it in a separate method like this is more efficient because -// many bitmap manipulaitons can be performed between a lock and unlock. -// UnlockScene() should always be called after accesses are completed. -// Arguments: None. -// Return value: None. - - void LockScene(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UnlockScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Unlocks the scene's bitmaps and prevents access to display memory. -// Doing it in a separate method like this is more efficient because -// many bitmap accesses can be performed between a lock and an unlock. -// UnlockScene() should only be called after LockScene(). -// Arguments: None. -// Return value: None. - - void UnlockScene(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SceneIsLocked -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Indicates whether the entire scene is currently locked or not. -// Arguments: None. -// Return value: Whether the entire scene is currently locked or not. - - bool SceneIsLocked() const; - - /// - /// Registers an area to be drawn upon, so it can be tracked and cleared later. - /// - /// The bitmap being drawn upon. - /// The MOID, if we're drawing MOIDs. - /// The left boundary of the draw area. - /// The top boundary of the drawn area. - /// The right boundary of the draw area. - /// The bottom boundary of the draw area. - void RegisterDrawing(const BITMAP *bitmap, int moid, int left, int top, int right, int bottom); - - /// - /// Registers an area of to be drawn upon, so it can be tracked and cleared later. - /// - /// The bitmap being drawn upon. - /// The MOID, if we're drawing MOIDs. - /// The centre position of the drawn area. - /// The radius of the drawn area. - void RegisterDrawing(const BITMAP *bitmap, int moid, const Vector ¢er, float radius); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearAllMOIDDrawings -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all registered drawn areas of the MOID layer to the g_NoMOID -// color and clears the registrations too. Should be done each sim update. -// Arguments: None. -// Return value: None. - - void ClearAllMOIDDrawings(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WillPenetrate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Test whether a pixel of the scene would be knocked loose and -// turned into a MO by another particle of a certain material going at a -// certain velocity. Scene needs to be locked to do this! -// Arguments: The X and Y coords of the scene pixel that is collided with. -// The velocity of the incoming particle. -// The mass of the incoming particle. -// Return value: A bool indicating wether the scene pixel would be knocked loose or -// not. If the pixel location specified happens to be of the air -// material (0) false will be returned here. - - bool WillPenetrate(const int posX, - const int posY, - const Vector &velocity, - const float mass) { return WillPenetrate(posX, posY, velocity * mass); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WillPenetrate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Test whether a pixel of the scene would be knocked loose and -// turned into a MO by a certian impulse force. Scene needs to be locked -// to do this! -// Arguments: The X and Y coords of the scene pixel that is collided with. -// The impulse force vector, in Kg * m/s. -// Return value: A bool indicating wether the scene pixel would be knocked loose or -// not. If the pixel location specified happens to be of the air -// material (0) false will be returned here. - - bool WillPenetrate(const int posX, - const int posY, - const Vector &impulse); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TryPenetrate -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculate whether a pixel of the scene would be knocked loose and -// turned into a MO by another particle of a certain material going at a -// certain velocity. If so, the incoming particle will knock loose the -// specified pixel in the scene and momentarily take its place. -// Scene needs to be locked to do this! -// Arguments: The X and Y coord of the scene pixel that is to be collided with. -// The impulse force exerted on the terrain pixel. If this magnitude -// exceeds the strength threshold of the material of the terrain pixel -// hit, the terrain pixel will be knocked loose an turned into an MO. -// The velocity of the the point hitting the terrain here. -// A float reference screen will be set to the factor with screen to -// multiply the collision velocity to get the resulting retardation -// (negative acceleration) that occurs when a penetration happens. -// The normalized probability ratio between 0.0 and 1.0 that determines -// the chance of a penetration to remove a pixel from the scene and -// thus replace it with and air pixel. 1.0 = always, 0.0 = never. -// How many consecutive penetrations in a row immediately before this try. -// The size of the area to look for orphaned terrain elements. -// Max area or orphaned area to remove. -// Orphan area removal trigger rate. -// Return value: A bool indicating wether the scene pixel was knocked loose or not. -// If the pixel location specified happens to be of the air material (0) -// false will be returned here. - - bool TryPenetrate(int posX, - int posY, - const Vector &impulse, - const Vector &velocity, - float &retardation, - const float airRatio, - const int numPenetrations = 0, - const int removeOrphansRadius = 0, - const int removeOrphansMaxArea = 0, - const float removeOrphansRate = 0.0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveOrphans -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the area of an orphaned region at specified coordinates. -// Arguments: Coordinates to check for region, whether the orphaned region should be converted into MOPixels and region removed. -// Area of orphaned object calculated during recursve function call to check if we're out of limits -// Size of the are to look for orphaned objects -// Max area of orphaned object to remove -// Whether to actually remove orphaned pixels or not -// Whether to clear internal terrain tracking bitmap or not -// Return value: The area of orphaned region at posX,posY - - int RemoveOrphans(int posX, int posY, int radius, int maxArea, bool remove = false); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveOrphans -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the area of an orphaned region at specified coordinates. -// Arguments: Coordinates to check for region, whether the orphaned region should be converted into MOPixels and region removed. -// Coordinates of initial terrain penetration to check, which serves as a center of orphaned object detection. -// Area of orphaned object calculated during recursve function call to check if we're out of limits -// Size of the are to look for orphaned objects -// Max area of orphaned object to remove -// Whether to actually remove orphaned pixels or not -// Whether to clear internal terrain tracking bitmap or not -// Return value: The area of orphaned region at posX,posY - - int RemoveOrphans(int posX, - int posY, - int centerPosX, - int centerPosY, - int accumulatedArea, - int radius, - int maxArea, - bool remove = false); - - /// - /// Removes a pixel from the terrain and adds it to MovableMan. - /// - /// The X coordinate of the terrain pixel. - /// The Y coordinate of the terrain pixel. - /// The newly dislodged pixel, if one was found. - MovableObject * DislodgePixel(int posX, int posY); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: MakeAllUnseen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets one team's view of the scene to be unseen, using a generated map -// of a specific resolution chunkiness. -// Arguments: The dimensions of the pixels that should make up the unseen layer. -// The team we're talking about. -// Return value: None. - - void MakeAllUnseen(Vector pixelSize, const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: MakeAllSeen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets one team's view of the scene to be all seen. -// Arguments: The team we're talking about. -// Return value: None. - - void MakeAllSeen(const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadUnseenLayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads a bitmap from file and use it as the unseen layer for a team. -// Arguments: The path to the bitmap to use as the unseen layer. -// Which team we're talking about. -// Return value: Whether the loading was successful or not. - - bool LoadUnseenLayer(std::string bitmapPath, const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AnythingUnseen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a team has anything still unseen on the scene. -// Arguments: The team we're talking about. -// Return value: A bool indicating whether that team has anyhting yet unseen. - - bool AnythingUnseen(const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetUnseenResolution -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows what the resolution factor of the unseen map to the entire Scene -// is, in both axes. -// Arguments: The team we're talking about. -// Return value: A vector witht he factors in each element representing the factors. - - Vector GetUnseenResolution(const int team) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsUnseen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether a pixel is in an unseen area on of a specific team. -// Arguments: The X and Y coords of the scene pixel that is to be checked. -// The team we're talking about. -// Return value: A bool indicating whether that point is yet unseen. - - bool IsUnseen(const int posX, const int posY, const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RevealUnseen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reveals a pixel on the unseen map for a specific team, if there is any. -// Arguments: The X and Y coord of the scene pixel that is to be revealed. -// The team to reveal for. -// Return value: A bool indicating whether there was an unseen pixel revealed there. - - bool RevealUnseen(const int posX, const int posY, const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RestoreUnseen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Hides a pixel on the unseen map for a specific team, if there is any. -// Arguments: The X and Y coord of the scene pixel that is to be revealed. -// The team to hide for. -// Return value: A bool indicating whether there was a seen pixel hidden there. - - bool RestoreUnseen(const int posX, const int posY, const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RevealUnseenBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reveals a box on the unseen map for a specific team, if there is any. -// Arguments: The X and Y coords of the upper left corner of the box to be revealed. -// The width and height of the box to be revealed, in scene units (pixels) -// The team to reveal for. -// Return value: None. - - void RevealUnseenBox(const int posX, const int posY, const int width, const int height, const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RestoreUnseenBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Restores a box on the unseen map for a specific team, if there is any. -// Arguments: The X and Y coords of the upper left corner of the box to be revealed. -// The width and height of the box to be restored, in scene units (pixels) -// The team to restore for. -// Return value: None. - - void RestoreUnseenBox(const int posX, const int posY, const int width, const int height, const int team); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastUnseenRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and reveals or hides pixels on the unseen layer of a team -// as long as the accumulated material strengths traced through the terrain -// don't exceed a specific value. -// Arguments: The team to see for. -// The starting position. -// The vector to trace along. -// A Vector that will be set to the position of where the sight ray was -// terminated. If it reached the end, it will be set to the end of the ray. -// The material strength limit where -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Whether the ray should reveal or restore unseen layer -// Return value: Whether any unseen pixels were revealed as a result of this seeing. - - bool CastUnseenRay(int team, const Vector &start, const Vector &ray, Vector &endPos, int strengthLimit, int skip, bool reveal); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastSeeRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and reveals pixels on the unseen layer of a team -// as long as the accumulated material strengths traced through the terrain -// don't exceed a specific value. -// Arguments: The team to see for. -// The starting position. -// The vector to trace along. -// A Vector that will be set to the position of where the sight ray was -// terminated. If it reached the end, it will be set to the end of the ray. -// The material strength limit where -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Return value: Whether any unseen pixels were revealed as a result of this seeing. - - bool CastSeeRay(int team, const Vector &start, const Vector &ray, Vector &endPos, int strengthLimit, int skip = 0); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastUnseeRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and hides pixels on the unseen layer of a team -// as long as the accumulated material strengths traced through the terrain -// don't exceed a specific value. -// Arguments: The team to see for. -// The starting position. -// The vector to trace along. -// A Vector that will be set to the position of where the sight ray was -// terminated. If it reached the end, it will be set to the end of the ray. -// The material strength limit where -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Return value: Whether any unseen pixels were revealed as a result of this seeing. - - bool CastUnseeRay(int team, const Vector &start, const Vector &ray, Vector &endPos, int strengthLimit, int skip = 0); - - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastMaterialRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and gets the location of the first encountered -// pixel of a specific material in the terrain. -// Arguments: The starting position. -// The vector to trace along. -// The material ID to look for. -// A reference to the vector screen will be filled out with the absolute -// location of the found terrain pixel of the above material. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Whetehr the ray should wrap around the scene if it crosses a seam. -// Return value: Whether the material was found along the ray. If not, the fourth -// parameter will not have been altered (and may still not be 0!) - - bool CastMaterialRay(const Vector &start, const Vector &ray, unsigned char material, Vector &result, int skip = 0, bool wrap = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastMaterialRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and returns how far along that ray there is an -// encounter with a pixel of a specific material in the terrain. -// Arguments: The starting position. -// The vector to trace along. -// The material ID to look for. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Return value: How far along, in pixel units, the ray the material pixel was encountered. -// If no pixel of the right material was found, < 0 is returned. - - float CastMaterialRay(const Vector &start, const Vector &ray, unsigned char material, int skip = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastNotMaterialRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and gets the location of the first encountered -// pixel that is NOT of a specific material in the scene's terrain. -// Arguments: The starting position. -// The vector to trace along. -// The material ID to find something OTHER than. -// A reference to the vector screen will be filled out with the absolute -// location of the found terrain pixel of the above material. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Whether to check for MO layer collisions as well, not just terrain. -// Return value: Whether the a pixel other than the material was found along the ray. -// If not, the fourth parameter will not have been altered (and may still not be 0!) - - bool CastNotMaterialRay(const Vector &start, const Vector &ray, unsigned char material, Vector &result, int skip = 0, bool checkMOs = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastNotMaterialRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and returns how far along that ray there is an -// encounter with a pixel of OTHER than a specific material in the terrain. -// Arguments: The starting position. -// The vector to trace along. -// The material ID to find something OTHER than. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Whether to check for MO layer collisions as well, not just terrain. -// Return value: How far along, in pixel units, the ray the pixel of any other material -// was encountered. If no pixel of the right material was found, < 0 is returned. - - float CastNotMaterialRay(const Vector &start, const Vector &ray, unsigned char material, int skip = 0, bool checkMOs = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastStrengthSumRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and returns how the sum of all encountered pixels' -// material strength values. This will take wrapping into account. -// Arguments: The starting position. -// The ending position. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// A material ID to ignore, IN ADDITION to Air. -// Return value: The sum of all encountered pixels' material strength vales. So if it was -// all Air, then 0 is returned (Air's strength value is 0). - - float CastStrengthSumRay(const Vector &start, const Vector &end, int skip = 0, unsigned char ignoreMaterial = g_MaterialAir); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastMaxStrengthRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and returns the strongest of all encountered pixels' -// material strength values. -// This will take wrapping into account. -// Arguments: The starting position. -// The ending position. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// A material ID to ignore, IN ADDITION to Air. This defaults to doors, for legacy script purposes -// Return value: The max of all encountered pixels' material strength vales. So if it was -// all Air, then 0 is returned (Air's strength value is 0). - - // We use two accessors instead of default parameters, for lua compat - float CastMaxStrengthRay(const Vector &start, const Vector &end, int skip, unsigned char ignoreMaterial); - float CastMaxStrengthRay(const Vector &start, const Vector &end, int skip) { return CastMaxStrengthRay(start, end, skip, g_MaterialDoor); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastMaxStrengthRayMaterial -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and returns the strongest of all encountered pixels' materials -// This will take wrapping into account. -// Arguments: The starting position. -// The ending position. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// A material ID to ignore, IN ADDITION to Air. -// Return value: The strongest material encountered - const Material * CastMaxStrengthRayMaterial(const Vector &start, const Vector &end, int skip, unsigned char ignoreMaterial); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastStrengthRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and shows where along that ray there is an -// encounter with a pixel of a material with strength more than or equal -// to a specific value. -// Arguments: The starting position. -// The vector to trace along. -// The strength value of screen any found to be equal or more than will -// terminate the ray. -// A reference to the vector screen will be filled out with the absolute -// location of the found terrain pixel of less than or equal to above strength. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// A material ID to ignore, IN ADDITION to Air. -// Whetehr the ray should wrap around the scene if it crosses a seam. -// Return value: Whether a material of equal or more strength was found along the ray. -// If not, the fourth parameter have been set to last position of the ray. - - bool CastStrengthRay(const Vector &start, const Vector &ray, float strength, Vector &result, int skip = 0, unsigned char ignoreMaterial = g_MaterialAir, bool wrap = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastWeaknessRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and shows where along that ray there is an -// encounter with a pixel of a material with strength less than or equal -// to a specific value. -// Arguments: The starting position. -// The vector to trace along. -// The strength value of screen any found to be equal or less than will -// terminate the ray. -// A reference to the vector screen will be filled out with the absolute -// location of the found terrain pixel of less than or equal to above strength. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Whetehr the ray should wrap around the scene if it crosses a seam. -// Return value: Whether a material of equal or less strength was found along the ray. -// If not, the fourth parameter have been set to last position of the ray. - - bool CastWeaknessRay(const Vector &start, const Vector &ray, float strength, Vector &result, int skip = 0, bool wrap = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastMORay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and returns MOID of the first non-ignored -// non-NoMOID MO encountered. If a non-air terrain pixel is encountered -// first, g_NoMOID will be returned. -// Arguments: The starting position. -// The vector to trace along. -// An MOID to ignore. Any child MO's of this MOID will also be ignored. -// To enable ignoring of all MOIDs associated with an object of a specific -// team which also has team ignoring enabled itself. -// A specific material ID to ignore hits with. -// Whether to ignore all terrain hits or not. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Return value: The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. - - MOID CastMORay(const Vector &start, const Vector &ray, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastFindMORay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and shows where a specific MOID has been found. -// Arguments: The starting position. -// The vector to trace along. -// An MOID to find. Any child MO's of this MOID will also be found. ------------ ??? -// A reference to the vector screen will be filled out with the absolute -// location of the found MO pixel of the above MOID. -// A specific material ID to ignore hits with. -// Whether to ignore all terrain hits or not. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Return value: Whether the target MOID was found along the ray or not. - - bool CastFindMORay(const Vector &start, const Vector &ray, MOID targetMOID, Vector &resultPos, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CastObstacleRay -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Traces along a vector and returns the length of how far the trace went -// without hitting any non-ignored terrain material or MOID at all. -// Arguments: The starting position. -// The vector to trace along. -// A reference to the vector screen will be filled out with the absolute -// location of the first obstacle, or the end of the ray if none was hit. -// A reference to the vector screen will be filled out with the absolute -// location of the last free position before hitting an obstacle, or the -// end of the ray if none was hit. This is only altered if thre are any -// free pixels encountered. -// An MOID to ignore. Any child MO's of this MOID will also be ignored. -// To enable ignoring of all MOIDs associated with an object of a specific -// team which also has team ignoring enabled itself. -// A specific material ID to ignore hits with. -// For every pixel checked along the line, how many to skip between them -// for optimization reasons. 0 = every pixel is checked. -// Return value: How far along, in pixel units, the ray the pixel of any obstacle was -// encountered. If no pixel of the right material was found, < 0 is returned. -// If an obstacle on the starting position was encountered, 0 is returned. - - float CastObstacleRay(const Vector &start, const Vector &ray, Vector &obstaclePos, Vector &freePos, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, int skip = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLastRayHitPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the abosulte pos of where the last cast ray hit somehting. -// Arguments: None. -// Return value: A vector with the absolute pos of where the last ray cast hit somehting. - - const Vector& GetLastRayHitPos(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FindAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the altitide of a certain point above the terrain, measured -// in pixels. -// Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. -// The accuracy within screen measurement is acceptable. Higher number -// here means less calculation. -// Return value: The altitude over the terrain, in pixels. - - float FindAltitude(const Vector &from, int max, int accuracy, bool fromSceneOrbitDirection); - float FindAltitude(const Vector &from, int max, int accuracy) { return FindAltitude(from, max, accuracy, false); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: OverAltitude -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the altitide of a certain point above the terrain, measured -// in pixels, and then tells if that point is over a certain value. -// Arguments: The altitude threshold you want to check for. -// The accuracy within screen measurement is acceptable. Higher number -// here means less costly. -// Return value: Whether the point is over the threshold altitude or not. - - bool OverAltitude(const Vector &point, int threshold, int accuracy = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: MovePointToGround -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes an arbitrary point in the air and calculates it to be straight -// down at a certain maximum distance from the ground. -// Arguments: The point to start from. Should be in the air, or the same point will -// be returned (null operation) -// The max altitude in px you want the point to be above the ground. -// The accuracy within screen measurement is acceptable. Higher number -// here means less calculation. -// Return value: The new point screen is no higher than accuracy + max altitude over -// the terrain. - - Vector MovePointToGround(const Vector &from, int maxAltitude = 0, int accuracy = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsWithinBounds -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether the integer coordinates passed in are within the -// bounds of the current Scene, considering its wrapping. -// Arguments: Int coordinates. -// A margin -// Return value: Whether within bounds or not, considering wrapping. - - bool IsWithinBounds(const int pixelX, const int pixelY, const int margin = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ForceBounds -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Wraps or bounds a position coordinate if it is off bounds of the -// Scene, depending on the wrap settings of this Scene. -// Arguments: The X and Y coordinates of the position to wrap, if needed. -// Return value: Whether wrapping was performed or not. (Does not report on bounding) - - bool ForceBounds(int &posX, int &posY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ForceBounds -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Wraps or bounds a position coordinate if it is off bounds of the -// Scene, depending on the wrap settings of this Scene. -// Arguments: The vector coordinates of the position to wrap, if needed. -// Return value: Whether wrapping was performed or not. (Does not report on bounding) - - bool ForceBounds(Vector &pos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapPosition -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Only wraps a position coordinate if it is off bounds of the Scene -// and wrapping in the corresponding axes are turned on. -// Arguments: The X and Y coordinates of the position to wrap, if needed. -// Return value: Whether wrapping was performed or not. - - bool WrapPosition(int &posX, int &posY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapPosition -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Only wraps a position coordinate if it is off bounds of the Scene -// and wrapping in the corresponding axes are turned on. -// Arguments: The vector coordinates of the position to wrap, if needed. -// Return value: Whether wrapping was performed or not. - - bool WrapPosition(Vector &pos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SnapPosition -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a position snapped to the current scene grid. -// Arguments: The vector coordinates of the position to snap. -// Whether to actually snap or not. This is useful for cleaner toggle code. -// Return value: The new snapped position. - - Vector SnapPosition(const Vector &pos, bool snap = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ShortestDistance -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the shortest distance between two points in scene -// coordinates, taking into account all wrapping and out of bounds of the -// two points. -// Arguments: The two Vector coordinates of the two positions to find the shortest -// distance between. -// Whether to check if the passed in points are outside the scene, and to -// wrap them if they are. -// Return value: The resulting vector screen shows the shortest distance, spanning over -// wrapping borders etc. Basically the ideal pos2 - pos1. - - Vector ShortestDistance(Vector pos1, Vector pos2, bool checkBounds = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ShortestDistanceX -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the shortest distance between two x values in scene -// coordinates, taking into account all wrapping and out of bounds of the -// two values. -// Arguments: The X coordinates of the two values to find the shortest distance between. -// Whether to check if the passed in points are outside the scene, and to -// wrap them if they are. -// Whether to constrain the distance to only be in a certain direction: -// 0 means no constraint, < 0 means only look in the negative dir, etc. -// If the scene doesn't wrap in the constraint's direction, the constraint -// will be ignored. -// Return value: The resulting X value screen shows the shortest distance, spanning over -// wrapping borders etc. Basically the ideal val2 - val1. - - float ShortestDistanceX(float val1, float val2, bool checkBounds = false, int direction = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ShortestDistanceY -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Calculates the shortest distance between two Y values in scene -// coordinates, taking into account all wrapping and out of bounds of the -// two values. -// Arguments: The Y coordinates of the two values to find the shortest distance between. -// Whether to check if the passed in points are outside the scene, and to -// wrap them if they are. -// Whether to constrain the distance to only be in a certain direction: -// 0 means no constraint, < 0 means only look in the negative dir, etc. -// If the scene doesn't wrap in the constraint's direction, the constraint -// will be ignored. -// Return value: The resulting Y value screen shows the shortest distance, spanning over -// wrapping borders etc. Basically the ideal val2 - val1. - - float ShortestDistanceY(float val1, float val2, bool checkBounds = false, int direction = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ObscuredPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a point on the scene is obscured by MOID or Terrain -// non-air material. -// Arguments: The point on the scene to check. -// Wheter to also check for unseen areas of a specific team. -1 means -// don't check this. -// Return value: Whether that point is obscured/obstructed or not. - - bool ObscuredPoint(Vector &point, int team = -1) { return ObscuredPoint(point.GetFloorIntX(), point.GetFloorIntY()); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ObscuredPoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a point on the scene is obscured by MOID or Terrain -// non-air material. -// Arguments: The point on the scene to check. -// Wheter to also check for unseen areas of a specific team. -1 means -// don't check this. -// Return value: Whether that point is obscured/obstructed or not. - - bool ObscuredPoint(int x, int y, int team = -1); - -/* -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SceneRectsIntersect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether two IntRect:s in the scene intersect, while taking -// wrapping into account. -// Arguments: The point on the scene to check. -// Return value: Whether that point is obscured/obstructed or not. - - bool SceneRectsIntersect(int x, int y); -*/ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapRect -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes a rect and adds all possible wrapped appearances of that rect -// to a passed-in list. IF if a passed in rect straddles the seam of a -// wrapped scene axis, it will be added twice to the output list. If it -// doesn't straddle any seam, it will be only added once. -// Arguments: The IntRect to check for wrapping of and add to the output list below. -// A reference to a list of IntRect:s that will only be added to, never -// cleared. -// Return value: How many additions of the passed in rect was added to the list. 1 if -// no wrapping need was detected, up to 4 possible (if straddling both seams) - - int WrapRect(const IntRect &wrapRect, std::list &outputList); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: WrapBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes a Box and adds all possible scenewrapped appearances of that Box -// to a passed-in list. IF if a passed in rect straddles the seam of a -// wrapped scene axis, it will be added twice to the output list. If it -// doesn't straddle any seam, it will be only added once. -// Arguments: The IntRect to check for wrapping of and add to the output list below. -// A reference to a list of IntRect:s that will only be added to, never -// cleared. -// Return value: How many additions of the passed in Box was added to the list. 1 if -// no wrapping need was detected, up to 4 possible (if straddling both seams) - - int WrapBox(const Box &wrapBox, std::list &outputList); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddSceneObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Takes any scene object and adds it to the scene in the appropriate way. -// If it's a TerrainObject, then it gets applied to the terrain, if it's -// an MO, it gets added to the correct type group in MovableMan. -// Arguments: The SceneObject to add. Ownership IS transferred! -// Return value: Whether the SceneObject was successfully added or not. Either way, -// ownership was transferred. If no success, the object was deleted. - - bool AddSceneObject(SceneObject *pObject); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this SceneMan. Supposed to be done every frame -// before drawing. -// Arguments: Which screen to update for. -// Return value: None. - - void Update(int screenId = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws this SceneMan's current graphical representation to a -// BITMAP of choice. -// Arguments: A pointer to a BITMAP to draw on, appropriately sized for the split -// screen segment. -// The offset into the scene where the target bitmap's upper left corner -// is located. -// Return value: None. - - void Draw(BITMAP *targetBitmap, BITMAP *targetGUIBitmap, const Vector &targetPos = Vector(), bool skipBackgroundLayers = false, bool skipTerrain = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearMOColorLayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the color MO layer. Should be done every frame. -// Arguments: None. -// Return value: None. - - void ClearMOColorLayer(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearSeenPixels -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the list of pixels on the unseen map that have been revealed. -// Arguments: None. -// Return value: None. - - void ClearSeenPixels(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddMaterialCopy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Creates a copy of passed material and stores it into internal vector -// to make sure there's only one material owner -// Arguments: Material to add. -// Return value: Pointer to stored material. - - Material * AddMaterialCopy(Material *mat); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RegisterTerrainChange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Registers terrain change event for the network server to be then sent to clients. -// Arguments: x,y - scene coordinates of change, w,h - size of the changed region, -// color - changed color for one-pixel events, -// back - if true, then background bitmap was changed if false then foreground. -// Return value: None. - - void RegisterTerrainChange(int x, int y, int w, int h, unsigned char color, bool back); - - - /// - /// Gets an intermediate bitmap that is used for drawing a settled MovableObject into the terrain. - /// - /// The diameter of the MovableObject to calculate the required bitmap size. - /// Pointer to the temp BITMAP of the appropriate size. Ownership is NOT transferred! - BITMAP * GetIntermediateBitmapForSettlingIntoTerrain(int moDiameter) const; - - /// - /// Sets the current scene pointer to null - /// - void ClearCurrentScene(); - - /// - /// Gets the maximum height of a column of scrap terrain to collapse, when the bottom pixel is knocked loose. - /// - /// The compacting height of scrap terrain. - int GetScrapCompactingHeight() const { return m_ScrapCompactingHeight; } - - /// - /// Sets the maximum height of a column of scrap terrain to collapse, when the bottom pixel is knocked loose. - /// - /// The new compacting height, in pixels. - void SetScrapCompactingHeight(int newHeight) { m_ScrapCompactingHeight = newHeight; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Protected member variable and method declarations - - protected: - - static std::vector> m_IntermediateSettlingBitmaps; //!< Intermediate bitmaps of different sizes that are used to draw settled MovableObjects into the terrain. - - // Default Scene name to load if nothing else is specified - std::string m_DefaultSceneName; - // Scene reference to load from, if any. NOT OWNED - a clone of this actually gets loaded - const Scene *m_pSceneToLoad; - // Whether to place objects later when loading a clone of the above scene - bool m_PlaceObjects; - // Whether to place units and deployments when loading scence - bool m_PlaceUnits; - - // Current scene being used - Scene *m_pCurrentScene; - // Color MO layer - SceneLayerTracked *m_pMOColorLayer; - // MovableObject ID layer - SceneLayerTracked *m_pMOIDLayer; - // A spatial partitioning grid of MOIDs, used to optimize collision and distance queries - SpatialPartitionGrid m_MOIDsGrid; - - // Debug layer for seeing cast rays etc - SceneLayer *m_pDebugLayer; - - // The mode we're drawing layers in to the screen - int m_LayerDrawMode; - - // Material palette stuff - std::map m_MatNameMap; - // This gets filled with holes, not contigous from 0 onward, but whatever the ini specifies. The Material objects are owned here - std::array m_apMatPalette; - // The total number of added materials so far - int m_MaterialCount; - - // Non original materials added by inheritance - std::vector m_MaterialCopiesVector; - - // Sound of an unseen pixel on an unseen layer being revealed. - SoundContainer *m_pUnseenRevealSound; - - bool m_DrawRayCastVisualizations; //!< Whether to visibly draw RayCasts to the Scene debug Bitmap. - bool m_DrawPixelCheckVisualizations; //!< Whether to visibly draw pixel checks (GetTerrMatter and GetMOIDPixel) to the Scene debug Bitmap. - - // The last screen everything has been updated to - int m_LastUpdatedScreen; - // Whether we're in second pass of the structural computations. - // Second pass is where structurally unsound areas of the Terrain are turned into - // MovableObject:s. - bool m_SecondStructPass; - - // The Timer that keeps track of how much time there is left for - // structural calculations each frame. - Timer m_CalcTimer; - - // The Timer to measure time between cleanings of the color layer of the Terrain. - Timer m_CleanTimer; - // Bitmap to look for orphaned regions - BITMAP * m_pOrphanSearchBitmap; - - int m_ScrapCompactingHeight; //!< The maximum height of a column of scrap terrain to collapse, when the bottom pixel is knocked loose. - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this SceneMan, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - // Disallow the use of some implicit methods. - SceneMan(const SceneMan &reference) = delete; - SceneMan & operator=(const SceneMan &rhs) = delete; - -}; + // Class: SceneMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The singleton manager of all terrain and backgrounds in the RTE. + // Parent(s): Singleton, Serializable. + // Class history: 12/25/2001 SceneMan created. + + class SceneMan : public Singleton, public Serializable { + friend class SettingsMan; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + SerializableClassNameGetter; + SerializableOverrideMethods; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: SceneMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a SceneMan object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + SceneMan() { + m_pOrphanSearchBitmap = 0; + Clear(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~SceneMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a SceneMan object before deletion + // from system memory. + // Arguments: None. + + ~SceneMan() { Destroy(); } + + /// + /// Makes the SceneMan object ready for use. + /// + void Initialize() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SceneMan object ready for use. + // Arguments: A string with the filepath to a Reader file from screen this SceneMan's + // data should be created. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(std::string readerFile); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetDefaultSceneName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the instance name of the default Scene to be loaded if nothing + // else is available. + // Arguments: The default scene instance name. + // Return value: None. + + void SetDefaultSceneName(std::string defaultSceneName) { m_DefaultSceneName = defaultSceneName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDefaultSceneName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the name of the default A to be loaded if nothing + // else is available. + // Arguments: None. + // Return value: The default Scene instance name. + + std::string GetDefaultSceneName() const { return m_DefaultSceneName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Actually loads a new Scene into memory. has to be done before using + // this object. + // Arguments: The instance of the Scene, ownership IS transferred! + // Whether the scene should actually apply all its SceneObject:s placed + // in its definition. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int LoadScene(Scene* pNewScene, bool placeObjects = true, bool placeUnits = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSceneToLoad + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Stores a Scene reference to be loaded later into the SceneMan. + // Arguments: The instance reference of the Scene, ownership IS NOT (!!) transferred! + // Whether the scene should actually apply all its SceneObject:s placed + // in its definition. + // Return value: None. + + void SetSceneToLoad(const Scene* pLoadScene, bool placeObjects = true, bool placeUnits = true) { + m_pSceneToLoad = pLoadScene; + m_PlaceObjects = placeObjects; + m_PlaceUnits = placeUnits; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetSceneToLoad + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets a scene to load later, by preset name. + // Arguments: The name of the Scene preset instance to load. + // Whether the scene should actually apply all its SceneObject:s placed + // in its definition. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int SetSceneToLoad(std::string sceneName, bool placeObjects = true, bool placeUnits = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneToLoad + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the stored Scene reference to be loaded later into the SceneMan. + // Arguments: None. + // Return value: The instance reference of the Scene, ownership IS NOT (!!) transferred! + + const Scene* GetSceneToLoad() { return m_pSceneToLoad; } + + /// + /// Gets whether objects are placed when the Scene is initially started. Used for saving/loading games. + /// + /// Whether objects are placed when the Scene is initially started. + bool GetPlaceObjectsOnLoad() const { return m_PlaceObjects; } + + /// + /// Gets whether units are placed when the Scene is initially started. Used for saving/loading games. + /// + /// Whether units are placed when the Scene is initially started. + bool GetPlaceUnitsOnLoad() const { return m_PlaceUnits; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Actually loads the Scene set to be loaded in SetSceneToLoad. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int LoadScene(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads a Scene right now, by preset name. + // Arguments: The name of the Scene preset instance to load. + // Whether the scene should actually apply all its SceneObject:s placed + // in its definition. + // Whether the scene should actually deploy all units placed in its definition. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int LoadScene(std::string sceneName, bool placeObjects = true, bool placeUnits = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads a Scene right now, by preset name. + // Arguments: The name of the Scene preset instance to load. + // Whether the scene should actually apply all its SceneObject:s placed + // in its definition. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int LoadScene(std::string sceneName, bool placeObjects = true) { return LoadScene(sceneName, placeObjects, true); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire SceneMan, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneMan object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the currently loaded scene, if any. + // Arguments: None. + // Return value: The scene, ownership IS NOT TRANSFERRED! + + Scene* GetScene() const { return m_pCurrentScene; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneDim + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total dimensions (width and height) of the scene, in pixels. + // Arguments: None. + // Return value: A Vector describing the scene dimensions. + + Vector GetSceneDim() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneWidth + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total width of the scene, in pixels. + // Arguments: None. + // Return value: An int describing the scene width. + + int GetSceneWidth() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetSceneHeight + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total height of the scene, in pixels. + // Arguments: None. + // Return value: An int describing the scene width. + + int GetSceneHeight() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaterialPalette + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets access to the whole material palette array of 256 entries. + // Arguments: None. + // Return value: A const reference to the material palette array. + + const std::array& GetMaterialPalette() const { return m_apMatPalette; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaterial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a specific material by name. Ownership is NOT transferred! + // Arguments: The string name of the Material to get. + // Return value: A pointer to the requested material, or 0 if no material with that + // name was found. + + Material const* GetMaterial(const std::string& matName); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMaterialFromID + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a specific material from the material palette. Ownership is NOT + // transferred! + // Arguments: The unsigned char index specifying screen material to get (0-255). + // Return value: A reference to the requested material. OWNERSHIP IS NOT TRANSFERRED! + + Material const* GetMaterialFromID(unsigned char screen) { return screen >= 0 && screen < c_PaletteEntriesNumber && m_apMatPalette[screen] ? m_apMatPalette[screen] : m_apMatPalette[g_MaterialAir]; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SceneWrapsX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the scene wraps its scrolling around the X axis. + // Arguments: None. + // Return value: Whether the scene wraps around the X axis or not. + + bool SceneWrapsX() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SceneWrapsY + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the scene wraps its scrolling around the Y axis. + // Arguments: None. + // Return value: Whether the scene wraps around the Y axis or not. + + bool SceneWrapsY() const; + + /// + /// Gets the orbit direction for the current scene. + /// + /// The orbit direction for the current scene. + Directions GetSceneOrbitDirection() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTerrain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the SLTerrain, or 0 if no scene is loaded. + // Arguments: None. + // Return value: A pointer to the SLTerrain. Ownership is NOT transferred! + + SLTerrain* GetTerrain(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMOColorBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bitmap of the intermediary collection SceneLayer that all + // MovableObject:s draw themselves onto before it itself gets drawn onto + // the screen back buffer. + // Arguments: None. + // Return value: A BITMAP pointer to the MO bitmap. Ownership is NOT transferred! + + BITMAP* GetMOColorBitmap() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDebugBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bitmap of the SceneLayer that debug graphics is drawn onto. + // Will only return valid BITMAP if building with DEBUG_BUILD. + // Arguments: None. + // Return value: A BITMAP pointer to the debug bitmap. Ownership is NOT transferred! + + BITMAP* GetDebugBitmap() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMOIDBitmap + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the bitmap of the SceneLayer that all MovableObject:s draw thir + // current (for the frame only!) MOID's onto. + // Arguments: None. + // Return value: A BITMAP pointer to the MO bitmap. Ownership is NOT transferred! + + BITMAP* GetMOIDBitmap() const; + + // TEMP! + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: MOIDClearCheck + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes sure the MOID bitmap layer is completely of NoMOID color. + // If found to be not, dumps MOID layer and the FG actor color layer for + // debugging. + // Arguments: None. + // Return value: Was it clear? + + bool MOIDClearCheck(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLayerDrawMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current drawing mode of the SceneMan. + // Arguments: None. + // Return value: The current layer draw mode, see the LayerDrawMode enumeration for the + // different possible mode settings. + + int GetLayerDrawMode() const { return m_LayerDrawMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTerrMatter + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets a specific pixel from the total material representation of + // this Scene. LockScene() must be called before using this method. + // Arguments: The X and Y coordinates of screen material pixel to get. + // Return value: An unsigned char specifying the requested pixel's material index. + + unsigned char GetTerrMatter(int pixelX, int pixelY); + + /// + /// Gets a MOID from pixel coordinates in the Scene. LockScene() must be called before using this method. + /// + /// The X coordinate of the Scene pixel to test. + /// The Y coordinate of the Scene pixel to test. + /// The team to ignore. + /// The MOID currently at the specified pixel coordinates. + MOID GetMOIDPixel(int pixelX, int pixelY, int ignoreTeam); + + /// + /// Gets a MOID from pixel coordinates in the Scene. LockScene() must be called before using this method. + /// + /// The X coordinate of the Scene pixel to test. + /// The Y coordinate of the Scene pixel to test. + /// The MOID currently at the specified pixel coordinates. + MOID GetMOIDPixel(int pixelX, int pixelY) { return GetMOIDPixel(pixelX, pixelY, Activity::NoTeam); } + + /// + /// Gets this Scene's MOID SpatialPartitionGrid. + /// + /// This Scene's MOID SpatialPartitionGrid. + const SpatialPartitionGrid& GetMOIDGrid() const { return m_MOIDsGrid; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGlobalAcc + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the global acceleration (in m/s^2) that is applied to all movable + // objects' velocities during every frame. Typically models gravity. + // Arguments: None. + // Return value: A Vector describing the global acceleration. + + Vector GetGlobalAcc() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOzPerKg + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how many Ounces there are in a metric Kilogram + // Arguments: None. + // Return value: A float describing the Oz/Kg ratio. + + float GetOzPerKg() const { return 35.27396; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetKgPerOz + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets how many metric Kilograms there are in an Ounce. + // Arguments: None. + // Return value: A float describing the Kg/Oz ratio. + + float GetKgPerOz() const { return 0.02834952; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetLayerDrawMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the drawing mode of the SceneMan, to easily view what's going on + // in the different internal SceneLayer:s. + // Arguments: The layer mode to draw in, see the LayerDrawMode enumeration for the + // different possible settings. + // Return value: None. + + void SetLayerDrawMode(int mode) { m_LayerDrawMode = mode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LockScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Locks all dynamic internal scene bitmaps so that manipulaitons of the + // scene's color and matter representations can take place. + // Doing it in a separate method like this is more efficient because + // many bitmap manipulaitons can be performed between a lock and unlock. + // UnlockScene() should always be called after accesses are completed. + // Arguments: None. + // Return value: None. + + void LockScene(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UnlockScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Unlocks the scene's bitmaps and prevents access to display memory. + // Doing it in a separate method like this is more efficient because + // many bitmap accesses can be performed between a lock and an unlock. + // UnlockScene() should only be called after LockScene(). + // Arguments: None. + // Return value: None. + + void UnlockScene(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SceneIsLocked + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Indicates whether the entire scene is currently locked or not. + // Arguments: None. + // Return value: Whether the entire scene is currently locked or not. + + bool SceneIsLocked() const; + + /// + /// Registers an area to be drawn upon, so it can be tracked and cleared later. + /// + /// The bitmap being drawn upon. + /// The MOID, if we're drawing MOIDs. + /// The left boundary of the draw area. + /// The top boundary of the drawn area. + /// The right boundary of the draw area. + /// The bottom boundary of the draw area. + void RegisterDrawing(const BITMAP* bitmap, int moid, int left, int top, int right, int bottom); + + /// + /// Registers an area of to be drawn upon, so it can be tracked and cleared later. + /// + /// The bitmap being drawn upon. + /// The MOID, if we're drawing MOIDs. + /// The centre position of the drawn area. + /// The radius of the drawn area. + void RegisterDrawing(const BITMAP* bitmap, int moid, const Vector& center, float radius); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearAllMOIDDrawings + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all registered drawn areas of the MOID layer to the g_NoMOID + // color and clears the registrations too. Should be done each sim update. + // Arguments: None. + // Return value: None. + + void ClearAllMOIDDrawings(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WillPenetrate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Test whether a pixel of the scene would be knocked loose and + // turned into a MO by another particle of a certain material going at a + // certain velocity. Scene needs to be locked to do this! + // Arguments: The X and Y coords of the scene pixel that is collided with. + // The velocity of the incoming particle. + // The mass of the incoming particle. + // Return value: A bool indicating wether the scene pixel would be knocked loose or + // not. If the pixel location specified happens to be of the air + // material (0) false will be returned here. + + bool WillPenetrate(const int posX, + const int posY, + const Vector& velocity, + const float mass) { return WillPenetrate(posX, posY, velocity * mass); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WillPenetrate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Test whether a pixel of the scene would be knocked loose and + // turned into a MO by a certian impulse force. Scene needs to be locked + // to do this! + // Arguments: The X and Y coords of the scene pixel that is collided with. + // The impulse force vector, in Kg * m/s. + // Return value: A bool indicating wether the scene pixel would be knocked loose or + // not. If the pixel location specified happens to be of the air + // material (0) false will be returned here. + + bool WillPenetrate(const int posX, + const int posY, + const Vector& impulse); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TryPenetrate + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculate whether a pixel of the scene would be knocked loose and + // turned into a MO by another particle of a certain material going at a + // certain velocity. If so, the incoming particle will knock loose the + // specified pixel in the scene and momentarily take its place. + // Scene needs to be locked to do this! + // Arguments: The X and Y coord of the scene pixel that is to be collided with. + // The impulse force exerted on the terrain pixel. If this magnitude + // exceeds the strength threshold of the material of the terrain pixel + // hit, the terrain pixel will be knocked loose an turned into an MO. + // The velocity of the the point hitting the terrain here. + // A float reference screen will be set to the factor with screen to + // multiply the collision velocity to get the resulting retardation + // (negative acceleration) that occurs when a penetration happens. + // The normalized probability ratio between 0.0 and 1.0 that determines + // the chance of a penetration to remove a pixel from the scene and + // thus replace it with and air pixel. 1.0 = always, 0.0 = never. + // How many consecutive penetrations in a row immediately before this try. + // The size of the area to look for orphaned terrain elements. + // Max area or orphaned area to remove. + // Orphan area removal trigger rate. + // Return value: A bool indicating wether the scene pixel was knocked loose or not. + // If the pixel location specified happens to be of the air material (0) + // false will be returned here. + + bool TryPenetrate(int posX, + int posY, + const Vector& impulse, + const Vector& velocity, + float& retardation, + const float airRatio, + const int numPenetrations = 0, + const int removeOrphansRadius = 0, + const int removeOrphansMaxArea = 0, + const float removeOrphansRate = 0.0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveOrphans + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the area of an orphaned region at specified coordinates. + // Arguments: Coordinates to check for region, whether the orphaned region should be converted into MOPixels and region removed. + // Area of orphaned object calculated during recursve function call to check if we're out of limits + // Size of the are to look for orphaned objects + // Max area of orphaned object to remove + // Whether to actually remove orphaned pixels or not + // Whether to clear internal terrain tracking bitmap or not + // Return value: The area of orphaned region at posX,posY + + int RemoveOrphans(int posX, int posY, int radius, int maxArea, bool remove = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveOrphans + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the area of an orphaned region at specified coordinates. + // Arguments: Coordinates to check for region, whether the orphaned region should be converted into MOPixels and region removed. + // Coordinates of initial terrain penetration to check, which serves as a center of orphaned object detection. + // Area of orphaned object calculated during recursve function call to check if we're out of limits + // Size of the are to look for orphaned objects + // Max area of orphaned object to remove + // Whether to actually remove orphaned pixels or not + // Whether to clear internal terrain tracking bitmap or not + // Return value: The area of orphaned region at posX,posY + + int RemoveOrphans(int posX, + int posY, + int centerPosX, + int centerPosY, + int accumulatedArea, + int radius, + int maxArea, + bool remove = false); + + /// + /// Removes a pixel from the terrain and adds it to MovableMan. + /// + /// The X coordinate of the terrain pixel. + /// The Y coordinate of the terrain pixel. + /// The newly dislodged pixel, if one was found. + MovableObject* DislodgePixel(int posX, int posY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: MakeAllUnseen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets one team's view of the scene to be unseen, using a generated map + // of a specific resolution chunkiness. + // Arguments: The dimensions of the pixels that should make up the unseen layer. + // The team we're talking about. + // Return value: None. + + void MakeAllUnseen(Vector pixelSize, const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: MakeAllSeen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets one team's view of the scene to be all seen. + // Arguments: The team we're talking about. + // Return value: None. + + void MakeAllSeen(const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadUnseenLayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads a bitmap from file and use it as the unseen layer for a team. + // Arguments: The path to the bitmap to use as the unseen layer. + // Which team we're talking about. + // Return value: Whether the loading was successful or not. + + bool LoadUnseenLayer(std::string bitmapPath, const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AnythingUnseen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a team has anything still unseen on the scene. + // Arguments: The team we're talking about. + // Return value: A bool indicating whether that team has anyhting yet unseen. + + bool AnythingUnseen(const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetUnseenResolution + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows what the resolution factor of the unseen map to the entire Scene + // is, in both axes. + // Arguments: The team we're talking about. + // Return value: A vector witht he factors in each element representing the factors. + + Vector GetUnseenResolution(const int team) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsUnseen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether a pixel is in an unseen area on of a specific team. + // Arguments: The X and Y coords of the scene pixel that is to be checked. + // The team we're talking about. + // Return value: A bool indicating whether that point is yet unseen. + + bool IsUnseen(const int posX, const int posY, const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RevealUnseen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reveals a pixel on the unseen map for a specific team, if there is any. + // Arguments: The X and Y coord of the scene pixel that is to be revealed. + // The team to reveal for. + // Return value: A bool indicating whether there was an unseen pixel revealed there. + + bool RevealUnseen(const int posX, const int posY, const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RestoreUnseen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Hides a pixel on the unseen map for a specific team, if there is any. + // Arguments: The X and Y coord of the scene pixel that is to be revealed. + // The team to hide for. + // Return value: A bool indicating whether there was a seen pixel hidden there. + + bool RestoreUnseen(const int posX, const int posY, const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RevealUnseenBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reveals a box on the unseen map for a specific team, if there is any. + // Arguments: The X and Y coords of the upper left corner of the box to be revealed. + // The width and height of the box to be revealed, in scene units (pixels) + // The team to reveal for. + // Return value: None. + + void RevealUnseenBox(const int posX, const int posY, const int width, const int height, const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RestoreUnseenBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Restores a box on the unseen map for a specific team, if there is any. + // Arguments: The X and Y coords of the upper left corner of the box to be revealed. + // The width and height of the box to be restored, in scene units (pixels) + // The team to restore for. + // Return value: None. + + void RestoreUnseenBox(const int posX, const int posY, const int width, const int height, const int team); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastUnseenRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and reveals or hides pixels on the unseen layer of a team + // as long as the accumulated material strengths traced through the terrain + // don't exceed a specific value. + // Arguments: The team to see for. + // The starting position. + // The vector to trace along. + // A Vector that will be set to the position of where the sight ray was + // terminated. If it reached the end, it will be set to the end of the ray. + // The material strength limit where + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Whether the ray should reveal or restore unseen layer + // Return value: Whether any unseen pixels were revealed as a result of this seeing. + + bool CastUnseenRay(int team, const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip, bool reveal); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastSeeRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and reveals pixels on the unseen layer of a team + // as long as the accumulated material strengths traced through the terrain + // don't exceed a specific value. + // Arguments: The team to see for. + // The starting position. + // The vector to trace along. + // A Vector that will be set to the position of where the sight ray was + // terminated. If it reached the end, it will be set to the end of the ray. + // The material strength limit where + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Return value: Whether any unseen pixels were revealed as a result of this seeing. + + bool CastSeeRay(int team, const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastUnseeRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and hides pixels on the unseen layer of a team + // as long as the accumulated material strengths traced through the terrain + // don't exceed a specific value. + // Arguments: The team to see for. + // The starting position. + // The vector to trace along. + // A Vector that will be set to the position of where the sight ray was + // terminated. If it reached the end, it will be set to the end of the ray. + // The material strength limit where + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Return value: Whether any unseen pixels were revealed as a result of this seeing. + + bool CastUnseeRay(int team, const Vector& start, const Vector& ray, Vector& endPos, int strengthLimit, int skip = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastMaterialRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and gets the location of the first encountered + // pixel of a specific material in the terrain. + // Arguments: The starting position. + // The vector to trace along. + // The material ID to look for. + // A reference to the vector screen will be filled out with the absolute + // location of the found terrain pixel of the above material. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Whetehr the ray should wrap around the scene if it crosses a seam. + // Return value: Whether the material was found along the ray. If not, the fourth + // parameter will not have been altered (and may still not be 0!) + + bool CastMaterialRay(const Vector& start, const Vector& ray, unsigned char material, Vector& result, int skip = 0, bool wrap = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastMaterialRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and returns how far along that ray there is an + // encounter with a pixel of a specific material in the terrain. + // Arguments: The starting position. + // The vector to trace along. + // The material ID to look for. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Return value: How far along, in pixel units, the ray the material pixel was encountered. + // If no pixel of the right material was found, < 0 is returned. + + float CastMaterialRay(const Vector& start, const Vector& ray, unsigned char material, int skip = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastNotMaterialRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and gets the location of the first encountered + // pixel that is NOT of a specific material in the scene's terrain. + // Arguments: The starting position. + // The vector to trace along. + // The material ID to find something OTHER than. + // A reference to the vector screen will be filled out with the absolute + // location of the found terrain pixel of the above material. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Whether to check for MO layer collisions as well, not just terrain. + // Return value: Whether the a pixel other than the material was found along the ray. + // If not, the fourth parameter will not have been altered (and may still not be 0!) + + bool CastNotMaterialRay(const Vector& start, const Vector& ray, unsigned char material, Vector& result, int skip = 0, bool checkMOs = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastNotMaterialRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and returns how far along that ray there is an + // encounter with a pixel of OTHER than a specific material in the terrain. + // Arguments: The starting position. + // The vector to trace along. + // The material ID to find something OTHER than. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Whether to check for MO layer collisions as well, not just terrain. + // Return value: How far along, in pixel units, the ray the pixel of any other material + // was encountered. If no pixel of the right material was found, < 0 is returned. + + float CastNotMaterialRay(const Vector& start, const Vector& ray, unsigned char material, int skip = 0, bool checkMOs = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastStrengthSumRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and returns how the sum of all encountered pixels' + // material strength values. This will take wrapping into account. + // Arguments: The starting position. + // The ending position. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // A material ID to ignore, IN ADDITION to Air. + // Return value: The sum of all encountered pixels' material strength vales. So if it was + // all Air, then 0 is returned (Air's strength value is 0). + + float CastStrengthSumRay(const Vector& start, const Vector& end, int skip = 0, unsigned char ignoreMaterial = g_MaterialAir); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastMaxStrengthRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and returns the strongest of all encountered pixels' + // material strength values. + // This will take wrapping into account. + // Arguments: The starting position. + // The ending position. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // A material ID to ignore, IN ADDITION to Air. This defaults to doors, for legacy script purposes + // Return value: The max of all encountered pixels' material strength vales. So if it was + // all Air, then 0 is returned (Air's strength value is 0). + + // We use two accessors instead of default parameters, for lua compat + float CastMaxStrengthRay(const Vector& start, const Vector& end, int skip, unsigned char ignoreMaterial); + float CastMaxStrengthRay(const Vector& start, const Vector& end, int skip) { return CastMaxStrengthRay(start, end, skip, g_MaterialDoor); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastMaxStrengthRayMaterial + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and returns the strongest of all encountered pixels' materials + // This will take wrapping into account. + // Arguments: The starting position. + // The ending position. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // A material ID to ignore, IN ADDITION to Air. + // Return value: The strongest material encountered + const Material* CastMaxStrengthRayMaterial(const Vector& start, const Vector& end, int skip, unsigned char ignoreMaterial); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastStrengthRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and shows where along that ray there is an + // encounter with a pixel of a material with strength more than or equal + // to a specific value. + // Arguments: The starting position. + // The vector to trace along. + // The strength value of screen any found to be equal or more than will + // terminate the ray. + // A reference to the vector screen will be filled out with the absolute + // location of the found terrain pixel of less than or equal to above strength. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // A material ID to ignore, IN ADDITION to Air. + // Whetehr the ray should wrap around the scene if it crosses a seam. + // Return value: Whether a material of equal or more strength was found along the ray. + // If not, the fourth parameter have been set to last position of the ray. + + bool CastStrengthRay(const Vector& start, const Vector& ray, float strength, Vector& result, int skip = 0, unsigned char ignoreMaterial = g_MaterialAir, bool wrap = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastWeaknessRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and shows where along that ray there is an + // encounter with a pixel of a material with strength less than or equal + // to a specific value. + // Arguments: The starting position. + // The vector to trace along. + // The strength value of screen any found to be equal or less than will + // terminate the ray. + // A reference to the vector screen will be filled out with the absolute + // location of the found terrain pixel of less than or equal to above strength. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Whetehr the ray should wrap around the scene if it crosses a seam. + // Return value: Whether a material of equal or less strength was found along the ray. + // If not, the fourth parameter have been set to last position of the ray. + + bool CastWeaknessRay(const Vector& start, const Vector& ray, float strength, Vector& result, int skip = 0, bool wrap = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastMORay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and returns MOID of the first non-ignored + // non-NoMOID MO encountered. If a non-air terrain pixel is encountered + // first, g_NoMOID will be returned. + // Arguments: The starting position. + // The vector to trace along. + // An MOID to ignore. Any child MO's of this MOID will also be ignored. + // To enable ignoring of all MOIDs associated with an object of a specific + // team which also has team ignoring enabled itself. + // A specific material ID to ignore hits with. + // Whether to ignore all terrain hits or not. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Return value: The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. + + MOID CastMORay(const Vector& start, const Vector& ray, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastFindMORay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and shows where a specific MOID has been found. + // Arguments: The starting position. + // The vector to trace along. + // An MOID to find. Any child MO's of this MOID will also be found. ------------ ??? + // A reference to the vector screen will be filled out with the absolute + // location of the found MO pixel of the above MOID. + // A specific material ID to ignore hits with. + // Whether to ignore all terrain hits or not. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Return value: Whether the target MOID was found along the ray or not. + + bool CastFindMORay(const Vector& start, const Vector& ray, MOID targetMOID, Vector& resultPos, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CastObstacleRay + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Traces along a vector and returns the length of how far the trace went + // without hitting any non-ignored terrain material or MOID at all. + // Arguments: The starting position. + // The vector to trace along. + // A reference to the vector screen will be filled out with the absolute + // location of the first obstacle, or the end of the ray if none was hit. + // A reference to the vector screen will be filled out with the absolute + // location of the last free position before hitting an obstacle, or the + // end of the ray if none was hit. This is only altered if thre are any + // free pixels encountered. + // An MOID to ignore. Any child MO's of this MOID will also be ignored. + // To enable ignoring of all MOIDs associated with an object of a specific + // team which also has team ignoring enabled itself. + // A specific material ID to ignore hits with. + // For every pixel checked along the line, how many to skip between them + // for optimization reasons. 0 = every pixel is checked. + // Return value: How far along, in pixel units, the ray the pixel of any obstacle was + // encountered. If no pixel of the right material was found, < 0 is returned. + // If an obstacle on the starting position was encountered, 0 is returned. + + float CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, int skip = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLastRayHitPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the abosulte pos of where the last cast ray hit somehting. + // Arguments: None. + // Return value: A vector with the absolute pos of where the last ray cast hit somehting. + + const Vector& GetLastRayHitPos(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FindAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the altitide of a certain point above the terrain, measured + // in pixels. + // Arguments: The max altitude you care to check for. 0 Means check the whole scene's height. + // The accuracy within screen measurement is acceptable. Higher number + // here means less calculation. + // Return value: The altitude over the terrain, in pixels. + + float FindAltitude(const Vector& from, int max, int accuracy, bool fromSceneOrbitDirection); + float FindAltitude(const Vector& from, int max, int accuracy) { return FindAltitude(from, max, accuracy, false); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: OverAltitude + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the altitide of a certain point above the terrain, measured + // in pixels, and then tells if that point is over a certain value. + // Arguments: The altitude threshold you want to check for. + // The accuracy within screen measurement is acceptable. Higher number + // here means less costly. + // Return value: Whether the point is over the threshold altitude or not. + + bool OverAltitude(const Vector& point, int threshold, int accuracy = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: MovePointToGround + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes an arbitrary point in the air and calculates it to be straight + // down at a certain maximum distance from the ground. + // Arguments: The point to start from. Should be in the air, or the same point will + // be returned (null operation) + // The max altitude in px you want the point to be above the ground. + // The accuracy within screen measurement is acceptable. Higher number + // here means less calculation. + // Return value: The new point screen is no higher than accuracy + max altitude over + // the terrain. + + Vector MovePointToGround(const Vector& from, int maxAltitude = 0, int accuracy = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsWithinBounds + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether the integer coordinates passed in are within the + // bounds of the current Scene, considering its wrapping. + // Arguments: Int coordinates. + // A margin + // Return value: Whether within bounds or not, considering wrapping. + + bool IsWithinBounds(const int pixelX, const int pixelY, const int margin = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ForceBounds + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Wraps or bounds a position coordinate if it is off bounds of the + // Scene, depending on the wrap settings of this Scene. + // Arguments: The X and Y coordinates of the position to wrap, if needed. + // Return value: Whether wrapping was performed or not. (Does not report on bounding) + + bool ForceBounds(int& posX, int& posY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ForceBounds + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Wraps or bounds a position coordinate if it is off bounds of the + // Scene, depending on the wrap settings of this Scene. + // Arguments: The vector coordinates of the position to wrap, if needed. + // Return value: Whether wrapping was performed or not. (Does not report on bounding) + + bool ForceBounds(Vector& pos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapPosition + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Only wraps a position coordinate if it is off bounds of the Scene + // and wrapping in the corresponding axes are turned on. + // Arguments: The X and Y coordinates of the position to wrap, if needed. + // Return value: Whether wrapping was performed or not. + + bool WrapPosition(int& posX, int& posY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapPosition + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Only wraps a position coordinate if it is off bounds of the Scene + // and wrapping in the corresponding axes are turned on. + // Arguments: The vector coordinates of the position to wrap, if needed. + // Return value: Whether wrapping was performed or not. + + bool WrapPosition(Vector& pos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SnapPosition + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a position snapped to the current scene grid. + // Arguments: The vector coordinates of the position to snap. + // Whether to actually snap or not. This is useful for cleaner toggle code. + // Return value: The new snapped position. + + Vector SnapPosition(const Vector& pos, bool snap = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ShortestDistance + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the shortest distance between two points in scene + // coordinates, taking into account all wrapping and out of bounds of the + // two points. + // Arguments: The two Vector coordinates of the two positions to find the shortest + // distance between. + // Whether to check if the passed in points are outside the scene, and to + // wrap them if they are. + // Return value: The resulting vector screen shows the shortest distance, spanning over + // wrapping borders etc. Basically the ideal pos2 - pos1. + + Vector ShortestDistance(Vector pos1, Vector pos2, bool checkBounds = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ShortestDistanceX + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the shortest distance between two x values in scene + // coordinates, taking into account all wrapping and out of bounds of the + // two values. + // Arguments: The X coordinates of the two values to find the shortest distance between. + // Whether to check if the passed in points are outside the scene, and to + // wrap them if they are. + // Whether to constrain the distance to only be in a certain direction: + // 0 means no constraint, < 0 means only look in the negative dir, etc. + // If the scene doesn't wrap in the constraint's direction, the constraint + // will be ignored. + // Return value: The resulting X value screen shows the shortest distance, spanning over + // wrapping borders etc. Basically the ideal val2 - val1. + + float ShortestDistanceX(float val1, float val2, bool checkBounds = false, int direction = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ShortestDistanceY + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Calculates the shortest distance between two Y values in scene + // coordinates, taking into account all wrapping and out of bounds of the + // two values. + // Arguments: The Y coordinates of the two values to find the shortest distance between. + // Whether to check if the passed in points are outside the scene, and to + // wrap them if they are. + // Whether to constrain the distance to only be in a certain direction: + // 0 means no constraint, < 0 means only look in the negative dir, etc. + // If the scene doesn't wrap in the constraint's direction, the constraint + // will be ignored. + // Return value: The resulting Y value screen shows the shortest distance, spanning over + // wrapping borders etc. Basically the ideal val2 - val1. + + float ShortestDistanceY(float val1, float val2, bool checkBounds = false, int direction = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ObscuredPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a point on the scene is obscured by MOID or Terrain + // non-air material. + // Arguments: The point on the scene to check. + // Wheter to also check for unseen areas of a specific team. -1 means + // don't check this. + // Return value: Whether that point is obscured/obstructed or not. + + bool ObscuredPoint(Vector& point, int team = -1) { return ObscuredPoint(point.GetFloorIntX(), point.GetFloorIntY()); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ObscuredPoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a point on the scene is obscured by MOID or Terrain + // non-air material. + // Arguments: The point on the scene to check. + // Wheter to also check for unseen areas of a specific team. -1 means + // don't check this. + // Return value: Whether that point is obscured/obstructed or not. + + bool ObscuredPoint(int x, int y, int team = -1); + + /* + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SceneRectsIntersect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether two IntRect:s in the scene intersect, while taking + // wrapping into account. + // Arguments: The point on the scene to check. + // Return value: Whether that point is obscured/obstructed or not. + + bool SceneRectsIntersect(int x, int y); + */ + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapRect + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes a rect and adds all possible wrapped appearances of that rect + // to a passed-in list. IF if a passed in rect straddles the seam of a + // wrapped scene axis, it will be added twice to the output list. If it + // doesn't straddle any seam, it will be only added once. + // Arguments: The IntRect to check for wrapping of and add to the output list below. + // A reference to a list of IntRect:s that will only be added to, never + // cleared. + // Return value: How many additions of the passed in rect was added to the list. 1 if + // no wrapping need was detected, up to 4 possible (if straddling both seams) + + int WrapRect(const IntRect& wrapRect, std::list& outputList); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: WrapBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes a Box and adds all possible scenewrapped appearances of that Box + // to a passed-in list. IF if a passed in rect straddles the seam of a + // wrapped scene axis, it will be added twice to the output list. If it + // doesn't straddle any seam, it will be only added once. + // Arguments: The IntRect to check for wrapping of and add to the output list below. + // A reference to a list of IntRect:s that will only be added to, never + // cleared. + // Return value: How many additions of the passed in Box was added to the list. 1 if + // no wrapping need was detected, up to 4 possible (if straddling both seams) + + int WrapBox(const Box& wrapBox, std::list& outputList); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddSceneObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Takes any scene object and adds it to the scene in the appropriate way. + // If it's a TerrainObject, then it gets applied to the terrain, if it's + // an MO, it gets added to the correct type group in MovableMan. + // Arguments: The SceneObject to add. Ownership IS transferred! + // Return value: Whether the SceneObject was successfully added or not. Either way, + // ownership was transferred. If no success, the object was deleted. + + bool AddSceneObject(SceneObject* pObject); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this SceneMan. Supposed to be done every frame + // before drawing. + // Arguments: Which screen to update for. + // Return value: None. + + void Update(int screenId = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this SceneMan's current graphical representation to a + // BITMAP of choice. + // Arguments: A pointer to a BITMAP to draw on, appropriately sized for the split + // screen segment. + // The offset into the scene where the target bitmap's upper left corner + // is located. + // Return value: None. + + void Draw(BITMAP* targetBitmap, BITMAP* targetGUIBitmap, const Vector& targetPos = Vector(), bool skipBackgroundLayers = false, bool skipTerrain = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearMOColorLayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the color MO layer. Should be done every frame. + // Arguments: None. + // Return value: None. + + void ClearMOColorLayer(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearSeenPixels + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the list of pixels on the unseen map that have been revealed. + // Arguments: None. + // Return value: None. + + void ClearSeenPixels(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddMaterialCopy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Creates a copy of passed material and stores it into internal vector + // to make sure there's only one material owner + // Arguments: Material to add. + // Return value: Pointer to stored material. + + Material* AddMaterialCopy(Material* mat); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RegisterTerrainChange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Registers terrain change event for the network server to be then sent to clients. + // Arguments: x,y - scene coordinates of change, w,h - size of the changed region, + // color - changed color for one-pixel events, + // back - if true, then background bitmap was changed if false then foreground. + // Return value: None. + + void RegisterTerrainChange(int x, int y, int w, int h, unsigned char color, bool back); + + /// + /// Gets an intermediate bitmap that is used for drawing a settled MovableObject into the terrain. + /// + /// The diameter of the MovableObject to calculate the required bitmap size. + /// Pointer to the temp BITMAP of the appropriate size. Ownership is NOT transferred! + BITMAP* GetIntermediateBitmapForSettlingIntoTerrain(int moDiameter) const; + + /// + /// Sets the current scene pointer to null + /// + void ClearCurrentScene(); + + /// + /// Gets the maximum height of a column of scrap terrain to collapse, when the bottom pixel is knocked loose. + /// + /// The compacting height of scrap terrain. + int GetScrapCompactingHeight() const { return m_ScrapCompactingHeight; } + + /// + /// Sets the maximum height of a column of scrap terrain to collapse, when the bottom pixel is knocked loose. + /// + /// The new compacting height, in pixels. + void SetScrapCompactingHeight(int newHeight) { m_ScrapCompactingHeight = newHeight; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + static std::vector> m_IntermediateSettlingBitmaps; //!< Intermediate bitmaps of different sizes that are used to draw settled MovableObjects into the terrain. + + // Default Scene name to load if nothing else is specified + std::string m_DefaultSceneName; + // Scene reference to load from, if any. NOT OWNED - a clone of this actually gets loaded + const Scene* m_pSceneToLoad; + // Whether to place objects later when loading a clone of the above scene + bool m_PlaceObjects; + // Whether to place units and deployments when loading scence + bool m_PlaceUnits; + + // Current scene being used + Scene* m_pCurrentScene; + // Color MO layer + SceneLayerTracked* m_pMOColorLayer; + // MovableObject ID layer + SceneLayerTracked* m_pMOIDLayer; + // A spatial partitioning grid of MOIDs, used to optimize collision and distance queries + SpatialPartitionGrid m_MOIDsGrid; + + // Debug layer for seeing cast rays etc + SceneLayer* m_pDebugLayer; + + // The mode we're drawing layers in to the screen + int m_LayerDrawMode; + + // Material palette stuff + std::map m_MatNameMap; + // This gets filled with holes, not contigous from 0 onward, but whatever the ini specifies. The Material objects are owned here + std::array m_apMatPalette; + // The total number of added materials so far + int m_MaterialCount; + + // Non original materials added by inheritance + std::vector m_MaterialCopiesVector; + + // Sound of an unseen pixel on an unseen layer being revealed. + SoundContainer* m_pUnseenRevealSound; + + bool m_DrawRayCastVisualizations; //!< Whether to visibly draw RayCasts to the Scene debug Bitmap. + bool m_DrawPixelCheckVisualizations; //!< Whether to visibly draw pixel checks (GetTerrMatter and GetMOIDPixel) to the Scene debug Bitmap. + + // The last screen everything has been updated to + int m_LastUpdatedScreen; + // Whether we're in second pass of the structural computations. + // Second pass is where structurally unsound areas of the Terrain are turned into + // MovableObject:s. + bool m_SecondStructPass; + + // The Timer that keeps track of how much time there is left for + // structural calculations each frame. + Timer m_CalcTimer; + + // The Timer to measure time between cleanings of the color layer of the Terrain. + Timer m_CleanTimer; + // Bitmap to look for orphaned regions + BITMAP* m_pOrphanSearchBitmap; + + int m_ScrapCompactingHeight; //!< The maximum height of a column of scrap terrain to collapse, when the bottom pixel is knocked loose. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this SceneMan, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + SceneMan(const SceneMan& reference) = delete; + SceneMan& operator=(const SceneMan& rhs) = delete; + }; } // namespace RTE diff --git a/Source/Managers/SettingsMan.cpp b/Source/Managers/SettingsMan.cpp index 6afd9221b..f356bfec5 100644 --- a/Source/Managers/SettingsMan.cpp +++ b/Source/Managers/SettingsMan.cpp @@ -15,7 +15,7 @@ namespace RTE { const std::string SettingsMan::c_ClassName = "SettingsMan"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsMan::Clear() { m_SettingsPath = System::GetUserdataDirectory() + "Settings.ini"; @@ -52,7 +52,7 @@ namespace RTE { m_DisableFactionBuyMenuThemeCursors = false; m_PathFinderGridNodeSize = c_PPM; m_AIUpdateInterval = 2; - + m_NumberOfLuaStatesOverride = -1; m_ForceImmediatePathingRequestCompletion = false; @@ -72,10 +72,12 @@ namespace RTE { m_EnabledGlobalScripts.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int SettingsMan::Initialize() { - if (const char *settingsTempPath = std::getenv("CCCP_SETTINGSPATH")) { m_SettingsPath = std::string(settingsTempPath); } + if (const char* settingsTempPath = std::getenv("CCCP_SETTINGSPATH")) { + m_SettingsPath = std::string(settingsTempPath); + } Reader settingsReader(m_SettingsPath, false, nullptr, true, true); @@ -103,18 +105,18 @@ namespace RTE { return failureCode; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsMan::UpdateSettingsFile() const { Writer settingsWriter(m_SettingsPath); g_SettingsMan.Save(settingsWriter); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SettingsMan::ReadProperty(const std::string_view &propName, Reader &reader) { + int SettingsMan::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("PaletteFile", { reader >> g_FrameMan.m_PaletteFile; }); MatchProperty("ResolutionX", { reader >> g_WindowMan.m_ResX; }); MatchProperty("ResolutionY", { reader >> g_WindowMan.m_ResY; }); @@ -132,14 +134,13 @@ namespace RTE { MatchProperty("SoundPanningEffectStrength", { reader >> g_AudioMan.m_SoundPanningEffectStrength; - ////////////////////////////////////////////////// - //TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking by pawnis. + ////////////////////////////////////////////////// + // TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking by pawnis. }); MatchProperty("ListenerZOffset", { reader >> g_AudioMan.m_ListenerZOffset; }); MatchProperty("MinimumDistanceForPanning", { reader >> g_AudioMan.m_MinimumDistanceForPanning; - ////////////////////////////////////////////////// - + ////////////////////////////////////////////////// }); MatchProperty("ShowForeignItems", { reader >> m_ShowForeignItems; }); MatchProperty("FlashOnBrainDamage", { reader >> m_FlashOnBrainDamage; }); @@ -230,13 +231,13 @@ namespace RTE { } } }); - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SettingsMan::Save(Writer &writer) const { + int SettingsMan::Save(Writer& writer) const { Serializable::Save(writer); writer.NewDivider(false); @@ -264,7 +265,7 @@ namespace RTE { writer.NewPropertyWithValue("SoundPanningEffectStrength", g_AudioMan.m_SoundPanningEffectStrength); ////////////////////////////////////////////////// - //TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking. + // TODO These need to be removed when our soundscape is sorted out. They're only here temporarily to allow for easier tweaking. writer.NewPropertyWithValue("ListenerZOffset", g_AudioMan.m_ListenerZOffset); writer.NewPropertyWithValue("MinimumDistanceForPanning", g_AudioMan.m_MinimumDistanceForPanning); ////////////////////////////////////////////////// @@ -325,13 +326,13 @@ namespace RTE { writer.NewPropertyWithValue("EnableParticleSettling", g_MovableMan.m_SettlingEnabled); writer.NewPropertyWithValue("EnableMOSubtraction", g_MovableMan.m_MOSubtractionEnabled); writer.NewPropertyWithValue("DeltaTime", g_TimerMan.GetDeltaTimeSecs()); - + // No experimental settings right now :) - //writer.NewLine(false, 2); - //writer.NewDivider(false); - //writer.NewLineString("// Engine Settings - EXPERIMENTAL", false); - //writer.NewLineString("// These settings are experimental! They may break mods, crash the game, corrupt saves or worse. Use at your own risk.", false); - //writer.NewLine(false); + // writer.NewLine(false, 2); + // writer.NewDivider(false); + // writer.NewLineString("// Engine Settings - EXPERIMENTAL", false); + // writer.NewLineString("// These settings are experimental! They may break mods, crash the game, corrupt saves or worse. Use at your own risk.", false); + // writer.NewLine(false); writer.NewLine(false, 2); writer.NewDivider(false); @@ -401,7 +402,7 @@ namespace RTE { writer.NewDivider(false); writer.NewLineString("// Enabled Bunker Assembly Groups", false); writer.NewLine(false); - for (const std::string &visibleAssembly : m_VisibleAssemblyGroupsList) { + for (const std::string& visibleAssembly: m_VisibleAssemblyGroupsList) { writer.NewPropertyWithValue("VisibleAssemblyGroup", visibleAssembly); } } @@ -411,8 +412,10 @@ namespace RTE { writer.NewDivider(false); writer.NewLineString("// Disabled Mods", false); writer.NewLine(false); - for (const auto &[modPath, modDisabled] : m_DisabledMods) { - if (modDisabled) { writer.NewPropertyWithValue("DisableMod", modPath); } + for (const auto& [modPath, modDisabled]: m_DisabledMods) { + if (modDisabled) { + writer.NewPropertyWithValue("DisableMod", modPath); + } } } @@ -421,8 +424,10 @@ namespace RTE { writer.NewDivider(false); writer.NewLineString("// Enabled Global Scripts", false); writer.NewLine(false); - for (const auto &[scriptPresetName, scriptEnabled] : m_EnabledGlobalScripts) { - if (scriptEnabled) { writer.NewPropertyWithValue("EnableGlobalScript", scriptPresetName); } + for (const auto& [scriptPresetName, scriptEnabled]: m_EnabledGlobalScripts) { + if (scriptEnabled) { + writer.NewPropertyWithValue("EnableGlobalScript", scriptPresetName); + } } } @@ -449,4 +454,4 @@ namespace RTE { return 0; } -} +} // namespace RTE diff --git a/Source/Managers/SettingsMan.h b/Source/Managers/SettingsMan.h index 5e30ca27b..240b3ca67 100644 --- a/Source/Managers/SettingsMan.h +++ b/Source/Managers/SettingsMan.h @@ -14,7 +14,6 @@ namespace RTE { class SettingsMan : public Singleton, public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -299,7 +298,7 @@ namespace RTE { /// Sets the player name that will be used in network multiplayer matches. /// /// String with the new player name to use. - void SetPlayerNetworkName(const std::string &newName) { m_PlayerNetworkName = newName.empty() ? "Dummy" : newName; } + void SetPlayerNetworkName(const std::string& newName) { m_PlayerNetworkName = newName.empty() ? "Dummy" : newName; } /// /// Gets the LAN server address to connect to. @@ -311,43 +310,43 @@ namespace RTE { /// Sets the LAN server address to connect to. /// /// New LAN server address to connect to. - void SetNetworkServerAddress(const std::string &newAddress) { m_NetworkServerAddress = newAddress.empty() ? "127.0.0.1:8000" : newAddress; } + void SetNetworkServerAddress(const std::string& newAddress) { m_NetworkServerAddress = newAddress.empty() ? "127.0.0.1:8000" : newAddress; } /// /// Gets the NAT punch-through server address. /// /// The current NAT punch-through server address to connect to. - std::string & GetNATServiceAddress() { return m_NATServiceAddress; } + std::string& GetNATServiceAddress() { return m_NATServiceAddress; } /// /// Sets the NAT punch-through server address. /// /// New NAT punch-through server address to connect to. - void SetNATServiceAddress(const std::string &newAddress) { m_NATServiceAddress = newAddress.empty() ? "127.0.0.1:61111" : newAddress; } + void SetNATServiceAddress(const std::string& newAddress) { m_NATServiceAddress = newAddress.empty() ? "127.0.0.1:61111" : newAddress; } /// /// Gets the server name used when connecting via NAT punch-through service. /// /// Name of the NAT punch-through server. - std::string & GetNATServerName() { return m_NATServerName; } + std::string& GetNATServerName() { return m_NATServerName; } /// /// Sets the server name to use when connecting via NAT punch-through service. /// /// New NAT punch-through server name. - void SetNATServerName(const std::string &newName) { m_NATServerName = newName.empty() ? "DefaultServerName" : newName; } + void SetNATServerName(const std::string& newName) { m_NATServerName = newName.empty() ? "DefaultServerName" : newName; } /// /// Gets the server password to use when connecting via NAT punch-through service. /// /// The server password to use when connecting via NAT punch-through service. - std::string & GetNATServerPassword() { return m_NATServerPassword; } + std::string& GetNATServerPassword() { return m_NATServerPassword; } /// /// Sets the server password to use when connecting via NAT punch-through service. /// /// New password to use when connecting via NAT punch-through service. - void SetNATServerPassword(const std::string &newValue) { m_NATServerPassword = newValue.empty() ? "DefaultServerPassword" : newValue; } + void SetNATServerPassword(const std::string& newValue) { m_NATServerPassword = newValue.empty() ? "DefaultServerPassword" : newValue; } /// /// Gets whether or not experimental multiplayer speedboosts should be used. @@ -387,27 +386,27 @@ namespace RTE { /// Gets the map of mods which are disabled. /// /// Map of mods which are disabled. - std::unordered_map & GetDisabledModsMap() { return m_DisabledMods; } + std::unordered_map& GetDisabledModsMap() { return m_DisabledMods; } /// /// Gets whether the specified mod is disabled in the settings. /// /// Mod to check. /// Whether the mod is disabled via settings. - bool IsModDisabled(const std::string &modModule) const { return (m_DisabledMods.find(modModule) != m_DisabledMods.end()) ? m_DisabledMods.at(modModule) : false; } + bool IsModDisabled(const std::string& modModule) const { return (m_DisabledMods.find(modModule) != m_DisabledMods.end()) ? m_DisabledMods.at(modModule) : false; } /// /// Gets the map of global scripts which are enabled. /// /// Map of global scripts which are enabled. - std::unordered_map & GetEnabledGlobalScriptMap() { return m_EnabledGlobalScripts; } + std::unordered_map& GetEnabledGlobalScriptMap() { return m_EnabledGlobalScripts; } /// /// Gets whether the specified global script is enabled in the settings. /// /// Global script to check. /// Whether the global script is enabled via settings. - bool IsGlobalScriptEnabled(const std::string &scriptName) const { return (m_EnabledGlobalScripts.find(scriptName) != m_EnabledGlobalScripts.end()) ? m_EnabledGlobalScripts.at(scriptName) : false; } + bool IsGlobalScriptEnabled(const std::string& scriptName) const { return (m_EnabledGlobalScripts.find(scriptName) != m_EnabledGlobalScripts.end()) ? m_EnabledGlobalScripts.at(scriptName) : false; } #pragma endregion #pragma region Misc Settings @@ -527,7 +526,6 @@ namespace RTE { #pragma endregion protected: - bool m_SettingsNeedOverwrite; //!< Whether the settings file was generated with minimal defaults and needs to be overwritten to be fully populated. bool m_ShowForeignItems; //!< Do not show foreign items in buy menu. @@ -581,7 +579,6 @@ namespace RTE { std::unordered_map m_EnabledGlobalScripts; //!< Map of the global script names we enabled. private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this. std::string m_SettingsPath; //!< String containing the Path to the Settings.ini file. @@ -592,8 +589,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - SettingsMan(const SettingsMan &reference) = delete; - SettingsMan & operator=(const SettingsMan &rhs) = delete; + SettingsMan(const SettingsMan& reference) = delete; + SettingsMan& operator=(const SettingsMan& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Managers/ThreadMan.cpp b/Source/Managers/ThreadMan.cpp index 5b20b6988..42a7ab4c6 100644 --- a/Source/Managers/ThreadMan.cpp +++ b/Source/Managers/ThreadMan.cpp @@ -3,54 +3,46 @@ ////////////////////////////////////////////////////////////////////////////////////////// // Description: Source file for the ThreadMan class. // Project: Retro Terrain Engine -// Author(s): -// -// - +// Author(s): +// +// ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files - #include "ThreadMan.h" using namespace std; -namespace RTE -{ - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ThreadMan, effectively -// resetting the members of this abstraction level only. - -void ThreadMan::Clear() -{ - m_PriorityThreadPool.reset(); - m_BackgroundThreadPool.reset(std::thread::hardware_concurrency() / 2); -} +namespace RTE { + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ThreadMan, effectively + // resetting the members of this abstraction level only. -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ThreadMan object ready for use. + void ThreadMan::Clear() { + m_PriorityThreadPool.reset(); + m_BackgroundThreadPool.reset(std::thread::hardware_concurrency() / 2); + } -int ThreadMan::Create() -{ - return 0; -} + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ThreadMan object ready for use. + int ThreadMan::Create() { + return 0; + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ThreadMan object. + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ThreadMan object. -void ThreadMan::Destroy() -{ - Clear(); -} + void ThreadMan::Destroy() { + Clear(); + } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/ThreadMan.h b/Source/Managers/ThreadMan.h index 7cf623a66..69f2be9b0 100644 --- a/Source/Managers/ThreadMan.h +++ b/Source/Managers/ThreadMan.h @@ -6,10 +6,9 @@ ////////////////////////////////////////////////////////////////////////////////////////// // Description: Header file for the ThreadMan class. // Project: Retro Terrain Engine -// Author(s): -// -// - +// Author(s): +// +// ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,121 +18,109 @@ #include "BS_thread_pool.hpp" -namespace RTE -{ - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: ThreadMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: The centralized singleton manager of all threads. -// Parent(s): Singleton -// Class history: 03/29/2014 ThreadMan created. - - -class ThreadMan: - public Singleton -{ - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: ThreadMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a ThreadMan object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - ThreadMan() { Clear(); Create(); } - - /// - /// Makes the TimerMan object ready for use. - /// - void Initialize() { }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~ThreadMan -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a ThreadMan object before deletion -// from system memory. -// Arguments: None. - - virtual ~ThreadMan() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the ThreadMan object ready for use. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - virtual int Create(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Virtual method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire ThreadMan, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - virtual void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the ThreadMan object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - - BS::thread_pool& GetPriorityThreadPool() { return m_PriorityThreadPool; } - - BS::thread_pool& GetBackgroundThreadPool() { return m_BackgroundThreadPool; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this ThreadMan, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - // Disallow the use of some implicit methods. - ThreadMan(const ThreadMan &reference); - ThreadMan & operator=(const ThreadMan &rhs); - - // For tasks that we want to be performed ASAP, i.e needs to be complete this frame at some point - BS::thread_pool m_PriorityThreadPool; - - // For background tasks that we can just let happen whenever over multiple frames - BS::thread_pool m_BackgroundThreadPool; -}; +namespace RTE { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: ThreadMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: The centralized singleton manager of all threads. + // Parent(s): Singleton + // Class history: 03/29/2014 ThreadMan created. + + class ThreadMan : + public Singleton { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: ThreadMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a ThreadMan object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + ThreadMan() { + Clear(); + Create(); + } + + /// + /// Makes the TimerMan object ready for use. + /// + void Initialize(){}; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~ThreadMan + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a ThreadMan object before deletion + // from system memory. + // Arguments: None. + + virtual ~ThreadMan() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the ThreadMan object ready for use. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + virtual int Create(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Virtual method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire ThreadMan, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + virtual void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the ThreadMan object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + BS::thread_pool& GetPriorityThreadPool() { return m_PriorityThreadPool; } + + BS::thread_pool& GetBackgroundThreadPool() { return m_BackgroundThreadPool; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this ThreadMan, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + ThreadMan(const ThreadMan& reference); + ThreadMan& operator=(const ThreadMan& rhs); + + // For tasks that we want to be performed ASAP, i.e needs to be complete this frame at some point + BS::thread_pool m_PriorityThreadPool; + + // For background tasks that we can just let happen whenever over multiple frames + BS::thread_pool m_BackgroundThreadPool; + }; } // namespace RTE diff --git a/Source/Managers/TimerMan.cpp b/Source/Managers/TimerMan.cpp index 44d06b309..49b331557 100644 --- a/Source/Managers/TimerMan.cpp +++ b/Source/Managers/TimerMan.cpp @@ -12,7 +12,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TimerMan::Clear() { m_StartTime = std::chrono::steady_clock::now(); @@ -31,34 +31,36 @@ namespace RTE { m_SimPaused = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TimerMan::Initialize() { // Get the frequency of ticks/s for this machine m_TicksPerSecond = 1000000; ResetTime(); - if (m_DeltaTimeS <= 0) { SetDeltaTimeSecs(c_DefaultDeltaTimeS); } + if (m_DeltaTimeS <= 0) { + SetDeltaTimeSecs(c_DefaultDeltaTimeS); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// long long TimerMan::GetAbsoluteTime() const { return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float TimerMan::GetRealToSimCap() const { return c_RealToSimCap; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float TimerMan::GetAIDeltaTimeSecs() const { return m_DeltaTimeS * static_cast(g_SettingsMan.GetAIUpdateInterval()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TimerMan::ResetTime() { m_StartTime = std::chrono::steady_clock::now(); @@ -72,7 +74,7 @@ namespace RTE { m_TimeScale = 1.0F; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TimerMan::UpdateSim() { if (TimeForSimUpdate()) { @@ -90,7 +92,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TimerMan::Update() { long long prevTime = m_RealTimeTicks; @@ -115,9 +117,9 @@ namespace RTE { // Reset the counter since the last drawn update. Set it negative since we're counting full pure sim updates and this will be incremented to 0 on next SimUpdate. if (m_DrawnSimUpdate) { - m_SimUpdatesSinceDrawn = -1; + m_SimUpdatesSinceDrawn = -1; } m_SimSpeed = std::min(maxPossibleSimSpeed, GetTimeScale()); } -} +} // namespace RTE diff --git a/Source/Managers/TimerMan.h b/Source/Managers/TimerMan.h index d02c897ae..b3826bf09 100644 --- a/Source/Managers/TimerMan.h +++ b/Source/Managers/TimerMan.h @@ -14,12 +14,14 @@ namespace RTE { class TimerMan : public Singleton { public: - #pragma region Creation /// /// Constructor method used to instantiate a TimerMan object in system memory. Initialize() should be called before using this object. /// - TimerMan() { Clear(); Initialize(); }; + TimerMan() { + Clear(); + Initialize(); + }; /// /// Makes the TimerMan object ready for use. @@ -46,7 +48,11 @@ namespace RTE { /// This also clears the accumulator, to avoid the case where the sim may update while paused when behind schedule. /// /// Whether the sim should be paused or not. - void PauseSim(bool pause = false) { m_SimPaused = pause; if(pause) m_SimAccumulator = 0.0F; } + void PauseSim(bool pause = false) { + m_SimPaused = pause; + if (pause) + m_SimAccumulator = 0.0F; + } /// /// Tells whether there is enough sim time accumulated to do at least one physics update. @@ -131,7 +137,10 @@ namespace RTE { /// Sets the number of ticks that a simulation update delta time should take. /// /// The new delta time in ticks. - void SetDeltaTimeTicks(int newDelta) { m_DeltaTime = newDelta; m_DeltaTimeS = static_cast(m_DeltaTime) / static_cast(m_TicksPerSecond); } + void SetDeltaTimeTicks(int newDelta) { + m_DeltaTime = newDelta; + m_DeltaTimeS = static_cast(m_DeltaTime) / static_cast(m_TicksPerSecond); + } /// /// Gets the current fixed delta time of the simulation updates, in ms. @@ -161,7 +170,10 @@ namespace RTE { /// Sets the number of seconds that a simulation update delta time should take. /// /// The new delta time in seconds. - void SetDeltaTimeSecs(float newDelta) { m_DeltaTimeS = newDelta; m_DeltaTime = static_cast(m_DeltaTimeS * static_cast(m_TicksPerSecond)); } + void SetDeltaTimeSecs(float newDelta) { + m_DeltaTimeS = newDelta; + m_DeltaTime = static_cast(m_DeltaTimeS * static_cast(m_TicksPerSecond)); + } #pragma endregion #pragma region Concrete Methods @@ -190,7 +202,6 @@ namespace RTE { #pragma endregion protected: - std::chrono::steady_clock::time_point m_StartTime; //!< The point in real time when the simulation (re)started. long long m_TicksPerSecond; //!< The frequency of ticks each second, ie the resolution of the timer. long long m_RealTimeTicks; //!< The number of actual microseconds counted so far. @@ -211,15 +222,14 @@ namespace RTE { bool m_SimPaused; //!< Simulation paused; no real time ticks will go to the sim accumulator. private: - /// /// Clears all the member variables of this TimerMan, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - TimerMan(const TimerMan &reference) = delete; - TimerMan & operator=(const TimerMan &rhs) = delete; + TimerMan(const TimerMan& reference) = delete; + TimerMan& operator=(const TimerMan& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Managers/UInputMan.cpp b/Source/Managers/UInputMan.cpp index b1b57d2f9..193e18968 100644 --- a/Source/Managers/UInputMan.cpp +++ b/Source/Managers/UInputMan.cpp @@ -24,11 +24,12 @@ namespace RTE { std::vector UInputMan::s_PrevJoystickStates(Players::MaxPlayerCount); std::vector UInputMan::s_ChangedJoystickStates(Players::MaxPlayerCount); -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::Clear() { m_SkipHandlingSpecialInput = false; - m_TextInput.clear();; + m_TextInput.clear(); + ; m_NumJoysticks = 0; m_OverrideInput = false; m_AbsoluteMousePos.Reset(); @@ -37,7 +38,7 @@ namespace RTE { m_MouseSensitivity = 0.6F; m_MouseWheelChange = 0; m_TrapMousePos = false; - m_PlayerScreenMouseBounds = { 0, 0, 0, 0 }; + m_PlayerScreenMouseBounds = {0, 0, 0, 0}; m_MouseTrapRadius = 350; m_LastDeviceWhichControlledGUICursor = InputDevice::DEVICE_KEYB_ONLY; m_DisableKeyboard = false; @@ -53,7 +54,7 @@ namespace RTE { std::fill(s_PrevMouseButtonStates.begin(), s_PrevMouseButtonStates.end(), false); std::fill(s_ChangedMouseButtonStates.begin(), s_ChangedMouseButtonStates.end(), false); - for (Gamepad &gamepad: s_PrevJoystickStates) { + for (Gamepad& gamepad: s_PrevJoystickStates) { if (gamepad.m_JoystickID != -1) { SDL_GameControllerClose(SDL_GameControllerFromInstanceID(gamepad.m_JoystickID)); gamepad.m_JoystickID = -1; @@ -86,18 +87,18 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int UInputMan::Initialize() { int numKeys; - const Uint8 *keyboardState = SDL_GetKeyboardState(&numKeys); + const Uint8* keyboardState = SDL_GetKeyboardState(&numKeys); std::copy(keyboardState, keyboardState + numKeys, s_PrevKeyStates.begin()); int controllerIndex = 0; for (size_t index = 0; index < std::min(SDL_NumJoysticks(), static_cast(Players::MaxPlayerCount)); ++index) { if (SDL_IsGameController(index)) { - SDL_GameController *controller = SDL_GameControllerOpen(index); + SDL_GameController* controller = SDL_GameControllerOpen(index); if (!controller) { g_ConsoleMan.PrintString("ERROR: Failed to connect gamepad " + std::to_string(index) + " " + std::string(SDL_GetError())); continue; @@ -109,7 +110,7 @@ namespace RTE { controllerIndex++; m_NumJoysticks++; } else { - SDL_Joystick *joy = SDL_JoystickOpen(index); + SDL_Joystick* joy = SDL_JoystickOpen(index); if (!joy) { g_ConsoleMan.PrintString("ERROR: Failed to connect joystick."); continue; @@ -123,34 +124,33 @@ namespace RTE { } m_PlayerScreenMouseBounds = { - 0, - 0, - static_cast(g_FrameMan.GetPlayerFrameBufferWidth(Players::NoPlayer) * g_WindowMan.GetResMultiplier()), - static_cast(g_FrameMan.GetPlayerFrameBufferHeight(Players::NoPlayer) * g_WindowMan.GetResMultiplier()) - }; + 0, + 0, + static_cast(g_FrameMan.GetPlayerFrameBufferWidth(Players::NoPlayer) * g_WindowMan.GetResMultiplier()), + static_cast(g_FrameMan.GetPlayerFrameBufferHeight(Players::NoPlayer) * g_WindowMan.GetResMultiplier())}; return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::LoadDeviceIcons() { - m_DeviceIcons[InputDevice::DEVICE_KEYB_ONLY] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Keyboard")); - m_DeviceIcons[InputDevice::DEVICE_MOUSE_KEYB] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Mouse")); + m_DeviceIcons[InputDevice::DEVICE_KEYB_ONLY] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Keyboard")); + m_DeviceIcons[InputDevice::DEVICE_MOUSE_KEYB] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Mouse")); for (int gamepad = InputDevice::DEVICE_GAMEPAD_1; gamepad < InputDevice::DEVICE_COUNT; gamepad++) { - m_DeviceIcons[gamepad] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad " + std::to_string(gamepad - 1))); + m_DeviceIcons[gamepad] = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device Gamepad " + std::to_string(gamepad - 1))); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector UInputMan::AnalogMoveValues(int whichPlayer) { Vector moveValues(0, 0); InputDevice device = m_ControlScheme.at(whichPlayer).GetDevice(); if (device >= InputDevice::DEVICE_GAMEPAD_1) { int whichJoy = GetJoystickIndex(device); - const std::array *inputElements = m_ControlScheme.at(whichPlayer).GetInputMappings(); + const std::array* inputElements = m_ControlScheme.at(whichPlayer).GetInputMappings(); // Assume axes are stretched out over up-down, and left-right. if (inputElements->at(InputElements::INPUT_L_LEFT).JoyDirMapped()) { @@ -163,12 +163,14 @@ namespace RTE { return moveValues; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector UInputMan::AnalogAimValues(int whichPlayer) { InputDevice device = m_ControlScheme.at(whichPlayer).GetDevice(); - if (IsInMultiplayerMode()) { device = InputDevice::DEVICE_MOUSE_KEYB; } + if (IsInMultiplayerMode()) { + device = InputDevice::DEVICE_MOUSE_KEYB; + } Vector aimValues(0, 0); if (device == InputDevice::DEVICE_MOUSE_KEYB) { @@ -176,7 +178,7 @@ namespace RTE { } if (device >= InputDevice::DEVICE_GAMEPAD_1) { int whichJoy = GetJoystickIndex(device); - const std::array *inputElements = m_ControlScheme.at(whichPlayer).GetInputMappings(); + const std::array* inputElements = m_ControlScheme.at(whichPlayer).GetInputMappings(); // Assume axes are stretched out over up-down, and left-right if (inputElements->at(InputElements::INPUT_R_LEFT).JoyDirMapped()) { @@ -189,7 +191,7 @@ namespace RTE { return aimValues; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector UInputMan::GetMenuDirectional() { Vector allInput(0, 0); @@ -237,27 +239,35 @@ namespace RTE { return allInput; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyKeyOrJoyInput() const { bool input = AnyKeyPress(); - if (!input) { input = AnyJoyInput(); } + if (!input) { + input = AnyJoyInput(); + } return input; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyPress() const { bool pressed = false; - if (!pressed) { pressed = AnyKeyPress(); } - if (!pressed) { pressed = AnyMouseButtonPress(); } - if (!pressed) { pressed = AnyJoyPress(); } + if (!pressed) { + pressed = AnyKeyPress(); + } + if (!pressed) { + pressed = AnyMouseButtonPress(); + } + if (!pressed) { + pressed = AnyJoyPress(); + } return pressed; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyStartPress(bool includeSpacebar) { if (KeyPressed(SDLK_ESCAPE) || (includeSpacebar && KeyPressed(SDLK_SPACE))) { @@ -271,7 +281,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyBackPress() { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { @@ -282,7 +292,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyKeyPress() const { for (size_t testKey = SDL_SCANCODE_A; testKey < SDL_NUM_SCANCODES; ++testKey) { @@ -293,7 +303,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int UInputMan::MouseUsedByPlayer() const { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { @@ -304,7 +314,7 @@ namespace RTE { return Players::NoPlayer; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::DisableMouseMoving(bool disable) { if (disable) { @@ -317,7 +327,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector UInputMan::GetMouseMovement(int whichPlayer) const { if (IsInMultiplayerMode() && whichPlayer >= Players::PlayerOne && whichPlayer < Players::MaxPlayerCount) { @@ -329,7 +339,7 @@ namespace RTE { return Vector(0, 0); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::SetMouseValueMagnitude(float magCap, int whichPlayer) { if (IsInMultiplayerMode() && whichPlayer >= Players::PlayerOne && whichPlayer < Players::MaxPlayerCount) { @@ -338,7 +348,7 @@ namespace RTE { m_AnalogMouseData.SetMagnitude(m_MouseTrapRadius * magCap); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::SetMouseValueAngle(float angle, int whichPlayer) { if (IsInMultiplayerMode() && whichPlayer >= Players::PlayerOne && whichPlayer < Players::MaxPlayerCount) { @@ -347,16 +357,16 @@ namespace RTE { m_AnalogMouseData.SetAbsRadAngle(angle); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void UInputMan::SetMousePos(const Vector &newPos, int whichPlayer) const { + void UInputMan::SetMousePos(const Vector& newPos, int whichPlayer) const { // Only mess with the mouse if the original mouse position is not above the screen and may be grabbing the title bar of the game window if (!m_DisableMouseMoving && !m_TrapMousePos && (whichPlayer == Players::NoPlayer || m_ControlScheme.at(whichPlayer).GetDevice() == InputDevice::DEVICE_MOUSE_KEYB)) { SDL_WarpMouseInWindow(g_WindowMan.GetWindow(), newPos.GetFloorIntX(), newPos.GetFloorIntY()); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyMouseButtonPress() const { for (int button = MouseButtons::MOUSE_LEFT; button < MouseButtons::MAX_MOUSE_BUTTONS; ++button) { @@ -367,7 +377,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::TrapMousePos(bool trap, int whichPlayer) { if (!IsInMultiplayerMode() && (whichPlayer == Players::NoPlayer || m_ControlScheme.at(whichPlayer).GetDevice() == InputDevice::DEVICE_MOUSE_KEYB)) { @@ -377,7 +387,7 @@ namespace RTE { m_TrapMousePosPerPlayer[whichPlayer] = trap; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::ForceMouseWithinBox(int x, int y, int width, int height, int whichPlayer) const { // Only mess with the mouse if the original mouse position is not above the screen and may be grabbing the title bar of the game window. @@ -400,11 +410,10 @@ namespace RTE { } } else { SDL_Rect newMouseBounds = { - std::clamp(m_PlayerScreenMouseBounds.x + x, m_PlayerScreenMouseBounds.x, rightMostPos), - std::clamp(m_PlayerScreenMouseBounds.y + y, m_PlayerScreenMouseBounds.y, bottomMostPos), - std::clamp(width, 0, rightMostPos - x), - std::clamp(height, 0, bottomMostPos - y) - }; + std::clamp(m_PlayerScreenMouseBounds.x + x, m_PlayerScreenMouseBounds.x, rightMostPos), + std::clamp(m_PlayerScreenMouseBounds.y + y, m_PlayerScreenMouseBounds.y, bottomMostPos), + std::clamp(width, 0, rightMostPos - x), + std::clamp(height, 0, bottomMostPos - y)}; if (newMouseBounds.x >= rightMostPos || newMouseBounds.y >= bottomMostPos) { g_ConsoleMan.PrintString("ERROR: Trying to force mouse wihin a box that is outside the player screen bounds!"); @@ -415,7 +424,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::ForceMouseWithinPlayerScreen(bool force, int whichPlayer) { float resMultiplier = g_WindowMan.GetResMultiplier(); @@ -426,20 +435,20 @@ namespace RTE { switch (g_ActivityMan.GetActivity()->ScreenOfPlayer(whichPlayer)) { case 0: - m_PlayerScreenMouseBounds = { 0, 0, screenWidth, screenHeight }; + m_PlayerScreenMouseBounds = {0, 0, screenWidth, screenHeight}; break; case 1: if (g_FrameMan.GetVSplit()) { - m_PlayerScreenMouseBounds = { screenWidth, 0, screenWidth, screenHeight }; + m_PlayerScreenMouseBounds = {screenWidth, 0, screenWidth, screenHeight}; } else { - m_PlayerScreenMouseBounds = { 0, screenHeight, screenWidth, screenHeight }; + m_PlayerScreenMouseBounds = {0, screenHeight, screenWidth, screenHeight}; } break; case 2: - m_PlayerScreenMouseBounds = { 0, screenHeight, screenWidth, screenHeight }; + m_PlayerScreenMouseBounds = {0, screenHeight, screenWidth, screenHeight}; break; case 3: - m_PlayerScreenMouseBounds = { screenWidth, screenHeight, screenWidth, screenHeight }; + m_PlayerScreenMouseBounds = {screenWidth, screenHeight, screenWidth, screenHeight}; break; default: force = false; @@ -456,12 +465,12 @@ namespace RTE { } } else { // Set the mouse bounds to the whole window so ForceMouseWithinBox is not stuck being relative to some player screen, because it can still bind the mouse even if this doesn't. - m_PlayerScreenMouseBounds = { 0, 0, static_cast(g_WindowMan.GetResX() * resMultiplier), static_cast(g_WindowMan.GetResY() * resMultiplier) }; + m_PlayerScreenMouseBounds = {0, 0, static_cast(g_WindowMan.GetResX() * resMultiplier), static_cast(g_WindowMan.GetResY() * resMultiplier)}; SDL_SetWindowMouseRect(g_WindowMan.GetWindow(), nullptr); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int UInputMan::GetJoystickAxisCount(int whichJoy) const { if (whichJoy >= 0 && whichJoy < s_PrevJoystickStates.size()) { @@ -470,7 +479,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int UInputMan::WhichJoyButtonHeld(int whichJoy) const { if (whichJoy >= 0 && whichJoy < s_PrevJoystickStates.size()) { @@ -484,7 +493,7 @@ namespace RTE { return JoyButtons::JOY_NONE; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int UInputMan::WhichJoyButtonPressed(int whichJoy) const { if (whichJoy >= 0 && whichJoy < s_PrevJoystickStates.size()) { @@ -497,7 +506,7 @@ namespace RTE { return JoyButtons::JOY_NONE; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float UInputMan::AnalogAxisValue(int whichJoy, int whichAxis) const { if (whichJoy < s_PrevJoystickStates.size() && whichAxis < s_PrevJoystickStates[whichJoy].m_Axis.size()) { @@ -506,14 +515,14 @@ namespace RTE { return analogValue; } } - return 0; + return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyJoyInput(bool checkForPresses) const { int gamepadIndex = 0; - for (const Gamepad &gamepad : s_PrevJoystickStates) { + for (const Gamepad& gamepad: s_PrevJoystickStates) { for (int button = 0; button < gamepad.m_Buttons.size(); ++button) { if (!checkForPresses) { if (gamepad.m_Buttons[button]) { @@ -537,7 +546,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::AnyJoyButtonPress(int whichJoy) const { for (int button = 0; button < s_PrevJoystickStates[whichJoy].m_Buttons.size(); ++button) { @@ -548,7 +557,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Vector UInputMan::GetNetworkAccumulatedRawMouseMovement(int player) { Vector accumulatedMovement = m_NetworkAccumulatedRawMouseMovement[player]; @@ -556,7 +565,7 @@ namespace RTE { return accumulatedMovement; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::ClearNetworkAccumulatedStates() { for (int inputState = InputState::Pressed; inputState < InputState::InputStateCount; inputState++) { @@ -566,7 +575,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::GetInputElementState(int whichPlayer, int whichElement, InputState whichState) { if (IsInMultiplayerMode() && whichPlayer >= Players::PlayerOne && whichPlayer < Players::MaxPlayerCount) { @@ -574,17 +583,21 @@ namespace RTE { } bool elementState = false; InputDevice device = m_ControlScheme.at(whichPlayer).GetDevice(); - const InputMapping *element = &(m_ControlScheme.at(whichPlayer).GetInputMappings()->at(whichElement)); + const InputMapping* element = &(m_ControlScheme.at(whichPlayer).GetInputMappings()->at(whichElement)); if (!elementState && device == InputDevice::DEVICE_KEYB_ONLY || (device == InputDevice::DEVICE_MOUSE_KEYB && !(whichElement == InputElements::INPUT_AIM_UP || whichElement == InputElements::INPUT_AIM_DOWN))) { elementState = GetKeyboardButtonState(static_cast(element->GetKey()), whichState); } - if (!elementState && device == InputDevice::DEVICE_MOUSE_KEYB && m_TrapMousePos) { elementState = GetMouseButtonState(whichPlayer, element->GetMouseButton(), whichState); } + if (!elementState && device == InputDevice::DEVICE_MOUSE_KEYB && m_TrapMousePos) { + elementState = GetMouseButtonState(whichPlayer, element->GetMouseButton(), whichState); + } if (!elementState && device >= InputDevice::DEVICE_GAMEPAD_1) { int whichJoy = GetJoystickIndex(device); elementState = GetJoystickButtonState(whichJoy, element->GetJoyButton(), whichState); - if (!elementState && element->JoyDirMapped()) { elementState = GetJoystickDirectionState(whichJoy, element->GetAxis(), element->GetDirection(), whichState); } + if (!elementState && element->JoyDirMapped()) { + elementState = GetJoystickDirectionState(whichJoy, element->GetAxis(), element->GetDirection(), whichState); + } } return elementState; } @@ -605,7 +618,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::GetMenuButtonState(int whichButton, InputState whichState) { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { @@ -625,7 +638,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::GetKeyboardButtonState(SDL_Scancode scancodeToTest, InputState whichState) const { if (m_DisableKeyboard && (scancodeToTest >= SDL_SCANCODE_0 && scancodeToTest < SDL_SCANCODE_ESCAPE)) { @@ -644,7 +657,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::GetMouseButtonState(int whichPlayer, int whichButton, InputState whichState) const { if (whichButton < MouseButtons::MOUSE_LEFT || whichButton >= MouseButtons::MAX_MOUSE_BUTTONS) { @@ -668,7 +681,7 @@ namespace RTE { } bool UInputMan::GetNetworkMouseButtonState(int whichPlayer, int whichButton, InputState whichState) const { - + if (whichPlayer == Players::NoPlayer || whichPlayer >= Players::MaxPlayerCount) { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { if (GetNetworkMouseButtonState(player, whichButton, whichState)) { @@ -691,7 +704,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::GetJoystickButtonState(int whichJoy, int whichButton, InputState whichState) const { if (whichJoy < 0 || whichJoy >= s_PrevJoystickStates.size() || whichButton < 0 || whichButton >= s_PrevJoystickStates[whichJoy].m_Buttons.size()) { @@ -715,7 +728,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool UInputMan::GetJoystickDirectionState(int whichJoy, int whichAxis, int whichDir, InputState whichState) const { if (whichJoy < 0 || whichJoy >= s_PrevJoystickStates.size() || whichAxis < 0 || whichAxis >= s_PrevJoystickStates[whichJoy].m_DigitalAxis.size()) { @@ -752,20 +765,20 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void UInputMan::QueueInputEvent(const SDL_Event &inputEvent) { + void UInputMan::QueueInputEvent(const SDL_Event& inputEvent) { m_EventQueue.emplace_back(inputEvent); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int UInputMan::Update() { m_LastDeviceWhichControlledGUICursor = InputDevice::DEVICE_KEYB_ONLY; std::fill(s_ChangedKeyStates.begin(), s_ChangedKeyStates.end(), false); std::fill(s_ChangedMouseButtonStates.begin(), s_ChangedMouseButtonStates.end(), false); - for (Gamepad &gamepad : s_ChangedJoystickStates) { + for (Gamepad& gamepad: s_ChangedJoystickStates) { std::fill(gamepad.m_Buttons.begin(), gamepad.m_Buttons.end(), false); std::fill(gamepad.m_Axis.begin(), gamepad.m_Axis.end(), 0); std::fill(gamepad.m_DigitalAxis.begin(), gamepad.m_DigitalAxis.end(), 0); @@ -841,7 +854,7 @@ namespace RTE { case SDL_CONTROLLERBUTTONUP: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: - if (std::vector::iterator device = std::find(s_PrevJoystickStates.begin(), s_PrevJoystickStates.end(), (inputEvent.type == SDL_CONTROLLERBUTTONDOWN || inputEvent.type == SDL_CONTROLLERBUTTONUP) ? inputEvent.cbutton.which : inputEvent.jbutton.which); device != s_PrevJoystickStates.end()) { + if (std::vector::iterator device = std::find(s_PrevJoystickStates.begin(), s_PrevJoystickStates.end(), (inputEvent.type == SDL_CONTROLLERBUTTONDOWN || inputEvent.type == SDL_CONTROLLERBUTTONUP) ? inputEvent.cbutton.which : inputEvent.jbutton.which); device != s_PrevJoystickStates.end()) { int button = -1; int state = -1; if (SDL_IsGameController(device->m_DeviceIndex)) { @@ -881,7 +894,6 @@ namespace RTE { default: break; } - } m_EventQueue.clear(); m_RawMouseMovement *= m_MouseSensitivity; @@ -900,7 +912,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::HandleSpecialInput() { // If we launched into editor directly, skip the logic and quit quickly. @@ -910,7 +922,7 @@ namespace RTE { } if (g_ActivityMan.IsInActivity()) { - const GameActivity *gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); + const GameActivity* gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); // Don't allow pausing and returning to main menu when running in server mode to not disrupt the simulation for the clients if (!g_NetworkServer.IsServerModeEnabled() && AnyStartPress(false) && (!gameActivity || !gameActivity->IsBuyGUIVisible(-1))) { g_ActivityMan.PauseActivity(true, FlagShiftState()); @@ -933,13 +945,13 @@ namespace RTE { // Ctrl+S to save continuous ScreenDumps if (KeyHeld(SDLK_s)) { g_FrameMan.SaveScreenToPNG("ScreenDump"); - // Ctrl+W to save a WorldDump + // Ctrl+W to save a WorldDump } else if (KeyPressed(SDLK_w)) { g_FrameMan.SaveWorldToPNG("WorldDump"); - // Ctrl+M to cycle draw modes + // Ctrl+M to cycle draw modes } else if (KeyPressed(SDLK_m)) { g_SceneMan.SetLayerDrawMode((g_SceneMan.GetLayerDrawMode() + 1) % 3); - // Ctrl+P to toggle performance stats + // Ctrl+P to toggle performance stats } else if (KeyPressed(SDLK_p)) { g_PerformanceMan.ShowPerformanceStats(!g_PerformanceMan.IsShowingPerformanceStats()); } else if (KeyPressed(SDLK_F2)) { @@ -956,10 +968,10 @@ namespace RTE { } else if (!FlagCtrlState() && FlagAltState()) { if (KeyPressed(SDLK_F2)) { ContentFile::ReloadAllBitmaps(); - // Alt+Enter to switch resolution multiplier + // Alt+Enter to switch resolution multiplier } else if (KeyPressed(SDLK_RETURN)) { g_WindowMan.ToggleFullscreen(); - // Alt+W to save ScenePreviewDump (miniature WorldDump) + // Alt+W to save ScenePreviewDump (miniature WorldDump) } else if (KeyPressed(SDLK_w)) { g_FrameMan.SaveWorldPreviewToPNG("ScenePreviewDump"); } else if (g_PerformanceMan.IsShowingPerformanceStats()) { @@ -986,7 +998,7 @@ namespace RTE { g_ActivityMan.LoadAndLaunchGame("QuickSave"); } else if (KeyPressed(SDLK_F10)) { g_ConsoleMan.ClearLog(); - // F12 to save a single ScreenDump - Note that F12 triggers a breakpoint when the VS debugger is attached, regardless of config - this is by design. Thanks Microsoft. + // F12 to save a single ScreenDump - Note that F12 triggers a breakpoint when the VS debugger is attached, regardless of config - this is by design. Thanks Microsoft. } else if (KeyPressed(SDLK_F12)) { g_FrameMan.SaveScreenToPNG("ScreenDump"); } @@ -1011,7 +1023,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::UpdateMouseInput() { // Detect and store mouse movement input, translated to analog stick emulation @@ -1037,9 +1049,7 @@ namespace RTE { } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::UpdateJoystickAxis(std::vector::iterator device, int axis, int value) { if (device != s_PrevJoystickStates.end()) { @@ -1067,7 +1077,7 @@ namespace RTE { bool isAxisMapped = false; if (joystickPlayer != Players::NoPlayer && deadZone > 0.0F) { Vector aimValues; - const std::array *inputElements = m_ControlScheme[joystickPlayer].GetInputMappings(); + const std::array* inputElements = m_ControlScheme[joystickPlayer].GetInputMappings(); std::array elementsToCheck = {InputElements::INPUT_L_LEFT, InputElements::INPUT_L_UP, InputElements::INPUT_R_LEFT, InputElements::INPUT_R_UP}; for (size_t i = 0; i < elementsToCheck.size(); i += 2) { @@ -1109,7 +1119,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::UpdateJoystickDigitalAxis() { for (size_t i = 0; i < s_PrevJoystickStates.size(); ++i) { @@ -1130,16 +1140,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::HandleGamepadHotPlug(int deviceIndex) { - SDL_Joystick *controller = nullptr; + SDL_Joystick* controller = nullptr; int controllerIndex = 0; for (controllerIndex = 0; controllerIndex < s_PrevJoystickStates.size(); ++controllerIndex) { if (s_PrevJoystickStates[controllerIndex].m_DeviceIndex == deviceIndex || s_PrevJoystickStates[controllerIndex].m_DeviceIndex == -1) { if (SDL_IsGameController(deviceIndex)) { - SDL_GameController *gameController = SDL_GameControllerOpen(deviceIndex); + SDL_GameController* gameController = SDL_GameControllerOpen(deviceIndex); if (!gameController) { std::string connectString = s_PrevJoystickStates[controllerIndex].m_DeviceIndex == deviceIndex ? "reconnect" : "connect"; g_ConsoleMan.PrintString("ERROR: Failed to " + connectString + " Gamepad " + std::to_string(controllerIndex + 1)); @@ -1182,8 +1192,7 @@ namespace RTE { } } - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::UpdateNetworkMouseMovement() { for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; player++) { if (!m_NetworkAccumulatedRawMouseMovement[player].IsZero()) { @@ -1194,24 +1203,23 @@ namespace RTE { } m_NetworkAccumulatedRawMouseMovement[player].Reset(); - // Reset mouse wheel state to stop over-wheeling m_NetworkMouseWheelState[player] = 0; } } void UInputMan::ClearNetworkChangedState() { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - for (int element = InputElements::INPUT_L_UP; element < InputElements::INPUT_COUNT; element++) { - m_NetworkServerChangedInputElementState[player][element] = false; - } - for (int mouseButton = MouseButtons::MOUSE_LEFT; mouseButton < MouseButtons::MAX_MOUSE_BUTTONS; mouseButton++) { - m_NetworkServerChangedMouseButtonState[player][mouseButton] = false; - } - m_NetworkMouseWheelState[player] = 0; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + for (int element = InputElements::INPUT_L_UP; element < InputElements::INPUT_COUNT; element++) { + m_NetworkServerChangedInputElementState[player][element] = false; + } + for (int mouseButton = MouseButtons::MOUSE_LEFT; mouseButton < MouseButtons::MAX_MOUSE_BUTTONS; mouseButton++) { + m_NetworkServerChangedMouseButtonState[player][mouseButton] = false; } + m_NetworkMouseWheelState[player] = 0; + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::SetNetworkInputElementState(int player, int element, bool newState) { if (element >= InputElements::INPUT_L_UP && element < InputElements::INPUT_COUNT && player >= Players::PlayerOne && player < Players::MaxPlayerCount) { m_NetworkServerChangedInputElementState[player][element] = (newState != m_NetworkServerPreviousInputElementState[player][element]); @@ -1219,7 +1227,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::SetNetworkMouseButtonState(int player, int whichButton, InputState whichState, bool newState) { if (whichButton >= MouseButtons::MOUSE_LEFT && whichButton < MouseButtons::MAX_MOUSE_BUTTONS && player >= Players::PlayerOne && player < Players::MaxPlayerCount) { m_NetworkServerChangedMouseButtonState[player][whichButton] = (newState != m_NetworkServerPreviousMouseButtonState[player][whichButton]); @@ -1227,7 +1235,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void UInputMan::StoreInputEventsForNextUpdate() { // Store pressed and released events to be picked by NetworkClient during its update. These will be cleared after update so we don't care about false but we store the result regardless. for (int inputState = InputState::Pressed; inputState < InputState::InputStateCount; inputState++) { @@ -1237,7 +1245,4 @@ namespace RTE { } } - - - -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/UInputMan.h b/Source/Managers/UInputMan.h index 65d2950ad..e2861f2f0 100644 --- a/Source/Managers/UInputMan.h +++ b/Source/Managers/UInputMan.h @@ -11,7 +11,7 @@ #define g_UInputMan UInputMan::Instance() extern "C" { - struct SDL_Rect; +struct SDL_Rect; } namespace RTE { @@ -25,11 +25,14 @@ namespace RTE { friend class SettingsMan; public: - /// /// Enumeration for the mouse cursor actions in menus. /// - enum MenuCursorButtons { MENU_PRIMARY, MENU_SECONDARY, MENU_EITHER }; + enum MenuCursorButtons { + MENU_PRIMARY, + MENU_SECONDARY, + MENU_EITHER + }; #pragma region Creation /// @@ -66,7 +69,7 @@ namespace RTE { /// Adds an (input) SDL_Event to the Event queue for processing on Update. /// /// The SDL input event to queue. - void QueueInputEvent(const SDL_Event &inputEvent); + void QueueInputEvent(const SDL_Event& inputEvent); /// /// Updates the state of this UInputMan. Supposed to be done every frame. @@ -94,21 +97,21 @@ namespace RTE { /// /// Which player to get the scheme for. /// A pointer to the requested player's control scheme. Ownership is NOT transferred! - InputScheme * GetControlScheme(int whichPlayer) { return IsInMultiplayerMode() ? &m_ControlScheme[Players::PlayerOne] : &m_ControlScheme.at(whichPlayer); } + InputScheme* GetControlScheme(int whichPlayer) { return IsInMultiplayerMode() ? &m_ControlScheme[Players::PlayerOne] : &m_ControlScheme.at(whichPlayer); } /// /// Get the current device Icon of a specific player's scheme. /// /// Which player to get the scheme device icon of. /// A const pointer to the requested player's control scheme icon. Ownership is NOT transferred! - const Icon * GetSchemeIcon(int whichPlayer) const { return (whichPlayer < Players::PlayerOne || whichPlayer >= Players::MaxPlayerCount) ? nullptr : m_DeviceIcons[m_ControlScheme.at(whichPlayer).GetDevice()]; } + const Icon* GetSchemeIcon(int whichPlayer) const { return (whichPlayer < Players::PlayerOne || whichPlayer >= Players::MaxPlayerCount) ? nullptr : m_DeviceIcons[m_ControlScheme.at(whichPlayer).GetDevice()]; } /// /// Get the current device Icon of a specific device. /// /// Which device to get the icon of. /// A const pointer to the requested device's control scheme icon. Ownership is NOT transferred! - const Icon * GetDeviceIcon(int whichDevice) const { return (whichDevice < InputDevice::DEVICE_KEYB_ONLY || whichDevice > InputDevice::DEVICE_GAMEPAD_4) ? nullptr : m_DeviceIcons[whichDevice]; } + const Icon* GetDeviceIcon(int whichDevice) const { return (whichDevice < InputDevice::DEVICE_KEYB_ONLY || whichDevice > InputDevice::DEVICE_GAMEPAD_4) ? nullptr : m_DeviceIcons[whichDevice]; } #pragma endregion #pragma region General Input Handling @@ -246,7 +249,7 @@ namespace RTE { /// /// A keycode to test. See SDL_KeyCode enumeration. /// Whether the key is held or not. - bool KeyHeld(SDL_Keycode keycodeToTest) const { return KeyHeld(SDL_GetScancodeFromKey(keycodeToTest));} + bool KeyHeld(SDL_Keycode keycodeToTest) const { return KeyHeld(SDL_GetScancodeFromKey(keycodeToTest)); } /// /// Gets whether a key was pressed between the last update and the one previous to it, by scancode. @@ -270,7 +273,7 @@ namespace RTE { bool KeyReleased(SDL_Scancode scancodeToTest) const { return GetKeyboardButtonState(scancodeToTest, InputState::Released); } /// - ///Gets whether a key was released between the last update and the one previous to it, by keycode. + /// Gets whether a key was released between the last update and the one previous to it, by keycode. /// /// A keycode to test. See SDL_KeyCode enumeration. /// Whether the key is released or not. @@ -287,7 +290,10 @@ namespace RTE { /// /// The std::string to fill. /// Whether there is text input. - bool GetTextInput(std::string &text) const { text = m_TextInput; return !m_TextInput.empty(); } + bool GetTextInput(std::string& text) const { + text = m_TextInput; + return !m_TextInput.empty(); + } /// /// Returns whether text input events are available. @@ -298,7 +304,7 @@ namespace RTE { /// Returns the current text input. /// /// The current text input. - const std::string& GetTextInput() const {return m_TextInput; } + const std::string& GetTextInput() const { return m_TextInput; } #pragma endregion #pragma region Mouse Handling @@ -325,7 +331,7 @@ namespace RTE { /// Set the absolute mouse position (e.g. for player input mouse movement). Does not move the system cursor. /// /// The new mouse position. - void SetAbsoluteMousePosition(const Vector &pos) { m_AbsoluteMousePos = pos; } + void SetAbsoluteMousePosition(const Vector& pos) { m_AbsoluteMousePos = pos; } /// /// Gets the relative movement of the mouse since last update. Only returns true if the selected player is actually using the mouse. @@ -353,7 +359,7 @@ namespace RTE { /// /// Where to place the mouse. /// Which player is trying to control the mouse. Only the player with actual control over the mouse will be affected. -1 means do it regardless of player. - void SetMousePos(const Vector &newPos, int whichPlayer = -1) const; + void SetMousePos(const Vector& newPos, int whichPlayer = -1) const; /// /// Gets mouse sensitivity while in Activity. @@ -581,7 +587,7 @@ namespace RTE { /// /// The player to set for. /// The new position of the mouse. - void SetNetworkMouseMovement(int player, const Vector &input) { m_NetworkAccumulatedRawMouseMovement[player] += input; } + void SetNetworkMouseMovement(int player, const Vector& input) { m_NetworkAccumulatedRawMouseMovement[player] += input; } /// /// Sets whether an input element is held by a player during network multiplayer. @@ -620,7 +626,11 @@ namespace RTE { /// /// The player to set for. /// The new state of the mouse wheel. - void SetNetworkMouseWheelState(int player, int state) { if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { m_NetworkMouseWheelState[player] += state; } } + void SetNetworkMouseWheelState(int player, int state) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { + m_NetworkMouseWheelState[player] += state; + } + } /// /// Gets whether the specified input element is pressed during network multiplayer. @@ -643,11 +653,15 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for the different states an input element or button can be in. /// - enum InputState { Held, Pressed, Released, InputStateCount }; + enum InputState { + Held, + Pressed, + Released, + InputStateCount + }; static std::array s_PrevKeyStates; //!< Key states as they were the previous update. static std::array s_ChangedKeyStates; //!< Key states that have changed. @@ -670,7 +684,7 @@ namespace RTE { bool m_OverrideInput; //!< If true then this instance operates in multiplayer mode and the input is overridden by network input. std::array m_ControlScheme; //!< Which control scheme is being used by each player. - const Icon *m_DeviceIcons[InputDevice::DEVICE_COUNT]; //!< The Icons representing all different devices. + const Icon* m_DeviceIcons[InputDevice::DEVICE_COUNT]; //!< The Icons representing all different devices. Vector m_AbsoluteMousePos; //!< The absolute mouse position in screen coordinates. Vector m_RawMouseMovement; //!< The raw absolute movement of the mouse between the last two Updates. @@ -738,7 +752,7 @@ namespace RTE { /// Which menu button to check for. See MenuButtons enumeration. /// Which state to check for. See InputState enumeration. /// Whether the menu button is in the specified state or not. - bool GetMenuButtonState(int whichButton, InputState whichState) ; + bool GetMenuButtonState(int whichButton, InputState whichState); /// /// Gets whether a keyboard key is in the specified state. @@ -854,8 +868,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - UInputMan(const UInputMan &reference) = delete; - UInputMan & operator=(const UInputMan &rhs) = delete; + UInputMan(const UInputMan& reference) = delete; + UInputMan& operator=(const UInputMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Managers/WindowMan.cpp b/Source/Managers/WindowMan.cpp index 20691eca9..c76777066 100644 --- a/Source/Managers/WindowMan.cpp +++ b/Source/Managers/WindowMan.cpp @@ -24,13 +24,13 @@ namespace RTE { - void SDLWindowDeleter::operator()(SDL_Window *window) const { SDL_DestroyWindow(window); } - void SDLRendererDeleter::operator()(SDL_Renderer *renderer) const { SDL_DestroyRenderer(renderer); } - void SDLTextureDeleter::operator()(SDL_Texture *texture) const { SDL_DestroyTexture(texture); } + void SDLWindowDeleter::operator()(SDL_Window* window) const { SDL_DestroyWindow(window); } + void SDLRendererDeleter::operator()(SDL_Renderer* renderer) const { SDL_DestroyRenderer(renderer); } + void SDLTextureDeleter::operator()(SDL_Texture* texture) const { SDL_DestroyTexture(texture); } void SDLContextDeleter::operator()(SDL_GLContext context) const { SDL_GL_DeleteContext(context); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::Clear() { m_EventQueue.clear(); @@ -67,7 +67,7 @@ namespace RTE { m_UseMultiDisplays = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::ClearMultiDisplayData() { m_MultiDisplayTextureOffsets.clear(); @@ -75,13 +75,13 @@ namespace RTE { m_MultiDisplayWindows.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// WindowMan::WindowMan() { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// WindowMan::~WindowMan() = default; @@ -93,7 +93,7 @@ namespace RTE { glDeleteFramebuffers(1, &m_ScreenBufferFBO); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::Initialize() { m_NumDisplays = SDL_GetNumVideoDisplays(); @@ -129,7 +129,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::CreatePrimaryWindow() { std::string windowTitle = "Cortex Command Community Project"; @@ -180,7 +180,7 @@ namespace RTE { } #ifdef __linux__ - SDL_Surface *iconSurface = IMG_ReadXPMFromArray(ccicon); + SDL_Surface* iconSurface = IMG_ReadXPMFromArray(ccicon); if (iconSurface) { SDL_SetWindowIcon(m_PrimaryWindow.get(), iconSurface); SDL_FreeSurface(iconSurface); @@ -213,7 +213,7 @@ namespace RTE { glBufferData(GL_ARRAY_BUFFER, sizeof(c_Quad), c_Quad.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); glEnableVertexAttribArray(1); glBindVertexArray(0); glGenTextures(1, &m_BackBuffer32Texture); @@ -222,7 +222,7 @@ namespace RTE { TracyGpuContext; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::CreateBackBufferTexture() { glBindTexture(GL_TEXTURE_2D, m_BackBuffer32Texture); @@ -235,7 +235,7 @@ namespace RTE { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int WindowMan::GetWindowResX() { int w, h; @@ -263,7 +263,7 @@ namespace RTE { SDL_GL_SetSwapInterval(sdlEnableVSync); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::UpdatePrimaryDisplayInfo() { m_PrimaryWindowDisplayIndex = SDL_GetWindowDisplayIndex(m_PrimaryWindow.get()); @@ -276,14 +276,14 @@ namespace RTE { } SDL_Rect WindowMan::GetUsableBoundsWithDecorations(int display) { - if(m_Fullscreen) { + if (m_Fullscreen) { SDL_Rect displayBounds; SDL_GetDisplayBounds(display, &displayBounds); return displayBounds; } SDL_Rect displayBounds; SDL_GetDisplayUsableBounds(display, &displayBounds); - + int top, left, bottom, right; SDL_GetWindowBordersSize(m_PrimaryWindow.get(), &top, &left, &bottom, &right); displayBounds.x += left; @@ -298,15 +298,14 @@ namespace RTE { if (resMultiplier == 1) { return (resX == displayBounds.w) && (resY == displayBounds.h); } else { - return glm::epsilonEqual(resX * resMultiplier, displayBounds.w, resMultiplier) - && glm::epsilonEqual(resY * resMultiplier, displayBounds.h, resMultiplier); + return glm::epsilonEqual(resX * resMultiplier, displayBounds.w, resMultiplier) && glm::epsilonEqual(resY * resMultiplier, displayBounds.h, resMultiplier); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::MapDisplays(bool updatePrimaryDisplayInfo) { - auto setSingleDisplayMode = [this](const std::string &errorMsg = "") { + auto setSingleDisplayMode = [this](const std::string& errorMsg = "") { m_MaxResX = m_PrimaryWindowDisplayWidth; m_MaxResY = m_PrimaryWindowDisplayHeight; m_MaxResMultiplier = std::min(m_MaxResX / static_cast(c_MinResX), m_MaxResY / static_cast(c_MinResY)); @@ -361,11 +360,11 @@ namespace RTE { } std::stable_sort(m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen.begin(), m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen.end(), - [](auto left, auto right) { - return left.second.x < right.second.x; - }); + [](auto left, auto right) { + return left.second.x < right.second.x; + }); - for (const auto &[displayIndex, displayBounds] : m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen) { + for (const auto& [displayIndex, displayBounds]: m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen) { // Translate display offsets to backbuffer offsets, where the top left corner is (0,0) to figure out if the display arrangement is unreasonable garbage, i.e not top or bottom edge aligned. // If any of the translated offsets ends up negative, or over-positive for the Y offset, disallow going into multi-display fullscreen // because we'll just end up with an access violation when trying to read from the backbuffer pixel array during rendering. @@ -378,7 +377,7 @@ namespace RTE { } } - for (const auto &[displayIndex, displayBounds] : m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen) { + for (const auto& [displayIndex, displayBounds]: m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen) { #if SDL_VERSION_ATLEAST(2, 24, 0) m_DisplayArrangmentLeftMostDisplayIndex = SDL_GetRectDisplayIndex(&displayBounds); if (m_DisplayArrangmentLeftMostDisplayIndex >= 0) { @@ -404,17 +403,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void WindowMan::ValidateResolution(int &resX, int &resY, float &resMultiplier) const { + void WindowMan::ValidateResolution(int& resX, int& resY, float& resMultiplier) const { if (resX < c_MinResX || resY < c_MinResY) { resX = c_MinResX; resY = c_MinResY; resMultiplier = 1.0f; RTEError::ShowMessageBox("Resolution too low, overriding to fit!"); g_SettingsMan.SetSettingsNeedOverwrite(); - } - else if (resMultiplier > m_MaxResMultiplier) { + } else if (resMultiplier > m_MaxResMultiplier) { resMultiplier = 1.0f; RTEError::ShowMessageBox("Resolution multiplier too high, overriding to fit!"); g_SettingsMan.SetSettingsNeedOverwrite(); @@ -440,7 +438,7 @@ namespace RTE { m_PrimaryWindowViewport = std::make_unique(offsetX, windowH - offsetY - height, width, height); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::AttemptToRevertToPreviousResolution(bool revertToDefaults) { auto setDefaultResSettings = [this]() { @@ -474,7 +472,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::ChangeResolution(int newResX, int newResY, float newResMultiplier, bool fullscreen, bool displaysAlreadyMapped) { @@ -540,7 +538,7 @@ namespace RTE { g_ConsoleMan.PrintString("SYSTEM: " + std::string(!recoveredToPreviousSettings ? "Switched to different resolution." : "Failed to switch to different resolution. Reverted to previous settings.")); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::ToggleFullscreen() { bool fullscreen = !m_Fullscreen; @@ -557,7 +555,7 @@ namespace RTE { ChangeResolution(m_ResX, m_ResY, m_ResMultiplier, fullscreen, true); } - if(!fullscreen) { + if (!fullscreen) { SDL_SetWindowFullscreen(m_PrimaryWindow.get(), 0); SDL_SetWindowMinimumSize(m_PrimaryWindow.get(), c_MinResX, c_MinResY); } else { @@ -571,7 +569,7 @@ namespace RTE { SetViewportLetterboxed(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool WindowMan::ChangeResolutionToMultiDisplayFullscreen(float resMultiplier) { if (!m_CanMultiDisplayFullscreen) { @@ -589,7 +587,7 @@ namespace RTE { bool errorSettingFullscreen = false; - for (const auto &[displayIndex, displayBounds] : m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen) { + for (const auto& [displayIndex, displayBounds]: m_ValidDisplayIndicesAndBoundsForMultiDisplayFullscreen) { int displayOffsetX = displayBounds.x; int displayOffsetY = displayBounds.y; int displayWidth = displayBounds.w; @@ -613,11 +611,11 @@ namespace RTE { glm::mat4 textureOffset = glm::translate(glm::mat4(1), {m_DisplayArrangementLeftMostOffset, m_DisplayArrangementTopMostOffset, 0.0f}); textureOffset = glm::scale(textureOffset, {m_MaxResX * 0.5f, m_MaxResY * 0.5f, 1.0f}); - textureOffset = glm::translate(textureOffset, {1.0f, 1.0f, 0.0f}); //Shift the quad so we're scaling from top left instead of center. + textureOffset = glm::translate(textureOffset, {1.0f, 1.0f, 0.0f}); // Shift the quad so we're scaling from top left instead of center. m_MultiDisplayTextureOffsets.emplace_back(textureOffset); glm::mat4 projection = glm::ortho(static_cast(textureOffsetX), static_cast(textureOffsetX + displayWidth), static_cast(textureOffsetY), static_cast(textureOffsetY + displayHeight), -1.0f, 1.0f); - m_MultiDisplayProjections.emplace_back( projection); + m_MultiDisplayProjections.emplace_back(projection); } if (errorSettingFullscreen) { @@ -630,14 +628,14 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void WindowMan::DisplaySwitchIn(SDL_Window *windowThatShouldTakeInputFocus) const { + void WindowMan::DisplaySwitchIn(SDL_Window* windowThatShouldTakeInputFocus) const { g_UInputMan.DisableMouseMoving(false); g_UInputMan.DisableKeys(false); if (!m_MultiDisplayWindows.empty()) { - for (const auto &window : m_MultiDisplayWindows) { + for (const auto& window: m_MultiDisplayWindows) { SDL_RaiseWindow(window.get()); } SDL_RaiseWindow(windowThatShouldTakeInputFocus); @@ -649,7 +647,7 @@ namespace RTE { SDL_ShowCursor(SDL_DISABLE); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::DisplaySwitchOut() const { g_UInputMan.DisableMouseMoving(true); @@ -660,16 +658,16 @@ namespace RTE { SDL_SetCursor(nullptr); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void WindowMan::QueueWindowEvent(const SDL_Event &windowEvent) { + void WindowMan::QueueWindowEvent(const SDL_Event& windowEvent) { if (g_UInputMan.IsInMultiplayerMode()) { return; } m_EventQueue.emplace_back(windowEvent); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::Update() { // Some bullshit we have to deal with to correctly focus windows in multi-display fullscreen so mouse binding/unbinding works correctly. Not relevant for single window. @@ -693,7 +691,7 @@ namespace RTE { switch (windowEvent.window.event) { case SDL_WINDOWEVENT_ENTER: if (SDL_GetWindowID(SDL_GetMouseFocus()) > 0 && m_AnyWindowHasFocus && FullyCoversAllDisplays()) { - for (const auto &window : m_MultiDisplayWindows) { + for (const auto& window: m_MultiDisplayWindows) { SDL_RaiseWindow(window.get()); } SDL_RaiseWindow(SDL_GetWindowFromID(windowID)); @@ -724,7 +722,7 @@ namespace RTE { m_EventQueue.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::ClearRenderer() { glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -737,7 +735,7 @@ namespace RTE { m_DrawPostProcessBuffer = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void WindowMan::UploadFrame() { TracyGpuZone("Upload Frame"); @@ -804,4 +802,4 @@ namespace RTE { FrameMark; } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Managers/WindowMan.h b/Source/Managers/WindowMan.h index 292813702..711bb0ebd 100644 --- a/Source/Managers/WindowMan.h +++ b/Source/Managers/WindowMan.h @@ -7,11 +7,11 @@ #define g_WindowMan WindowMan::Instance() extern "C" { - struct SDL_Window; - struct SDL_Renderer; - struct SDL_Texture; - struct SDL_Rect; - union SDL_Event; +struct SDL_Window; +struct SDL_Renderer; +struct SDL_Texture; +struct SDL_Rect; +union SDL_Event; } namespace RTE { @@ -19,19 +19,19 @@ namespace RTE { class Shader; struct SDLWindowDeleter { - void operator() (SDL_Window *window) const; + void operator()(SDL_Window* window) const; }; struct SDLRendererDeleter { - void operator()(SDL_Renderer *renderer) const; + void operator()(SDL_Renderer* renderer) const; }; struct SDLTextureDeleter { - void operator()(SDL_Texture *texture) const; + void operator()(SDL_Texture* texture) const; }; struct SDLContextDeleter { - void operator()(void *context) const; + void operator()(void* context) const; }; /// @@ -41,7 +41,6 @@ namespace RTE { friend class SettingsMan; public: - #pragma region Creation /// /// Constructor method used to instantiate a WindowMan object in system memory. Initialize() should be called before using the object. @@ -71,7 +70,7 @@ namespace RTE { /// Gets a pointer to the primary game window. OWNERSHIP IS NOT TRANSFERRED! /// /// Pointer to the primary game window. - SDL_Window * GetWindow() const { return m_PrimaryWindow.get(); } + SDL_Window* GetWindow() const { return m_PrimaryWindow.get(); } /// /// Gets whether any of the game windows is currently in focus. @@ -109,7 +108,6 @@ namespace RTE { /// The horizontal resolution the game window is currently sized at, in pixels. int GetWindowResX(); - /// /// Gets the vertical resolution the game window is currently sized at, in pixels. /// @@ -227,7 +225,7 @@ namespace RTE { /// Adds an SDL_Event to the Event queue for processing on Update. /// /// The SDL window event to queue. - void QueueWindowEvent(const SDL_Event &windowEvent); + void QueueWindowEvent(const SDL_Event& windowEvent); /// /// Updates the state of this WindowMan. @@ -251,7 +249,6 @@ namespace RTE { #pragma endregion private: - std::vector m_EventQueue; //!< List of incoming window events. bool m_FocusEventsDispatchedByMovingBetweenWindows; //!< Whether queued events were dispatched due to raising windows when moving between windows in multi-display fullscreen in the previous update. @@ -351,7 +348,7 @@ namespace RTE { /// Game window width to check. /// Game window height to check. /// Game window resolution multiplier to check. - void ValidateResolution(int &resX, int &resY, float &resMultiplier) const; + void ValidateResolution(int& resX, int& resY, float& resMultiplier) const; /// /// Attempts to revert to the previous resolution settings if the new ones failed for whatever reason. Will recursively attempt to revert to defaults if previous settings fail as well. @@ -360,7 +357,7 @@ namespace RTE { void AttemptToRevertToPreviousResolution(bool revertToDefaults = false); #pragma endregion -#pragma region Multi-Display Handling +#pragma region Multi - Display Handling /// /// Clears all the multi-display data, resetting the game to a single-window-single-display state. /// @@ -379,7 +376,7 @@ namespace RTE { /// Handles focus gain when switching back to the game window. /// /// The window that should take focus of input after all the windows are raised. This is only relevant in multi-display fullscreen. - void DisplaySwitchIn(SDL_Window *windowThatShouldTakeInputFocus) const; + void DisplaySwitchIn(SDL_Window* windowThatShouldTakeInputFocus) const; /// /// Handles focus loss when switching away from the game window. @@ -394,8 +391,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - WindowMan(const WindowMan &reference) = delete; - WindowMan & operator=(const WindowMan &rhs) = delete; + WindowMan(const WindowMan& reference) = delete; + WindowMan& operator=(const WindowMan& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/AreaEditorGUI.cpp b/Source/Menus/AreaEditorGUI.cpp index 960f6d8fb..3bbbeafc0 100644 --- a/Source/Menus/AreaEditorGUI.cpp +++ b/Source/Menus/AreaEditorGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datArealms.com // http://www.datArealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -37,95 +36,89 @@ using namespace RTE; // Description: Clears all the member variables of this AreaEditorGUI, effectively // resetting the members of this abstraction level only. -void AreaEditorGUI::Clear() -{ - m_pController = 0; - m_FullFeatured = false; - m_EditMade = false; - m_EditorGUIMode = PICKINGAREA; - m_PreviousMode = PREADDMOVEBOX; - m_BlinkTimer.Reset(); - m_BlinkMode = NOBLINK; - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); +void AreaEditorGUI::Clear() { + m_pController = 0; + m_FullFeatured = false; + m_EditMade = false; + m_EditorGUIMode = PICKINGAREA; + m_PreviousMode = PREADDMOVEBOX; + m_BlinkTimer.Reset(); + m_BlinkMode = NOBLINK; + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); m_PieMenu = nullptr; - m_pPicker = 0; - m_GridSnapping = true; - m_CursorPos.Reset(); - m_CursorOffset.Reset(); - m_CursorInAir = true; - m_pCurrentArea = 0; - m_EditedBox.Reset(); - m_pBoxToBlink = 0; + m_pPicker = 0; + m_GridSnapping = true; + m_CursorPos.Reset(); + m_CursorOffset.Reset(); + m_CursorInAir = true; + m_pCurrentArea = 0; + m_EditedBox.Reset(); + m_pBoxToBlink = 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the AreaEditorGUI Area ready for use. -int AreaEditorGUI::Create(Controller *pController, bool fullFeatured, int whichModuleSpace) -{ - RTEAssert(pController, "No controller sent to AreaEditorGUI on creation!"); - m_pController = pController; +int AreaEditorGUI::Create(Controller* pController, bool fullFeatured, int whichModuleSpace) { + RTEAssert(pController, "No controller sent to AreaEditorGUI on creation!"); + m_pController = pController; - m_FullFeatured = fullFeatured; + m_FullFeatured = fullFeatured; - if (m_PieMenu) { m_PieMenu = nullptr; } + if (m_PieMenu) { + m_PieMenu = nullptr; + } std::string pieMenuName = m_FullFeatured ? "Area Editor Full Pie Menu" : "Area Editor Minimal Pie Menu"; - m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", pieMenuName)->Clone())); + m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", pieMenuName)->Clone())); m_PieMenu->SetMenuController(pController); - // Allocate and (re)create the Editor GUIs - if (!m_pPicker) - m_pPicker = new AreaPickerGUI(); - else - m_pPicker->Destroy(); - m_pPicker->Create(pController); + // Allocate and (re)create the Editor GUIs + if (!m_pPicker) + m_pPicker = new AreaPickerGUI(); + else + m_pPicker->Destroy(); + m_pPicker->Create(pController); - // Cursor init - m_CursorPos = g_SceneMan.GetSceneDim() / 2; + // Cursor init + m_CursorPos = g_SceneMan.GetSceneDim() / 2; - // Set initial focus, category list, and label settings - m_EditorGUIMode = PICKINGAREA; - m_pCurrentArea = 0; + // Set initial focus, category list, and label settings + m_EditorGUIMode = PICKINGAREA; + m_pCurrentArea = 0; - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); - return 0; + return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the AreaEditorGUI Area. -void AreaEditorGUI::Destroy() -{ - delete m_pPicker; +void AreaEditorGUI::Destroy() { + delete m_pPicker; - Clear(); + Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetController ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the controller used by this. The ownership of the controller is // NOT transferred! -void AreaEditorGUI::SetController(Controller *pController) -{ - m_pController = pController; +void AreaEditorGUI::SetController(Controller* pController) { + m_pController = pController; m_PieMenu->SetMenuController(pController); - m_pPicker->SetController(pController); + m_pPicker->SetController(pController); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetPosOnScreen ////////////////////////////////////////////////////////////////////////////////////////// @@ -133,12 +126,10 @@ void AreaEditorGUI::SetController(Controller *pController) // left corner, then 0, 0. This will affect the way the mouse is positioned // etc. -void AreaEditorGUI::SetPosOnScreen(int newPosX, int newPosY) -{ - m_pPicker->SetPosOnScreen(newPosX, newPosY); +void AreaEditorGUI::SetPosOnScreen(int newPosX, int newPosY) { + m_pPicker->SetPosOnScreen(newPosX, newPosY); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetActivatedPieSlice ////////////////////////////////////////////////////////////////////////////////////////// @@ -148,147 +139,139 @@ PieSlice::SliceType AreaEditorGUI::GetActivatedPieSlice() const { return m_PieMenu->GetPieCommand(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetCurrentArea ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the currently selected Area of this Editor. Ownership IS NOT // transferred! -void AreaEditorGUI::SetCurrentArea(Scene::Area *pArea) -{ - if (!pArea) - return; - - m_pCurrentArea = pArea; - // Display the name of the newly seclected Area in the center of the screen - g_FrameMan.ClearScreenText(g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - g_FrameMan.SetScreenText(m_pCurrentArea->GetName(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer()), 0, 1500, true); - // Make the yellow outline edited box vanish - m_EditedBox.Reset(); - - // Jump the cursor pos to a reasonable center of the newly selected Area's coverage area - if (!m_pCurrentArea->m_BoxList.empty()) - { - // Average center of the all the boxes, weighted by their respective areas - m_CursorPos = m_pCurrentArea->GetCenterPoint(); - } +void AreaEditorGUI::SetCurrentArea(Scene::Area* pArea) { + if (!pArea) + return; + + m_pCurrentArea = pArea; + // Display the name of the newly seclected Area in the center of the screen + g_FrameMan.ClearScreenText(g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + g_FrameMan.SetScreenText(m_pCurrentArea->GetName(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer()), 0, 1500, true); + // Make the yellow outline edited box vanish + m_EditedBox.Reset(); + + // Jump the cursor pos to a reasonable center of the newly selected Area's coverage area + if (!m_pCurrentArea->m_BoxList.empty()) { + // Average center of the all the boxes, weighted by their respective areas + m_CursorPos = m_pCurrentArea->GetCenterPoint(); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePickerList ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the list that the GUI's Area picker has, from the current // scene state. -void AreaEditorGUI::UpdatePickerList(std::string selectAreaName) -{ - m_pPicker->UpdateAreasList(selectAreaName); +void AreaEditorGUI::UpdatePickerList(std::string selectAreaName) { + m_pPicker->UpdateAreasList(selectAreaName); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Update ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void AreaEditorGUI::Update() -{ - // Update the user controller -// m_pController->Update(); - - if (!g_SceneMan.GetScene()) - return; - - // If no Area is selected yet, and there are Areas in the current scene, then select the first one automatically - if (!m_pCurrentArea && !g_SceneMan.GetScene()->m_AreaList.empty()) - m_pCurrentArea = &(g_SceneMan.GetScene()->m_AreaList.front()); - - m_EditMade = false; - m_pBoxToBlink = 0; - - //////////////////////////////////////////// - // Blinking logic -/* - if (m_BlinkMode == OBJECTBLINK) - { - m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); - } - else if (m_BlinkMode == NOCRAFT) - { - bool blink = m_BlinkTimer.AlternateSim(250); - m_pCraftLabel->SetVisible(blink); - m_pCraftBox->SetVisible(blink); - } - - // Time out the blinker - if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) - { - m_pCostLabel->SetVisible(true); - m_pCraftLabel->SetVisible(true); - m_pCraftBox->SetVisible(true); - m_BlinkMode = NOBLINK; - } -*/ - ///////////////////////////////////////////// - // Repeating input logic - - bool pressLeft = m_pController->IsState(PRESS_LEFT); - bool pressRight = m_pController->IsState(PRESS_RIGHT); - bool pressUp = m_pController->IsState(PRESS_UP); - bool pressDown = m_pController->IsState(PRESS_DOWN); - - // If no direciton is held down, then cancel the repeating - if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) - { - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - } - - // Check if any direction has been held for the starting amount of time to get into repeat mode - if (m_RepeatStartTimer.IsPastRealMS(200)) - { - // Check for the repeat interval - if (m_RepeatTimer.IsPastRealMS(30)) - { - if (m_pController->IsState(MOVE_RIGHT)) - pressRight = true; - else if (m_pController->IsState(MOVE_LEFT)) - pressLeft = true; - - if (m_pController->IsState(MOVE_UP)) - pressUp = true; - else if (m_pController->IsState(MOVE_DOWN)) - pressDown = true; - - m_RepeatTimer.Reset(); - } - } - - /////////////////////////////////////////////// - // Analog cursor input - - Vector analogInput; - if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) - analogInput = m_pController->GetAnalogMove(); -// else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) -// analogInput = m_pController->GetAnalogAim(); - - ///////////////////////////////////////////// - // PIE MENU - - m_PieMenu->Update(); - - // Show the pie menu only when the secondary button is held down - if (m_pController->IsState(PRESS_SECONDARY) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGAREA) { +void AreaEditorGUI::Update() { + // Update the user controller + // m_pController->Update(); + + if (!g_SceneMan.GetScene()) + return; + + // If no Area is selected yet, and there are Areas in the current scene, then select the first one automatically + if (!m_pCurrentArea && !g_SceneMan.GetScene()->m_AreaList.empty()) + m_pCurrentArea = &(g_SceneMan.GetScene()->m_AreaList.front()); + + m_EditMade = false; + m_pBoxToBlink = 0; + + //////////////////////////////////////////// + // Blinking logic + /* + if (m_BlinkMode == OBJECTBLINK) + { + m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); + } + else if (m_BlinkMode == NOCRAFT) + { + bool blink = m_BlinkTimer.AlternateSim(250); + m_pCraftLabel->SetVisible(blink); + m_pCraftBox->SetVisible(blink); + } + + // Time out the blinker + if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) + { + m_pCostLabel->SetVisible(true); + m_pCraftLabel->SetVisible(true); + m_pCraftBox->SetVisible(true); + m_BlinkMode = NOBLINK; + } + */ + ///////////////////////////////////////////// + // Repeating input logic + + bool pressLeft = m_pController->IsState(PRESS_LEFT); + bool pressRight = m_pController->IsState(PRESS_RIGHT); + bool pressUp = m_pController->IsState(PRESS_UP); + bool pressDown = m_pController->IsState(PRESS_DOWN); + + // If no direciton is held down, then cancel the repeating + if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) { + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + } + + // Check if any direction has been held for the starting amount of time to get into repeat mode + if (m_RepeatStartTimer.IsPastRealMS(200)) { + // Check for the repeat interval + if (m_RepeatTimer.IsPastRealMS(30)) { + if (m_pController->IsState(MOVE_RIGHT)) + pressRight = true; + else if (m_pController->IsState(MOVE_LEFT)) + pressLeft = true; + + if (m_pController->IsState(MOVE_UP)) + pressUp = true; + else if (m_pController->IsState(MOVE_DOWN)) + pressDown = true; + + m_RepeatTimer.Reset(); + } + } + + /////////////////////////////////////////////// + // Analog cursor input + + Vector analogInput; + if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) + analogInput = m_pController->GetAnalogMove(); + // else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) + // analogInput = m_pController->GetAnalogAim(); + + ///////////////////////////////////////////// + // PIE MENU + + m_PieMenu->Update(); + + // Show the pie menu only when the secondary button is held down + if (m_pController->IsState(PRESS_SECONDARY) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGAREA) { m_PieMenu->SetPos(m_GridSnapping ? g_SceneMan.SnapPosition(m_CursorPos) : m_CursorPos); m_PieMenu->SetEnabled(true); - } + } - if (!m_pController->IsState(PIE_MENU_ACTIVE) || m_EditorGUIMode == INACTIVE || m_EditorGUIMode == PICKINGAREA) { m_PieMenu->SetEnabled(false); } + if (!m_pController->IsState(PIE_MENU_ACTIVE) || m_EditorGUIMode == INACTIVE || m_EditorGUIMode == PICKINGAREA) { + m_PieMenu->SetEnabled(false); + } - if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { + if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorPick) { m_EditorGUIMode = PICKINGAREA; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorMove) { @@ -298,373 +281,332 @@ void AreaEditorGUI::Update() } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorDone) { m_EditorGUIMode = DONEEDITING; } - } - - ////////////////////////////////////////// - // Picker logic - - // Enable or disable the picker - m_pPicker->SetEnabled(m_EditorGUIMode == PICKINGAREA); - - // Update the picker GUI - m_pPicker->Update(); - - if (m_EditorGUIMode == PICKINGAREA && m_pPicker->AreaPicked()) - { - // Assign the pointer of the picked Area to be the currently selected one. - if (m_pPicker->AreaPicked()) - { - SetCurrentArea(m_pPicker->AreaPicked()); -// TODO: Make the view center on the newly picked Area, somehow using average of all its Box:es centers? - - // If done picking, revert to adding/movind Box mode for the newly selected Area - if (m_pPicker->DonePicking()) - { - m_EditorGUIMode = PREADDMOVEBOX; - } - } - } - - if (!m_pPicker->IsVisible()) - g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - if (m_EditorGUIMode != PICKINGAREA) - { - // Mousewheel is used as shortcut for getting next and prev items in the picker's Area list - if (m_pController->IsState(SCROLL_UP)) - { - // Assign the non-owned pointer of the next picked Area to be the currently selected one. - Scene::Area *pNewArea = m_pPicker->GetPrevArea(); - if (pNewArea) - SetCurrentArea(pNewArea); - } - else if (m_pController->IsState(SCROLL_DOWN)) - { - // Assign the non-owned pointer of the next picked Area to be the currently selected one. - Scene::Area *pNewArea = m_pPicker->GetNextArea(); - if (pNewArea) - SetCurrentArea(pNewArea); - } - } - - // Make sure we have a picked area if there are any areas at all! - if (!m_pCurrentArea && !g_SceneMan.GetScene()->m_AreaList.empty()) - m_pCurrentArea = &(g_SceneMan.GetScene()->m_AreaList.front()); - // If there are no Area:s, AreaEditor should detect it and force user to create a new one with a dialog -// else -// m_EditorGUIMode = PREADDMOVEBOX; - - ///////////////////////////////////// - // ADDING or MOVING BOX MODE - - if (m_pCurrentArea && m_EditorGUIMode == PREADDMOVEBOX && !m_PieMenu->IsEnabled()) - { - g_FrameMan.SetScreenText("Click and drag to ADD a new box to the Area - Drag existing ones to MOVE them", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput * 8; - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= SCENESNAPSIZE; - if (pressRight) - m_CursorPos.m_X += SCENESNAPSIZE; - if (pressDown) - m_CursorPos.m_Y += SCENESNAPSIZE; - if (pressLeft) - m_CursorPos.m_X -= SCENESNAPSIZE; - // Re-enable snapping only when the cursor is moved again - if (pressUp || pressRight || pressDown || pressLeft) - m_GridSnapping = true; - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - - Box *pBox = 0; - - // Start the timer when the button is first pressed, and when the picker has deactivated - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - m_BlinkTimer.Reset(); - - // See if the start of the drag is inside an existing Box, and set the next mode (MOVE) accordingly - if (pBox = m_pCurrentArea->GetBoxInside(m_CursorPos)) - { - // Save a copy of the dragged box - m_EditedBox = *pBox; - // Set the offset between the Box being dragged and the cursor so the box doesn't jump - m_CursorOffset = m_CursorPos - m_EditedBox.GetCorner(); - // Remove the dragged box from the area, we are now in control of it - m_pCurrentArea->RemoveBoxInside(m_CursorPos); - // Switch the mode - m_EditorGUIMode = MOVINGBOX; - m_PreviousMode = PREADDMOVEBOX; - } - // Or outside all, and set the next mode to be NEW instead to start a new box drag to add to the current Area - else - { - // Place the start corner of the new box - m_EditedBox.SetCorner(m_CursorPos); - // Cursor offset is 0 becuase we're placing the corner with current cursor pos - m_CursorOffset.Reset(); - // Switch mode - m_EditorGUIMode = ADDINGBOX; - m_PreviousMode = PREADDMOVEBOX; - } - - g_GUISound.PlacementBlip()->Play(); - } - // Just hovering over things, show what would be moved if we started dragging - else - { - pBox = m_pCurrentArea->GetBoxInside(m_CursorPos); - if (pBox) - m_EditedBox = *pBox; - else - m_EditedBox.Reset(); - } - } - - ///////////////////////////////////////////////////////////// - // POINTING AT/DRAGGING MODES WITHOUT SNAPPING - - else if (m_pCurrentArea && (m_EditorGUIMode == MOVINGBOX || m_EditorGUIMode == ADDINGBOX || m_EditorGUIMode == DELETINGBOX) && !m_PieMenu->IsEnabled()) - { - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - m_CursorPos += analogInput * 4; - else if (!m_pController->GetMouseMovement().IsZero()) - m_CursorPos += m_pController->GetMouseMovement() / 2; - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= 1; - if (pressRight) - m_CursorPos.m_X += 1; - if (pressDown) - m_CursorPos.m_Y += 1; - if (pressLeft) - m_CursorPos.m_X -= 1; - } - - ///////////////////////////////// - // MOVING BOX MODE - - if (m_EditorGUIMode == MOVINGBOX) - { - g_FrameMan.SetScreenText("Keep dragging the box to MOVE it", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // While primary is kept held down, keep dragging the Box - if (m_pController->IsState(PRIMARY_ACTION)) - { -// TODO: really wrap? - Vector wrappedCorner = m_CursorPos - m_CursorOffset; - g_SceneMan.WrapPosition(wrappedCorner); - m_EditedBox.SetCorner(wrappedCorner); - } - // When released, we are done moving that box and go back to prev mode - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - // Add it back to the Area - m_EditedBox.Unflip(); - m_pCurrentArea->AddBox(m_EditedBox); - // Make the yellow outline edited box vanish - m_EditedBox.Reset(); - m_EditMade = true; - m_EditorGUIMode = PREADDMOVEBOX; - m_PreviousMode = MOVINGBOX; - g_GUISound.PlacementThud()->Play(); - } - } - - ///////////////////////////////// - // ADDING BOX MODE - - if (m_EditorGUIMode == ADDINGBOX) - { - g_FrameMan.SetScreenText("Keep dragging the new box out - release and it is ADDED to the current Area", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // While primary is kept held down, keep dragging out the otehr corner of the Box being defined - if (m_pController->IsState(PRIMARY_ACTION)) - { - Vector dimensions = g_SceneMan.ShortestDistance(m_EditedBox.GetCorner(), m_CursorPos).GetFloored(); - m_EditedBox.SetWidth(dimensions.m_X); - m_EditedBox.SetHeight(dimensions.m_Y); - } - // When released, we are done with that box and go back to prev mode - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - m_EditedBox.Unflip(); - m_pCurrentArea->AddBox(m_EditedBox); - // Make the yellow outline edited box vanish - m_EditedBox.Reset(); - m_EditMade = true; - m_EditorGUIMode = PREADDMOVEBOX; - m_PreviousMode = ADDINGBOX; - g_GUISound.PlacementThud()->Play(); - } - } - - //////////////////////////// - // REMOVING BOX MODE - - else if (m_EditorGUIMode == DELETINGBOX) - { - g_FrameMan.SetScreenText("Click and hold to select a Box - release to DELETE it", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - m_EditedBox.Reset(); - - // When primary is held down, pick Box and show which one will be nuked if released - if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) - { - Box *pBoxToDelete = m_pCurrentArea->GetBoxInside(m_CursorPos); - // Indicate which box we're talking aobut to delete - if (pBoxToDelete) - m_EditedBox = *pBoxToDelete; - } - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - Box removed = m_pCurrentArea->RemoveBoxInside(m_CursorPos); - // If we didnt' remove any box, play error sound - if (removed.IsEmpty()) - g_GUISound.UserErrorSound()->Play(); - else - m_EditMade = true; - } - } - } - else if (m_EditorGUIMode == DONEEDITING) - { -// if (!m_FullFeatured) -// g_FrameMan.SetScreenText("DONE editing, wait for all other players to finish too...", ScreenOfPlayer(m_pController->GetPlayer())); - } - - // Remove cursor offset if not applicable anymore - if (m_EditorGUIMode == PREADDMOVEBOX) - m_CursorOffset.Reset(); - - // Keep the cursor position within the world - bool cursorWrapped = g_SceneMan.ForceBounds(m_CursorPos); -// TODO: make setscrolltarget with 'sloppy' target - // Scroll to the cursor's scene position - g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); -} + } + + ////////////////////////////////////////// + // Picker logic + // Enable or disable the picker + m_pPicker->SetEnabled(m_EditorGUIMode == PICKINGAREA); + + // Update the picker GUI + m_pPicker->Update(); + + if (m_EditorGUIMode == PICKINGAREA && m_pPicker->AreaPicked()) { + // Assign the pointer of the picked Area to be the currently selected one. + if (m_pPicker->AreaPicked()) { + SetCurrentArea(m_pPicker->AreaPicked()); + // TODO: Make the view center on the newly picked Area, somehow using average of all its Box:es centers? + + // If done picking, revert to adding/movind Box mode for the newly selected Area + if (m_pPicker->DonePicking()) { + m_EditorGUIMode = PREADDMOVEBOX; + } + } + } + + if (!m_pPicker->IsVisible()) + g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + if (m_EditorGUIMode != PICKINGAREA) { + // Mousewheel is used as shortcut for getting next and prev items in the picker's Area list + if (m_pController->IsState(SCROLL_UP)) { + // Assign the non-owned pointer of the next picked Area to be the currently selected one. + Scene::Area* pNewArea = m_pPicker->GetPrevArea(); + if (pNewArea) + SetCurrentArea(pNewArea); + } else if (m_pController->IsState(SCROLL_DOWN)) { + // Assign the non-owned pointer of the next picked Area to be the currently selected one. + Scene::Area* pNewArea = m_pPicker->GetNextArea(); + if (pNewArea) + SetCurrentArea(pNewArea); + } + } + + // Make sure we have a picked area if there are any areas at all! + if (!m_pCurrentArea && !g_SceneMan.GetScene()->m_AreaList.empty()) + m_pCurrentArea = &(g_SceneMan.GetScene()->m_AreaList.front()); + // If there are no Area:s, AreaEditor should detect it and force user to create a new one with a dialog + // else + // m_EditorGUIMode = PREADDMOVEBOX; + + ///////////////////////////////////// + // ADDING or MOVING BOX MODE + + if (m_pCurrentArea && m_EditorGUIMode == PREADDMOVEBOX && !m_PieMenu->IsEnabled()) { + g_FrameMan.SetScreenText("Click and drag to ADD a new box to the Area - Drag existing ones to MOVE them", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) { + m_CursorPos += analogInput * 8; + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= SCENESNAPSIZE; + if (pressRight) + m_CursorPos.m_X += SCENESNAPSIZE; + if (pressDown) + m_CursorPos.m_Y += SCENESNAPSIZE; + if (pressLeft) + m_CursorPos.m_X -= SCENESNAPSIZE; + // Re-enable snapping only when the cursor is moved again + if (pressUp || pressRight || pressDown || pressLeft) + m_GridSnapping = true; + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + + Box* pBox = 0; + + // Start the timer when the button is first pressed, and when the picker has deactivated + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + m_BlinkTimer.Reset(); + + // See if the start of the drag is inside an existing Box, and set the next mode (MOVE) accordingly + if (pBox = m_pCurrentArea->GetBoxInside(m_CursorPos)) { + // Save a copy of the dragged box + m_EditedBox = *pBox; + // Set the offset between the Box being dragged and the cursor so the box doesn't jump + m_CursorOffset = m_CursorPos - m_EditedBox.GetCorner(); + // Remove the dragged box from the area, we are now in control of it + m_pCurrentArea->RemoveBoxInside(m_CursorPos); + // Switch the mode + m_EditorGUIMode = MOVINGBOX; + m_PreviousMode = PREADDMOVEBOX; + } + // Or outside all, and set the next mode to be NEW instead to start a new box drag to add to the current Area + else { + // Place the start corner of the new box + m_EditedBox.SetCorner(m_CursorPos); + // Cursor offset is 0 becuase we're placing the corner with current cursor pos + m_CursorOffset.Reset(); + // Switch mode + m_EditorGUIMode = ADDINGBOX; + m_PreviousMode = PREADDMOVEBOX; + } + + g_GUISound.PlacementBlip()->Play(); + } + // Just hovering over things, show what would be moved if we started dragging + else { + pBox = m_pCurrentArea->GetBoxInside(m_CursorPos); + if (pBox) + m_EditedBox = *pBox; + else + m_EditedBox.Reset(); + } + } + + ///////////////////////////////////////////////////////////// + // POINTING AT/DRAGGING MODES WITHOUT SNAPPING + + else if (m_pCurrentArea && (m_EditorGUIMode == MOVINGBOX || m_EditorGUIMode == ADDINGBOX || m_EditorGUIMode == DELETINGBOX) && !m_PieMenu->IsEnabled()) { + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) + m_CursorPos += analogInput * 4; + else if (!m_pController->GetMouseMovement().IsZero()) + m_CursorPos += m_pController->GetMouseMovement() / 2; + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= 1; + if (pressRight) + m_CursorPos.m_X += 1; + if (pressDown) + m_CursorPos.m_Y += 1; + if (pressLeft) + m_CursorPos.m_X -= 1; + } + + ///////////////////////////////// + // MOVING BOX MODE + + if (m_EditorGUIMode == MOVINGBOX) { + g_FrameMan.SetScreenText("Keep dragging the box to MOVE it", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // While primary is kept held down, keep dragging the Box + if (m_pController->IsState(PRIMARY_ACTION)) { + // TODO: really wrap? + Vector wrappedCorner = m_CursorPos - m_CursorOffset; + g_SceneMan.WrapPosition(wrappedCorner); + m_EditedBox.SetCorner(wrappedCorner); + } + // When released, we are done moving that box and go back to prev mode + else if (m_pController->IsState(RELEASE_PRIMARY)) { + // Add it back to the Area + m_EditedBox.Unflip(); + m_pCurrentArea->AddBox(m_EditedBox); + // Make the yellow outline edited box vanish + m_EditedBox.Reset(); + m_EditMade = true; + m_EditorGUIMode = PREADDMOVEBOX; + m_PreviousMode = MOVINGBOX; + g_GUISound.PlacementThud()->Play(); + } + } + + ///////////////////////////////// + // ADDING BOX MODE + + if (m_EditorGUIMode == ADDINGBOX) { + g_FrameMan.SetScreenText("Keep dragging the new box out - release and it is ADDED to the current Area", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // While primary is kept held down, keep dragging out the otehr corner of the Box being defined + if (m_pController->IsState(PRIMARY_ACTION)) { + Vector dimensions = g_SceneMan.ShortestDistance(m_EditedBox.GetCorner(), m_CursorPos).GetFloored(); + m_EditedBox.SetWidth(dimensions.m_X); + m_EditedBox.SetHeight(dimensions.m_Y); + } + // When released, we are done with that box and go back to prev mode + else if (m_pController->IsState(RELEASE_PRIMARY)) { + m_EditedBox.Unflip(); + m_pCurrentArea->AddBox(m_EditedBox); + // Make the yellow outline edited box vanish + m_EditedBox.Reset(); + m_EditMade = true; + m_EditorGUIMode = PREADDMOVEBOX; + m_PreviousMode = ADDINGBOX; + g_GUISound.PlacementThud()->Play(); + } + } + + //////////////////////////// + // REMOVING BOX MODE + + else if (m_EditorGUIMode == DELETINGBOX) { + g_FrameMan.SetScreenText("Click and hold to select a Box - release to DELETE it", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + m_EditedBox.Reset(); + + // When primary is held down, pick Box and show which one will be nuked if released + if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) { + Box* pBoxToDelete = m_pCurrentArea->GetBoxInside(m_CursorPos); + // Indicate which box we're talking aobut to delete + if (pBoxToDelete) + m_EditedBox = *pBoxToDelete; + } else if (m_pController->IsState(RELEASE_PRIMARY)) { + Box removed = m_pCurrentArea->RemoveBoxInside(m_CursorPos); + // If we didnt' remove any box, play error sound + if (removed.IsEmpty()) + g_GUISound.UserErrorSound()->Play(); + else + m_EditMade = true; + } + } + } else if (m_EditorGUIMode == DONEEDITING) { + // if (!m_FullFeatured) + // g_FrameMan.SetScreenText("DONE editing, wait for all other players to finish too...", ScreenOfPlayer(m_pController->GetPlayer())); + } + + // Remove cursor offset if not applicable anymore + if (m_EditorGUIMode == PREADDMOVEBOX) + m_CursorOffset.Reset(); + + // Keep the cursor position within the world + bool cursorWrapped = g_SceneMan.ForceBounds(m_CursorPos); + // TODO: make setscrolltarget with 'sloppy' target + // Scroll to the cursor's scene position + g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); +} ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the menu -void AreaEditorGUI::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) const -{ - // Done or can't, so don't draw the UI - if (!m_pCurrentArea || m_EditorGUIMode == DONEEDITING) - return; - - // List to capture scene-wrapped boxes - std::list wrappedBoxes; - - // First draw all the objects placed in the scene by the Scene Editor - const std::list *pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); - if (m_FullFeatured) - { - // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene - int i = 0; - for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr, ++i) - { - (*itr)->Draw(pTargetBitmap, targetPos); - // Draw basic HUD if an actor - Actor *pActor = dynamic_cast(*itr); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - } - - // Draw the Box:es defined for the currently selected Area - Vector adjCorner; - const std::vector *pBoxList = &(m_pCurrentArea->m_BoxList); - if (m_FullFeatured) - { - // Set the drawin mode to be transparent and use the -// g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - g_FrameMan.SetTransTableFromPreset(TransparencyPreset::MoreTrans); - drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); - - // Draw all already placed Box:es, and the currently edited one - for (std::vector::const_iterator bItr = pBoxList->begin(); bItr != pBoxList->end(); ++bItr) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(*bItr, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - // Draw the rectangle of each Box, adjusted for the offet of the target bitmap in the scene - adjCorner = (*wItr).GetCorner() - targetPos; - rectfill(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_RedColor); - } - } - } - - // Draw the currently edited box outline in glowing yellow - drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); - if (!m_EditedBox.IsEmpty()) - { - // Handle wrapped boxes properly - wrappedBoxes.clear(); - g_SceneMan.WrapBox(m_EditedBox, wrappedBoxes); - - // Iterate through the wrapped boxes - will only be one if there's no wrapping - for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) - { - adjCorner = (*wItr).GetCorner() - targetPos; - // Special 'X' drawing when deleting - if (m_EditorGUIMode == DELETINGBOX) - { - line(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_YellowGlowColor); - line(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y + (*wItr).GetHeight(), adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y, g_YellowGlowColor); - } - else - rect(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_YellowGlowColor); - } - } - - // Set drawing mode back to solid - drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); - - // Draw picking Area crosshairs - Vector center = m_CursorPos - targetPos; - putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); - - m_pPicker->Draw(pTargetBitmap); - - // Draw the pie menu +void AreaEditorGUI::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) const { + // Done or can't, so don't draw the UI + if (!m_pCurrentArea || m_EditorGUIMode == DONEEDITING) + return; + + // List to capture scene-wrapped boxes + std::list wrappedBoxes; + + // First draw all the objects placed in the scene by the Scene Editor + const std::list* pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); + if (m_FullFeatured) { + // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene + int i = 0; + for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr, ++i) { + (*itr)->Draw(pTargetBitmap, targetPos); + // Draw basic HUD if an actor + Actor* pActor = dynamic_cast(*itr); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + } + + // Draw the Box:es defined for the currently selected Area + Vector adjCorner; + const std::vector* pBoxList = &(m_pCurrentArea->m_BoxList); + if (m_FullFeatured) { + // Set the drawin mode to be transparent and use the + // g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + g_FrameMan.SetTransTableFromPreset(TransparencyPreset::MoreTrans); + drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); + + // Draw all already placed Box:es, and the currently edited one + for (std::vector::const_iterator bItr = pBoxList->begin(); bItr != pBoxList->end(); ++bItr) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(*bItr, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + // Draw the rectangle of each Box, adjusted for the offet of the target bitmap in the scene + adjCorner = (*wItr).GetCorner() - targetPos; + rectfill(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_RedColor); + } + } + } + + // Draw the currently edited box outline in glowing yellow + drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); + if (!m_EditedBox.IsEmpty()) { + // Handle wrapped boxes properly + wrappedBoxes.clear(); + g_SceneMan.WrapBox(m_EditedBox, wrappedBoxes); + + // Iterate through the wrapped boxes - will only be one if there's no wrapping + for (std::list::iterator wItr = wrappedBoxes.begin(); wItr != wrappedBoxes.end(); ++wItr) { + adjCorner = (*wItr).GetCorner() - targetPos; + // Special 'X' drawing when deleting + if (m_EditorGUIMode == DELETINGBOX) { + line(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_YellowGlowColor); + line(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y + (*wItr).GetHeight(), adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y, g_YellowGlowColor); + } else + rect(pTargetBitmap, adjCorner.m_X, adjCorner.m_Y, adjCorner.m_X + (*wItr).GetWidth(), adjCorner.m_Y + (*wItr).GetHeight(), g_YellowGlowColor); + } + } + + // Set drawing mode back to solid + drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); + + // Draw picking Area crosshairs + Vector center = m_CursorPos - targetPos; + putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); + + m_pPicker->Draw(pTargetBitmap); + + // Draw the pie menu m_PieMenu->Draw(pTargetBitmap, targetPos); -} \ No newline at end of file +} diff --git a/Source/Menus/AreaEditorGUI.h b/Source/Menus/AreaEditorGUI.h index 93113ac03..0bbe2f0be 100644 --- a/Source/Menus/AreaEditorGUI.h +++ b/Source/Menus/AreaEditorGUI.h @@ -10,7 +10,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -24,301 +23,271 @@ struct BITMAP; - -namespace RTE -{ - -class AreaPickerGUI; -class PieMenu; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: AreaEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A full menu system that represents the scene editing GUI for Cortex Command -// Parent(s): None. -// Class history: 7/08/2007 AreaEditorGUI Created. - -class AreaEditorGUI { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - // Different modes of this editor - enum EditorGUIMode - { - INACTIVE = 0, - PICKINGAREA, - PREADDMOVEBOX, - ADDINGBOX, - MOVINGBOX, - DELETINGBOX, - DONEEDITING, - EDITORGUIMODECOUNT - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: AreaEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a AreaEditorGUI Area in system -// memory. Create() should be called before using the Area. -// Arguments: None. - - AreaEditorGUI() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~AreaEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a AreaEditorGUI Area before deletion -// from system memory. -// Arguments: None. - - ~AreaEditorGUI() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AreaEditorGUI Area ready for use. -// Arguments: A poitner to a Controller which will control this Menu. Ownership is -// NOT TRANSFERRED! -// Whether the editor should have all the features enabled, like load/save -// and undo capabilities. -// Which module space that this eidtor will be able to pick Areas from. -// -1 means all modules. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(Controller *pController, bool fullFeatured = false, int whichModuleSpace = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire AreaEditorGUI, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AreaEditorGUI Area. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the controller used by this. The ownership of the controller is -// NOT transferred! -// Arguments: The new controller for this menu. Ownership is NOT transferred -// Return value: None. - - void SetController(Controller *pController); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPosOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where on the screen that this GUI is being drawn to. If upper -// left corner, then 0, 0. This will affect the way the mouse is positioned -// etc. -// Arguments: The new screen position of this entire GUI. - - void SetPosOnScreen(int newPosX, int newPosY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCursorPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the absolute scene coordinates of the cursor of this Editor. -// Arguments: The new cursor position in absolute scene units. -// Return value: None. - - void SetCursorPos(const Vector &newCursorPos) { m_CursorPos = newCursorPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActivatedPieSlice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets any Pie menu slice command activated last update. -// Arguments: None. -// Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. - - PieSlice::SliceType GetActivatedPieSlice() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCurrentArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the currently selected Area of this Editor. Ownership IS NOT -// transferred! -// Arguments: The new area for this to work with, if any. OWNERSHIP IS NOT TRANSFERRED! -// Return value: None. - - void SetCurrentArea(Scene::Area *pArea); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the currently held Area in the cursor of this Editor. Ownership -// IS NOT transferred! -// Arguments: None. -// Return value: The currently held Area, if any. OWNERSHIP IS NOT TRANSFERRED! - - Scene::Area * GetCurrentArea() { return m_pCurrentArea; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EditMade -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether an edit on the scene was made in the last Update. -// Arguments: None. -// Return value: Whether any edit was made. - - bool EditMade() const { return m_EditMade; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePickerList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the list that the GUI's Area picker has, from the current -// scene state. -// Arguments: The name of the Area to leave selected after the list is updated. -// Return value: None. - - void UpdatePickerList(std::string selectAreaName = ""); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Menu each frame -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the editor -// Arguments: The bitmap to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - - enum BlinkMode - { - NOBLINK = 0, - OBJECTBLINKON, - OBJECTBLINKOFF, - BLINKMODECOUNT - }; - - // Controller which conrols this menu. Not owned - Controller *m_pController; - // Full featured or the in-game version - bool m_FullFeatured; - // Whether an editor was made to the Scene in the last Update - bool m_EditMade; - // The current mode of the whole GUI. See EditorGUIMode enum. - EditorGUIMode m_EditorGUIMode; - // The previous mode of the whole GUI, to go back to when the current mode is done in some cases - EditorGUIMode m_PreviousMode; - // Notification blink timer - Timer m_BlinkTimer; - // What we're blinking - int m_BlinkMode; - // Measures the time to when to start repeating inputs when they're held down - Timer m_RepeatStartTimer; - // Measures the interval between input repeats - Timer m_RepeatTimer; - - std::unique_ptr m_PieMenu; //!< The PieMenu for this AreaEditorGUI. - // The Area picker - AreaPickerGUI *m_pPicker; - // Grid snapping enabled - bool m_GridSnapping; - // Current cursor position, in absolute scene coordinates - Vector m_CursorPos; - // The offset from the currently dragged Box's corner position to the cursor, if any - Vector m_CursorOffset; - // Cursor position in free air, or over something - bool m_CursorInAir; - // Currently selected Area. NOT OWNED BY THIS - Scene::Area *m_pCurrentArea; - // Whether to draw the currently held Area - bool m_DrawCurrentArea; - // The Box currently being added/moved - Box m_EditedBox; - // Currently placed scene Area to make blink when drawing it. NOT OWNED. - const Box *m_pBoxToBlink; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AreaEditorGUI, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - AreaEditorGUI(const AreaEditorGUI &reference) = delete; - AreaEditorGUI & operator=(const AreaEditorGUI &rhs) = delete; - -}; +namespace RTE { + + class AreaPickerGUI; + class PieMenu; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: AreaEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A full menu system that represents the scene editing GUI for Cortex Command + // Parent(s): None. + // Class history: 7/08/2007 AreaEditorGUI Created. + + class AreaEditorGUI { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Different modes of this editor + enum EditorGUIMode { + INACTIVE = 0, + PICKINGAREA, + PREADDMOVEBOX, + ADDINGBOX, + MOVINGBOX, + DELETINGBOX, + DONEEDITING, + EDITORGUIMODECOUNT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: AreaEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a AreaEditorGUI Area in system + // memory. Create() should be called before using the Area. + // Arguments: None. + + AreaEditorGUI() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~AreaEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a AreaEditorGUI Area before deletion + // from system memory. + // Arguments: None. + + ~AreaEditorGUI() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AreaEditorGUI Area ready for use. + // Arguments: A poitner to a Controller which will control this Menu. Ownership is + // NOT TRANSFERRED! + // Whether the editor should have all the features enabled, like load/save + // and undo capabilities. + // Which module space that this eidtor will be able to pick Areas from. + // -1 means all modules. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(Controller* pController, bool fullFeatured = false, int whichModuleSpace = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire AreaEditorGUI, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AreaEditorGUI Area. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the controller used by this. The ownership of the controller is + // NOT transferred! + // Arguments: The new controller for this menu. Ownership is NOT transferred + // Return value: None. + + void SetController(Controller* pController); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPosOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where on the screen that this GUI is being drawn to. If upper + // left corner, then 0, 0. This will affect the way the mouse is positioned + // etc. + // Arguments: The new screen position of this entire GUI. + + void SetPosOnScreen(int newPosX, int newPosY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCursorPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the absolute scene coordinates of the cursor of this Editor. + // Arguments: The new cursor position in absolute scene units. + // Return value: None. + + void SetCursorPos(const Vector& newCursorPos) { m_CursorPos = newCursorPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActivatedPieSlice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets any Pie menu slice command activated last update. + // Arguments: None. + // Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. + + PieSlice::SliceType GetActivatedPieSlice() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCurrentArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the currently selected Area of this Editor. Ownership IS NOT + // transferred! + // Arguments: The new area for this to work with, if any. OWNERSHIP IS NOT TRANSFERRED! + // Return value: None. + + void SetCurrentArea(Scene::Area* pArea); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the currently held Area in the cursor of this Editor. Ownership + // IS NOT transferred! + // Arguments: None. + // Return value: The currently held Area, if any. OWNERSHIP IS NOT TRANSFERRED! + + Scene::Area* GetCurrentArea() { return m_pCurrentArea; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EditMade + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether an edit on the scene was made in the last Update. + // Arguments: None. + // Return value: Whether any edit was made. + + bool EditMade() const { return m_EditMade; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePickerList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the list that the GUI's Area picker has, from the current + // scene state. + // Arguments: The name of the Area to leave selected after the list is updated. + // Return value: None. + + void UpdatePickerList(std::string selectAreaName = ""); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Menu each frame + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the editor + // Arguments: The bitmap to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + enum BlinkMode { + NOBLINK = 0, + OBJECTBLINKON, + OBJECTBLINKOFF, + BLINKMODECOUNT + }; + + // Controller which conrols this menu. Not owned + Controller* m_pController; + // Full featured or the in-game version + bool m_FullFeatured; + // Whether an editor was made to the Scene in the last Update + bool m_EditMade; + // The current mode of the whole GUI. See EditorGUIMode enum. + EditorGUIMode m_EditorGUIMode; + // The previous mode of the whole GUI, to go back to when the current mode is done in some cases + EditorGUIMode m_PreviousMode; + // Notification blink timer + Timer m_BlinkTimer; + // What we're blinking + int m_BlinkMode; + // Measures the time to when to start repeating inputs when they're held down + Timer m_RepeatStartTimer; + // Measures the interval between input repeats + Timer m_RepeatTimer; + + std::unique_ptr m_PieMenu; //!< The PieMenu for this AreaEditorGUI. + // The Area picker + AreaPickerGUI* m_pPicker; + // Grid snapping enabled + bool m_GridSnapping; + // Current cursor position, in absolute scene coordinates + Vector m_CursorPos; + // The offset from the currently dragged Box's corner position to the cursor, if any + Vector m_CursorOffset; + // Cursor position in free air, or over something + bool m_CursorInAir; + // Currently selected Area. NOT OWNED BY THIS + Scene::Area* m_pCurrentArea; + // Whether to draw the currently held Area + bool m_DrawCurrentArea; + // The Box currently being added/moved + Box m_EditedBox; + // Currently placed scene Area to make blink when drawing it. NOT OWNED. + const Box* m_pBoxToBlink; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AreaEditorGUI, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + AreaEditorGUI(const AreaEditorGUI& reference) = delete; + AreaEditorGUI& operator=(const AreaEditorGUI& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Menus/AreaPickerGUI.cpp b/Source/Menus/AreaPickerGUI.cpp index 7ac5ff330..808da95ad 100644 --- a/Source/Menus/AreaPickerGUI.cpp +++ b/Source/Menus/AreaPickerGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -37,7 +36,7 @@ using namespace RTE; -BITMAP *RTE::AreaPickerGUI::s_pCursor = 0; +BITMAP* RTE::AreaPickerGUI::s_pCursor = 0; ////////////////////////////////////////////////////////////////////////////////////////// // Method: Clear @@ -45,160 +44,145 @@ BITMAP *RTE::AreaPickerGUI::s_pCursor = 0; // Description: Clears all the member variables of this AreaPickerGUI, effectively // resetting the members of this abstraction level only. -void AreaPickerGUI::Clear() -{ - m_pController = 0; - m_pGUIScreen = 0; - m_pGUIInput = 0; - m_pGUIController = 0; - m_PickerEnabled = DISABLED; - m_MenuSpeed = 0.3; - m_ShowType.clear(); - m_SelectedGroupIndex = 0; - m_SelectedAreaIndex = 0; - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - m_pParentBox = 0; - m_pAreasList = 0; - m_pDeleteAreaButton = 0; - m_pPickedArea = 0; - m_CursorPos.Reset(); +void AreaPickerGUI::Clear() { + m_pController = 0; + m_pGUIScreen = 0; + m_pGUIInput = 0; + m_pGUIController = 0; + m_PickerEnabled = DISABLED; + m_MenuSpeed = 0.3; + m_ShowType.clear(); + m_SelectedGroupIndex = 0; + m_SelectedAreaIndex = 0; + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + m_pParentBox = 0; + m_pAreasList = 0; + m_pDeleteAreaButton = 0; + m_pPickedArea = 0; + m_CursorPos.Reset(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the AreaPickerGUI area ready for use. -int AreaPickerGUI::Create(Controller *pController, std::string onlyOfType) -{ - RTEAssert(pController, "No controller sent to AreaPickerGUI on creation!"); - m_pController = pController; - - if (!m_pGUIScreen) - m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer8()); - if (!m_pGUIInput) - m_pGUIInput = new GUIInputWrapper(pController->GetPlayer()); - if (!m_pGUIController) - m_pGUIController = new GUIControlManager(); +int AreaPickerGUI::Create(Controller* pController, std::string onlyOfType) { + RTEAssert(pController, "No controller sent to AreaPickerGUI on creation!"); + m_pController = pController; + + if (!m_pGUIScreen) + m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer8()); + if (!m_pGUIInput) + m_pGUIInput = new GUIInputWrapper(pController->GetPlayer()); + if (!m_pGUIController) + m_pGUIController = new GUIControlManager(); if (!m_pGUIController->Create(m_pGUIScreen, m_pGUIInput, "Base.rte/GUIs/Skins", "DefaultSkin.ini")) { RTEAbort("Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/DefaultSkin.ini"); } - m_pGUIController->Load("Base.rte/GUIs/AreaPickerGUI.ini"); - m_pGUIController->EnableMouse(pController->IsMouseControlled()); - - if (!s_pCursor) - { - ContentFile cursorFile("Base.rte/GUIs/Skins/Cursor.png"); - s_pCursor = cursorFile.GetAsBitmap(); - } - - // Stretch the invisible root box to fill the screen - dynamic_cast(m_pGUIController->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); - - // Make sure we have convenient points to teh containing GUI colleciton boxes that we will manipulate the positions of - if (!m_pParentBox) - { - m_pParentBox = dynamic_cast(m_pGUIController->GetControl("PickerGUIBox")); - - // Set the background image of the parent collection box -// ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); -// m_pParentBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); -// m_pParentBox->SetDrawBackground(true); -// m_pParentBox->SetDrawType(GUICollectionBox::Image); - m_pParentBox->SetDrawType(GUICollectionBox::Color); - } - m_pParentBox->SetPositionAbs(g_FrameMan.GetPlayerScreenWidth(), 0); - m_pParentBox->SetEnabled(false); - m_pParentBox->SetVisible(false); - - m_pAreasList = dynamic_cast(m_pGUIController->GetControl("AreasLB")); - m_pDeleteAreaButton = dynamic_cast(m_pGUIController->GetControl("DeleteAreaButton")); - - // If we're not split screen horizontally, then stretch out the layout for all the relevant controls - if (!g_FrameMan.GetHSplit()) - { - int stretchAmount = g_WindowMan.GetResY() / 2; - m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); - m_pAreasList->SetSize(m_pAreasList->GetWidth(), m_pAreasList->GetHeight() + stretchAmount); - m_pDeleteAreaButton->SetPositionAbs(m_pDeleteAreaButton->GetXPos(), m_pDeleteAreaButton->GetYPos() + stretchAmount); - } - - m_pAreasList->SetAlternateDrawMode(false); - m_pAreasList->SetMultiSelect(false); - - // Populate the Areas list with the current Scene's Area:s - UpdateAreasList(); - - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - - return 0; -} + m_pGUIController->Load("Base.rte/GUIs/AreaPickerGUI.ini"); + m_pGUIController->EnableMouse(pController->IsMouseControlled()); + + if (!s_pCursor) { + ContentFile cursorFile("Base.rte/GUIs/Skins/Cursor.png"); + s_pCursor = cursorFile.GetAsBitmap(); + } + + // Stretch the invisible root box to fill the screen + dynamic_cast(m_pGUIController->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + + // Make sure we have convenient points to teh containing GUI colleciton boxes that we will manipulate the positions of + if (!m_pParentBox) { + m_pParentBox = dynamic_cast(m_pGUIController->GetControl("PickerGUIBox")); + // Set the background image of the parent collection box + // ContentFile backgroundFile("Base.rte/GUIs/BuyMenuBackground.png"); + // m_pParentBox->SetDrawImage(new AllegroBitmap(backgroundFile.GetAsBitmap())); + // m_pParentBox->SetDrawBackground(true); + // m_pParentBox->SetDrawType(GUICollectionBox::Image); + m_pParentBox->SetDrawType(GUICollectionBox::Color); + } + m_pParentBox->SetPositionAbs(g_FrameMan.GetPlayerScreenWidth(), 0); + m_pParentBox->SetEnabled(false); + m_pParentBox->SetVisible(false); + + m_pAreasList = dynamic_cast(m_pGUIController->GetControl("AreasLB")); + m_pDeleteAreaButton = dynamic_cast(m_pGUIController->GetControl("DeleteAreaButton")); + + // If we're not split screen horizontally, then stretch out the layout for all the relevant controls + if (!g_FrameMan.GetHSplit()) { + int stretchAmount = g_WindowMan.GetResY() / 2; + m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); + m_pAreasList->SetSize(m_pAreasList->GetWidth(), m_pAreasList->GetHeight() + stretchAmount); + m_pDeleteAreaButton->SetPositionAbs(m_pDeleteAreaButton->GetXPos(), m_pDeleteAreaButton->GetYPos() + stretchAmount); + } + + m_pAreasList->SetAlternateDrawMode(false); + m_pAreasList->SetMultiSelect(false); + + // Populate the Areas list with the current Scene's Area:s + UpdateAreasList(); + + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + + return 0; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the AreaPickerGUI area. -void AreaPickerGUI::Destroy() -{ - delete m_pGUIController; - delete m_pGUIInput; - delete m_pGUIScreen; +void AreaPickerGUI::Destroy() { + delete m_pGUIController; + delete m_pGUIInput; + delete m_pGUIScreen; - Clear(); + Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetEnabled ////////////////////////////////////////////////////////////////////////////////////////// // Description: Enables or disables the menu. This will animate it in and out of view. -void AreaPickerGUI::SetEnabled(bool enable) -{ - if (enable && m_PickerEnabled != ENABLED && m_PickerEnabled != ENABLING) - { - // If we're not split screen horizontally, then stretch out the layout for all the relevant controls - int stretchAmount = g_FrameMan.GetPlayerScreenHeight() - m_pParentBox->GetHeight(); - if (stretchAmount != 0) - { - m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); - m_pAreasList->SetSize(m_pAreasList->GetWidth(), m_pAreasList->GetHeight() + stretchAmount); - } - - m_PickerEnabled = ENABLING; - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - // Set the mouse cursor free - g_UInputMan.TrapMousePos(false, m_pController->GetPlayer()); - // Move the mouse cursor to the middle of the player's screen - int mouseOffX, mouseOffY; - m_pGUIInput->GetMouseOffset(mouseOffX, mouseOffY); - Vector mousePos(-mouseOffX + (g_FrameMan.GetPlayerScreenWidth() / 2), -mouseOffY + (g_FrameMan.GetPlayerScreenHeight() / 2)); - g_UInputMan.SetMousePos(mousePos, m_pController->GetPlayer()); - g_GUISound.EnterMenuSound()->Play(); - - // Repopulate with the current Scene's list of Area:s - UpdateAreasList(); - } - else if (!enable && m_PickerEnabled != DISABLED && m_PickerEnabled != DISABLING) - { - m_PickerEnabled = DISABLING; - // Trap the mouse cursor again - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - // Only play switching away sound -// if (!m_pPickedArea) - g_GUISound.ExitMenuSound()->Play(); - } +void AreaPickerGUI::SetEnabled(bool enable) { + if (enable && m_PickerEnabled != ENABLED && m_PickerEnabled != ENABLING) { + // If we're not split screen horizontally, then stretch out the layout for all the relevant controls + int stretchAmount = g_FrameMan.GetPlayerScreenHeight() - m_pParentBox->GetHeight(); + if (stretchAmount != 0) { + m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); + m_pAreasList->SetSize(m_pAreasList->GetWidth(), m_pAreasList->GetHeight() + stretchAmount); + } + + m_PickerEnabled = ENABLING; + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + // Set the mouse cursor free + g_UInputMan.TrapMousePos(false, m_pController->GetPlayer()); + // Move the mouse cursor to the middle of the player's screen + int mouseOffX, mouseOffY; + m_pGUIInput->GetMouseOffset(mouseOffX, mouseOffY); + Vector mousePos(-mouseOffX + (g_FrameMan.GetPlayerScreenWidth() / 2), -mouseOffY + (g_FrameMan.GetPlayerScreenHeight() / 2)); + g_UInputMan.SetMousePos(mousePos, m_pController->GetPlayer()); + g_GUISound.EnterMenuSound()->Play(); + + // Repopulate with the current Scene's list of Area:s + UpdateAreasList(); + } else if (!enable && m_PickerEnabled != DISABLED && m_PickerEnabled != DISABLING) { + m_PickerEnabled = DISABLING; + // Trap the mouse cursor again + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + // Only play switching away sound + // if (!m_pPickedArea) + g_GUISound.ExitMenuSound()->Play(); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetPosOnScreen ////////////////////////////////////////////////////////////////////////////////////////// @@ -206,368 +190,317 @@ void AreaPickerGUI::SetEnabled(bool enable) // left corner, then 0, 0. This will affect the way the mouse is positioned // etc. -void AreaPickerGUI::SetPosOnScreen(int newPosX, int newPosY) -{ - m_pGUIController->SetPosOnScreen(newPosX, newPosY); +void AreaPickerGUI::SetPosOnScreen(int newPosX, int newPosY) { + m_pGUIController->SetPosOnScreen(newPosX, newPosY); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetNextArea ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gets the next area in the areas list, even if the picker is disabled. -Scene::Area * AreaPickerGUI::GetNextArea() -{ - m_SelectedAreaIndex++; - // Loop around - if (m_SelectedAreaIndex >= m_pAreasList->GetItemList()->size()) - m_SelectedAreaIndex = 0; - - m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); - // Report the newly selected item as being 'picked', but don't close the picker - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - { - g_GUISound.SelectionChangeSound()->Play(); - return g_SceneMan.GetScene()->GetArea(pItem->m_Name); - } - return 0; +Scene::Area* AreaPickerGUI::GetNextArea() { + m_SelectedAreaIndex++; + // Loop around + if (m_SelectedAreaIndex >= m_pAreasList->GetItemList()->size()) + m_SelectedAreaIndex = 0; + + m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); + // Report the newly selected item as being 'picked', but don't close the picker + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) { + g_GUISound.SelectionChangeSound()->Play(); + return g_SceneMan.GetScene()->GetArea(pItem->m_Name); + } + return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetPrevArea ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gets the prev area in the areas list, even if the picker is disabled. -Scene::Area * AreaPickerGUI::GetPrevArea() -{ - m_SelectedAreaIndex--; - // Loop around - if (m_SelectedAreaIndex < 0) - m_SelectedAreaIndex = m_pAreasList->GetItemList()->size() - 1; - - m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); - // Report the newly selected item as being 'picked', but don't close the picker - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - { - g_GUISound.SelectionChangeSound()->Play(); - return g_SceneMan.GetScene()->GetArea(pItem->m_Name); - } - return 0; +Scene::Area* AreaPickerGUI::GetPrevArea() { + m_SelectedAreaIndex--; + // Loop around + if (m_SelectedAreaIndex < 0) + m_SelectedAreaIndex = m_pAreasList->GetItemList()->size() - 1; + + m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); + // Report the newly selected item as being 'picked', but don't close the picker + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) { + g_GUISound.SelectionChangeSound()->Play(); + return g_SceneMan.GetScene()->GetArea(pItem->m_Name); + } + return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateAreasList ////////////////////////////////////////////////////////////////////////////////////////// // Description: Adds all areas of a specific type already defined in PresetMan // to the current Areas list -void AreaPickerGUI::UpdateAreasList(std::string selectAreaName) -{ - m_pAreasList->ClearList(); - - if (g_SceneMan.GetScene() && !g_SceneMan.GetScene()->m_AreaList.empty()) - { - Scene *pScene = g_SceneMan.GetScene(); - int indexToSelect = 0; - // Add all the current Scene's Area:s to the list! - for (std::list::iterator itr = pScene->m_AreaList.begin(); itr != pScene->m_AreaList.end(); ++itr) - { - m_pAreasList->AddItem((*itr).GetName()); - // If an Area's name matches the one we're supposed to leave selected after update, then save teh index - if ((*itr).GetName() == selectAreaName) - m_SelectedAreaIndex = indexToSelect; - indexToSelect++; - } - - m_pAreasList->ScrollToTop(); - // No actually select the Area with the matching name/index - m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); - // Set the picked area to be the one now selected at the top - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - m_pPickedArea = pScene->GetArea(pItem->m_Name); - } +void AreaPickerGUI::UpdateAreasList(std::string selectAreaName) { + m_pAreasList->ClearList(); + + if (g_SceneMan.GetScene() && !g_SceneMan.GetScene()->m_AreaList.empty()) { + Scene* pScene = g_SceneMan.GetScene(); + int indexToSelect = 0; + // Add all the current Scene's Area:s to the list! + for (std::list::iterator itr = pScene->m_AreaList.begin(); itr != pScene->m_AreaList.end(); ++itr) { + m_pAreasList->AddItem((*itr).GetName()); + // If an Area's name matches the one we're supposed to leave selected after update, then save teh index + if ((*itr).GetName() == selectAreaName) + m_SelectedAreaIndex = indexToSelect; + indexToSelect++; + } + + m_pAreasList->ScrollToTop(); + // No actually select the Area with the matching name/index + m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); + // Set the picked area to be the one now selected at the top + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) + m_pPickedArea = pScene->GetArea(pItem->m_Name); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Update ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void AreaPickerGUI::Update() -{ - // Enable mouse input if the controller allows it - m_pGUIController->EnableMouse(m_pController->IsMouseControlled()); - - // Reset the picked selector - m_pPickedArea = 0; - - //////////////////////////////////////////////////////////////////////// - // Animate the menu into and out of view if enabled or disabled - - if (m_PickerEnabled == ENABLING) - { - m_pParentBox->SetEnabled(true); - m_pParentBox->SetVisible(true); - - Vector position, occlusion; - - float enabledPos = g_FrameMan.GetPlayerScreenWidth() - m_pParentBox->GetWidth(); - - float toGo = std::floor((enabledPos - (float)m_pParentBox->GetXPos()) * m_MenuSpeed); - position.m_X = m_pParentBox->GetXPos() + toGo; - occlusion.m_X = m_pParentBox->GetXPos() - g_FrameMan.GetPlayerScreenWidth(); - - m_pParentBox->SetPositionAbs(position.m_X, position.m_Y); - g_CameraMan.SetScreenOcclusion(occlusion, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - if (m_pParentBox->GetXPos() <= enabledPos) - m_PickerEnabled = ENABLED; - } - // Animate the menu out of view - else if (m_PickerEnabled == DISABLING) - { - float disabledPos = g_FrameMan.GetPlayerScreenWidth(); - - float toGo = std::ceil((disabledPos - (float)m_pParentBox->GetXPos()) * m_MenuSpeed); - m_pParentBox->SetPositionAbs(m_pParentBox->GetXPos() + toGo, 0); - g_CameraMan.SetScreenOcclusion(Vector(m_pParentBox->GetXPos() - g_FrameMan.GetPlayerScreenWidth(), 0), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - if (m_pParentBox->GetXPos() >= g_FrameMan.GetPlayerScreenWidth()) - { - m_pParentBox->SetEnabled(false); - m_pParentBox->SetVisible(false); - m_PickerEnabled = DISABLED; - } - } - else if (m_PickerEnabled == ENABLED) - { - m_pParentBox->SetEnabled(true); - m_pParentBox->SetVisible(true); - } - else if (m_PickerEnabled == DISABLED) - { - m_pParentBox->SetEnabled(false); - m_pParentBox->SetVisible(false); - } - - // Quit now if we aren't enabled - if (m_PickerEnabled != ENABLED && m_PickerEnabled != ENABLING) - return; - - // Update the user controller -// m_pController->Update(); - - - ///////////////////////////////////////////////////// - // Mouse cursor logic - - int mouseX, mouseY; - m_pGUIInput->GetMousePosition(&mouseX, &mouseY); - m_CursorPos.SetXY(mouseX, mouseY); - - ///////////////////////////////////////////// - // Repeating input logic - - bool pressLeft = m_pController->IsState(PRESS_LEFT); - bool pressRight = m_pController->IsState(PRESS_RIGHT); - bool pressUp = m_pController->IsState(PRESS_UP) || m_pController->IsState(SCROLL_UP); - bool pressDown = m_pController->IsState(PRESS_DOWN) || m_pController->IsState(SCROLL_DOWN); - - // If no direciton is held down, then cancel the repeating - if (!(/*m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || */m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) - { - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - } - - // Check if any direction has been held for the starting amount of time to get into repeat mode - if (m_RepeatStartTimer.IsPastRealMS(200)) - { - // Check for the repeat interval - if (m_RepeatTimer.IsPastRealMS(75)) - { -/* L-R Not needed for picker - if (m_pController->IsState(MOVE_RIGHT)) - pressRight = true; - else if (m_pController->IsState(MOVE_LEFT)) - pressLeft = true; -*/ - if (m_pController->IsState(MOVE_UP)) - pressUp = true; - else if (m_pController->IsState(MOVE_DOWN)) - pressDown = true; - - m_RepeatTimer.Reset(); - } - } - - - ///////////////////////////////////////// - // AREAS LIST - - int listSize = m_pAreasList->GetItemList()->size(); - if (pressDown) - { - m_SelectedAreaIndex++; - // Loop around - if (m_SelectedAreaIndex >= listSize) - m_SelectedAreaIndex = 0; - - m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); - // Report the newly selected item as being 'picked', but don't close the picker - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name); - g_GUISound.SelectionChangeSound()->Play(); - } - else if (pressUp) - { - m_SelectedAreaIndex--; - // Loop around - if (m_SelectedAreaIndex < 0) - m_SelectedAreaIndex = listSize - 1; - - m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); - // Report the newly selected item as being 'picked', but don't close the picker - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name); - - g_GUISound.SelectionChangeSound()->Play(); - } - - // Fire button picks the area and deactivates the picker GUI - if (m_PickerEnabled == ENABLED && m_pController->IsState(PRESS_FACEBUTTON)) - { - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - { - // User has made final selection, so close the Picker - if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) - { - g_GUISound.AreaPickedSound()->Play(); - SetEnabled(false); - } - } - } - - // Right click, or pie menu press close the menu - if (m_pController->IsState(PRESS_SECONDARY)) - { - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - { - // User has made final selection, so close the Picker - if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) - { - g_GUISound.AreaPickedSound()->Play(); - SetEnabled(false); - } - } - } - - ////////////////////////////////////////// +void AreaPickerGUI::Update() { + // Enable mouse input if the controller allows it + m_pGUIController->EnableMouse(m_pController->IsMouseControlled()); + + // Reset the picked selector + m_pPickedArea = 0; + + //////////////////////////////////////////////////////////////////////// + // Animate the menu into and out of view if enabled or disabled + + if (m_PickerEnabled == ENABLING) { + m_pParentBox->SetEnabled(true); + m_pParentBox->SetVisible(true); + + Vector position, occlusion; + + float enabledPos = g_FrameMan.GetPlayerScreenWidth() - m_pParentBox->GetWidth(); + + float toGo = std::floor((enabledPos - (float)m_pParentBox->GetXPos()) * m_MenuSpeed); + position.m_X = m_pParentBox->GetXPos() + toGo; + occlusion.m_X = m_pParentBox->GetXPos() - g_FrameMan.GetPlayerScreenWidth(); + + m_pParentBox->SetPositionAbs(position.m_X, position.m_Y); + g_CameraMan.SetScreenOcclusion(occlusion, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + if (m_pParentBox->GetXPos() <= enabledPos) + m_PickerEnabled = ENABLED; + } + // Animate the menu out of view + else if (m_PickerEnabled == DISABLING) { + float disabledPos = g_FrameMan.GetPlayerScreenWidth(); + + float toGo = std::ceil((disabledPos - (float)m_pParentBox->GetXPos()) * m_MenuSpeed); + m_pParentBox->SetPositionAbs(m_pParentBox->GetXPos() + toGo, 0); + g_CameraMan.SetScreenOcclusion(Vector(m_pParentBox->GetXPos() - g_FrameMan.GetPlayerScreenWidth(), 0), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + if (m_pParentBox->GetXPos() >= g_FrameMan.GetPlayerScreenWidth()) { + m_pParentBox->SetEnabled(false); + m_pParentBox->SetVisible(false); + m_PickerEnabled = DISABLED; + } + } else if (m_PickerEnabled == ENABLED) { + m_pParentBox->SetEnabled(true); + m_pParentBox->SetVisible(true); + } else if (m_PickerEnabled == DISABLED) { + m_pParentBox->SetEnabled(false); + m_pParentBox->SetVisible(false); + } + + // Quit now if we aren't enabled + if (m_PickerEnabled != ENABLED && m_PickerEnabled != ENABLING) + return; + + // Update the user controller + // m_pController->Update(); + + ///////////////////////////////////////////////////// + // Mouse cursor logic + + int mouseX, mouseY; + m_pGUIInput->GetMousePosition(&mouseX, &mouseY); + m_CursorPos.SetXY(mouseX, mouseY); + + ///////////////////////////////////////////// + // Repeating input logic + + bool pressLeft = m_pController->IsState(PRESS_LEFT); + bool pressRight = m_pController->IsState(PRESS_RIGHT); + bool pressUp = m_pController->IsState(PRESS_UP) || m_pController->IsState(SCROLL_UP); + bool pressDown = m_pController->IsState(PRESS_DOWN) || m_pController->IsState(SCROLL_DOWN); + + // If no direciton is held down, then cancel the repeating + if (!(/*m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || */ m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) { + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + } + + // Check if any direction has been held for the starting amount of time to get into repeat mode + if (m_RepeatStartTimer.IsPastRealMS(200)) { + // Check for the repeat interval + if (m_RepeatTimer.IsPastRealMS(75)) { + /* L-R Not needed for picker + if (m_pController->IsState(MOVE_RIGHT)) + pressRight = true; + else if (m_pController->IsState(MOVE_LEFT)) + pressLeft = true; + */ + if (m_pController->IsState(MOVE_UP)) + pressUp = true; + else if (m_pController->IsState(MOVE_DOWN)) + pressDown = true; + + m_RepeatTimer.Reset(); + } + } + + ///////////////////////////////////////// + // AREAS LIST + + int listSize = m_pAreasList->GetItemList()->size(); + if (pressDown) { + m_SelectedAreaIndex++; + // Loop around + if (m_SelectedAreaIndex >= listSize) + m_SelectedAreaIndex = 0; + + m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); + // Report the newly selected item as being 'picked', but don't close the picker + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) + m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name); + g_GUISound.SelectionChangeSound()->Play(); + } else if (pressUp) { + m_SelectedAreaIndex--; + // Loop around + if (m_SelectedAreaIndex < 0) + m_SelectedAreaIndex = listSize - 1; + + m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); + // Report the newly selected item as being 'picked', but don't close the picker + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) + m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name); + + g_GUISound.SelectionChangeSound()->Play(); + } + + // Fire button picks the area and deactivates the picker GUI + if (m_PickerEnabled == ENABLED && m_pController->IsState(PRESS_FACEBUTTON)) { + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) { + // User has made final selection, so close the Picker + if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) { + g_GUISound.AreaPickedSound()->Play(); + SetEnabled(false); + } + } + } + + // Right click, or pie menu press close the menu + if (m_pController->IsState(PRESS_SECONDARY)) { + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) { + // User has made final selection, so close the Picker + if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) { + g_GUISound.AreaPickedSound()->Play(); + SetEnabled(false); + } + } + } + + ////////////////////////////////////////// // Update the ControlManager m_pGUIController->Update(); - - //////////////////////////////////////////////////////// - // Handle events for mouse input on the controls + //////////////////////////////////////////////////////// + // Handle events for mouse input on the controls GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { - // If we're not supposed to have mouse control, then ignore these messages - if (!m_pController->IsMouseControlled()) - break; - - if (anEvent.GetType() == GUIEvent::Command) - { - // Delete area button - if(anEvent.GetControl() == m_pDeleteAreaButton) - { - UpdateAreasList(); - m_pDeleteAreaButton->SetFocus(); - - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - // Only delete if there's more than one Area left - if (pItem && g_SceneMan.GetScene()->m_AreaList.size() > 1) - { - // Pick the next area, then remove the one specified - m_pPickedArea = GetNextArea(); - g_SceneMan.GetScene()->RemoveArea(pItem->m_Name); - // Update the list so it shows the one removed - UpdateAreasList(m_pPickedArea->GetName()); - g_GUISound.AreaPickedSound()->Play(); - } - else - g_GUISound.UserErrorSound()->Play(); + while (m_pGUIController->GetEvent(&anEvent)) { + // If we're not supposed to have mouse control, then ignore these messages + if (!m_pController->IsMouseControlled()) + break; + + if (anEvent.GetType() == GUIEvent::Command) { + // Delete area button + if (anEvent.GetControl() == m_pDeleteAreaButton) { + UpdateAreasList(); + m_pDeleteAreaButton->SetFocus(); + + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + // Only delete if there's more than one Area left + if (pItem && g_SceneMan.GetScene()->m_AreaList.size() > 1) { + // Pick the next area, then remove the one specified + m_pPickedArea = GetNextArea(); + g_SceneMan.GetScene()->RemoveArea(pItem->m_Name); + // Update the list so it shows the one removed + UpdateAreasList(m_pPickedArea->GetName()); + g_GUISound.AreaPickedSound()->Play(); + } else + g_GUISound.UserErrorSound()->Play(); + } + } else if (anEvent.GetType() == GUIEvent::Notification) { + /////////////////////////////////////////////// + // Clicks on the Areas List + + if (anEvent.GetControl() == m_pAreasList) { + if (anEvent.GetMsg() == GUIListBox::MouseDown && (anEvent.GetData() & GUIListBox::MOUSE_LEFT)) { + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) { + m_SelectedAreaIndex = m_pAreasList->GetSelectedIndex(); + // User has made final selection, so close the Picker + if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) { + g_GUISound.AreaPickedSound()->Play(); + SetEnabled(false); + } + } + // Undo the click deselection if nothing was selected + else + m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); + } } - } - else if (anEvent.GetType() == GUIEvent::Notification) - { - /////////////////////////////////////////////// - // Clicks on the Areas List - - if (anEvent.GetControl() == m_pAreasList) - { - if(anEvent.GetMsg() == GUIListBox::MouseDown && (anEvent.GetData() & GUIListBox::MOUSE_LEFT)) - { - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - { - m_SelectedAreaIndex = m_pAreasList->GetSelectedIndex(); - // User has made final selection, so close the Picker - if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) - { - g_GUISound.AreaPickedSound()->Play(); - SetEnabled(false); - } - } - // Undo the click deselection if nothing was selected - else - m_pAreasList->SetSelectedIndex(m_SelectedAreaIndex); + } + + // If clicked outside the picker, then close the picker GUI + if (anEvent.GetMsg() == GUIListBox::Click && m_PickerEnabled == ENABLED && m_CursorPos.m_X < m_pParentBox->GetXPos()) { + GUIListPanel::Item* pItem = m_pAreasList->GetSelected(); + if (pItem) { + // User has made final selection, so close the Picker + if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) { + g_GUISound.AreaPickedSound()->Play(); + SetEnabled(false); } - } - } - - // If clicked outside the picker, then close the picker GUI - if (anEvent.GetMsg() == GUIListBox::Click && m_PickerEnabled == ENABLED && m_CursorPos.m_X < m_pParentBox->GetXPos()) - { - GUIListPanel::Item *pItem = m_pAreasList->GetSelected(); - if (pItem) - { - // User has made final selection, so close the Picker - if (m_pPickedArea = g_SceneMan.GetScene()->GetArea(pItem->m_Name)) - { - g_GUISound.AreaPickedSound()->Play(); - SetEnabled(false); - } - } - } - } + } + } + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the menu -void AreaPickerGUI::Draw(BITMAP *drawBitmap) const -{ - AllegroScreen drawScreen(drawBitmap); - m_pGUIController->Draw(&drawScreen); +void AreaPickerGUI::Draw(BITMAP* drawBitmap) const { + AllegroScreen drawScreen(drawBitmap); + m_pGUIController->Draw(&drawScreen); - // Draw the cursor on top of everything - if (IsEnabled() && m_pController->IsMouseControlled()) - draw_sprite(drawBitmap, s_pCursor, m_CursorPos.GetFloorIntX(), m_CursorPos.GetFloorIntY()); -} \ No newline at end of file + // Draw the cursor on top of everything + if (IsEnabled() && m_pController->IsMouseControlled()) + draw_sprite(drawBitmap, s_pCursor, m_CursorPos.GetFloorIntX(), m_CursorPos.GetFloorIntY()); +} diff --git a/Source/Menus/AreaPickerGUI.h b/Source/Menus/AreaPickerGUI.h index 98bdb462a..fe55f3b7f 100644 --- a/Source/Menus/AreaPickerGUI.h +++ b/Source/Menus/AreaPickerGUI.h @@ -10,7 +10,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -21,293 +20,266 @@ struct BITMAP; -namespace RTE -{ - -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: AreaPickerGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A GUI for picking isntance areas in Cortex Command -// Parent(s): None. -// Class history: 7/16/2007 AreaPickerGUI Created. - -class AreaPickerGUI { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: AreaPickerGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a AreaPickerGUI area in system -// memory. Create() should be called before using the area. -// Arguments: None. - - AreaPickerGUI() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~AreaPickerGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a AreaPickerGUI area before deletion -// from system memory. -// Arguments: None. - - ~AreaPickerGUI() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AreaPickerGUI area ready for use. -// Arguments: A poitner to a Controller which will control this Menu. Ownership is -// NOT TRANSFERRED! -// Which lowest common denominator type to be showing. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(Controller *pController, std::string onlyOfType = "All"); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire AreaPickerGUI, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AreaPickerGUI area. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the controller used by this. The ownership of the controller is -// NOT transferred! -// Arguments: The new controller for this menu. Ownership is NOT transferred -// Return value: None. - - void SetController(Controller *pController) { m_pController = pController; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Enables or disables the menu. This will animate it in and out of view. -// Arguments: Whether to enable or disable the menu. -// Return value: None. - - void SetEnabled(bool enable = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the menu is enabled or not. -// Arguments: None. -// Return value: None. - - bool IsEnabled() const { return m_PickerEnabled == ENABLED || m_PickerEnabled == ENABLING; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the menu is at all visible or not. -// Arguments: None. -// Return value: None. - - bool IsVisible() const { return m_PickerEnabled != DISABLED; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPosOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where on the screen that this GUI is being drawn to. If upper -// left corner, then 0, 0. This will affect the way the mouse is positioned -// etc. -// Arguments: The new screen position of this entire GUI. - - void SetPosOnScreen(int newPosX, int newPosY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AreaPicked -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether and which Area has been picked by the player. This -// may happen even though the player isn't done with the picker. (ie -// a different area is picked each time the user selects something else -// in the areas list). -// Arguments: None. -// Return value: Whether an area has been picked bt the player. 0 if not. Ownership -// is NOT transferred! - - Scene::Area * AreaPicked() { return m_pPickedArea; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DonePicking -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the user has finished using the picker, and the final -// picked Area is returned. -// Arguments: None. -// Return value: Whether an area has been positively and finally picked bt the player. -// 0 if not. Ownership is NOT transferred! - - Scene::Area * DonePicking() { return !IsEnabled() && m_pPickedArea ? m_pPickedArea : 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetNextArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the next area in the areas list, even if the picker is disabled. -// Arguments: None. -// Return value: The next area in the picker list, looping around if necessary. -// 0 if no area can be selected. OWNERSHIP IS NOT TRANSFERRED! - - Scene::Area * GetNextArea(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPrevArea -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the prev area in the areas list, even if the picker is disabled. -// Arguments: None. -// Return value: The prev area in the picker list, looping around if necessary. -// 0 if no area can be selected. OWNERSHIP IS NOT TRANSFERRED! - - Scene::Area * GetPrevArea(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateAreasList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds all areas of the currently selected group to the Areas list. -// Arguments: The name of the Area to leave selected after the list is updated. -// Return value: None. - - void UpdateAreasList(std::string selectAreaName = ""); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Menu each frame -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the menu -// Arguments: The bitmap to draw on. -// Return value: None. - - void Draw(BITMAP *drawBitmap) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - enum PickerEnabled - { - ENABLING = 0, - ENABLED, - DISABLING, - DISABLED - }; - - // Controller which conrols this menu. Not owned - Controller *m_pController; - // GUI Screen for use by the in-game GUI - GUIScreen *m_pGUIScreen; - // Input controller - GUIInput *m_pGUIInput; - // The control manager which holds all the controls - GUIControlManager *m_pGUIController; - // Visibility state of the area picker - int m_PickerEnabled; - // Speed at which the menus appear and disappear - float m_MenuSpeed; - // Only show areas of this type. "" or "All" will show areas of all types - std::string m_ShowType; - // Which Group in the groups list box we have selected - int m_SelectedGroupIndex; - // Which Oroup in the Areas list box we have selected - int m_SelectedAreaIndex; - // Measures the time to when to start repeating inputs when they're held down - Timer m_RepeatStartTimer; - // Measures the interval between input repeats - Timer m_RepeatTimer; - - // Collection box of the puicker GUI - GUICollectionBox *m_pParentBox; - // The Listbox which lists all the groups - GUIListBox *m_pGroupsList; - // The Listbox which lists all the areas in the currently selected group - GUIListBox *m_pAreasList; - // The Button for deleting the currently selected Area - GUIButton *m_pDeleteAreaButton; - // Currently picked area. This is 0 until the user actually picks somehting, not just has the cursor over it - // Not owned by this. - Scene::Area *m_pPickedArea; - // The cursor image shared by all pickers - static BITMAP *s_pCursor; - // Screen position of the cursor - Vector m_CursorPos; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AreaPickerGUI, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - AreaPickerGUI(const AreaPickerGUI &reference) = delete; - AreaPickerGUI & operator=(const AreaPickerGUI &rhs) = delete; - -}; +namespace RTE { + + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: AreaPickerGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A GUI for picking isntance areas in Cortex Command + // Parent(s): None. + // Class history: 7/16/2007 AreaPickerGUI Created. + + class AreaPickerGUI { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: AreaPickerGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a AreaPickerGUI area in system + // memory. Create() should be called before using the area. + // Arguments: None. + + AreaPickerGUI() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~AreaPickerGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a AreaPickerGUI area before deletion + // from system memory. + // Arguments: None. + + ~AreaPickerGUI() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AreaPickerGUI area ready for use. + // Arguments: A poitner to a Controller which will control this Menu. Ownership is + // NOT TRANSFERRED! + // Which lowest common denominator type to be showing. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(Controller* pController, std::string onlyOfType = "All"); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire AreaPickerGUI, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AreaPickerGUI area. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the controller used by this. The ownership of the controller is + // NOT transferred! + // Arguments: The new controller for this menu. Ownership is NOT transferred + // Return value: None. + + void SetController(Controller* pController) { m_pController = pController; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Enables or disables the menu. This will animate it in and out of view. + // Arguments: Whether to enable or disable the menu. + // Return value: None. + + void SetEnabled(bool enable = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the menu is enabled or not. + // Arguments: None. + // Return value: None. + + bool IsEnabled() const { return m_PickerEnabled == ENABLED || m_PickerEnabled == ENABLING; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the menu is at all visible or not. + // Arguments: None. + // Return value: None. + + bool IsVisible() const { return m_PickerEnabled != DISABLED; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPosOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where on the screen that this GUI is being drawn to. If upper + // left corner, then 0, 0. This will affect the way the mouse is positioned + // etc. + // Arguments: The new screen position of this entire GUI. + + void SetPosOnScreen(int newPosX, int newPosY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AreaPicked + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether and which Area has been picked by the player. This + // may happen even though the player isn't done with the picker. (ie + // a different area is picked each time the user selects something else + // in the areas list). + // Arguments: None. + // Return value: Whether an area has been picked bt the player. 0 if not. Ownership + // is NOT transferred! + + Scene::Area* AreaPicked() { return m_pPickedArea; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DonePicking + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the user has finished using the picker, and the final + // picked Area is returned. + // Arguments: None. + // Return value: Whether an area has been positively and finally picked bt the player. + // 0 if not. Ownership is NOT transferred! + + Scene::Area* DonePicking() { return !IsEnabled() && m_pPickedArea ? m_pPickedArea : 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetNextArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the next area in the areas list, even if the picker is disabled. + // Arguments: None. + // Return value: The next area in the picker list, looping around if necessary. + // 0 if no area can be selected. OWNERSHIP IS NOT TRANSFERRED! + + Scene::Area* GetNextArea(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPrevArea + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the prev area in the areas list, even if the picker is disabled. + // Arguments: None. + // Return value: The prev area in the picker list, looping around if necessary. + // 0 if no area can be selected. OWNERSHIP IS NOT TRANSFERRED! + + Scene::Area* GetPrevArea(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateAreasList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds all areas of the currently selected group to the Areas list. + // Arguments: The name of the Area to leave selected after the list is updated. + // Return value: None. + + void UpdateAreasList(std::string selectAreaName = ""); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Menu each frame + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the menu + // Arguments: The bitmap to draw on. + // Return value: None. + + void Draw(BITMAP* drawBitmap) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + enum PickerEnabled { + ENABLING = 0, + ENABLED, + DISABLING, + DISABLED + }; + + // Controller which conrols this menu. Not owned + Controller* m_pController; + // GUI Screen for use by the in-game GUI + GUIScreen* m_pGUIScreen; + // Input controller + GUIInput* m_pGUIInput; + // The control manager which holds all the controls + GUIControlManager* m_pGUIController; + // Visibility state of the area picker + int m_PickerEnabled; + // Speed at which the menus appear and disappear + float m_MenuSpeed; + // Only show areas of this type. "" or "All" will show areas of all types + std::string m_ShowType; + // Which Group in the groups list box we have selected + int m_SelectedGroupIndex; + // Which Oroup in the Areas list box we have selected + int m_SelectedAreaIndex; + // Measures the time to when to start repeating inputs when they're held down + Timer m_RepeatStartTimer; + // Measures the interval between input repeats + Timer m_RepeatTimer; + + // Collection box of the puicker GUI + GUICollectionBox* m_pParentBox; + // The Listbox which lists all the groups + GUIListBox* m_pGroupsList; + // The Listbox which lists all the areas in the currently selected group + GUIListBox* m_pAreasList; + // The Button for deleting the currently selected Area + GUIButton* m_pDeleteAreaButton; + // Currently picked area. This is 0 until the user actually picks somehting, not just has the cursor over it + // Not owned by this. + Scene::Area* m_pPickedArea; + // The cursor image shared by all pickers + static BITMAP* s_pCursor; + // Screen position of the cursor + Vector m_CursorPos; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AreaPickerGUI, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + AreaPickerGUI(const AreaPickerGUI& reference) = delete; + AreaPickerGUI& operator=(const AreaPickerGUI& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Menus/AssemblyEditorGUI.cpp b/Source/Menus/AssemblyEditorGUI.cpp index 16dc10b3d..a76619488 100644 --- a/Source/Menus/AssemblyEditorGUI.cpp +++ b/Source/Menus/AssemblyEditorGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -42,8 +41,8 @@ using namespace RTE; #define BLUEPRINTREVEALRATE 150 #define BLUEPRINTREVEALPAUSE 1500 -BITMAP *AssemblyEditorGUI::s_pValidPathDot = 0; -BITMAP *AssemblyEditorGUI::s_pInvalidPathDot = 0; +BITMAP* AssemblyEditorGUI::s_pValidPathDot = 0; +BITMAP* AssemblyEditorGUI::s_pInvalidPathDot = 0; ////////////////////////////////////////////////////////////////////////////////////////// // Method: Clear @@ -51,140 +50,133 @@ BITMAP *AssemblyEditorGUI::s_pInvalidPathDot = 0; // Description: Clears all the member variables of this AssemblyEditorGUI, effectively // resetting the members of this abstraction level only. -void AssemblyEditorGUI::Clear() -{ - m_pController = 0; - m_FeatureSet = ONLOADEDIT; - m_EditMade = false; - m_EditorGUIMode = PICKINGOBJECT; - m_PreviousMode = ADDINGOBJECT; - m_ModeChanged = true; - m_BlinkTimer.Reset(); - m_BlinkMode = NOBLINK; - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - m_RevealTimer.Reset(); - m_RevealIndex = 0; +void AssemblyEditorGUI::Clear() { + m_pController = 0; + m_FeatureSet = ONLOADEDIT; + m_EditMade = false; + m_EditorGUIMode = PICKINGOBJECT; + m_PreviousMode = ADDINGOBJECT; + m_ModeChanged = true; + m_BlinkTimer.Reset(); + m_BlinkMode = NOBLINK; + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + m_RevealTimer.Reset(); + m_RevealIndex = 0; m_PieMenu = nullptr; - m_pPicker = 0; - m_NativeTechModule = 0; - m_ForeignCostMult = 4.0; - m_GridSnapping = true; - m_CursorPos.Reset(); - m_CursorOffset.Reset(); - m_CursorInAir = true; - m_FacingLeft = false; - m_PlaceTeam = Activity::TeamOne; - m_pCurrentObject = 0; - m_ObjectListOrder = -1; - m_DrawCurrentObject = true; - m_pObjectToBlink = 0; - m_BrainSkyPath.clear(); - m_BrainSkyPathCost = 0; + m_pPicker = 0; + m_NativeTechModule = 0; + m_ForeignCostMult = 4.0; + m_GridSnapping = true; + m_CursorPos.Reset(); + m_CursorOffset.Reset(); + m_CursorInAir = true; + m_FacingLeft = false; + m_PlaceTeam = Activity::TeamOne; + m_pCurrentObject = 0; + m_ObjectListOrder = -1; + m_DrawCurrentObject = true; + m_pObjectToBlink = 0; + m_BrainSkyPath.clear(); + m_BrainSkyPathCost = 0; m_RequireClearPathToOrbit = true; m_pCurrentScheme = 0; m_CurrentAssemblyName.clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the AssemblyEditorGUI object ready for use. -int AssemblyEditorGUI::Create(Controller *pController, FeatureSets featureSet, int whichModuleSpace, int nativeTechModule, float foreignCostMult) -{ - RTEAssert(pController, "No controller sent to AssemblyEditorGUI on creation!"); - m_pController = pController; +int AssemblyEditorGUI::Create(Controller* pController, FeatureSets featureSet, int whichModuleSpace, int nativeTechModule, float foreignCostMult) { + RTEAssert(pController, "No controller sent to AssemblyEditorGUI on creation!"); + m_pController = pController; - m_FeatureSet = featureSet; + m_FeatureSet = featureSet; - if (m_PieMenu) { m_PieMenu = nullptr; } - m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", "Assembly Editor Pie Menu")->Clone())); + if (m_PieMenu) { + m_PieMenu = nullptr; + } + m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", "Assembly Editor Pie Menu")->Clone())); m_PieMenu->SetMenuController(pController); - // Update the brain path - UpdateBrainPath(); - - // Allocate and (re)create the Editor GUIs - if (!m_pPicker) - m_pPicker = new ObjectPickerGUI(); - else - m_pPicker->Reset(); - m_pPicker->Create(pController, whichModuleSpace); - - m_NativeTechModule = nativeTechModule; - m_ForeignCostMult = foreignCostMult; - // Also apply these to the picker - m_pPicker->SetNativeTechModule(m_NativeTechModule); - m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); - - // Cursor init - m_CursorPos = g_SceneMan.GetSceneDim() / 2; - - // Set initial focus, category list, and label settings - m_EditorGUIMode = PICKINGOBJECT; - m_ModeChanged = true; - m_pCurrentObject = 0; - - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - m_RevealTimer.Reset(); - m_RevealTimer.SetRealTimeLimitMS(100); - - //Check if we need to check for a clear path to orbit + // Update the brain path + UpdateBrainPath(); + + // Allocate and (re)create the Editor GUIs + if (!m_pPicker) + m_pPicker = new ObjectPickerGUI(); + else + m_pPicker->Reset(); + m_pPicker->Create(pController, whichModuleSpace); + + m_NativeTechModule = nativeTechModule; + m_ForeignCostMult = foreignCostMult; + // Also apply these to the picker + m_pPicker->SetNativeTechModule(m_NativeTechModule); + m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); + + // Cursor init + m_CursorPos = g_SceneMan.GetSceneDim() / 2; + + // Set initial focus, category list, and label settings + m_EditorGUIMode = PICKINGOBJECT; + m_ModeChanged = true; + m_pCurrentObject = 0; + + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + m_RevealTimer.Reset(); + m_RevealTimer.SetRealTimeLimitMS(100); + + // Check if we need to check for a clear path to orbit m_RequireClearPathToOrbit = true; - GameActivity * gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); + GameActivity* gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); if (gameActivity) m_RequireClearPathToOrbit = gameActivity->GetRequireClearPathToOrbit(); // Always disable clear path requirement in scene editor - SceneEditor * editorActivity = dynamic_cast(g_ActivityMan.GetActivity()); + SceneEditor* editorActivity = dynamic_cast(g_ActivityMan.GetActivity()); if (editorActivity) m_RequireClearPathToOrbit = false; - // Only load the static dot bitmaps once - if (!s_pValidPathDot) - { - ContentFile dotFile("Base.rte/GUIs/Indicators/PathDotValid.png"); - s_pValidPathDot = dotFile.GetAsBitmap(); - dotFile.SetDataPath("Base.rte/GUIs/Indicators/PathDotInvalid.png"); - s_pInvalidPathDot = dotFile.GetAsBitmap(); - } + // Only load the static dot bitmaps once + if (!s_pValidPathDot) { + ContentFile dotFile("Base.rte/GUIs/Indicators/PathDotValid.png"); + s_pValidPathDot = dotFile.GetAsBitmap(); + dotFile.SetDataPath("Base.rte/GUIs/Indicators/PathDotInvalid.png"); + s_pInvalidPathDot = dotFile.GetAsBitmap(); + } - return 0; + return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the AssemblyEditorGUI object. -void AssemblyEditorGUI::Destroy() -{ - delete m_pPicker; - delete m_pCurrentObject; +void AssemblyEditorGUI::Destroy() { + delete m_pPicker; + delete m_pCurrentObject; delete m_pCurrentScheme; - Clear(); + Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetController ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the controller used by this. The ownership of the controller is // NOT transferred! -void AssemblyEditorGUI::SetController(Controller *pController) -{ - m_pController = pController; +void AssemblyEditorGUI::SetController(Controller* pController) { + m_pController = pController; m_PieMenu->SetMenuController(pController); - m_pPicker->SetController(pController); + m_pPicker->SetController(pController); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetPosOnScreen ////////////////////////////////////////////////////////////////////////////////////////// @@ -192,100 +184,84 @@ void AssemblyEditorGUI::SetController(Controller *pController) // left corner, then 0, 0. This will affect the way the mouse is positioned // etc. -void AssemblyEditorGUI::SetPosOnScreen(int newPosX, int newPosY) -{ - m_pPicker->SetPosOnScreen(newPosX, newPosY); +void AssemblyEditorGUI::SetPosOnScreen(int newPosX, int newPosY) { + m_pPicker->SetPosOnScreen(newPosX, newPosY); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetCurrentObject ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the new Object to be held at the cursor of this Editor. Ownership // IS transferred! -bool AssemblyEditorGUI::SetCurrentObject(SceneObject *pNewObject) -{ - if (m_pCurrentObject == pNewObject) - return true; +bool AssemblyEditorGUI::SetCurrentObject(SceneObject* pNewObject) { + if (m_pCurrentObject == pNewObject) + return true; - // Replace the current object with the new one - if (MovableObject *asMo = dynamic_cast(m_pCurrentObject)) { - asMo->DestroyScriptState(); - } - delete m_pCurrentObject; - m_pCurrentObject = pNewObject; - - if (!m_pCurrentObject) - return false; - - m_pCurrentObject->SetTeam(m_FeatureSet == ONLOADEDIT ? m_PlaceTeam : m_pController->GetTeam()); - m_pCurrentObject->SetPlacedByPlayer(m_pController->GetPlayer()); - - // Disable any controller, if an actor - if (Actor *pActor = dynamic_cast(m_pCurrentObject)) - { - pActor->GetController()->SetDisabled(true); - pActor->SetStatus(Actor::INACTIVE); - } + // Replace the current object with the new one + if (MovableObject* asMo = dynamic_cast(m_pCurrentObject)) { + asMo->DestroyScriptState(); + } + delete m_pCurrentObject; + m_pCurrentObject = pNewObject; + if (!m_pCurrentObject) + return false; + m_pCurrentObject->SetTeam(m_FeatureSet == ONLOADEDIT ? m_PlaceTeam : m_pController->GetTeam()); + m_pCurrentObject->SetPlacedByPlayer(m_pController->GetPlayer()); + // Disable any controller, if an actor + if (Actor* pActor = dynamic_cast(m_pCurrentObject)) { + pActor->GetController()->SetDisabled(true); + pActor->SetStatus(Actor::INACTIVE); + } - return true; + return true; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetActivatedPieSlice ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gets any Pie menu slice command activated last update. PieSlice::SliceType AssemblyEditorGUI::GetActivatedPieSlice() const { - return m_PieMenu->GetPieCommand(); + return m_PieMenu->GetPieCommand(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetModuleSpace ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets which DataModule space to be picking objects from. If -1, then // let the player pick from all loaded modules. -void AssemblyEditorGUI::SetModuleSpace(int moduleSpaceID) -{ - m_pPicker->SetModuleSpace(moduleSpaceID); +void AssemblyEditorGUI::SetModuleSpace(int moduleSpaceID) { + m_pPicker->SetModuleSpace(moduleSpaceID); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetNativeTechModule ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets which DataModule ID should be treated as the native tech of the // user of this menu. -void AssemblyEditorGUI::SetNativeTechModule(int whichModule) -{ - if (whichModule >= 0 && whichModule < g_PresetMan.GetTotalModuleCount()) - { - m_NativeTechModule = whichModule; - m_pPicker->SetNativeTechModule(m_NativeTechModule); - } +void AssemblyEditorGUI::SetNativeTechModule(int whichModule) { + if (whichModule >= 0 && whichModule < g_PresetMan.GetTotalModuleCount()) { + m_NativeTechModule = whichModule; + m_pPicker->SetNativeTechModule(m_NativeTechModule); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetForeignCostMultiplier ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the multiplier of the cost of any foreign Tech items. -void AssemblyEditorGUI::SetForeignCostMultiplier(float newMultiplier) -{ - m_ForeignCostMult = newMultiplier; - m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); +void AssemblyEditorGUI::SetForeignCostMultiplier(float newMultiplier) { + m_ForeignCostMult = newMultiplier; + m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: TestBrainResidence ////////////////////////////////////////////////////////////////////////////////////////// @@ -295,109 +271,104 @@ void AssemblyEditorGUI::SetForeignCostMultiplier(float newMultiplier) // current resident brain if the current placement is no bueno. It also // removes the faulty brain from residence in the scene! -bool AssemblyEditorGUI::TestBrainResidence(bool noBrainIsOK) -{ +bool AssemblyEditorGUI::TestBrainResidence(bool noBrainIsOK) { // Brain is fine, leave it be - return false; + return false; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Update ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void AssemblyEditorGUI::Update() -{ - // Update the user controller -// m_pController->Update(); +void AssemblyEditorGUI::Update() { + // Update the user controller + // m_pController->Update(); - std::string selectedAssembly = "\nSelected scheme: "; + std::string selectedAssembly = "\nSelected scheme: "; - if (m_pCurrentScheme) - { - std::list assemblies; + if (m_pCurrentScheme) { + std::list assemblies; g_PresetMan.GetAllOfGroup(assemblies, m_pCurrentScheme->GetPresetName(), "BunkerAssembly"); std::stringstream assemblyName; - assemblyName << m_pCurrentScheme->GetPresetName() << " [ " << assemblies.size() << " ]"; + assemblyName << m_pCurrentScheme->GetPresetName() << " [ " << assemblies.size() << " ]"; selectedAssembly += assemblyName.str(); } selectedAssembly += "\nCurrent assembly: " + m_CurrentAssemblyName; - m_EditMade = false; - m_pObjectToBlink = 0; - // Which set of placed objects in the scene we're editing - int editedSet = Scene::PLACEONLOAD; - - ///////////////////////////////////////////// - // Repeating input logic - - bool pressLeft = m_pController->IsState(PRESS_LEFT); - bool pressRight = m_pController->IsState(PRESS_RIGHT); - bool pressUp = m_pController->IsState(PRESS_UP); - bool pressDown = m_pController->IsState(PRESS_DOWN); - - // If no direciton is held down, then cancel the repeating - if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) - { - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - } - - // Check if any direction has been held for the starting amount of time to get into repeat mode - if (m_RepeatStartTimer.IsPastRealMS(200)) - { - // Check for the repeat interval - if (m_RepeatTimer.IsPastRealMS(30)) - { - if (m_pController->IsState(MOVE_RIGHT)) - pressRight = true; - else if (m_pController->IsState(MOVE_LEFT)) - pressLeft = true; - - if (m_pController->IsState(MOVE_UP)) - pressUp = true; - else if (m_pController->IsState(MOVE_DOWN)) - pressDown = true; - - m_RepeatTimer.Reset(); - } - } - - /////////////////////////////////////////////// - // Analog cursor input - - Vector analogInput; - if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) - analogInput = m_pController->GetAnalogMove(); -// else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) -// analogInput = m_pController->GetAnalogAim(); - - ///////////////////////////////////////////// - // PIE MENU + m_EditMade = false; + m_pObjectToBlink = 0; + // Which set of placed objects in the scene we're editing + int editedSet = Scene::PLACEONLOAD; + + ///////////////////////////////////////////// + // Repeating input logic + + bool pressLeft = m_pController->IsState(PRESS_LEFT); + bool pressRight = m_pController->IsState(PRESS_RIGHT); + bool pressUp = m_pController->IsState(PRESS_UP); + bool pressDown = m_pController->IsState(PRESS_DOWN); + + // If no direciton is held down, then cancel the repeating + if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) { + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + } + + // Check if any direction has been held for the starting amount of time to get into repeat mode + if (m_RepeatStartTimer.IsPastRealMS(200)) { + // Check for the repeat interval + if (m_RepeatTimer.IsPastRealMS(30)) { + if (m_pController->IsState(MOVE_RIGHT)) + pressRight = true; + else if (m_pController->IsState(MOVE_LEFT)) + pressLeft = true; + + if (m_pController->IsState(MOVE_UP)) + pressUp = true; + else if (m_pController->IsState(MOVE_DOWN)) + pressDown = true; + + m_RepeatTimer.Reset(); + } + } + + /////////////////////////////////////////////// + // Analog cursor input + + Vector analogInput; + if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) + analogInput = m_pController->GetAnalogMove(); + // else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) + // analogInput = m_pController->GetAnalogAim(); + + ///////////////////////////////////////////// + // PIE MENU m_PieMenu->Update(); - // Show the pie menu only when the secondary button is held down - if (m_pController->IsState(PRESS_SECONDARY) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGOBJECT) { + // Show the pie menu only when the secondary button is held down + if (m_pController->IsState(PRESS_SECONDARY) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGOBJECT) { m_PieMenu->SetPos(m_GridSnapping ? g_SceneMan.SnapPosition(m_CursorPos) : m_CursorPos); m_PieMenu->SetEnabled(true); - PieSlice *saveSlice = m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorSave); + PieSlice* saveSlice = m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorSave); if (saveSlice) { saveSlice->SetEnabled(m_pCurrentScheme != nullptr); saveSlice->SetDescription(m_pCurrentScheme != nullptr ? "Save Assembly" : "Can't Save Assembly, Scheme Not Selected!"); } - } + } - if (!m_pController->IsState(PIE_MENU_ACTIVE) || m_EditorGUIMode == INACTIVE || m_EditorGUIMode == PICKINGOBJECT) { m_PieMenu->SetEnabled(false); } + if (!m_pController->IsState(PIE_MENU_ACTIVE) || m_EditorGUIMode == INACTIVE || m_EditorGUIMode == PICKINGOBJECT) { + m_PieMenu->SetEnabled(false); + } - /////////////////////////////////////// - // Handle pie menu selections + /////////////////////////////////////// + // Handle pie menu selections - if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { + if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorPick) { m_EditorGUIMode = PICKINGOBJECT; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorMove) { @@ -408,268 +379,233 @@ void AssemblyEditorGUI::Update() m_EditorGUIMode = DONEEDITING; } - UpdateBrainPath(); - m_ModeChanged = true; - } - - ////////////////////////////////////////// - // Picker logic - - // Enable or disable the picker - m_pPicker->SetEnabled(m_EditorGUIMode == PICKINGOBJECT); - - // Update the picker GUI - m_pPicker->Update(); - - if (m_EditorGUIMode == PICKINGOBJECT && m_pPicker->ObjectPicked()) - { - // Assign a copy of the picked object to be the currently held one. - if (SetCurrentObject(dynamic_cast(m_pPicker->ObjectPicked()->Clone()))) - { - // Set the team - if (m_FeatureSet != ONLOADEDIT) - m_pCurrentObject->SetTeam(m_pController->GetTeam()); - // Set the list order to be at the end so new objects are added there - m_ObjectListOrder = -1; - // Update the object - m_pCurrentObject->FullUpdate(); - // Update the path to the brain, or clear it if there's none - UpdateBrainPath(); - - // If done picking, revert to moving object mode - if (m_pPicker->DonePicking()) - { - m_EditorGUIMode = ADDINGOBJECT; - UpdateBrainPath(); - m_ModeChanged = true; - } - } - } - - if (!m_pPicker->IsVisible()) - g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - else - g_FrameMan.SetScreenText("Pick what you want to place next" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - ///////////////////////////////////// - // ADDING OBJECT MODE - - if (m_EditorGUIMode == ADDINGOBJECT && !m_PieMenu->IsEnabled()) - { - if (m_ModeChanged) - { - m_ModeChanged = false; - } - g_FrameMan.SetScreenText("Click to ADD a new object - Drag for precision" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - - m_DrawCurrentObject = true; - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput * 8; - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= SCENESNAPSIZE; - if (pressRight) - m_CursorPos.m_X += SCENESNAPSIZE; - if (pressDown) - m_CursorPos.m_Y += SCENESNAPSIZE; - if (pressLeft) - m_CursorPos.m_X -= SCENESNAPSIZE; - // Re-enable snapping only when the cursor is moved again - if (pressUp || pressRight || pressDown || pressLeft) - m_GridSnapping = true; - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - - // Mousewheel is used as shortcut for getting next and prev items in teh picker's object list - if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(ControlState::ACTOR_NEXT)) - { - // Assign a copy of the next picked object to be the currently held one. - const SceneObject *pNewObject = m_pPicker->GetPrevObject(); - if (pNewObject) - { - // Set and update the cursor object - if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) - m_pCurrentObject->FullUpdate(); - } - } - else if (m_pController->IsState(SCROLL_DOWN) || m_pController->IsState(ControlState::ACTOR_PREV)) - { - // Assign a copy of the next picked object to be the currently held one. - const SceneObject *pNewObject = m_pPicker->GetNextObject(); - if (pNewObject) - { - // Set and update the object - if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) - m_pCurrentObject->FullUpdate(); - } - } - - // Start the timer when the button is first pressed, and when the picker has deactivated - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - m_BlinkTimer.Reset(); - m_EditorGUIMode = PLACINGOBJECT; - m_PreviousMode = ADDINGOBJECT; - m_ModeChanged = true; - g_GUISound.PlacementBlip()->Play(); - } - - // Apply the team to the current actor, if applicable - if (m_pCurrentObject && m_DrawCurrentObject) - { - // Set the team of SceneObject based on what's been selected - // Only if full featured mode, otherwise it's based on the controller when placed - if (m_FeatureSet == ONLOADEDIT) - m_pCurrentObject->SetTeam(m_PlaceTeam); - } - } - - ///////////////////////////////////////////////////////////// - // PLACING MODE - - if (m_EditorGUIMode == PLACINGOBJECT) - { - if (m_ModeChanged) - { - m_ModeChanged = false; - } - - if (m_PreviousMode == MOVINGOBJECT) - g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - else - g_FrameMan.SetScreenText("Release to ADD the new object - Tap other button to cancel" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - m_DrawCurrentObject = true; - - // Freeze when first pressing down and grid snapping is still engaged - if (!(m_pController->IsState(PRIMARY_ACTION) && m_GridSnapping)) - { - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput; - m_FacingLeft = analogInput.m_X < 0 || (m_FacingLeft && analogInput.m_X == 0); - } - // Try the mouse - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - m_FacingLeft = m_pController->GetMouseMovement().m_X < 0 || (m_FacingLeft && m_pController->GetMouseMovement().m_X == 0); - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= 1; - if (pressRight) - { - m_CursorPos.m_X += 1; - m_FacingLeft = false; - } - if (pressDown) - m_CursorPos.m_Y += 1; - if (pressLeft) - { - m_CursorPos.m_X -= 1; - m_FacingLeft = true; - } - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - // Also check that it isn't over unseen areas, can't place there - m_CursorInAir = m_CursorInAir && !g_SceneMan.IsUnseen(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY(), m_pController->GetTeam()); - } - - // Constrain the cursor to only be within specific scene areas -// TODO: THIS!!! - - // Disable snapping after a small interval of holding down the button, to avoid unintentional nudges when just placing on the grid - if (m_pController->IsState(PRIMARY_ACTION) && m_BlinkTimer.IsPastRealMS(333) && m_GridSnapping) - { - m_GridSnapping = false; - m_CursorPos = g_SceneMan.SnapPosition(m_CursorPos); - } - - // Cancel placing if secondary button is pressed - if (m_pController->IsState(PRESS_SECONDARY) || m_pController->IsState(PIE_MENU_ACTIVE)) - { - m_EditorGUIMode = m_PreviousMode; - m_ModeChanged = true; - } - // If previous mode was moving, tear the gib loose if the button is released to soo - else if (m_PreviousMode == MOVINGOBJECT && m_pController->IsState(RELEASE_PRIMARY) && !m_BlinkTimer.IsPastRealMS(150)) - { - m_EditorGUIMode = ADDINGOBJECT; - m_ModeChanged = true; - } - // Only place if the picker and pie menus are completely out of view, to avoid immediate placing after picking - else if (m_pCurrentObject && m_pController->IsState(RELEASE_PRIMARY) && !m_pPicker->IsVisible()) - { - m_pCurrentObject->FullUpdate(); - //If true we need to place object in the end, if false, then it was already given to an actor + UpdateBrainPath(); + m_ModeChanged = true; + } + + ////////////////////////////////////////// + // Picker logic + + // Enable or disable the picker + m_pPicker->SetEnabled(m_EditorGUIMode == PICKINGOBJECT); + + // Update the picker GUI + m_pPicker->Update(); + + if (m_EditorGUIMode == PICKINGOBJECT && m_pPicker->ObjectPicked()) { + // Assign a copy of the picked object to be the currently held one. + if (SetCurrentObject(dynamic_cast(m_pPicker->ObjectPicked()->Clone()))) { + // Set the team + if (m_FeatureSet != ONLOADEDIT) + m_pCurrentObject->SetTeam(m_pController->GetTeam()); + // Set the list order to be at the end so new objects are added there + m_ObjectListOrder = -1; + // Update the object + m_pCurrentObject->FullUpdate(); + // Update the path to the brain, or clear it if there's none + UpdateBrainPath(); + + // If done picking, revert to moving object mode + if (m_pPicker->DonePicking()) { + m_EditorGUIMode = ADDINGOBJECT; + UpdateBrainPath(); + m_ModeChanged = true; + } + } + } + + if (!m_pPicker->IsVisible()) + g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + else + g_FrameMan.SetScreenText("Pick what you want to place next" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + ///////////////////////////////////// + // ADDING OBJECT MODE + + if (m_EditorGUIMode == ADDINGOBJECT && !m_PieMenu->IsEnabled()) { + if (m_ModeChanged) { + m_ModeChanged = false; + } + g_FrameMan.SetScreenText("Click to ADD a new object - Drag for precision" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + m_DrawCurrentObject = true; + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) { + m_CursorPos += analogInput * 8; + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= SCENESNAPSIZE; + if (pressRight) + m_CursorPos.m_X += SCENESNAPSIZE; + if (pressDown) + m_CursorPos.m_Y += SCENESNAPSIZE; + if (pressLeft) + m_CursorPos.m_X -= SCENESNAPSIZE; + // Re-enable snapping only when the cursor is moved again + if (pressUp || pressRight || pressDown || pressLeft) + m_GridSnapping = true; + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + + // Mousewheel is used as shortcut for getting next and prev items in teh picker's object list + if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(ControlState::ACTOR_NEXT)) { + // Assign a copy of the next picked object to be the currently held one. + const SceneObject* pNewObject = m_pPicker->GetPrevObject(); + if (pNewObject) { + // Set and update the cursor object + if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) + m_pCurrentObject->FullUpdate(); + } + } else if (m_pController->IsState(SCROLL_DOWN) || m_pController->IsState(ControlState::ACTOR_PREV)) { + // Assign a copy of the next picked object to be the currently held one. + const SceneObject* pNewObject = m_pPicker->GetNextObject(); + if (pNewObject) { + // Set and update the object + if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) + m_pCurrentObject->FullUpdate(); + } + } + + // Start the timer when the button is first pressed, and when the picker has deactivated + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + m_BlinkTimer.Reset(); + m_EditorGUIMode = PLACINGOBJECT; + m_PreviousMode = ADDINGOBJECT; + m_ModeChanged = true; + g_GUISound.PlacementBlip()->Play(); + } + + // Apply the team to the current actor, if applicable + if (m_pCurrentObject && m_DrawCurrentObject) { + // Set the team of SceneObject based on what's been selected + // Only if full featured mode, otherwise it's based on the controller when placed + if (m_FeatureSet == ONLOADEDIT) + m_pCurrentObject->SetTeam(m_PlaceTeam); + } + } + + ///////////////////////////////////////////////////////////// + // PLACING MODE + + if (m_EditorGUIMode == PLACINGOBJECT) { + if (m_ModeChanged) { + m_ModeChanged = false; + } + + if (m_PreviousMode == MOVINGOBJECT) + g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + else + g_FrameMan.SetScreenText("Release to ADD the new object - Tap other button to cancel" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + m_DrawCurrentObject = true; + + // Freeze when first pressing down and grid snapping is still engaged + if (!(m_pController->IsState(PRIMARY_ACTION) && m_GridSnapping)) { + if (!analogInput.IsZero()) { + m_CursorPos += analogInput; + m_FacingLeft = analogInput.m_X < 0 || (m_FacingLeft && analogInput.m_X == 0); + } + // Try the mouse + else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + m_FacingLeft = m_pController->GetMouseMovement().m_X < 0 || (m_FacingLeft && m_pController->GetMouseMovement().m_X == 0); + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= 1; + if (pressRight) { + m_CursorPos.m_X += 1; + m_FacingLeft = false; + } + if (pressDown) + m_CursorPos.m_Y += 1; + if (pressLeft) { + m_CursorPos.m_X -= 1; + m_FacingLeft = true; + } + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + // Also check that it isn't over unseen areas, can't place there + m_CursorInAir = m_CursorInAir && !g_SceneMan.IsUnseen(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY(), m_pController->GetTeam()); + } + + // Constrain the cursor to only be within specific scene areas + // TODO: THIS!!! + + // Disable snapping after a small interval of holding down the button, to avoid unintentional nudges when just placing on the grid + if (m_pController->IsState(PRIMARY_ACTION) && m_BlinkTimer.IsPastRealMS(333) && m_GridSnapping) { + m_GridSnapping = false; + m_CursorPos = g_SceneMan.SnapPosition(m_CursorPos); + } + + // Cancel placing if secondary button is pressed + if (m_pController->IsState(PRESS_SECONDARY) || m_pController->IsState(PIE_MENU_ACTIVE)) { + m_EditorGUIMode = m_PreviousMode; + m_ModeChanged = true; + } + // If previous mode was moving, tear the gib loose if the button is released to soo + else if (m_PreviousMode == MOVINGOBJECT && m_pController->IsState(RELEASE_PRIMARY) && !m_BlinkTimer.IsPastRealMS(150)) { + m_EditorGUIMode = ADDINGOBJECT; + m_ModeChanged = true; + } + // Only place if the picker and pie menus are completely out of view, to avoid immediate placing after picking + else if (m_pCurrentObject && m_pController->IsState(RELEASE_PRIMARY) && !m_pPicker->IsVisible()) { + m_pCurrentObject->FullUpdate(); + // If true we need to place object in the end, if false, then it was already given to an actor bool toPlace = true; - //If we're placing an item then give that item to actor instead of dropping it nearby - HeldDevice *pHeldDevice = dynamic_cast(m_pCurrentObject); - if (pHeldDevice) - { - if (dynamic_cast(pHeldDevice) || dynamic_cast(pHeldDevice)) - { + // If we're placing an item then give that item to actor instead of dropping it nearby + HeldDevice* pHeldDevice = dynamic_cast(m_pCurrentObject); + if (pHeldDevice) { + if (dynamic_cast(pHeldDevice) || dynamic_cast(pHeldDevice)) { int objectListPosition = -1; - //Find out if we have AHuman under the cursor - const SceneObject *pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &objectListPosition); - const Actor *pAHuman = 0; + // Find out if we have AHuman under the cursor + const SceneObject* pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &objectListPosition); + const Actor* pAHuman = 0; // Looks like we got nothing, search for actors in range then if (!pPickedSceneObject) - pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); + pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); - if (pPickedSceneObject) - { - pAHuman = dynamic_cast(pPickedSceneObject); + if (pPickedSceneObject) { + pAHuman = dynamic_cast(pPickedSceneObject); - if (!pAHuman) - { + if (!pAHuman) { // Maybe we clicked the underlying bunker module, search for actor in range - pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); + pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); if (pPickedSceneObject) - pAHuman = dynamic_cast(pPickedSceneObject); + pAHuman = dynamic_cast(pPickedSceneObject); } - if (pAHuman) - { - //Create a new AHuman instead of old one, give him an item, and delete old AHuman - SceneObject * pNewObject = dynamic_cast(pPickedSceneObject->Clone()); + if (pAHuman) { + // Create a new AHuman instead of old one, give him an item, and delete old AHuman + SceneObject* pNewObject = dynamic_cast(pPickedSceneObject->Clone()); g_SceneMan.GetScene()->RemovePlacedObject(editedSet, objectListPosition); - AHuman *pAHuman = dynamic_cast(pNewObject); - if (pAHuman) - { - pAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); + AHuman* pAHuman = dynamic_cast(pNewObject); + if (pAHuman) { + pAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); pAHuman->FlashWhite(150); } @@ -679,19 +615,14 @@ void AssemblyEditorGUI::Update() g_GUISound.PlacementThud()->Play(); toPlace = false; } - } - else - { - //No human? Look for brains robots then - SceneObject *pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); - if (pBrain) - { - if (g_SceneMan.ShortestDistance(pBrain->GetPos(), m_CursorPos,true).MagnitudeIsLessThan(20.0F)) - { - AHuman * pBrainAHuman = dynamic_cast(pBrain); - if (pBrainAHuman) - { - pBrainAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); + } else { + // No human? Look for brains robots then + SceneObject* pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); + if (pBrain) { + if (g_SceneMan.ShortestDistance(pBrain->GetPos(), m_CursorPos, true).MagnitudeIsLessThan(20.0F)) { + AHuman* pBrainAHuman = dynamic_cast(pBrain); + if (pBrainAHuman) { + pBrainAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); pBrainAHuman->FlashWhite(150); m_EditMade = true; g_GUISound.PlacementThud()->Play(); @@ -703,37 +634,32 @@ void AssemblyEditorGUI::Update() } } - BunkerAssemblyScheme *pBAS = dynamic_cast(m_pCurrentObject); - if (pBAS) - { - //Clear current scheme and assign new one + BunkerAssemblyScheme* pBAS = dynamic_cast(m_pCurrentObject); + if (pBAS) { + // Clear current scheme and assign new one delete m_pCurrentScheme; - m_pCurrentScheme = dynamic_cast(m_pCurrentObject->Clone()); + m_pCurrentScheme = dynamic_cast(m_pCurrentObject->Clone()); m_CurrentAssemblyName = pBAS->GetPresetName(); // Look through available assemblies and set the name appropriately int number = 1; - std::list assemblies; + std::list assemblies; g_PresetMan.GetAllOfGroup(assemblies, pBAS->GetPresetName(), "BunkerAssembly", -1); - for (int i = 1; i < 256; i++) - { + for (int i = 1; i < 256; i++) { number = i; char currentName[256]; std::snprintf(currentName, sizeof(currentName), "%s - %d", m_CurrentAssemblyName.c_str(), 1); - for (std::list::iterator itr = assemblies.begin(); itr != assemblies.end(); itr++) - { + for (std::list::iterator itr = assemblies.begin(); itr != assemblies.end(); itr++) { std::snprintf(currentName, sizeof(currentName), "%s - %d", m_CurrentAssemblyName.c_str(), number); - if ((*itr)->GetPresetName() == currentName) - { + if ((*itr)->GetPresetName() == currentName) { number = 0; break; } } - if (number > 0) - { + if (number > 0) { m_CurrentAssemblyName = currentName; break; } @@ -746,32 +672,28 @@ void AssemblyEditorGUI::Update() // When we're trying to place bunker assembly it replaces current Scheme with it's parent Scheme // and places all included objects - BunkerAssembly *pBA = dynamic_cast(m_pCurrentObject); - if (pBA) - { - //Clear current scheme and assign new one + BunkerAssembly* pBA = dynamic_cast(m_pCurrentObject); + if (pBA) { + // Clear current scheme and assign new one delete m_pCurrentScheme; - const Entity *pPreset = g_PresetMan.GetEntityPreset("BunkerAssemblyScheme", pBA->GetParentAssemblySchemeName(), -1); - if (pPreset) - { - m_pCurrentScheme = dynamic_cast(pPreset->Clone()); + const Entity* pPreset = g_PresetMan.GetEntityPreset("BunkerAssemblyScheme", pBA->GetParentAssemblySchemeName(), -1); + if (pPreset) { + m_pCurrentScheme = dynamic_cast(pPreset->Clone()); m_pCurrentScheme->SetPos(m_pCurrentObject->GetPos()); } - //Place objects inlcuded in bunker assembly - const std::list *objects = pBA->GetPlacedObjects(); - - for (std::list::const_iterator oItr = objects->begin(); oItr != objects->end(); ++oItr) - { - SceneObject *pSO = dynamic_cast((*oItr)->Clone()); + // Place objects inlcuded in bunker assembly + const std::list* objects = pBA->GetPlacedObjects(); + + for (std::list::const_iterator oItr = objects->begin(); oItr != objects->end(); ++oItr) { + SceneObject* pSO = dynamic_cast((*oItr)->Clone()); // Convert relative coordinates to scene coordintaes Vector pos = pBA->GetPos() + pSO->GetPos() + pBA->GetBitmapOffset(); - //Wrap over seam - if (g_SceneMan.GetScene()->WrapsX()) - { + // Wrap over seam + if (g_SceneMan.GetScene()->WrapsX()) { if (pos.m_X < 0) pos.m_X += g_SceneMan.GetScene()->GetWidth(); @@ -779,8 +701,7 @@ void AssemblyEditorGUI::Update() pos.m_X -= g_SceneMan.GetScene()->GetWidth(); } - if (g_SceneMan.GetScene()->WrapsY()) - { + if (g_SceneMan.GetScene()->WrapsY()) { if (pos.m_Y < 0) pos.m_Y += g_SceneMan.GetScene()->GetHeight(); @@ -800,275 +721,243 @@ void AssemblyEditorGUI::Update() toPlace = false; } - //Finally place an object if still necessary - if (toPlace) - { - g_SceneMan.GetScene()->AddPlacedObject(editedSet, dynamic_cast(m_pCurrentObject->Clone()), m_ObjectListOrder); + // Finally place an object if still necessary + if (toPlace) { + g_SceneMan.GetScene()->AddPlacedObject(editedSet, dynamic_cast(m_pCurrentObject->Clone()), m_ObjectListOrder); // Increment the list order so we place over last placed item if (m_ObjectListOrder >= 0) m_ObjectListOrder++; g_GUISound.PlacementThud()->Play(); m_EditMade = true; - } -// TEMP REMOVE WEHN YOU CLEAN UP THE ABOVE HARDCODED BRAIN PLACEMENT - if (m_EditorGUIMode != PICKINGOBJECT) -// TEMP REMOVE ABOVE - // Go back to previous mode - m_EditorGUIMode = m_PreviousMode; - m_ModeChanged = true; - } - - // Set the facing of AHumans based on right/left cursor movements -// TODO: Improve - Actor *pActor = dynamic_cast(m_pCurrentObject); - if (pActor && dynamic_cast(pActor) || dynamic_cast(pActor)) - pActor->SetHFlipped(m_FacingLeft); - - Deployment *pDeployment = dynamic_cast(m_pCurrentObject); + } + // TEMP REMOVE WEHN YOU CLEAN UP THE ABOVE HARDCODED BRAIN PLACEMENT + if (m_EditorGUIMode != PICKINGOBJECT) + // TEMP REMOVE ABOVE + // Go back to previous mode + m_EditorGUIMode = m_PreviousMode; + m_ModeChanged = true; + } + + // Set the facing of AHumans based on right/left cursor movements + // TODO: Improve + Actor* pActor = dynamic_cast(m_pCurrentObject); + if (pActor && dynamic_cast(pActor) || dynamic_cast(pActor)) + pActor->SetHFlipped(m_FacingLeft); + + Deployment* pDeployment = dynamic_cast(m_pCurrentObject); if (pDeployment) pDeployment->SetHFlipped(m_FacingLeft); - } - - ///////////////////////////////////////////////////////////// - // POINTING AT MODES - - else if ((m_EditorGUIMode == MOVINGOBJECT || m_EditorGUIMode == DELETINGOBJECT) && !m_PieMenu->IsEnabled()) - { - m_DrawCurrentObject = false; - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - m_CursorPos += analogInput * 4; - else if (!m_pController->GetMouseMovement().IsZero()) - m_CursorPos += m_pController->GetMouseMovement() / 2; - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= 1; - if (pressRight) - m_CursorPos.m_X += 1; - if (pressDown) - m_CursorPos.m_Y += 1; - if (pressLeft) - m_CursorPos.m_X -= 1; - } - - ///////////////////////////////// - // MOVING OBJECT MODE - - if (m_EditorGUIMode == MOVINGOBJECT) - { - if (m_ModeChanged) - { - - m_ModeChanged = false; - } - g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // Pick an object under the cursor and start moving it - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - const SceneObject *pPicked = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder); - if (pPicked) - { - // Grab the position and a copy of the the object itself before killing it from the scene - SetCurrentObject(dynamic_cast(pPicked->Clone())); - m_CursorOffset = m_CursorPos - m_pCurrentObject->GetPos(); - g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); - m_EditMade = true; - - // Go to placing mode to move it around - m_EditorGUIMode = PLACINGOBJECT; - m_PreviousMode = MOVINGOBJECT; - m_ModeChanged = true; - m_BlinkTimer.Reset(); - g_GUISound.PlacementBlip()->Play(); - g_GUISound.PlacementGravel()->Play(); - } - else - g_GUISound.UserErrorSound()->Play(); - } - } - - //////////////////////////// - // REMOVING OBJECT MODE - - else if (m_EditorGUIMode == DELETINGOBJECT) - { - if (m_ModeChanged) - { - - m_ModeChanged = false; - } - g_FrameMan.SetScreenText("Click and hold to select an object - release to DELETE it" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // When primary is held down, pick object and show which one will be nuked if released - if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) - { - m_pObjectToBlink = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos); - } - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - if (g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder)) - { - // Nuke it! - g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); - m_EditMade = true; -// TODO: Add awesome destruction sound here - } - else - g_GUISound.UserErrorSound()->Play(); - } - } - } - else if (m_EditorGUIMode == DONEEDITING) - { - // Check first that the brain is in a good spot if finishing up a base edit - if (m_FeatureSet != ONLOADEDIT) - TestBrainResidence(); -// if (m_FeatureSet != ONLOADEDIT) -// g_FrameMan.SetScreenText("DONE editing, wait for all other players to finish too...", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - } - - // Remove cursor offset if not applicable anymore - if (m_EditorGUIMode != PLACINGOBJECT) - m_CursorOffset.Reset(); - - // Keep the cursor position within the world - g_SceneMan.ForceBounds(m_CursorPos); -// TODO: make setscrolltarget with 'sloppy' target - // Scroll to the cursor's scene position - g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - // Apply the cursor position to the currently held object - if (m_pCurrentObject && m_DrawCurrentObject) - { - m_pCurrentObject->SetPos(g_SceneMan.SnapPosition(m_CursorPos - m_CursorOffset, m_GridSnapping)); - // If an actor, set it to be inactive so it doesn't scan around and reveal unseen areas - if (Actor *pCurrentActor = dynamic_cast(m_pCurrentObject)) - { - pCurrentActor->SetStatus(Actor::INACTIVE); - pCurrentActor->GetController()->SetDisabled(true); - } - m_pCurrentObject->FullUpdate(); - } -} + } + + ///////////////////////////////////////////////////////////// + // POINTING AT MODES + + else if ((m_EditorGUIMode == MOVINGOBJECT || m_EditorGUIMode == DELETINGOBJECT) && !m_PieMenu->IsEnabled()) { + m_DrawCurrentObject = false; + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) + m_CursorPos += analogInput * 4; + else if (!m_pController->GetMouseMovement().IsZero()) + m_CursorPos += m_pController->GetMouseMovement() / 2; + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= 1; + if (pressRight) + m_CursorPos.m_X += 1; + if (pressDown) + m_CursorPos.m_Y += 1; + if (pressLeft) + m_CursorPos.m_X -= 1; + } + + ///////////////////////////////// + // MOVING OBJECT MODE + if (m_EditorGUIMode == MOVINGOBJECT) { + if (m_ModeChanged) { + + m_ModeChanged = false; + } + g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // Pick an object under the cursor and start moving it + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + const SceneObject* pPicked = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder); + if (pPicked) { + // Grab the position and a copy of the the object itself before killing it from the scene + SetCurrentObject(dynamic_cast(pPicked->Clone())); + m_CursorOffset = m_CursorPos - m_pCurrentObject->GetPos(); + g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); + m_EditMade = true; + + // Go to placing mode to move it around + m_EditorGUIMode = PLACINGOBJECT; + m_PreviousMode = MOVINGOBJECT; + m_ModeChanged = true; + m_BlinkTimer.Reset(); + g_GUISound.PlacementBlip()->Play(); + g_GUISound.PlacementGravel()->Play(); + } else + g_GUISound.UserErrorSound()->Play(); + } + } + + //////////////////////////// + // REMOVING OBJECT MODE + + else if (m_EditorGUIMode == DELETINGOBJECT) { + if (m_ModeChanged) { + + m_ModeChanged = false; + } + g_FrameMan.SetScreenText("Click and hold to select an object - release to DELETE it" + selectedAssembly, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // When primary is held down, pick object and show which one will be nuked if released + if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) { + m_pObjectToBlink = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos); + } else if (m_pController->IsState(RELEASE_PRIMARY)) { + if (g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder)) { + // Nuke it! + g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); + m_EditMade = true; + // TODO: Add awesome destruction sound here + } else + g_GUISound.UserErrorSound()->Play(); + } + } + } else if (m_EditorGUIMode == DONEEDITING) { + // Check first that the brain is in a good spot if finishing up a base edit + if (m_FeatureSet != ONLOADEDIT) + TestBrainResidence(); + // if (m_FeatureSet != ONLOADEDIT) + // g_FrameMan.SetScreenText("DONE editing, wait for all other players to finish too...", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + } + + // Remove cursor offset if not applicable anymore + if (m_EditorGUIMode != PLACINGOBJECT) + m_CursorOffset.Reset(); + + // Keep the cursor position within the world + g_SceneMan.ForceBounds(m_CursorPos); + // TODO: make setscrolltarget with 'sloppy' target + // Scroll to the cursor's scene position + g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + // Apply the cursor position to the currently held object + if (m_pCurrentObject && m_DrawCurrentObject) { + m_pCurrentObject->SetPos(g_SceneMan.SnapPosition(m_CursorPos - m_CursorOffset, m_GridSnapping)); + // If an actor, set it to be inactive so it doesn't scan around and reveal unseen areas + if (Actor* pCurrentActor = dynamic_cast(m_pCurrentObject)) { + pCurrentActor->SetStatus(Actor::INACTIVE); + pCurrentActor->GetController()->SetDisabled(true); + } + m_pCurrentObject->FullUpdate(); + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the menu -void AssemblyEditorGUI::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) const -{ - // Done, so don't draw the UI - if (m_EditorGUIMode == DONEEDITING) - return; - - // The get a list of the currently edited set of placed objects in the Scene - const std::list *pSceneObjectList = 0; - if (m_FeatureSet == ONLOADEDIT) - pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); - - // Draw the set of currently edited objects already placed in the Scene - if (pSceneObjectList) - { - // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene - int i = 0; - Actor *pActor = 0; -// HeldDevice *pDevice = 0; - for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr, ++i) - { - // Draw the currently held object into the order of the list if it is to be placed inside - if (m_pCurrentObject && m_DrawCurrentObject && i == m_ObjectListOrder) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); - pActor = dynamic_cast(m_pCurrentObject); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - - // Is the placed object an actor? - pActor = dynamic_cast(*itr); -// pItem = dynamic_cast(*itr); - - // Blink trans if we are supposed to blink this one - if ((*itr) == m_pObjectToBlink) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); - } - // Drawing of already placed objects that aren't highlighted or anything - else - { +void AssemblyEditorGUI::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) const { + // Done, so don't draw the UI + if (m_EditorGUIMode == DONEEDITING) + return; + + // The get a list of the currently edited set of placed objects in the Scene + const std::list* pSceneObjectList = 0; + if (m_FeatureSet == ONLOADEDIT) + pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); + + // Draw the set of currently edited objects already placed in the Scene + if (pSceneObjectList) { + // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene + int i = 0; + Actor* pActor = 0; + // HeldDevice *pDevice = 0; + for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr, ++i) { + // Draw the currently held object into the order of the list if it is to be placed inside + if (m_pCurrentObject && m_DrawCurrentObject && i == m_ObjectListOrder) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); + pActor = dynamic_cast(m_pCurrentObject); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + + // Is the placed object an actor? + pActor = dynamic_cast(*itr); + // pItem = dynamic_cast(*itr); + + // Blink trans if we are supposed to blink this one + if ((*itr) == m_pObjectToBlink) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); + } + // Drawing of already placed objects that aren't highlighted or anything + else { (*itr)->Draw(pTargetBitmap, targetPos); - } - - // Draw basic HUD if an actor - don't do this for blueprints.. it is confusing - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - } - - // Draw picking object crosshairs and not the selected object - if (!m_DrawCurrentObject) - { - Vector center = m_CursorPos - targetPos; - putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); - } - // If the held object will be placed at the end of the list, draw it last to the scene, transperent blinking - else if (m_pCurrentObject && (m_ObjectListOrder < 0 || (pSceneObjectList && m_ObjectListOrder == pSceneObjectList->size()))) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); - Actor *pActor = dynamic_cast(m_pCurrentObject); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } + } + + // Draw basic HUD if an actor - don't do this for blueprints.. it is confusing + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + } + + // Draw picking object crosshairs and not the selected object + if (!m_DrawCurrentObject) { + Vector center = m_CursorPos - targetPos; + putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); + } + // If the held object will be placed at the end of the list, draw it last to the scene, transperent blinking + else if (m_pCurrentObject && (m_ObjectListOrder < 0 || (pSceneObjectList && m_ObjectListOrder == pSceneObjectList->size()))) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); + Actor* pActor = dynamic_cast(m_pCurrentObject); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } if (m_pCurrentScheme) m_pCurrentScheme->Draw(pTargetBitmap, targetPos); - m_pPicker->Draw(pTargetBitmap); + m_pPicker->Draw(pTargetBitmap); - // Draw the pie menu + // Draw the pie menu m_PieMenu->Draw(pTargetBitmap, targetPos); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateBrainPath ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the brain path to the current resident brain, if any. If // there's none, the path is cleared. -bool AssemblyEditorGUI::UpdateBrainPath() -{ - // First see if we have a brain in hand - if (m_pCurrentObject && m_pCurrentObject->IsInGroup("Brains")) - { - m_BrainSkyPathCost = g_SceneMan.GetScene()->CalculatePath(m_CursorPos, Vector(m_CursorPos.m_X, 0), m_BrainSkyPath, c_PathFindingDefaultDigStrength, static_cast(m_pController->GetTeam())); - return true; - } - - // If not, then do we have a resident? - SceneObject *pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); - if (pBrain) - m_BrainSkyPathCost = g_SceneMan.GetScene()->CalculatePath(pBrain->GetPos(), Vector(pBrain->GetPos().m_X, 0), m_BrainSkyPath, c_PathFindingDefaultDigStrength, static_cast(m_pController->GetTeam())); - else - { - m_BrainSkyPath.clear(); - m_BrainSkyPathCost = 0; - return false; - } - return true; -} \ No newline at end of file +bool AssemblyEditorGUI::UpdateBrainPath() { + // First see if we have a brain in hand + if (m_pCurrentObject && m_pCurrentObject->IsInGroup("Brains")) { + m_BrainSkyPathCost = g_SceneMan.GetScene()->CalculatePath(m_CursorPos, Vector(m_CursorPos.m_X, 0), m_BrainSkyPath, c_PathFindingDefaultDigStrength, static_cast(m_pController->GetTeam())); + return true; + } + + // If not, then do we have a resident? + SceneObject* pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); + if (pBrain) + m_BrainSkyPathCost = g_SceneMan.GetScene()->CalculatePath(pBrain->GetPos(), Vector(pBrain->GetPos().m_X, 0), m_BrainSkyPath, c_PathFindingDefaultDigStrength, static_cast(m_pController->GetTeam())); + else { + m_BrainSkyPath.clear(); + m_BrainSkyPathCost = 0; + return false; + } + return true; +} diff --git a/Source/Menus/AssemblyEditorGUI.h b/Source/Menus/AssemblyEditorGUI.h index 3631bc331..934e6d9c8 100644 --- a/Source/Menus/AssemblyEditorGUI.h +++ b/Source/Menus/AssemblyEditorGUI.h @@ -10,7 +10,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -24,429 +23,389 @@ struct BITMAP; - -namespace RTE -{ - -class SceneObject; -class ObjectPickerGUI; -class PieMenu; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: AssemblyEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A full menu system that represents the scene editing GUI for Cortex Command -// Parent(s): None. -// Class history: 7/08/2007 AssemblyEditorGUI Created. - -class AssemblyEditorGUI { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - enum FeatureSets - { - ONLOADEDIT = 0 - }; - - // Different modes of this editor - enum EditorGUIMode - { - INACTIVE = 0, - PICKINGOBJECT, - ADDINGOBJECT, - PLACINGOBJECT, - MOVINGOBJECT, - DELETINGOBJECT, - DONEEDITING, - EDITORGUIMODECOUNT - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: AssemblyEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a AssemblyEditorGUI object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - AssemblyEditorGUI() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~AssemblyEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a AssemblyEditorGUI object before deletion -// from system memory. -// Arguments: None. - - ~AssemblyEditorGUI() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the AssemblyEditorGUI object ready for use. -// Arguments: A poitner to a Controller which will control this Menu. Ownership is -// NOT TRANSFERRED! -// Whether the editor should have all the features enabled, like load/save -// and undo capabilities. -// Which module space that this eidtor will be able to pick objects from. -// -1 means all modules. -// Which Tech module that will be presented as the native one to the player. -// The multiplier of all foreign techs' costs. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(Controller *pController, FeatureSets featureSet = ONLOADEDIT, int whichModuleSpace = -1, int nativeTechModule = 0, float foreignCostMult = 1.0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire AssemblyEditorGUI, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the AssemblyEditorGUI object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the controller used by this. The ownership of the controller is -// NOT transferred! -// Arguments: The new controller for this menu. Ownership is NOT transferred -// Return value: None. - - void SetController(Controller *pController); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPosOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where on the screen that this GUI is being drawn to. If upper -// left corner, then 0, 0. This will affect the way the mouse is positioned -// etc. -// Arguments: The new screen position of this entire GUI. - - void SetPosOnScreen(int newPosX, int newPosY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCursorPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the absolute scene coordinates of the cursor of this Editor. -// Arguments: The new cursor position in absolute scene units. -// Return value: None. - - void SetCursorPos(const Vector &newCursorPos) { m_CursorPos = newCursorPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCurrentObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the new Object to be held at the cursor of this Editor. Ownership -// IS transferred! -// Arguments: The new Object to be held by the cursor. Ownership IS transferred! -// Return value: Whether the cursor holds a valid object after setting. - - bool SetCurrentObject(SceneObject *pNewObject); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActivatedPieSlice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets any Pie menu slice command activated last update. -// Arguments: None. -// Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. - - PieSlice::SliceType GetActivatedPieSlice() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the currently held Object in the cursor of this Editor. Ownership -// IS NOT transferred! -// Arguments: None. -// Return value: The currently held object, if any. OWNERSHIP IS NOT TRANSFERRED! - - const SceneObject * GetCurrentObject() const { return m_pCurrentObject; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which DataModule space to be picking objects from. If -1, then -// let the player pick from all loaded modules. -// Arguments: The ID of the module to let the player pick objects from. All official -// modules' objects will alwayws be presented, in addition to the one -// passed in here. -// Return value: None. - - void SetModuleSpace(int moduleSpaceID = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetNativeTechModule -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which DataModule ID should be treated as the native tech of the -// user of this menu. -// Arguments: The module ID to set as the native one. 0 means everything is native. -// Return value: None. - - void SetNativeTechModule(int whichModule); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetForeignCostMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the multiplier of the cost of any foreign Tech items. -// Arguments: The scalar multiplier of the costs of foreign Tech items. -// Return value: None. - - void SetForeignCostMultiplier(float newMultiplier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EditMade -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether an edit on the scene was made in the last Update. -// Arguments: None. -// Return value: Whether any edit was made. - - bool EditMade() const { return m_EditMade; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TestBrainResidence -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether the resident brain is currently placed into a valid -// location in this scene, based on whether there is a clear path to the -// sky above it. This forces the editor into place brain mode with the -// current resident brain if the current placement is no bueno. It also -// removes the faulty brain from residence in the scene! -// Arguments: Whether it's OK if we dont' have a brain right now - ie don't force -// into isntallation mode if no brain was found. -// Return value: Whether a resident brain was found, AND found in a valid location! - - bool TestBrainResidence(bool noBrainIsOK = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Menu each frame -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the editor -// Arguments: The bitmap to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentAssemblyScheme -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a pointer to currently selected assembly scheme -// Arguments: None. -// Return value: Pointer to current assembly scheme. - - BunkerAssemblyScheme * GetCurrentAssemblyScheme() { return m_pCurrentScheme; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentAssemblyName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the name of currently edited assembly -// Arguments: None. -// Return value: Name of currently edited assembly. - - std::string GetCurrentAssemblyName() { return m_CurrentAssemblyName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCurrentAssemblyScheme -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets new name of currently edited assembly -// Arguments: New name for assembly. -// Return value: None. - - void SetCurrentAssemblyName(std::string newName) { m_CurrentAssemblyName = newName; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePieMenu -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the PieMenu config based ont eh current editor state. -// Arguments: None. -// Return value: None. - - void UpdatePieMenu(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateBrainPath -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the brain path to the current brain in cursor or resident -// in the scene, if any. If there's none, the path is cleared. -// Arguments: None. -// Return value: Whether a resident brain was found in the scene. - - bool UpdateBrainPath(); - - - enum BlinkMode - { - NOBLINK = 0, - OBJECTBLINKON, - OBJECTBLINKOFF, - BLINKMODECOUNT - }; - - // Controller which conrols this menu. Not owned - Controller *m_pController; - // Full featured or the in-game version, or the base building mode - int m_FeatureSet; - // Whether an edit was made to the Scene in the last Update - bool m_EditMade; - // The current mode of the whole GUI. See EditorGUIMode enum. - EditorGUIMode m_EditorGUIMode; - // The previous mode of the whole GUI, to go back to when the current mode is done in some cases - EditorGUIMode m_PreviousMode; - // Whether the editor mode has changed - bool m_ModeChanged; - // Notification blink timer - Timer m_BlinkTimer; - // What we're blinking - int m_BlinkMode; - // Measures the time to when to start repeating inputs when they're held down - Timer m_RepeatStartTimer; - // Measures the interval between input repeats - Timer m_RepeatTimer; - // Measures the interval between graphically revealing objects - Timer m_RevealTimer; - // The index which keeps track of the point in the build queue that blueprint objects go from being ghosted to revealed - int m_RevealIndex; - // Whether we need a clear path to orbit to place brain - bool m_RequireClearPathToOrbit; - - std::unique_ptr m_PieMenu; //!< The PieMenu for this AssemblyEditorGUI. - // The object picker - ObjectPickerGUI *m_pPicker; - // The ID of the DataModule that contains the native Tech of the Player using this menu - int m_NativeTechModule; - // The multiplier of costs of any foreign tech items - float m_ForeignCostMult; - // Grid snapping enabled - bool m_GridSnapping; - // Current cursor position, in absolute scene coordinates - Vector m_CursorPos; - // The offset from the current object's position to the cursor, if any - Vector m_CursorOffset; - // Cursor position in free air, or over something - bool m_CursorInAir; - // SceneObject facing left or not when placing - bool m_FacingLeft; - // The team of the placed SceneObject:s - int m_PlaceTeam; - // Currently held object. This is what is attached to the cursor and will be placed when the fire button is pressed - // OWNED by this. - SceneObject *m_pCurrentObject; - // Where in the scene's list order the next object should be placed. If -1, then place at the end of the list. - int m_ObjectListOrder; - // Whether to draw the currently held object - bool m_DrawCurrentObject; - // Currently placed scene object to make blink when drawing it. NOT OWNED. - const SceneObject *m_pObjectToBlink; - // Path found between brain pos and the sky to make sure fair brain placement - std::list m_BrainSkyPath; - // The cost of the path from the current position of the brain to the sky - float m_BrainSkyPathCost; - // Valid brain path line dots - static BITMAP *s_pValidPathDot; - // Invalid brain path line dots - static BITMAP *s_pInvalidPathDot; - - //Edited scheme type - BunkerAssemblyScheme *m_pCurrentScheme; - //Edited assembly name - std::string m_CurrentAssemblyName; - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this AssemblyEditorGUI, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - AssemblyEditorGUI(const AssemblyEditorGUI &reference) = delete; - AssemblyEditorGUI & operator=(const AssemblyEditorGUI &rhs) = delete; - -}; +namespace RTE { + + class SceneObject; + class ObjectPickerGUI; + class PieMenu; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: AssemblyEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A full menu system that represents the scene editing GUI for Cortex Command + // Parent(s): None. + // Class history: 7/08/2007 AssemblyEditorGUI Created. + + class AssemblyEditorGUI { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + enum FeatureSets { + ONLOADEDIT = 0 + }; + + // Different modes of this editor + enum EditorGUIMode { + INACTIVE = 0, + PICKINGOBJECT, + ADDINGOBJECT, + PLACINGOBJECT, + MOVINGOBJECT, + DELETINGOBJECT, + DONEEDITING, + EDITORGUIMODECOUNT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: AssemblyEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a AssemblyEditorGUI object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + AssemblyEditorGUI() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~AssemblyEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a AssemblyEditorGUI object before deletion + // from system memory. + // Arguments: None. + + ~AssemblyEditorGUI() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the AssemblyEditorGUI object ready for use. + // Arguments: A poitner to a Controller which will control this Menu. Ownership is + // NOT TRANSFERRED! + // Whether the editor should have all the features enabled, like load/save + // and undo capabilities. + // Which module space that this eidtor will be able to pick objects from. + // -1 means all modules. + // Which Tech module that will be presented as the native one to the player. + // The multiplier of all foreign techs' costs. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(Controller* pController, FeatureSets featureSet = ONLOADEDIT, int whichModuleSpace = -1, int nativeTechModule = 0, float foreignCostMult = 1.0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire AssemblyEditorGUI, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the AssemblyEditorGUI object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the controller used by this. The ownership of the controller is + // NOT transferred! + // Arguments: The new controller for this menu. Ownership is NOT transferred + // Return value: None. + + void SetController(Controller* pController); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPosOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where on the screen that this GUI is being drawn to. If upper + // left corner, then 0, 0. This will affect the way the mouse is positioned + // etc. + // Arguments: The new screen position of this entire GUI. + + void SetPosOnScreen(int newPosX, int newPosY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCursorPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the absolute scene coordinates of the cursor of this Editor. + // Arguments: The new cursor position in absolute scene units. + // Return value: None. + + void SetCursorPos(const Vector& newCursorPos) { m_CursorPos = newCursorPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCurrentObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the new Object to be held at the cursor of this Editor. Ownership + // IS transferred! + // Arguments: The new Object to be held by the cursor. Ownership IS transferred! + // Return value: Whether the cursor holds a valid object after setting. + + bool SetCurrentObject(SceneObject* pNewObject); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActivatedPieSlice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets any Pie menu slice command activated last update. + // Arguments: None. + // Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. + + PieSlice::SliceType GetActivatedPieSlice() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the currently held Object in the cursor of this Editor. Ownership + // IS NOT transferred! + // Arguments: None. + // Return value: The currently held object, if any. OWNERSHIP IS NOT TRANSFERRED! + + const SceneObject* GetCurrentObject() const { return m_pCurrentObject; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which DataModule space to be picking objects from. If -1, then + // let the player pick from all loaded modules. + // Arguments: The ID of the module to let the player pick objects from. All official + // modules' objects will alwayws be presented, in addition to the one + // passed in here. + // Return value: None. + + void SetModuleSpace(int moduleSpaceID = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetNativeTechModule + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which DataModule ID should be treated as the native tech of the + // user of this menu. + // Arguments: The module ID to set as the native one. 0 means everything is native. + // Return value: None. + + void SetNativeTechModule(int whichModule); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetForeignCostMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the multiplier of the cost of any foreign Tech items. + // Arguments: The scalar multiplier of the costs of foreign Tech items. + // Return value: None. + + void SetForeignCostMultiplier(float newMultiplier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EditMade + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether an edit on the scene was made in the last Update. + // Arguments: None. + // Return value: Whether any edit was made. + + bool EditMade() const { return m_EditMade; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TestBrainResidence + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether the resident brain is currently placed into a valid + // location in this scene, based on whether there is a clear path to the + // sky above it. This forces the editor into place brain mode with the + // current resident brain if the current placement is no bueno. It also + // removes the faulty brain from residence in the scene! + // Arguments: Whether it's OK if we dont' have a brain right now - ie don't force + // into isntallation mode if no brain was found. + // Return value: Whether a resident brain was found, AND found in a valid location! + + bool TestBrainResidence(bool noBrainIsOK = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Menu each frame + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the editor + // Arguments: The bitmap to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentAssemblyScheme + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a pointer to currently selected assembly scheme + // Arguments: None. + // Return value: Pointer to current assembly scheme. + + BunkerAssemblyScheme* GetCurrentAssemblyScheme() { return m_pCurrentScheme; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentAssemblyName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the name of currently edited assembly + // Arguments: None. + // Return value: Name of currently edited assembly. + + std::string GetCurrentAssemblyName() { return m_CurrentAssemblyName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCurrentAssemblyScheme + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets new name of currently edited assembly + // Arguments: New name for assembly. + // Return value: None. + + void SetCurrentAssemblyName(std::string newName) { m_CurrentAssemblyName = newName; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePieMenu + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the PieMenu config based ont eh current editor state. + // Arguments: None. + // Return value: None. + + void UpdatePieMenu(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateBrainPath + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the brain path to the current brain in cursor or resident + // in the scene, if any. If there's none, the path is cleared. + // Arguments: None. + // Return value: Whether a resident brain was found in the scene. + + bool UpdateBrainPath(); + + enum BlinkMode { + NOBLINK = 0, + OBJECTBLINKON, + OBJECTBLINKOFF, + BLINKMODECOUNT + }; + + // Controller which conrols this menu. Not owned + Controller* m_pController; + // Full featured or the in-game version, or the base building mode + int m_FeatureSet; + // Whether an edit was made to the Scene in the last Update + bool m_EditMade; + // The current mode of the whole GUI. See EditorGUIMode enum. + EditorGUIMode m_EditorGUIMode; + // The previous mode of the whole GUI, to go back to when the current mode is done in some cases + EditorGUIMode m_PreviousMode; + // Whether the editor mode has changed + bool m_ModeChanged; + // Notification blink timer + Timer m_BlinkTimer; + // What we're blinking + int m_BlinkMode; + // Measures the time to when to start repeating inputs when they're held down + Timer m_RepeatStartTimer; + // Measures the interval between input repeats + Timer m_RepeatTimer; + // Measures the interval between graphically revealing objects + Timer m_RevealTimer; + // The index which keeps track of the point in the build queue that blueprint objects go from being ghosted to revealed + int m_RevealIndex; + // Whether we need a clear path to orbit to place brain + bool m_RequireClearPathToOrbit; + + std::unique_ptr m_PieMenu; //!< The PieMenu for this AssemblyEditorGUI. + // The object picker + ObjectPickerGUI* m_pPicker; + // The ID of the DataModule that contains the native Tech of the Player using this menu + int m_NativeTechModule; + // The multiplier of costs of any foreign tech items + float m_ForeignCostMult; + // Grid snapping enabled + bool m_GridSnapping; + // Current cursor position, in absolute scene coordinates + Vector m_CursorPos; + // The offset from the current object's position to the cursor, if any + Vector m_CursorOffset; + // Cursor position in free air, or over something + bool m_CursorInAir; + // SceneObject facing left or not when placing + bool m_FacingLeft; + // The team of the placed SceneObject:s + int m_PlaceTeam; + // Currently held object. This is what is attached to the cursor and will be placed when the fire button is pressed + // OWNED by this. + SceneObject* m_pCurrentObject; + // Where in the scene's list order the next object should be placed. If -1, then place at the end of the list. + int m_ObjectListOrder; + // Whether to draw the currently held object + bool m_DrawCurrentObject; + // Currently placed scene object to make blink when drawing it. NOT OWNED. + const SceneObject* m_pObjectToBlink; + // Path found between brain pos and the sky to make sure fair brain placement + std::list m_BrainSkyPath; + // The cost of the path from the current position of the brain to the sky + float m_BrainSkyPathCost; + // Valid brain path line dots + static BITMAP* s_pValidPathDot; + // Invalid brain path line dots + static BITMAP* s_pInvalidPathDot; + + // Edited scheme type + BunkerAssemblyScheme* m_pCurrentScheme; + // Edited assembly name + std::string m_CurrentAssemblyName; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this AssemblyEditorGUI, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + AssemblyEditorGUI(const AssemblyEditorGUI& reference) = delete; + AssemblyEditorGUI& operator=(const AssemblyEditorGUI& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Menus/BuyMenuGUI.cpp b/Source/Menus/BuyMenuGUI.cpp index 2e0991202..9a8f6a925 100644 --- a/Source/Menus/BuyMenuGUI.cpp +++ b/Source/Menus/BuyMenuGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -46,7 +45,7 @@ using namespace RTE; -BITMAP *RTE::BuyMenuGUI::s_pCursor = 0; +BITMAP* RTE::BuyMenuGUI::s_pCursor = 0; const std::string BuyMenuGUI::c_DefaultBannerImagePath = "Base.rte/GUIs/BuyMenu/BuyMenuBanner.png"; const std::string BuyMenuGUI::c_DefaultLogoImagePath = "Base.rte/GUIs/BuyMenu/BuyMenuLogo.png"; @@ -57,46 +56,44 @@ const std::string BuyMenuGUI::c_DefaultLogoImagePath = "Base.rte/GUIs/BuyMenu/Bu // Description: Clears all the member variables of this BuyMenuGUI, effectively // resetting the members of this abstraction level only. -void BuyMenuGUI::Clear() -{ - m_pController = 0; - m_pGUIScreen = 0; - m_pGUIInput = 0; - m_pGUIController = 0; - m_MenuEnabled = DISABLED; - m_MenuFocus = OK; - m_FocusChange = false; - m_MenuCategory = CRAFT; - m_MenuSpeed = 8.0; - m_ListItemIndex = 0; - m_DraggedItemIndex = -1; - m_IsDragging = false; - m_LastHoveredMouseIndex = 0; - m_BlinkTimer.Reset(); - m_BlinkMode = NOBLINK; - m_MenuTimer.Reset(); - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - m_pParentBox = 0; - m_pPopupBox = 0; - m_pPopupText = 0; +void BuyMenuGUI::Clear() { + m_pController = 0; + m_pGUIScreen = 0; + m_pGUIInput = 0; + m_pGUIController = 0; + m_MenuEnabled = DISABLED; + m_MenuFocus = OK; + m_FocusChange = false; + m_MenuCategory = CRAFT; + m_MenuSpeed = 8.0; + m_ListItemIndex = 0; + m_DraggedItemIndex = -1; + m_IsDragging = false; + m_LastHoveredMouseIndex = 0; + m_BlinkTimer.Reset(); + m_BlinkMode = NOBLINK; + m_MenuTimer.Reset(); + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + m_pParentBox = 0; + m_pPopupBox = 0; + m_pPopupText = 0; m_Banner = nullptr; - m_Logo = nullptr; - for (int i = 0; i < CATEGORYCOUNT; ++i) - { - m_pCategoryTabs[i] = 0; - m_CategoryItemIndex[i] = 0; - } - m_MetaPlayer = Players::NoPlayer; - m_NativeTechModule = 0; - m_ForeignCostMult = 4.0; - int moduleCount = g_PresetMan.GetTotalModuleCount(); - m_aExpandedModules = new bool[moduleCount]; - for (int i = 0; i < moduleCount; ++i) - m_aExpandedModules[i] = i == 0 ? true : false; - m_pShopList = 0; - m_pCartList = 0; - m_pCraftBox = 0; + m_Logo = nullptr; + for (int i = 0; i < CATEGORYCOUNT; ++i) { + m_pCategoryTabs[i] = 0; + m_CategoryItemIndex[i] = 0; + } + m_MetaPlayer = Players::NoPlayer; + m_NativeTechModule = 0; + m_ForeignCostMult = 4.0; + int moduleCount = g_PresetMan.GetTotalModuleCount(); + m_aExpandedModules = new bool[moduleCount]; + for (int i = 0; i < moduleCount; ++i) + m_aExpandedModules[i] = i == 0 ? true : false; + m_pShopList = 0; + m_pCartList = 0; + m_pCraftBox = 0; m_pCraftCollectionBox = 0; m_pCraftNameLabel = 0; @@ -106,15 +103,15 @@ void BuyMenuGUI::Clear() m_pCraftMassCaptionLabel = 0; m_pCraftMassLabel = 0; - m_pSelectedCraft = 0; + m_pSelectedCraft = 0; m_DeliveryWidth = 0; - m_pCostLabel = 0; - m_pBuyButton = 0; + m_pCostLabel = 0; + m_pBuyButton = 0; m_ClearOrderButton = nullptr; - m_pSaveButton = 0; - m_pClearButton = 0; - m_Loadouts.clear(); - m_PurchaseMade = false; + m_pSaveButton = 0; + m_pClearButton = 0; + m_Loadouts.clear(); + m_PurchaseMade = false; m_EnforceMaxPassengersConstraint = true; m_EnforceMaxMassConstraint = true; @@ -124,120 +121,112 @@ void BuyMenuGUI::Clear() m_AlwaysAllowedItems.clear(); m_OwnedItems.clear(); - m_SelectingEquipment = false; - m_LastVisitedEquipmentTab = GUNS; - m_LastVisitedMainTab = BODIES; - m_LastEquipmentScrollPosition = -1; - m_LastMainScrollPosition = -1; - m_FirstMainTab = CRAFT; - m_LastMainTab = SETS; - m_FirstEquipmentTab = TOOLS; - m_LastEquipmentTab = SHIELDS; + m_SelectingEquipment = false; + m_LastVisitedEquipmentTab = GUNS; + m_LastVisitedMainTab = BODIES; + m_LastEquipmentScrollPosition = -1; + m_LastMainScrollPosition = -1; + m_FirstMainTab = CRAFT; + m_LastMainTab = SETS; + m_FirstEquipmentTab = TOOLS; + m_LastEquipmentTab = SHIELDS; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the BuyMenuGUI object ready for use. -int BuyMenuGUI::Create(Controller *pController) -{ - RTEAssert(pController, "No controller sent to BuyMenyGUI on creation!"); - m_pController = pController; - - if (!m_pGUIScreen) - m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer8()); - if (!m_pGUIInput) - m_pGUIInput = new GUIInputWrapper(pController->GetPlayer()); - if (!m_pGUIController) - m_pGUIController = new GUIControlManager(); +int BuyMenuGUI::Create(Controller* pController) { + RTEAssert(pController, "No controller sent to BuyMenyGUI on creation!"); + m_pController = pController; + + if (!m_pGUIScreen) + m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer8()); + if (!m_pGUIInput) + m_pGUIInput = new GUIInputWrapper(pController->GetPlayer()); + if (!m_pGUIController) + m_pGUIController = new GUIControlManager(); if (!m_pGUIController->Create(m_pGUIScreen, m_pGUIInput, "Base.rte/GUIs/Skins", "DefaultSkin.ini")) { RTEAbort("Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/DefaultSkin.ini"); } - m_pGUIController->Load("Base.rte/GUIs/BuyMenuGUI.ini"); - m_pGUIController->EnableMouse(pController->IsMouseControlled()); + m_pGUIController->Load("Base.rte/GUIs/BuyMenuGUI.ini"); + m_pGUIController->EnableMouse(pController->IsMouseControlled()); - if (!s_pCursor) - { - ContentFile cursorFile("Base.rte/GUIs/Skins/Cursor.png"); - s_pCursor = cursorFile.GetAsBitmap(); - } - - // Stretch the invisible root box to fill the screen - if (g_FrameMan.IsInMultiplayerMode()) - { - dynamic_cast(m_pGUIController->GetControl("base"))->SetSize(g_FrameMan.GetPlayerFrameBufferWidth(pController->GetPlayer()), g_FrameMan.GetPlayerFrameBufferHeight(pController->GetPlayer())); + if (!s_pCursor) { + ContentFile cursorFile("Base.rte/GUIs/Skins/Cursor.png"); + s_pCursor = cursorFile.GetAsBitmap(); } - else - { - dynamic_cast(m_pGUIController->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + + // Stretch the invisible root box to fill the screen + if (g_FrameMan.IsInMultiplayerMode()) { + dynamic_cast(m_pGUIController->GetControl("base"))->SetSize(g_FrameMan.GetPlayerFrameBufferWidth(pController->GetPlayer()), g_FrameMan.GetPlayerFrameBufferHeight(pController->GetPlayer())); + } else { + dynamic_cast(m_pGUIController->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); } - // Make sure we have convenient points to teh containing GUI colleciton boxes that we will manipulate the positions of + // Make sure we have convenient points to teh containing GUI colleciton boxes that we will manipulate the positions of if (!m_pParentBox) { - m_pParentBox = dynamic_cast(m_pGUIController->GetControl("BuyGUIBox")); + m_pParentBox = dynamic_cast(m_pGUIController->GetControl("BuyGUIBox")); m_pParentBox->SetDrawBackground(true); m_pParentBox->SetDrawType(GUICollectionBox::Color); - m_Banner = dynamic_cast(m_pGUIController->GetControl("CatalogHeader")); + m_Banner = dynamic_cast(m_pGUIController->GetControl("CatalogHeader")); SetBannerImage(c_DefaultBannerImagePath); - m_Logo = dynamic_cast(m_pGUIController->GetControl("CatalogLogo")); + m_Logo = dynamic_cast(m_pGUIController->GetControl("CatalogLogo")); SetLogoImage(c_DefaultLogoImagePath); } - m_pParentBox->SetPositionAbs(-m_pParentBox->GetWidth(), 0); - m_pParentBox->SetEnabled(false); - m_pParentBox->SetVisible(false); - - if (!m_pPopupBox) - { - m_pPopupBox = dynamic_cast(m_pGUIController->GetControl("BuyGUIPopup")); - m_pPopupText = dynamic_cast(m_pGUIController->GetControl("PopupText")); - - m_pPopupBox->SetDrawType(GUICollectionBox::Panel); - m_pPopupBox->SetDrawBackground(true); - // Never enable the popup, because it steals focus and cuases other windows to think teh cursor left them - m_pPopupBox->SetEnabled(false); - m_pPopupBox->SetVisible(false); - // Set the font - m_pPopupText->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); - } + m_pParentBox->SetPositionAbs(-m_pParentBox->GetWidth(), 0); + m_pParentBox->SetEnabled(false); + m_pParentBox->SetVisible(false); + + if (!m_pPopupBox) { + m_pPopupBox = dynamic_cast(m_pGUIController->GetControl("BuyGUIPopup")); + m_pPopupText = dynamic_cast(m_pGUIController->GetControl("PopupText")); + + m_pPopupBox->SetDrawType(GUICollectionBox::Panel); + m_pPopupBox->SetDrawBackground(true); + // Never enable the popup, because it steals focus and cuases other windows to think teh cursor left them + m_pPopupBox->SetEnabled(false); + m_pPopupBox->SetVisible(false); + // Set the font + m_pPopupText->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); + } - m_pCategoryTabs[CRAFT] = dynamic_cast(m_pGUIController->GetControl("CraftTab")); - m_pCategoryTabs[BODIES] = dynamic_cast(m_pGUIController->GetControl("BodiesTab")); - m_pCategoryTabs[MECHA] = dynamic_cast(m_pGUIController->GetControl("MechaTab")); - m_pCategoryTabs[TOOLS] = dynamic_cast(m_pGUIController->GetControl("ToolsTab")); - m_pCategoryTabs[GUNS] = dynamic_cast(m_pGUIController->GetControl("GunsTab")); - m_pCategoryTabs[BOMBS] = dynamic_cast(m_pGUIController->GetControl("BombsTab")); - m_pCategoryTabs[SHIELDS] = dynamic_cast(m_pGUIController->GetControl("ShieldsTab")); - m_pCategoryTabs[SETS] = dynamic_cast(m_pGUIController->GetControl("SetsTab")); - RefreshTabDisabledStates(); - - m_pShopList = dynamic_cast(m_pGUIController->GetControl("CatalogLB")); - m_pCartList = dynamic_cast(m_pGUIController->GetControl("OrderLB")); - m_pCraftLabel = dynamic_cast(m_pGUIController->GetControl("CraftLabel")); - m_pCraftBox = dynamic_cast(m_pGUIController->GetControl("CraftTB")); - - m_pCraftCollectionBox = dynamic_cast(m_pGUIController->GetControl("CraftCollection")); - m_pCraftNameLabel = dynamic_cast(m_pGUIController->GetControl("CraftNameLabel")); - m_pCraftPriceLabel = dynamic_cast(m_pGUIController->GetControl("CraftPriceLabel")); - m_pCraftPassengersCaptionLabel = dynamic_cast(m_pGUIController->GetControl("CraftPassengersCaptionLabel")); - m_pCraftPassengersLabel = dynamic_cast(m_pGUIController->GetControl("CraftPassengersLabel")); - m_pCraftMassCaptionLabel = dynamic_cast(m_pGUIController->GetControl("CraftMassCaptionLabel")); - m_pCraftMassLabel = dynamic_cast(m_pGUIController->GetControl("CraftMassLabel")); - - m_pCostLabel = dynamic_cast(m_pGUIController->GetControl("TotalLabel")); - m_pBuyButton = dynamic_cast(m_pGUIController->GetControl("BuyButton")); - m_ClearOrderButton = dynamic_cast(m_pGUIController->GetControl("OrderClearButton")); - m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveButton")); - m_pClearButton = dynamic_cast(m_pGUIController->GetControl("ClearButton")); - m_pSaveButton->SetVisible(false); - m_pClearButton->SetVisible(false); + m_pCategoryTabs[CRAFT] = dynamic_cast(m_pGUIController->GetControl("CraftTab")); + m_pCategoryTabs[BODIES] = dynamic_cast(m_pGUIController->GetControl("BodiesTab")); + m_pCategoryTabs[MECHA] = dynamic_cast(m_pGUIController->GetControl("MechaTab")); + m_pCategoryTabs[TOOLS] = dynamic_cast(m_pGUIController->GetControl("ToolsTab")); + m_pCategoryTabs[GUNS] = dynamic_cast(m_pGUIController->GetControl("GunsTab")); + m_pCategoryTabs[BOMBS] = dynamic_cast(m_pGUIController->GetControl("BombsTab")); + m_pCategoryTabs[SHIELDS] = dynamic_cast(m_pGUIController->GetControl("ShieldsTab")); + m_pCategoryTabs[SETS] = dynamic_cast(m_pGUIController->GetControl("SetsTab")); + RefreshTabDisabledStates(); + + m_pShopList = dynamic_cast(m_pGUIController->GetControl("CatalogLB")); + m_pCartList = dynamic_cast(m_pGUIController->GetControl("OrderLB")); + m_pCraftLabel = dynamic_cast(m_pGUIController->GetControl("CraftLabel")); + m_pCraftBox = dynamic_cast(m_pGUIController->GetControl("CraftTB")); + + m_pCraftCollectionBox = dynamic_cast(m_pGUIController->GetControl("CraftCollection")); + m_pCraftNameLabel = dynamic_cast(m_pGUIController->GetControl("CraftNameLabel")); + m_pCraftPriceLabel = dynamic_cast(m_pGUIController->GetControl("CraftPriceLabel")); + m_pCraftPassengersCaptionLabel = dynamic_cast(m_pGUIController->GetControl("CraftPassengersCaptionLabel")); + m_pCraftPassengersLabel = dynamic_cast(m_pGUIController->GetControl("CraftPassengersLabel")); + m_pCraftMassCaptionLabel = dynamic_cast(m_pGUIController->GetControl("CraftMassCaptionLabel")); + m_pCraftMassLabel = dynamic_cast(m_pGUIController->GetControl("CraftMassLabel")); + + m_pCostLabel = dynamic_cast(m_pGUIController->GetControl("TotalLabel")); + m_pBuyButton = dynamic_cast(m_pGUIController->GetControl("BuyButton")); + m_ClearOrderButton = dynamic_cast(m_pGUIController->GetControl("OrderClearButton")); + m_pSaveButton = dynamic_cast(m_pGUIController->GetControl("SaveButton")); + m_pClearButton = dynamic_cast(m_pGUIController->GetControl("ClearButton")); + m_pSaveButton->SetVisible(false); + m_pClearButton->SetVisible(false); // Stretch buy menu if in multiplayer mode - if (g_FrameMan.IsInMultiplayerMode()) - { + if (g_FrameMan.IsInMultiplayerMode()) { int stretchAmount = g_FrameMan.GetPlayerFrameBufferHeight(pController->GetPlayer()) / 2; m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); @@ -250,14 +239,11 @@ int BuyMenuGUI::Create(Controller *pController) m_pCostLabel->SetPositionAbs(m_pCostLabel->GetXPos(), m_pCostLabel->GetYPos() + stretchAmount); m_pBuyButton->SetPositionAbs(m_pBuyButton->GetXPos(), m_pBuyButton->GetYPos() + stretchAmount); - } - else - { + } else { // If we're not split screen horizontally, then stretch out the layout for all the relevant controls int stretchAmount = g_WindowMan.GetResY() / 2; - if (!g_FrameMan.GetHSplit()) - { + if (!g_FrameMan.GetHSplit()) { m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); m_pShopList->SetSize(m_pShopList->GetWidth(), m_pShopList->GetHeight() + stretchAmount); m_pCartList->SetSize(m_pCartList->GetWidth(), m_pCartList->GetHeight() + stretchAmount); @@ -271,59 +257,57 @@ int BuyMenuGUI::Create(Controller *pController) } } - m_pShopList->SetAlternateDrawMode(true); - m_pCartList->SetAlternateDrawMode(true); - m_pShopList->SetMultiSelect(false); - m_pCartList->SetMultiSelect(false); -// Do this manually with the MoseMoved notifications -// m_pShopList->SetHotTracking(true); -// m_pCartList->SetHotTracking(true); - m_pCraftBox->SetLocked(true); - m_pShopList->EnableScrollbars(false, true); + m_pShopList->SetAlternateDrawMode(true); + m_pCartList->SetAlternateDrawMode(true); + m_pShopList->SetMultiSelect(false); + m_pCartList->SetMultiSelect(false); + // Do this manually with the MoseMoved notifications + // m_pShopList->SetHotTracking(true); + // m_pCartList->SetHotTracking(true); + m_pCraftBox->SetLocked(true); + m_pShopList->EnableScrollbars(false, true); m_pShopList->SetScrollBarThickness(13); - m_pCartList->EnableScrollbars(false, true); + m_pCartList->EnableScrollbars(false, true); m_pCartList->SetScrollBarThickness(13); - // Load the loadouts initially.. this might be done again later as well by Activity scripts after they set metaplayer etc - LoadAllLoadoutsFromFile(); + // Load the loadouts initially.. this might be done again later as well by Activity scripts after they set metaplayer etc + LoadAllLoadoutsFromFile(); - // Set initial focus, category list, and label settings - m_MenuFocus = OK; - m_FocusChange = true; - m_MenuCategory = CRAFT; - CategoryChange(); - UpdateTotalCostLabel(m_pController->GetTeam()); + // Set initial focus, category list, and label settings + m_MenuFocus = OK; + m_FocusChange = true; + m_MenuCategory = CRAFT; + CategoryChange(); + UpdateTotalCostLabel(m_pController->GetTeam()); - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); - return 0; + return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the BuyMenuGUI object. -void BuyMenuGUI::Destroy() -{ - delete m_pGUIController; - delete m_pGUIInput; - delete m_pGUIScreen; +void BuyMenuGUI::Destroy() { + delete m_pGUIController; + delete m_pGUIInput; + delete m_pGUIScreen; - delete [] m_aExpandedModules; + delete[] m_aExpandedModules; - Clear(); + Clear(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void BuyMenuGUI::SetBannerImage(const std::string &imagePath) { +void BuyMenuGUI::SetBannerImage(const std::string& imagePath) { ContentFile bannerFile((imagePath.empty() ? c_DefaultBannerImagePath : imagePath).c_str()); m_Banner->SetDrawImage(new AllegroBitmap(bannerFile.GetAsBitmap())); m_Banner->SetDrawType(GUICollectionBox::Image); @@ -331,7 +315,7 @@ void BuyMenuGUI::SetBannerImage(const std::string &imagePath) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void BuyMenuGUI::SetLogoImage(const std::string &imagePath) { +void BuyMenuGUI::SetLogoImage(const std::string& imagePath) { ContentFile logoFile((imagePath.empty() ? c_DefaultLogoImagePath : imagePath).c_str()); m_Logo->SetDrawImage(new AllegroBitmap(logoFile.GetAsBitmap())); m_Logo->SetDrawType(GUICollectionBox::Image); @@ -339,17 +323,16 @@ void BuyMenuGUI::SetLogoImage(const std::string &imagePath) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void BuyMenuGUI::ClearCartList() -{ +void BuyMenuGUI::ClearCartList() { m_pCartList->ClearList(); - m_ListItemIndex = 0; + m_ListItemIndex = 0; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void BuyMenuGUI::AddCartItem(const std::string &name, const std::string &rightText, GUIBitmap *pBitmap, const Entity *pEntity, const int extraIndex) { - m_pCartList->AddItem(name, rightText, pBitmap, pEntity, extraIndex); - UpdateItemNestingLevels(); +void BuyMenuGUI::AddCartItem(const std::string& name, const std::string& rightText, GUIBitmap* pBitmap, const Entity* pEntity, const int extraIndex) { + m_pCartList->AddItem(name, rightText, pBitmap, pEntity, extraIndex); + UpdateItemNestingLevels(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -359,147 +342,138 @@ void BuyMenuGUI::DuplicateCartItem(const int itemIndex) { return; } - std::vector addedItems; + std::vector addedItems; - auto addDuplicateItemAtEnd = [&](const GUIListPanel::Item *itemToCopy) { - GUIBitmap *pItemBitmap = new AllegroBitmap(dynamic_cast(itemToCopy->m_pBitmap)->GetBitmap()); - m_pCartList->AddItem(itemToCopy->m_Name, itemToCopy->m_RightText, pItemBitmap, itemToCopy->m_pEntity, itemToCopy->m_ExtraIndex); - return m_pCartList->GetItem(m_pCartList->GetItemList()->size() - 1); - }; + auto addDuplicateItemAtEnd = [&](const GUIListPanel::Item* itemToCopy) { + GUIBitmap* pItemBitmap = new AllegroBitmap(dynamic_cast(itemToCopy->m_pBitmap)->GetBitmap()); + m_pCartList->AddItem(itemToCopy->m_Name, itemToCopy->m_RightText, pItemBitmap, itemToCopy->m_pEntity, itemToCopy->m_ExtraIndex); + return m_pCartList->GetItem(m_pCartList->GetItemList()->size() - 1); + }; - bool copyingActorWithInventory = m_pCartList->GetItem(itemIndex)->m_pEntity->GetClassName() == "AHuman"; + bool copyingActorWithInventory = m_pCartList->GetItem(itemIndex)->m_pEntity->GetClassName() == "AHuman"; - int currentIndex = itemIndex; - do { - GUIListPanel::Item *newItem = addDuplicateItemAtEnd(*(m_pCartList->GetItemList()->begin() + currentIndex)); - newItem->m_ID = currentIndex; - addedItems.push_back(newItem); + int currentIndex = itemIndex; + do { + GUIListPanel::Item* newItem = addDuplicateItemAtEnd(*(m_pCartList->GetItemList()->begin() + currentIndex)); + newItem->m_ID = currentIndex; + addedItems.push_back(newItem); - currentIndex++; - } while (copyingActorWithInventory && - currentIndex < m_pCartList->GetItemList()->size() - addedItems.size() && - dynamic_cast(m_pCartList->GetItem(currentIndex)->m_pEntity)); + currentIndex++; + } while (copyingActorWithInventory && + currentIndex < m_pCartList->GetItemList()->size() - addedItems.size() && + dynamic_cast(m_pCartList->GetItem(currentIndex)->m_pEntity)); - // Fix up the IDs of the items we're about to shift. - for (auto itr = m_pCartList->GetItemList()->begin() + itemIndex, itr_end = m_pCartList->GetItemList()->end() - addedItems.size(); itr < itr_end; ++itr) { - (*itr)->m_ID += addedItems.size(); - } + // Fix up the IDs of the items we're about to shift. + for (auto itr = m_pCartList->GetItemList()->begin() + itemIndex, itr_end = m_pCartList->GetItemList()->end() - addedItems.size(); itr < itr_end; ++itr) { + (*itr)->m_ID += addedItems.size(); + } - // Now shift all items up to make space. - std::copy(m_pCartList->GetItemList()->begin() + itemIndex, m_pCartList->GetItemList()->end() - addedItems.size(), m_pCartList->GetItemList()->begin() + itemIndex + addedItems.size()); + // Now shift all items up to make space. + std::copy(m_pCartList->GetItemList()->begin() + itemIndex, m_pCartList->GetItemList()->end() - addedItems.size(), m_pCartList->GetItemList()->begin() + itemIndex + addedItems.size()); - // And copy our new items into place. - std::copy(addedItems.begin(), addedItems.end(), m_pCartList->GetItemList()->begin() + itemIndex); + // And copy our new items into place. + std::copy(addedItems.begin(), addedItems.end(), m_pCartList->GetItemList()->begin() + itemIndex); - // Reselect the item, so our selection doesn't move. - m_pCartList->SetSelectedIndex(itemIndex); + // Reselect the item, so our selection doesn't move. + m_pCartList->SetSelectedIndex(itemIndex); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool BuyMenuGUI::LoadAllLoadoutsFromFile() -{ - // First clear out all loadouts - m_Loadouts.clear(); - // Try to load the player's loadout settings from file, if there is one - char loadoutPath[256]; +bool BuyMenuGUI::LoadAllLoadoutsFromFile() { + // First clear out all loadouts + m_Loadouts.clear(); + // Try to load the player's loadout settings from file, if there is one + char loadoutPath[256]; - // A metagame player - if (m_MetaPlayer != Players::NoPlayer) - { - // Start loading any additional stuff from the custom user file - std::snprintf(loadoutPath, sizeof(loadoutPath), "%s%s - LoadoutsMP%d.ini", (System::GetUserdataDirectory() + c_UserConquestSavesModuleName + "/").c_str(), g_MetaMan.GetGameName().c_str(), m_MetaPlayer + 1); - - if (!System::PathExistsCaseSensitive(loadoutPath)) - { - // If the file doesn't exist, then we're not loading it, are we? - loadoutPath[0] = 0; - } - } - // Not a metagame player, just a regular scenario player - else - { - std::snprintf(loadoutPath, sizeof(loadoutPath), "%sLoadoutsP%d.ini", System::GetUserdataDirectory().c_str(), m_pController->GetPlayer() + 1); + // A metagame player + if (m_MetaPlayer != Players::NoPlayer) { + // Start loading any additional stuff from the custom user file + std::snprintf(loadoutPath, sizeof(loadoutPath), "%s%s - LoadoutsMP%d.ini", (System::GetUserdataDirectory() + c_UserConquestSavesModuleName + "/").c_str(), g_MetaMan.GetGameName().c_str(), m_MetaPlayer + 1); + if (!System::PathExistsCaseSensitive(loadoutPath)) { + // If the file doesn't exist, then we're not loading it, are we? + loadoutPath[0] = 0; + } + } + // Not a metagame player, just a regular scenario player + else { + std::snprintf(loadoutPath, sizeof(loadoutPath), "%sLoadoutsP%d.ini", System::GetUserdataDirectory().c_str(), m_pController->GetPlayer() + 1); } - // Open the file - Reader loadoutFile(loadoutPath, false, nullptr, true, true); - - // Read any and all loadout presets from file - while (loadoutFile.ReaderOK() && loadoutFile.NextProperty()) - { - Loadout newLoad; - loadoutFile >> newLoad; - // If we successfully found everything this loadout requires, add it to the preset menu -// Why be picky? - if (!newLoad.GetCargoList()->empty())//newLoad.IsComplete()) - m_Loadouts.push_back(newLoad); - } + // Open the file + Reader loadoutFile(loadoutPath, false, nullptr, true, true); + + // Read any and all loadout presets from file + while (loadoutFile.ReaderOK() && loadoutFile.NextProperty()) { + Loadout newLoad; + loadoutFile >> newLoad; + // If we successfully found everything this loadout requires, add it to the preset menu + // Why be picky? + if (!newLoad.GetCargoList()->empty()) // newLoad.IsComplete()) + m_Loadouts.push_back(newLoad); + } - if (m_NativeTechModule > 0) - { + if (m_NativeTechModule > 0) { // Then try to get the different standard Loadouts for this' player's native tech module if it's not -All- - const Loadout *pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Default", m_NativeTechModule)); + const Loadout* pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Default", m_NativeTechModule)); // Add it to the Loadout list - it will be copied inside so no worry about passing in a preset instance if (pDefaultLoadoutPreset) m_Loadouts.push_back(*pDefaultLoadoutPreset); // Attempt to do it for all the other standard loadout types as well - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Light", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Light", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Heavy", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Heavy", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry CQB", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry CQB", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Grenadier", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Grenadier", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Sniper", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Sniper", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Engineer", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Engineer", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Mecha", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Mecha", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); - if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Turret", m_NativeTechModule))) + if (pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Turret", m_NativeTechModule))) m_Loadouts.push_back(*pDefaultLoadoutPreset); } - // If no file was found, try to load a Tech module-specified loadout defaults! - if (m_Loadouts.empty()) - { - // Try to get the default Loadout for this' player's native tech module - const Loadout *pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Default", m_NativeTechModule)); - // Add it to the Loadout list - it will be copied inside so no worry about passing in a preset instance - if (pDefaultLoadoutPreset) - m_Loadouts.push_back(*pDefaultLoadoutPreset); - } -/* This is dangerous, crash prone and unneccessary - // If there were no loadouts to load, or no file present, or default Presets defined, set up a single failsafe default one - if (m_Loadouts.empty()) - { - Loadout defaultLoadout; - // Default craft - defaultLoadout.SetDeliveryCraft(dynamic_cast(g_PresetMan.GetEntityPreset("ACRocket", "Rocket MK1"))); - // Default passenger - defaultLoadout.AddToCargoList(dynamic_cast(g_PresetMan.GetEntityPreset("AHuman", "Robot 1"))); - // Default primary weapon - defaultLoadout.AddToCargoList(dynamic_cast(g_PresetMan.GetEntityPreset("HDFirearm", "SMG"))); - // Default tool - defaultLoadout.AddToCargoList(dynamic_cast(g_PresetMan.GetEntityPreset("HDFirearm", "Medium Digger"))); - // Add to list - if (defaultLoadout.IsComplete()) - m_Loadouts.push_back(defaultLoadout); - } -*/ - // Load the first loadout preset into the cart by default - DeployLoadout(0); - - // Refresh all views so we see the new sets if we're in the preset category - CategoryChange(); - - return true; + // If no file was found, try to load a Tech module-specified loadout defaults! + if (m_Loadouts.empty()) { + // Try to get the default Loadout for this' player's native tech module + const Loadout* pDefaultLoadoutPreset = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Default", m_NativeTechModule)); + // Add it to the Loadout list - it will be copied inside so no worry about passing in a preset instance + if (pDefaultLoadoutPreset) + m_Loadouts.push_back(*pDefaultLoadoutPreset); + } + /* This is dangerous, crash prone and unneccessary + // If there were no loadouts to load, or no file present, or default Presets defined, set up a single failsafe default one + if (m_Loadouts.empty()) + { + Loadout defaultLoadout; + // Default craft + defaultLoadout.SetDeliveryCraft(dynamic_cast(g_PresetMan.GetEntityPreset("ACRocket", "Rocket MK1"))); + // Default passenger + defaultLoadout.AddToCargoList(dynamic_cast(g_PresetMan.GetEntityPreset("AHuman", "Robot 1"))); + // Default primary weapon + defaultLoadout.AddToCargoList(dynamic_cast(g_PresetMan.GetEntityPreset("HDFirearm", "SMG"))); + // Default tool + defaultLoadout.AddToCargoList(dynamic_cast(g_PresetMan.GetEntityPreset("HDFirearm", "Medium Digger"))); + // Add to list + if (defaultLoadout.IsComplete()) + m_Loadouts.push_back(defaultLoadout); + } + */ + // Load the first loadout preset into the cart by default + DeployLoadout(0); + + // Refresh all views so we see the new sets if we're in the preset category + CategoryChange(); + + return true; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: SaveAllLoadoutsToFile ////////////////////////////////////////////////////////////////////////////////////////// @@ -507,55 +481,49 @@ bool BuyMenuGUI::LoadAllLoadoutsFromFile() // any named presets which will be loaded from the standard preset // loadouts first anyway. -bool BuyMenuGUI::SaveAllLoadoutsToFile() -{ - // Nothing to save - if (m_Loadouts.empty()) - return true; - - char loadoutPath[256]; - // A metagame player - if (m_MetaPlayer != Players::NoPlayer) - { - // If a new metagame, then just save over the metagame autosave instead of to the new game save - // Since the players of a new game are likely to have different techs and therefore different default loadouts - // So we should start fresh with new loadouts loaded from tech defaults for each player - if (g_MetaMan.GetGameName() == DEFAULTGAMENAME) - std::snprintf(loadoutPath, sizeof(loadoutPath), "%s%s - LoadoutsMP%d.ini", (System::GetUserdataDirectory() + c_UserConquestSavesModuleName + "/").c_str(), AUTOSAVENAME, m_MetaPlayer + 1); - else - std::snprintf(loadoutPath, sizeof(loadoutPath), "%s%s - LoadoutsMP%d.ini", (System::GetUserdataDirectory() + c_UserConquestSavesModuleName + "/").c_str(), g_MetaMan.GetGameName().c_str(), m_MetaPlayer + 1); - } - else - std::snprintf(loadoutPath, sizeof(loadoutPath), "%sLoadoutsP%d.ini", System::GetUserdataDirectory().c_str(), m_pController->GetPlayer() + 1); +bool BuyMenuGUI::SaveAllLoadoutsToFile() { + // Nothing to save + if (m_Loadouts.empty()) + return true; + + char loadoutPath[256]; + // A metagame player + if (m_MetaPlayer != Players::NoPlayer) { + // If a new metagame, then just save over the metagame autosave instead of to the new game save + // Since the players of a new game are likely to have different techs and therefore different default loadouts + // So we should start fresh with new loadouts loaded from tech defaults for each player + if (g_MetaMan.GetGameName() == DEFAULTGAMENAME) + std::snprintf(loadoutPath, sizeof(loadoutPath), "%s%s - LoadoutsMP%d.ini", (System::GetUserdataDirectory() + c_UserConquestSavesModuleName + "/").c_str(), AUTOSAVENAME, m_MetaPlayer + 1); + else + std::snprintf(loadoutPath, sizeof(loadoutPath), "%s%s - LoadoutsMP%d.ini", (System::GetUserdataDirectory() + c_UserConquestSavesModuleName + "/").c_str(), g_MetaMan.GetGameName().c_str(), m_MetaPlayer + 1); + } else + std::snprintf(loadoutPath, sizeof(loadoutPath), "%sLoadoutsP%d.ini", System::GetUserdataDirectory().c_str(), m_pController->GetPlayer() + 1); - // Open the file - Writer loadoutFile(loadoutPath, false); + // Open the file + Writer loadoutFile(loadoutPath, false); // Write out all the loadouts that are user made. - for (const Loadout &loadoutEntry : m_Loadouts) { + for (const Loadout& loadoutEntry: m_Loadouts) { // Don't write out preset references, they'll be read first from PresetMan on load anyway - if (loadoutEntry.GetPresetName() == "None") { loadoutFile.NewPropertyWithValue("AddLoadout", loadoutEntry); } + if (loadoutEntry.GetPresetName() == "None") { + loadoutFile.NewPropertyWithValue("AddLoadout", loadoutEntry); + } } - return true; + return true; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetEnabled ////////////////////////////////////////////////////////////////////////////////////////// // Description: Enables or disables the menu. This will animate it in and out of view. -void BuyMenuGUI::SetEnabled(bool enable) -{ - if (enable && m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) - { - if (g_FrameMan.IsInMultiplayerMode()) - { +void BuyMenuGUI::SetEnabled(bool enable) { + if (enable && m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) { + if (g_FrameMan.IsInMultiplayerMode()) { // If we're not split screen horizontally, then stretch out the layout for all the relevant controls int stretchAmount = g_FrameMan.GetPlayerFrameBufferHeight(m_pController->GetPlayer()) - m_pParentBox->GetHeight(); - if (stretchAmount != 0) - { + if (stretchAmount != 0) { m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); m_pShopList->SetSize(m_pShopList->GetWidth(), m_pShopList->GetHeight() + stretchAmount); m_pCartList->SetSize(m_pCartList->GetWidth(), m_pCartList->GetHeight() + stretchAmount); @@ -567,13 +535,10 @@ void BuyMenuGUI::SetEnabled(bool enable) m_pCostLabel->SetPositionAbs(m_pCostLabel->GetXPos(), m_pCostLabel->GetYPos() + stretchAmount); m_pBuyButton->SetPositionAbs(m_pBuyButton->GetXPos(), m_pBuyButton->GetYPos() + stretchAmount); } - } - else - { + } else { // If we're not split screen horizontally, then stretch out the layout for all the relevant controls int stretchAmount = g_FrameMan.GetPlayerScreenHeight() - m_pParentBox->GetHeight(); - if (stretchAmount != 0) - { + if (stretchAmount != 0) { m_pParentBox->SetSize(m_pParentBox->GetWidth(), m_pParentBox->GetHeight() + stretchAmount); m_pShopList->SetSize(m_pShopList->GetWidth(), m_pShopList->GetHeight() + stretchAmount); m_pCartList->SetSize(m_pCartList->GetWidth(), m_pCartList->GetHeight() + stretchAmount); @@ -587,39 +552,38 @@ void BuyMenuGUI::SetEnabled(bool enable) } } - m_MenuEnabled = ENABLING; - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - // Set the mouse cursor free - g_UInputMan.TrapMousePos(false, m_pController->GetPlayer()); - // Move the mouse cursor to the middle of the player's screen - int mouseOffX, mouseOffY; - m_pGUIInput->GetMouseOffset(mouseOffX, mouseOffY); - Vector mousePos(-mouseOffX + (g_FrameMan.GetPlayerFrameBufferWidth(m_pController->GetPlayer()) / 2), -mouseOffY + (g_FrameMan.GetPlayerFrameBufferHeight(m_pController->GetPlayer()) / 2)); - g_UInputMan.SetMousePos(mousePos, m_pController->GetPlayer()); - - // Default focus to the menu button - m_MenuFocus = OK; - m_FocusChange = true; - UpdateTotalCostLabel(m_pController->GetTeam()); - - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); - - g_GUISound.EnterMenuSound()->Play(m_pController->GetPlayer()); - } else if (!enable && m_MenuEnabled != DISABLED && m_MenuEnabled != DISABLING) { - EnableEquipmentSelection(false); - m_MenuEnabled = DISABLING; - // Trap the mouse cursor again - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - // Only play switching away sound -// if (!m_PurchaseMade) - g_GUISound.ExitMenuSound()->Play(m_pController->GetPlayer()); - } + m_MenuEnabled = ENABLING; + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + // Set the mouse cursor free + g_UInputMan.TrapMousePos(false, m_pController->GetPlayer()); + // Move the mouse cursor to the middle of the player's screen + int mouseOffX, mouseOffY; + m_pGUIInput->GetMouseOffset(mouseOffX, mouseOffY); + Vector mousePos(-mouseOffX + (g_FrameMan.GetPlayerFrameBufferWidth(m_pController->GetPlayer()) / 2), -mouseOffY + (g_FrameMan.GetPlayerFrameBufferHeight(m_pController->GetPlayer()) / 2)); + g_UInputMan.SetMousePos(mousePos, m_pController->GetPlayer()); + + // Default focus to the menu button + m_MenuFocus = OK; + m_FocusChange = true; + UpdateTotalCostLabel(m_pController->GetTeam()); + + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + + g_GUISound.EnterMenuSound()->Play(m_pController->GetPlayer()); + } else if (!enable && m_MenuEnabled != DISABLED && m_MenuEnabled != DISABLING) { + EnableEquipmentSelection(false); + m_MenuEnabled = DISABLING; + // Trap the mouse cursor again + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + // Only play switching away sound + // if (!m_PurchaseMade) + g_GUISound.ExitMenuSound()->Play(m_pController->GetPlayer()); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetPosOnScreen ////////////////////////////////////////////////////////////////////////////////////////// @@ -627,25 +591,21 @@ void BuyMenuGUI::SetEnabled(bool enable) // left corner, then 0, 0. This will affect the way the mouse is positioned // etc. -void BuyMenuGUI::SetPosOnScreen(int newPosX, int newPosY) -{ - m_pGUIController->SetPosOnScreen(newPosX, newPosY); +void BuyMenuGUI::SetPosOnScreen(int newPosX, int newPosY) { + m_pGUIController->SetPosOnScreen(newPosX, newPosY); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetMetaPlayer ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets which MetaPlayer uses this menu, if any. -void BuyMenuGUI::SetMetaPlayer(int metaPlayer) -{ - if (metaPlayer >= Players::PlayerOne && metaPlayer < g_MetaMan.GetPlayerCount()) - { - m_MetaPlayer = metaPlayer; - SetNativeTechModule(g_MetaMan.GetPlayer(m_MetaPlayer)->GetNativeTechModule()); - SetForeignCostMultiplier(g_MetaMan.GetPlayer(m_MetaPlayer)->GetForeignCostMultiplier()); - } +void BuyMenuGUI::SetMetaPlayer(int metaPlayer) { + if (metaPlayer >= Players::PlayerOne && metaPlayer < g_MetaMan.GetPlayerCount()) { + m_MetaPlayer = metaPlayer; + SetNativeTechModule(g_MetaMan.GetPlayer(m_MetaPlayer)->GetNativeTechModule()); + SetForeignCostMultiplier(g_MetaMan.GetPlayer(m_MetaPlayer)->GetForeignCostMultiplier()); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -657,8 +617,8 @@ void BuyMenuGUI::SetNativeTechModule(int whichModule) { DeployLoadout(0); if (!g_SettingsMan.FactionBuyMenuThemesDisabled() && m_NativeTechModule > 0) { - if (const DataModule *techModule = g_PresetMan.GetDataModule(whichModule); techModule->IsFaction()) { - const DataModule::BuyMenuTheme &techBuyMenuTheme = techModule->GetFactionBuyMenuTheme(); + if (const DataModule* techModule = g_PresetMan.GetDataModule(whichModule); techModule->IsFaction()) { + const DataModule::BuyMenuTheme& techBuyMenuTheme = techModule->GetFactionBuyMenuTheme(); if (!techBuyMenuTheme.SkinFilePath.empty()) { // Not specifying the skin file directory allows us to load image files from the whole working directory in the skin file instead of just the specified directory. @@ -669,7 +629,9 @@ void BuyMenuGUI::SetNativeTechModule(int whichModule) { m_pGUIController->GetSkin()->GetValue("DescriptionBoxText", "Font", &themeDescriptionBoxTextFont); m_pPopupText->SetFont(m_pGUIController->GetSkin()->GetFont(themeDescriptionBoxTextFont)); } - if (techBuyMenuTheme.BackgroundColorIndex >= 0) { m_pParentBox->SetDrawColor(std::clamp(techBuyMenuTheme.BackgroundColorIndex, 0, 255)); } + if (techBuyMenuTheme.BackgroundColorIndex >= 0) { + m_pParentBox->SetDrawColor(std::clamp(techBuyMenuTheme.BackgroundColorIndex, 0, 255)); + } SetBannerImage(techBuyMenuTheme.BannerImagePath); SetLogoImage(techBuyMenuTheme.LogoImagePath); } @@ -683,130 +645,110 @@ void BuyMenuGUI::SetNativeTechModule(int whichModule) { // Description: Sets whether a data module shown in the item menu should be expanded // or not. -void BuyMenuGUI::SetModuleExpanded(int whichModule, bool expanded) -{ - int moduleCount = g_PresetMan.GetTotalModuleCount(); - if (whichModule > 0 && whichModule < moduleCount) - { - m_aExpandedModules[whichModule] = expanded; - // Refresh the item view with the newly expanded module items - CategoryChange(false); - } - // If base module (0), or out of range module, then affect all - else - { - for (int m = 0; m < moduleCount; ++m) - m_aExpandedModules[m] = expanded; - } +void BuyMenuGUI::SetModuleExpanded(int whichModule, bool expanded) { + int moduleCount = g_PresetMan.GetTotalModuleCount(); + if (whichModule > 0 && whichModule < moduleCount) { + m_aExpandedModules[whichModule] = expanded; + // Refresh the item view with the newly expanded module items + CategoryChange(false); + } + // If base module (0), or out of range module, then affect all + else { + for (int m = 0; m < moduleCount; ++m) + m_aExpandedModules[m] = expanded; + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetOrderList ////////////////////////////////////////////////////////////////////////////////////////// // Description: Return the list of things currently in the purchase order list box. -bool BuyMenuGUI::GetOrderList(std::list &listToFill) const -{ - if (m_pCartList->GetItemList()->empty()) - return false; +bool BuyMenuGUI::GetOrderList(std::list& listToFill) const { + if (m_pCartList->GetItemList()->empty()) + return false; - const SceneObject *pSObject = 0; - for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) - { - if (pSObject = dynamic_cast((*itr)->m_pEntity)) - listToFill.push_back(pSObject); - } + const SceneObject* pSObject = 0; + for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) { + if (pSObject = dynamic_cast((*itr)->m_pEntity)) + listToFill.push_back(pSObject); + } - return true; + return true; } -bool BuyMenuGUI::CommitPurchase(std::string presetName) -{ - if (m_OwnedItems.size() > 0) - { - if (m_OwnedItems.find(presetName) != m_OwnedItems.end() && m_OwnedItems[presetName] > 0) - { +bool BuyMenuGUI::CommitPurchase(std::string presetName) { + if (m_OwnedItems.size() > 0) { + if (m_OwnedItems.find(presetName) != m_OwnedItems.end() && m_OwnedItems[presetName] > 0) { m_OwnedItems[presetName] -= 1; return true; - } - else + } else return false; } return false; } -float BuyMenuGUI::GetTotalCost(bool includeDelivery) const -{ +float BuyMenuGUI::GetTotalCost(bool includeDelivery) const { float totalCost = 0; - if (m_OwnedItems.size() > 0) - { - std::map orderedItems; + if (m_OwnedItems.size() > 0) { + std::map orderedItems; - for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) - { + for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) { bool needsToBePaid = true; - std::string presetName = (*itr)->m_pEntity->GetModuleAndPresetName(); + std::string presetName = (*itr)->m_pEntity->GetModuleAndPresetName(); if (orderedItems.find(presetName) != orderedItems.end()) orderedItems[presetName] = 1; else orderedItems[presetName] += 1; - auto itrFound = m_OwnedItems.find(presetName); + auto itrFound = m_OwnedItems.find(presetName); if (itrFound != m_OwnedItems.end() && itrFound->second >= orderedItems[presetName]) needsToBePaid = false; - if (needsToBePaid) - { - totalCost += dynamic_cast((*itr)->m_pEntity)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); + if (needsToBePaid) { + totalCost += dynamic_cast((*itr)->m_pEntity)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); } } - if (m_pSelectedCraft && includeDelivery) - { + if (m_pSelectedCraft && includeDelivery) { bool needsToBePaid = true; - std::string presetName = m_pSelectedCraft->GetModuleAndPresetName(); + std::string presetName = m_pSelectedCraft->GetModuleAndPresetName(); if (orderedItems.find(presetName) != orderedItems.end()) orderedItems[presetName] = 1; else orderedItems[presetName] += 1; - auto itrFound = m_OwnedItems.find(presetName); + auto itrFound = m_OwnedItems.find(presetName); if (itrFound != m_OwnedItems.end() && itrFound->second >= orderedItems[presetName]) needsToBePaid = false; - if (needsToBePaid) - { - totalCost += dynamic_cast(m_pSelectedCraft)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); + if (needsToBePaid) { + totalCost += dynamic_cast(m_pSelectedCraft)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); } } - } - else - { - for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) - totalCost += dynamic_cast((*itr)->m_pEntity)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); + } else { + for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) + totalCost += dynamic_cast((*itr)->m_pEntity)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); // Add the delivery craft's cost - if (m_pSelectedCraft && includeDelivery) - { - totalCost += dynamic_cast(m_pSelectedCraft)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); + if (m_pSelectedCraft && includeDelivery) { + totalCost += dynamic_cast(m_pSelectedCraft)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); } } - return totalCost; + return totalCost; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - float BuyMenuGUI::GetTotalOrderMass() const { float totalMass = 0.0F; - for (const GUIListPanel::Item *cartItem : *m_pCartList->GetItemList()) { - const MovableObject *itemAsMO = dynamic_cast(cartItem->m_pEntity); + for (const GUIListPanel::Item* cartItem: *m_pCartList->GetItemList()) { + const MovableObject* itemAsMO = dynamic_cast(cartItem->m_pEntity); if (itemAsMO) { totalMass += itemAsMO->GetMass(); } else { @@ -817,7 +759,6 @@ float BuyMenuGUI::GetTotalOrderMass() const { return totalMass; } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float BuyMenuGUI::GetCraftMass() { @@ -825,12 +766,11 @@ float BuyMenuGUI::GetCraftMass() { // Add the delivery craft's mass if (m_pSelectedCraft) - totalMass += dynamic_cast(m_pSelectedCraft)->GetMass(); + totalMass += dynamic_cast(m_pSelectedCraft)->GetMass(); return totalMass; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetTotalOrderPassengers ////////////////////////////////////////////////////////////////////////////////////////// @@ -840,13 +780,11 @@ float BuyMenuGUI::GetCraftMass() { int BuyMenuGUI::GetTotalOrderPassengers() const { int passengers = 0; - for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) - { - const Actor* passenger = dynamic_cast((*itr)->m_pEntity); - if (passenger) - { - passengers += passenger->GetPassengerSlots(); - } + for (std::vector::iterator itr = m_pCartList->GetItemList()->begin(); itr != m_pCartList->GetItemList()->end(); ++itr) { + const Actor* passenger = dynamic_cast((*itr)->m_pEntity); + if (passenger) { + passengers += passenger->GetPassengerSlots(); + } } return passengers; @@ -855,36 +793,36 @@ int BuyMenuGUI::GetTotalOrderPassengers() const { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void BuyMenuGUI::EnableEquipmentSelection(bool enabled) { - if (enabled != m_SelectingEquipment && g_SettingsMan.SmartBuyMenuNavigationEnabled()) { - m_SelectingEquipment = enabled; - RefreshTabDisabledStates(); - - if (m_SelectingEquipment) { - m_LastVisitedMainTab = static_cast(m_MenuCategory); - m_LastMainScrollPosition = m_pShopList->GetScrollVerticalValue(); - m_MenuCategory = m_LastVisitedEquipmentTab; - } else { - m_LastVisitedEquipmentTab = static_cast(m_MenuCategory); - m_LastEquipmentScrollPosition = m_pShopList->GetScrollVerticalValue(); - m_MenuCategory = m_LastVisitedMainTab; - } + if (enabled != m_SelectingEquipment && g_SettingsMan.SmartBuyMenuNavigationEnabled()) { + m_SelectingEquipment = enabled; + RefreshTabDisabledStates(); + + if (m_SelectingEquipment) { + m_LastVisitedMainTab = static_cast(m_MenuCategory); + m_LastMainScrollPosition = m_pShopList->GetScrollVerticalValue(); + m_MenuCategory = m_LastVisitedEquipmentTab; + } else { + m_LastVisitedEquipmentTab = static_cast(m_MenuCategory); + m_LastEquipmentScrollPosition = m_pShopList->GetScrollVerticalValue(); + m_MenuCategory = m_LastVisitedMainTab; + } - CategoryChange(); - m_pShopList->ScrollTo(m_SelectingEquipment ? m_LastEquipmentScrollPosition : m_LastMainScrollPosition); + CategoryChange(); + m_pShopList->ScrollTo(m_SelectingEquipment ? m_LastEquipmentScrollPosition : m_LastMainScrollPosition); - m_MenuFocus = ITEMS; - m_FocusChange = 1; - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } + m_MenuFocus = ITEMS; + m_FocusChange = 1; + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void BuyMenuGUI::UpdateItemNestingLevels() { - const int ownedDeviceOffsetX = 8; + const int ownedDeviceOffsetX = 8; - int nextHeldDeviceBelongsToAHuman = false; - for (GUIListPanel::Item *cartItem : (*m_pCartList->GetItemList())) { + int nextHeldDeviceBelongsToAHuman = false; + for (GUIListPanel::Item* cartItem: (*m_pCartList->GetItemList())) { if (dynamic_cast(cartItem->m_pEntity)) { nextHeldDeviceBelongsToAHuman = true; } else if (!dynamic_cast(cartItem->m_pEntity)) { @@ -894,7 +832,7 @@ void BuyMenuGUI::UpdateItemNestingLevels() { } } - m_pCartList->BuildBitmap(false, true); + m_pCartList->BuildBitmap(false, true); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -918,488 +856,445 @@ void BuyMenuGUI::RefreshTabDisabledStates() { ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void BuyMenuGUI::Update() -{ - // Enable mouse input if the controller allows it - m_pGUIController->EnableMouse(m_pController->IsMouseControlled()); +void BuyMenuGUI::Update() { + // Enable mouse input if the controller allows it + m_pGUIController->EnableMouse(m_pController->IsMouseControlled()); - // Reset the purchasing indicator - m_PurchaseMade = false; + // Reset the purchasing indicator + m_PurchaseMade = false; - // Popup box is hidden by default - m_pPopupBox->SetVisible(false); + // Popup box is hidden by default + m_pPopupBox->SetVisible(false); - //////////////////////////////////////////////////////////////////////// - // Animate the menu into and out of view if enabled or disabled + //////////////////////////////////////////////////////////////////////// + // Animate the menu into and out of view if enabled or disabled - if (m_MenuEnabled == ENABLING) - { - m_pParentBox->SetEnabled(true); - m_pParentBox->SetVisible(true); - - Vector position, occlusion; - - float toGo = -std::floor((float)m_pParentBox->GetXPos()); - float goProgress = m_MenuSpeed * m_MenuTimer.GetElapsedRealTimeS(); - if (goProgress > 1.0) - goProgress = 1.0; - position.m_X = m_pParentBox->GetXPos() + std::ceil(toGo * goProgress); - occlusion.m_X = m_pParentBox->GetWidth() + m_pParentBox->GetXPos(); - - // If not split screened, then make the menu scroll in diagonally instead of straight from the side - // Tie it to the (X) horizontal position - // EDIT: nah, just make the menu larger, but do change the occlusion, looks better - if (!g_FrameMan.GetHSplit()) - { -// position.m_Y = -m_pParentBox->GetHeight() * fabs(position.m_X / m_pParentBox->GetWidth()); -// occlusion.m_Y = m_pParentBox->GetHeight() + m_pParentBox->GetYPos(); - occlusion.m_Y = m_pParentBox->GetHeight() / 2; - } + if (m_MenuEnabled == ENABLING) { + m_pParentBox->SetEnabled(true); + m_pParentBox->SetVisible(true); + + Vector position, occlusion; - m_pParentBox->SetPositionAbs(position.m_X, position.m_Y); - g_CameraMan.SetScreenOcclusion(occlusion, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + float toGo = -std::floor((float)m_pParentBox->GetXPos()); + float goProgress = m_MenuSpeed * m_MenuTimer.GetElapsedRealTimeS(); + if (goProgress > 1.0) + goProgress = 1.0; + position.m_X = m_pParentBox->GetXPos() + std::ceil(toGo * goProgress); + occlusion.m_X = m_pParentBox->GetWidth() + m_pParentBox->GetXPos(); + + // If not split screened, then make the menu scroll in diagonally instead of straight from the side + // Tie it to the (X) horizontal position + // EDIT: nah, just make the menu larger, but do change the occlusion, looks better + if (!g_FrameMan.GetHSplit()) { + // position.m_Y = -m_pParentBox->GetHeight() * fabs(position.m_X / m_pParentBox->GetWidth()); + // occlusion.m_Y = m_pParentBox->GetHeight() + m_pParentBox->GetYPos(); + occlusion.m_Y = m_pParentBox->GetHeight() / 2; + } - if (m_pParentBox->GetXPos() >= 0) - { + m_pParentBox->SetPositionAbs(position.m_X, position.m_Y); + g_CameraMan.SetScreenOcclusion(occlusion, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + if (m_pParentBox->GetXPos() >= 0) { m_MenuEnabled = ENABLED; CategoryChange(); } - } - // Animate the menu out of view - else if (m_MenuEnabled == DISABLING) - { - float toGo = -std::ceil(((float)m_pParentBox->GetWidth() + (float)m_pParentBox->GetXPos())); - float goProgress = m_MenuSpeed * m_MenuTimer.GetElapsedRealTimeS(); - if (goProgress > 1.0) - goProgress = 1.0; - m_pParentBox->SetPositionAbs(m_pParentBox->GetXPos() + std::floor(toGo * goProgress), 0); - g_CameraMan.SetScreenOcclusion(Vector(m_pParentBox->GetWidth() + m_pParentBox->GetXPos(), 0), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - m_pPopupBox->SetVisible(false); - - if (m_pParentBox->GetXPos() <= -m_pParentBox->GetWidth()) - { - m_pParentBox->SetEnabled(false); - m_pParentBox->SetVisible(false); - m_MenuEnabled = DISABLED; - } - } - else if (m_MenuEnabled == ENABLED) - { - m_pParentBox->SetEnabled(true); - m_pParentBox->SetVisible(true); - - } - else if (m_MenuEnabled == DISABLED) - { - m_pParentBox->SetEnabled(false); - m_pParentBox->SetVisible(false); - m_pPopupBox->SetVisible(false); - } + } + // Animate the menu out of view + else if (m_MenuEnabled == DISABLING) { + float toGo = -std::ceil(((float)m_pParentBox->GetWidth() + (float)m_pParentBox->GetXPos())); + float goProgress = m_MenuSpeed * m_MenuTimer.GetElapsedRealTimeS(); + if (goProgress > 1.0) + goProgress = 1.0; + m_pParentBox->SetPositionAbs(m_pParentBox->GetXPos() + std::floor(toGo * goProgress), 0); + g_CameraMan.SetScreenOcclusion(Vector(m_pParentBox->GetWidth() + m_pParentBox->GetXPos(), 0), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + m_pPopupBox->SetVisible(false); + + if (m_pParentBox->GetXPos() <= -m_pParentBox->GetWidth()) { + m_pParentBox->SetEnabled(false); + m_pParentBox->SetVisible(false); + m_MenuEnabled = DISABLED; + } + } else if (m_MenuEnabled == ENABLED) { + m_pParentBox->SetEnabled(true); + m_pParentBox->SetVisible(true); + + } else if (m_MenuEnabled == DISABLED) { + m_pParentBox->SetEnabled(false); + m_pParentBox->SetVisible(false); + m_pPopupBox->SetVisible(false); + } - // Reset the menu animation timer so we can measure how long it takes till next frame - m_MenuTimer.Reset(); + // Reset the menu animation timer so we can measure how long it takes till next frame + m_MenuTimer.Reset(); - // Quit now if we aren't enabled - if (m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) - return; + // Quit now if we aren't enabled + if (m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) + return; - // Update the user controller -// m_pController->Update(); + // Update the user controller + // m_pController->Update(); - // Gotto update this all the time because other players may have bought stuff and changed the funds available to the team - UpdateTotalCostLabel(m_pController->GetTeam()); + // Gotto update this all the time because other players may have bought stuff and changed the funds available to the team + UpdateTotalCostLabel(m_pController->GetTeam()); - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); - ///////////////////////////////////////////////////// - // Mouse cursor logic + ///////////////////////////////////////////////////// + // Mouse cursor logic int mousePosX; int mousePosY; - m_pGUIInput->GetMousePosition(&mousePosX, &mousePosY); + m_pGUIInput->GetMousePosition(&mousePosX, &mousePosY); - //////////////////////////////////////////// - // Notification blinking logic + //////////////////////////////////////////// + // Notification blinking logic - if (m_BlinkMode == NOFUNDS) - { - m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); - } - else if (m_BlinkMode == NOCRAFT) - { - bool blink = m_BlinkTimer.AlternateSim(250); - m_pCraftLabel->SetVisible(blink); - m_pCraftBox->SetVisible(blink); + if (m_BlinkMode == NOFUNDS) { + m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); + } else if (m_BlinkMode == NOCRAFT) { + bool blink = m_BlinkTimer.AlternateSim(250); + m_pCraftLabel->SetVisible(blink); + m_pCraftBox->SetVisible(blink); m_pCraftCollectionBox->SetVisible(blink); - } - else if (m_BlinkMode == MAXMASS) - { + } else if (m_BlinkMode == MAXMASS) { m_pCraftMassLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); m_pCraftMassCaptionLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); - } - else if (m_BlinkMode == MAXPASSENGERS) - { + } else if (m_BlinkMode == MAXPASSENGERS) { m_pCraftPassengersLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); m_pCraftPassengersCaptionLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); } - // Time out the blinker - if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) - { - m_pCostLabel->SetVisible(true); - m_pCraftLabel->SetVisible(true); - m_pCraftBox->SetVisible(true); + // Time out the blinker + if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) { + m_pCostLabel->SetVisible(true); + m_pCraftLabel->SetVisible(true); + m_pCraftBox->SetVisible(true); m_pCraftCollectionBox->SetVisible(true); m_pCraftMassCaptionLabel->SetVisible(true); m_pCraftMassLabel->SetVisible(true); m_pCraftPassengersCaptionLabel->SetVisible(true); m_pCraftPassengersLabel->SetVisible(true); m_BlinkMode = NOBLINK; - } + } - ///////////////////////////////////////////// - // Repeating input logic + ///////////////////////////////////////////// + // Repeating input logic - bool pressLeft = m_pController->IsState(PRESS_LEFT); - bool pressRight = m_pController->IsState(PRESS_RIGHT); - bool pressUp = m_pController->IsState(PRESS_UP); - bool pressDown = m_pController->IsState(PRESS_DOWN); - bool pressScrollUp = m_pController->IsState(SCROLL_UP); - bool pressScrollDown = m_pController->IsState(SCROLL_DOWN); + bool pressLeft = m_pController->IsState(PRESS_LEFT); + bool pressRight = m_pController->IsState(PRESS_RIGHT); + bool pressUp = m_pController->IsState(PRESS_UP); + bool pressDown = m_pController->IsState(PRESS_DOWN); + bool pressScrollUp = m_pController->IsState(SCROLL_UP); + bool pressScrollDown = m_pController->IsState(SCROLL_DOWN); - bool pressNextActor = m_pController->IsState(ACTOR_NEXT); - bool pressPrevActor = m_pController->IsState(ACTOR_PREV); + bool pressNextActor = m_pController->IsState(ACTOR_NEXT); + bool pressPrevActor = m_pController->IsState(ACTOR_PREV); - // If no direciton is held down, then cancel the repeating - if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN) || m_pController->IsState(ACTOR_NEXT_PREP) || m_pController->IsState(ACTOR_PREV_PREP))) - { - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - } - - // Check if any direction has been held for the starting amount of time to get into repeat mode - if (m_RepeatStartTimer.IsPastRealMS(200)) { - // Check for the repeat interval - if (m_RepeatTimer.IsPastRealMS(75)) { - if (m_pController->IsState(MOVE_RIGHT)) { - pressRight = true; - } else if (m_pController->IsState(MOVE_LEFT)) { - pressLeft = true; - } else if (m_pController->IsState(MOVE_UP)) { - pressUp = true; - } else if (m_pController->IsState(MOVE_DOWN)) { - pressDown = true; - } else if (m_pController->IsState(ACTOR_NEXT_PREP)) { - pressNextActor = true; - } else if (m_pController->IsState(ACTOR_PREV_PREP)) { - pressPrevActor = true; - } - m_RepeatTimer.Reset(); - } - } - - ///////////////////////////////////////////// - // Change focus as the user directs + // If no direciton is held down, then cancel the repeating + if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN) || m_pController->IsState(ACTOR_NEXT_PREP) || m_pController->IsState(ACTOR_PREV_PREP))) { + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + } - if (pressRight) - { - m_MenuFocus++; - m_FocusChange = 1; + // Check if any direction has been held for the starting amount of time to get into repeat mode + if (m_RepeatStartTimer.IsPastRealMS(200)) { + // Check for the repeat interval + if (m_RepeatTimer.IsPastRealMS(75)) { + if (m_pController->IsState(MOVE_RIGHT)) { + pressRight = true; + } else if (m_pController->IsState(MOVE_LEFT)) { + pressLeft = true; + } else if (m_pController->IsState(MOVE_UP)) { + pressUp = true; + } else if (m_pController->IsState(MOVE_DOWN)) { + pressDown = true; + } else if (m_pController->IsState(ACTOR_NEXT_PREP)) { + pressNextActor = true; + } else if (m_pController->IsState(ACTOR_PREV_PREP)) { + pressPrevActor = true; + } + m_RepeatTimer.Reset(); + } + } - // Went too far. Don't allow focusing the clear order button by pressing right, will most definitely lead to accidental clearing and rage. - if (m_MenuFocus >= MenuFocus::CLEARORDER) - { - m_MenuFocus = MenuFocus::CLEARORDER - 1; - m_FocusChange = 0; - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - // Skip categories if we're going sideways from the sets buttons - if (m_MenuFocus == CATEGORIES) - { - m_MenuFocus++; - m_FocusChange++; - } - // Skip giving focus to the items list if it's empty - if (m_MenuFocus == ITEMS && m_pShopList->GetItemList()->empty()) - { - m_MenuFocus++; - m_FocusChange++; - } - // Skip giving focus to the order list if it's empty - if (m_MenuFocus == ORDER && m_pCartList->GetItemList()->empty()) - { - m_MenuFocus++; - m_FocusChange++; - } - } - else if (pressLeft) - { - m_MenuFocus--; - m_FocusChange = -1; + ///////////////////////////////////////////// + // Change focus as the user directs - // Went too far - if (m_MenuFocus < 0) - { - m_MenuFocus = 0; - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - // Skip giving focus to the order or item list if they're empty - if (m_MenuFocus == ORDER && m_pCartList->GetItemList()->empty()) - { - m_MenuFocus--; - m_FocusChange--; - } - // Skip giving focus to the items list if it's empty - if (m_MenuFocus == ITEMS && m_pShopList->GetItemList()->empty()) - { - m_MenuFocus--; - m_FocusChange--; - } - } - // Play focus change sound, if applicable - if (m_FocusChange && m_MenuEnabled != ENABLING) - g_GUISound.FocusChangeSound()->Play(m_pController->GetPlayer()); - /* Blah, should control whatever is currently focused - // Mouse wheel only controls the categories, so switch to it and make the category go up or down - if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(SCROLL_DOWN)) - { - m_FocusChange = CATEGORIES - m_MenuFocus; - m_MenuFocus = CATEGORIES; - } - */ + if (pressRight) { + m_MenuFocus++; + m_FocusChange = 1; - ///////////////////////////////////////// - // Change Category directly + // Went too far. Don't allow focusing the clear order button by pressing right, will most definitely lead to accidental clearing and rage. + if (m_MenuFocus >= MenuFocus::CLEARORDER) { + m_MenuFocus = MenuFocus::CLEARORDER - 1; + m_FocusChange = 0; + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + // Skip categories if we're going sideways from the sets buttons + if (m_MenuFocus == CATEGORIES) { + m_MenuFocus++; + m_FocusChange++; + } + // Skip giving focus to the items list if it's empty + if (m_MenuFocus == ITEMS && m_pShopList->GetItemList()->empty()) { + m_MenuFocus++; + m_FocusChange++; + } + // Skip giving focus to the order list if it's empty + if (m_MenuFocus == ORDER && m_pCartList->GetItemList()->empty()) { + m_MenuFocus++; + m_FocusChange++; + } + } else if (pressLeft) { + m_MenuFocus--; + m_FocusChange = -1; + + // Went too far + if (m_MenuFocus < 0) { + m_MenuFocus = 0; + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + // Skip giving focus to the order or item list if they're empty + if (m_MenuFocus == ORDER && m_pCartList->GetItemList()->empty()) { + m_MenuFocus--; + m_FocusChange--; + } + // Skip giving focus to the items list if it's empty + if (m_MenuFocus == ITEMS && m_pShopList->GetItemList()->empty()) { + m_MenuFocus--; + m_FocusChange--; + } + } + // Play focus change sound, if applicable + if (m_FocusChange && m_MenuEnabled != ENABLING) + g_GUISound.FocusChangeSound()->Play(m_pController->GetPlayer()); + /* Blah, should control whatever is currently focused + // Mouse wheel only controls the categories, so switch to it and make the category go up or down + if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(SCROLL_DOWN)) + { + m_FocusChange = CATEGORIES - m_MenuFocus; + m_MenuFocus = CATEGORIES; + } + */ - if (pressNextActor || pressPrevActor) { - bool smartBuyMenuNavigationEnabled = g_SettingsMan.SmartBuyMenuNavigationEnabled(); - if (pressNextActor) { - m_MenuCategory++; - if (!smartBuyMenuNavigationEnabled) { - m_MenuCategory = m_MenuCategory >= MenuCategory::CATEGORYCOUNT ? 0 : m_MenuCategory; - } else if (m_SelectingEquipment && m_MenuCategory > m_LastEquipmentTab) { - m_MenuCategory = m_FirstEquipmentTab; - } else if (!m_SelectingEquipment) { - if (m_MenuCategory > m_LastMainTab) { - m_MenuCategory = m_FirstMainTab; - } else if (m_MenuCategory == m_FirstEquipmentTab) { - m_MenuCategory = m_LastMainTab; - } - } - } else if (pressPrevActor) { - m_MenuCategory--; - if (!smartBuyMenuNavigationEnabled) { - m_MenuCategory = m_MenuCategory < 0 ? MenuCategory::CATEGORYCOUNT - 1 : m_MenuCategory; - } else if (m_SelectingEquipment && m_MenuCategory < m_FirstEquipmentTab) { - m_MenuCategory = m_LastEquipmentTab; - } else if (!m_SelectingEquipment) { - if (m_MenuCategory < m_FirstMainTab) { - m_MenuCategory = m_LastMainTab; - } else if (m_MenuCategory == m_LastEquipmentTab) { - m_MenuCategory = m_FirstEquipmentTab - 1; - } - } - } + ///////////////////////////////////////// + // Change Category directly + + if (pressNextActor || pressPrevActor) { + bool smartBuyMenuNavigationEnabled = g_SettingsMan.SmartBuyMenuNavigationEnabled(); + if (pressNextActor) { + m_MenuCategory++; + if (!smartBuyMenuNavigationEnabled) { + m_MenuCategory = m_MenuCategory >= MenuCategory::CATEGORYCOUNT ? 0 : m_MenuCategory; + } else if (m_SelectingEquipment && m_MenuCategory > m_LastEquipmentTab) { + m_MenuCategory = m_FirstEquipmentTab; + } else if (!m_SelectingEquipment) { + if (m_MenuCategory > m_LastMainTab) { + m_MenuCategory = m_FirstMainTab; + } else if (m_MenuCategory == m_FirstEquipmentTab) { + m_MenuCategory = m_LastMainTab; + } + } + } else if (pressPrevActor) { + m_MenuCategory--; + if (!smartBuyMenuNavigationEnabled) { + m_MenuCategory = m_MenuCategory < 0 ? MenuCategory::CATEGORYCOUNT - 1 : m_MenuCategory; + } else if (m_SelectingEquipment && m_MenuCategory < m_FirstEquipmentTab) { + m_MenuCategory = m_LastEquipmentTab; + } else if (!m_SelectingEquipment) { + if (m_MenuCategory < m_FirstMainTab) { + m_MenuCategory = m_LastMainTab; + } else if (m_MenuCategory == m_LastEquipmentTab) { + m_MenuCategory = m_FirstEquipmentTab - 1; + } + } + } - CategoryChange(); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + CategoryChange(); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - m_MenuFocus = ITEMS; - m_FocusChange = 1; - } + m_MenuFocus = ITEMS; + m_FocusChange = 1; + } - ///////////////////////////////////////// - // Scroll buy menu + ///////////////////////////////////////// + // Scroll buy menu - if (pressScrollUp) { - m_pShopList->ScrollUp(); - } else if (pressScrollDown) { - m_pShopList->ScrollDown(); - } + if (pressScrollUp) { + m_pShopList->ScrollUp(); + } else if (pressScrollDown) { + m_pShopList->ScrollDown(); + } - //Special handling to allow user to click on disabled tab buttons with mouse. - RefreshTabDisabledStates(); - for (int category = 0; category < CATEGORYCOUNT; ++category) { - if (!m_pCategoryTabs[category]->IsEnabled()) { - if (m_MenuCategory == category) { m_pCategoryTabs[m_MenuCategory]->SetEnabled(true); } - if (m_pCategoryTabs[category]->PointInside(mousePosX + 3, mousePosY)) { - if (m_pController->IsState(PRESS_PRIMARY)) { - m_MenuCategory = category; - m_pCategoryTabs[m_MenuCategory]->SetFocus(); - m_pCategoryTabs[m_MenuCategory]->SetEnabled(true); - CategoryChange(); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } else if (!m_pCategoryTabs[category]->IsEnabled() && !m_pCategoryTabs[category]->HasFocus()) { - m_pCategoryTabs[category]->SetFocus(); - } - } - } - } + // Special handling to allow user to click on disabled tab buttons with mouse. + RefreshTabDisabledStates(); + for (int category = 0; category < CATEGORYCOUNT; ++category) { + if (!m_pCategoryTabs[category]->IsEnabled()) { + if (m_MenuCategory == category) { + m_pCategoryTabs[m_MenuCategory]->SetEnabled(true); + } + if (m_pCategoryTabs[category]->PointInside(mousePosX + 3, mousePosY)) { + if (m_pController->IsState(PRESS_PRIMARY)) { + m_MenuCategory = category; + m_pCategoryTabs[m_MenuCategory]->SetFocus(); + m_pCategoryTabs[m_MenuCategory]->SetEnabled(true); + CategoryChange(); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } else if (!m_pCategoryTabs[category]->IsEnabled() && !m_pCategoryTabs[category]->HasFocus()) { + m_pCategoryTabs[category]->SetFocus(); + } + } + } + } - ///////////////////////////////////////// - // SETS BUTTONS focus + ///////////////////////////////////////// + // SETS BUTTONS focus - if (m_MenuFocus == SETBUTTONS) - { - if (m_FocusChange) - { - // Set the correct special Sets category so the sets buttons show up - m_MenuCategory = SETS; - CategoryChange(); - m_pSaveButton->SetFocus(); - m_FocusChange = 0; - } + if (m_MenuFocus == SETBUTTONS) { + if (m_FocusChange) { + // Set the correct special Sets category so the sets buttons show up + m_MenuCategory = SETS; + CategoryChange(); + m_pSaveButton->SetFocus(); + m_FocusChange = 0; + } - if (m_pController->IsState(PRESS_FACEBUTTON)) - { - if (m_pSaveButton->HasFocus()) - SaveCurrentLoadout(); - else if (m_pClearButton->HasFocus() && m_Loadouts.size() != 0) - { - m_Loadouts.pop_back(); - // Update the list of loadout presets so the removal shows up - CategoryChange(); - // Set focus back on the save button (CatChange changed it) - m_pClearButton->SetFocus(); - } - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - } + if (m_pController->IsState(PRESS_FACEBUTTON)) { + if (m_pSaveButton->HasFocus()) + SaveCurrentLoadout(); + else if (m_pClearButton->HasFocus() && m_Loadouts.size() != 0) { + m_Loadouts.pop_back(); + // Update the list of loadout presets so the removal shows up + CategoryChange(); + // Set focus back on the save button (CatChange changed it) + m_pClearButton->SetFocus(); + } + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + } - // Switch back focus to the category list if the player presses up while on the save button - if (pressUp) - { - if (m_pSaveButton->HasFocus()) - { - m_MenuFocus = CATEGORIES; - m_FocusChange = 1; - } - else if (m_pClearButton->HasFocus()) - { - m_pSaveButton->SetFocus(); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - } - else if (pressDown) - { - if (m_pSaveButton->HasFocus()) - { - m_pClearButton->SetFocus(); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - else if (m_pClearButton->HasFocus()) - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - } + // Switch back focus to the category list if the player presses up while on the save button + if (pressUp) { + if (m_pSaveButton->HasFocus()) { + m_MenuFocus = CATEGORIES; + m_FocusChange = 1; + } else if (m_pClearButton->HasFocus()) { + m_pSaveButton->SetFocus(); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + } else if (pressDown) { + if (m_pSaveButton->HasFocus()) { + m_pClearButton->SetFocus(); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } else if (m_pClearButton->HasFocus()) + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + } - ///////////////////////////////////////// - // CATEGORIES focus + ///////////////////////////////////////// + // CATEGORIES focus - else if (m_MenuFocus == CATEGORIES) { - if (m_FocusChange) { - m_pCategoryTabs[m_MenuCategory]->SetFocus(); - m_FocusChange = 0; - } + else if (m_MenuFocus == CATEGORIES) { + if (m_FocusChange) { + m_pCategoryTabs[m_MenuCategory]->SetFocus(); + m_FocusChange = 0; + } - if (pressDown) { - m_MenuCategory++; - if (m_MenuCategory >= CATEGORYCOUNT) { - m_MenuCategory = CATEGORYCOUNT - 1; - m_MenuFocus = SETBUTTONS; - m_FocusChange = -1; - } else { - CategoryChange(); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - } else if (pressUp) { - m_MenuCategory--; - if (m_MenuCategory < 0) { - m_MenuCategory = 0; - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } else { - CategoryChange(); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - } - } + if (pressDown) { + m_MenuCategory++; + if (m_MenuCategory >= CATEGORYCOUNT) { + m_MenuCategory = CATEGORYCOUNT - 1; + m_MenuFocus = SETBUTTONS; + m_FocusChange = -1; + } else { + CategoryChange(); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + } else if (pressUp) { + m_MenuCategory--; + if (m_MenuCategory < 0) { + m_MenuCategory = 0; + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } else { + CategoryChange(); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + } + } - ///////////////////////////////////////// - // ITEMS LIST focus + ///////////////////////////////////////// + // ITEMS LIST focus + + else if (m_MenuFocus == ITEMS) { + if (m_FocusChange) { + m_pShopList->SetFocus(); + // Select the top one in the item list if none is already selected + if (!m_pShopList->GetItemList()->empty() && m_pShopList->GetSelectedIndex() < 0) + m_pShopList->SetSelectedIndex(m_ListItemIndex = 0); + // Synch our index with the one already sleected in the list + else { + m_ListItemIndex = m_pShopList->GetSelectedIndex(); + m_pShopList->ScrollToSelected(); + } - else if (m_MenuFocus == ITEMS) - { - if (m_FocusChange) - { - m_pShopList->SetFocus(); - // Select the top one in the item list if none is already selected - if (!m_pShopList->GetItemList()->empty() && m_pShopList->GetSelectedIndex() < 0) - m_pShopList->SetSelectedIndex(m_ListItemIndex = 0); - // Synch our index with the one already sleected in the list - else - { - m_ListItemIndex = m_pShopList->GetSelectedIndex(); - m_pShopList->ScrollToSelected(); - } + m_FocusChange = 0; + } - m_FocusChange = 0; - } + int listSize = m_pShopList->GetItemList()->size(); + if (pressDown) { + m_ListItemIndex++; + // Loop around + if (m_ListItemIndex >= listSize) + m_ListItemIndex = 0; + + // Update the selected shop item index + m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex; + m_pShopList->SetSelectedIndex(m_ListItemIndex); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } else if (pressUp) { + m_ListItemIndex--; + // Loop around + if (m_ListItemIndex < 0) + m_ListItemIndex = listSize - 1; + + // Update the selected shop item index + m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex; + m_pShopList->SetSelectedIndex(m_ListItemIndex); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } - int listSize = m_pShopList->GetItemList()->size(); - if (pressDown) - { - m_ListItemIndex++; - // Loop around - if (m_ListItemIndex >= listSize) - m_ListItemIndex = 0; - - // Update the selected shop item index - m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex; - m_pShopList->SetSelectedIndex(m_ListItemIndex); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - else if (pressUp) - { - m_ListItemIndex--; - // Loop around - if (m_ListItemIndex < 0) - m_ListItemIndex = listSize - 1; - - // Update the selected shop item index - m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex; - m_pShopList->SetSelectedIndex(m_ListItemIndex); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } + // Get handle to the currently selected item, if any + GUIListPanel::Item* pItem = m_pShopList->GetItem(m_ListItemIndex); + std::string description = ""; - // Get handle to the currently selected item, if any - GUIListPanel::Item *pItem = m_pShopList->GetItem(m_ListItemIndex); - std::string description = ""; - - if (pItem && pItem->m_pEntity) { - description = ((pItem->m_pEntity->GetDescription().empty()) ? "-No Information Found-": pItem->m_pEntity->GetDescription()) + "\n"; - const Entity *currentItem = pItem->m_pEntity; - const ACraft *itemAsCraft = dynamic_cast(currentItem); - if (itemAsCraft) { - int craftMaxPassengers = itemAsCraft->GetMaxPassengers(); - float craftMaxMass = itemAsCraft->GetMaxInventoryMass(); - if (craftMaxMass == 0) { - description += "\nNO CARGO SPACE!"; - } else if (craftMaxMass > 0) { - description += "\nMax Mass: " + RoundFloatToPrecision(craftMaxMass, craftMaxMass < 50.0F ? 1 : 0, 3) + " kg"; - } - if (craftMaxPassengers >= 0 && craftMaxMass != 0) { description += (craftMaxPassengers == 0) ? "\nNO PASSENGER SPACE!" : "\nMax Passengers: " + std::to_string(craftMaxPassengers); } - } else { + if (pItem && pItem->m_pEntity) { + description = ((pItem->m_pEntity->GetDescription().empty()) ? "-No Information Found-" : pItem->m_pEntity->GetDescription()) + "\n"; + const Entity* currentItem = pItem->m_pEntity; + const ACraft* itemAsCraft = dynamic_cast(currentItem); + if (itemAsCraft) { + int craftMaxPassengers = itemAsCraft->GetMaxPassengers(); + float craftMaxMass = itemAsCraft->GetMaxInventoryMass(); + if (craftMaxMass == 0) { + description += "\nNO CARGO SPACE!"; + } else if (craftMaxMass > 0) { + description += "\nMax Mass: " + RoundFloatToPrecision(craftMaxMass, craftMaxMass < 50.0F ? 1 : 0, 3) + " kg"; + } + if (craftMaxPassengers >= 0 && craftMaxMass != 0) { + description += (craftMaxPassengers == 0) ? "\nNO PASSENGER SPACE!" : "\nMax Passengers: " + std::to_string(craftMaxPassengers); + } + } else { // Items in the BuyMenu always have any remainder rounded up in their masses. - const Actor *itemAsActor = dynamic_cast(currentItem); - if (itemAsActor) { + const Actor* itemAsActor = dynamic_cast(currentItem); + if (itemAsActor) { description += "\nMass: " + (itemAsActor->GetMass() < 0.1F ? "<0.1 kg" : RoundFloatToPrecision(itemAsActor->GetMass(), itemAsActor->GetMass() < 50.0F ? 1 : 0, 3) + " kg"); - int passengerSlotsTaken = itemAsActor->GetPassengerSlots(); - if (passengerSlotsTaken > 1) { - description += "\nPassenger Slots: " + std::to_string(passengerSlotsTaken); - } - } else { - const MovableObject *itemAsMO = dynamic_cast(currentItem); - if (itemAsMO) { - const MOSRotating *itemAsMOSRotating = dynamic_cast(currentItem); + int passengerSlotsTaken = itemAsActor->GetPassengerSlots(); + if (passengerSlotsTaken > 1) { + description += "\nPassenger Slots: " + std::to_string(passengerSlotsTaken); + } + } else { + const MovableObject* itemAsMO = dynamic_cast(currentItem); + if (itemAsMO) { + const MOSRotating* itemAsMOSRotating = dynamic_cast(currentItem); float extraMass = 0; if (itemAsMOSRotating) { if (itemAsMOSRotating->NumberValueExists("Grenade Count")) { @@ -1412,36 +1307,36 @@ void BuyMenuGUI::Update() extraMass = itemAsMOSRotating->GetNumberValue("Belt Mass"); } } - description += "\nMass: " + (itemAsMO->GetMass() + extraMass < 0.1F ? "<0.1 kg" : RoundFloatToPrecision(itemAsMO->GetMass() + extraMass, itemAsMO->GetMass() + extraMass < 50.0F ? 1 : 0, 3) + " kg"); - } - } - } - } else if (pItem && pItem->m_ExtraIndex >= 0) { - const DataModule *pModule = g_PresetMan.GetDataModule(pItem->m_ExtraIndex); - if (pModule && !pModule->GetDescription().empty()) { - description = pModule->GetDescription(); - } - } + description += "\nMass: " + (itemAsMO->GetMass() + extraMass < 0.1F ? "<0.1 kg" : RoundFloatToPrecision(itemAsMO->GetMass() + extraMass, itemAsMO->GetMass() + extraMass < 50.0F ? 1 : 0, 3) + " kg"); + } + } + } + } else if (pItem && pItem->m_ExtraIndex >= 0) { + const DataModule* pModule = g_PresetMan.GetDataModule(pItem->m_ExtraIndex); + if (pModule && !pModule->GetDescription().empty()) { + description = pModule->GetDescription(); + } + } - // Show popup info box next to selected item if it has a description or tooltip. - if (!description.empty()) { - // Show the popup box with the hovered item's description - m_pPopupBox->SetVisible(true); - // Need to add an offset to make it look better and not have the cursor obscure text - m_pPopupBox->SetPositionAbs(m_pShopList->GetXPos() - 6 + m_pShopList->GetWidth(), m_pShopList->GetYPos() + m_pShopList->GetStackHeight(pItem) - m_pShopList->GetScrollVerticalValue()); - // Make sure the popup box doesn't drop out of sight - if (m_pPopupBox->GetYPos() + m_pPopupBox->GetHeight() > m_pParentBox->GetHeight()) - m_pPopupBox->SetPositionAbs(m_pPopupBox->GetXPos(), m_pParentBox->GetHeight() - m_pPopupBox->GetHeight()); - m_pPopupText->SetHAlignment(GUIFont::Left); - m_pPopupText->SetText(description); - // Resize the box height to fit the text - int newHeight = m_pPopupText->ResizeHeightToFit(); - m_pPopupBox->Resize(m_pPopupBox->GetWidth(), newHeight + 10); - } + // Show popup info box next to selected item if it has a description or tooltip. + if (!description.empty()) { + // Show the popup box with the hovered item's description + m_pPopupBox->SetVisible(true); + // Need to add an offset to make it look better and not have the cursor obscure text + m_pPopupBox->SetPositionAbs(m_pShopList->GetXPos() - 6 + m_pShopList->GetWidth(), m_pShopList->GetYPos() + m_pShopList->GetStackHeight(pItem) - m_pShopList->GetScrollVerticalValue()); + // Make sure the popup box doesn't drop out of sight + if (m_pPopupBox->GetYPos() + m_pPopupBox->GetHeight() > m_pParentBox->GetHeight()) + m_pPopupBox->SetPositionAbs(m_pPopupBox->GetXPos(), m_pParentBox->GetHeight() - m_pPopupBox->GetHeight()); + m_pPopupText->SetHAlignment(GUIFont::Left); + m_pPopupText->SetText(description); + // Resize the box height to fit the text + int newHeight = m_pPopupText->ResizeHeightToFit(); + m_pPopupBox->Resize(m_pPopupBox->GetWidth(), newHeight + 10); + } - // User selected to add an item to cart list! - if (m_pController->IsState(PRESS_FACEBUTTON)) { - // User pressed on a module group item; toggle its expansion! + // User selected to add an item to cart list! + if (m_pController->IsState(PRESS_FACEBUTTON)) { + // User pressed on a module group item; toggle its expansion! if (pItem && pItem->m_ExtraIndex >= 0) { // Make appropriate sound if (!m_aExpandedModules[pItem->m_ExtraIndex]) { @@ -1455,159 +1350,154 @@ void BuyMenuGUI::Update() // Re-populate the item list with the new module expansion configuation CategoryChange(false); } - // User pressed on a loadout set, so load it into the menu - else if (pItem && m_MenuCategory == SETS) { - // Beep if there's an error - if (!DeployLoadout(m_ListItemIndex)) - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - // User mashed button on a regular shop item, add it to cargo, or select craft - else if (pItem && pItem->m_pEntity) - { - // Select the craft - if (m_MenuCategory == CRAFT) - { - if (m_pSelectedCraft = dynamic_cast(pItem->m_pEntity)) - { - m_pCraftBox->SetText(pItem->m_Name); - m_pCraftBox->SetRightText(pItem->m_RightText); + // User pressed on a loadout set, so load it into the menu + else if (pItem && m_MenuCategory == SETS) { + // Beep if there's an error + if (!DeployLoadout(m_ListItemIndex)) + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + // User mashed button on a regular shop item, add it to cargo, or select craft + else if (pItem && pItem->m_pEntity) { + // Select the craft + if (m_MenuCategory == CRAFT) { + if (m_pSelectedCraft = dynamic_cast(pItem->m_pEntity)) { + m_pCraftBox->SetText(pItem->m_Name); + m_pCraftBox->SetRightText(pItem->m_RightText); m_pCraftNameLabel->SetText(pItem->m_Name); m_pCraftPriceLabel->SetText(pItem->m_RightText); - UpdateTotalPassengersLabel(dynamic_cast(pItem->m_pEntity), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(pItem->m_pEntity), m_pCraftMassLabel); + UpdateTotalPassengersLabel(dynamic_cast(pItem->m_pEntity), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(pItem->m_pEntity), m_pCraftMassLabel); } - } - // Regular ship inventory - else - { - // Gotto make a copy of the bitmap to pass it to the next list - GUIBitmap *pItemBitmap = new AllegroBitmap(dynamic_cast(pItem->m_pBitmap)->GetBitmap()); - AddCartItem(pItem->m_Name, pItem->m_RightText, pItemBitmap, pItem->m_pEntity); - // If I just selected an AHuman, enable equipment selection mode - if (m_MenuCategory == BODIES && pItem->m_pEntity->GetClassName() == "AHuman") - { - EnableEquipmentSelection(true); - } - } - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - } - - UpdateTotalCostLabel(m_pController->GetTeam()); - - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); - } - } + } + // Regular ship inventory + else { + // Gotto make a copy of the bitmap to pass it to the next list + GUIBitmap* pItemBitmap = new AllegroBitmap(dynamic_cast(pItem->m_pBitmap)->GetBitmap()); + AddCartItem(pItem->m_Name, pItem->m_RightText, pItemBitmap, pItem->m_pEntity); + // If I just selected an AHuman, enable equipment selection mode + if (m_MenuCategory == BODIES && pItem->m_pEntity->GetClassName() == "AHuman") { + EnableEquipmentSelection(true); + } + } + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + } - ///////////////////////////////////////// - // CART/ORDER LIST focus - - else if (m_MenuFocus == ORDER) { - // Changed to the list, so select the top one in the item list - if (m_FocusChange) { - m_pCartList->SetFocus(); - if (!m_pCartList->GetItemList()->empty() && m_pCartList->GetSelectedIndex() < 0) { - m_pCartList->SetSelectedIndex(m_ListItemIndex = 0); - // Synch our index with the one already selected in the list - } else { - m_ListItemIndex = m_pCartList->GetSelectedIndex(); - m_pCartList->ScrollToSelected(); - } - - m_FocusChange = 0; - } + UpdateTotalCostLabel(m_pController->GetTeam()); + + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + } + } + + ///////////////////////////////////////// + // CART/ORDER LIST focus + + else if (m_MenuFocus == ORDER) { + // Changed to the list, so select the top one in the item list + if (m_FocusChange) { + m_pCartList->SetFocus(); + if (!m_pCartList->GetItemList()->empty() && m_pCartList->GetSelectedIndex() < 0) { + m_pCartList->SetSelectedIndex(m_ListItemIndex = 0); + // Synch our index with the one already selected in the list + } else { + m_ListItemIndex = m_pCartList->GetSelectedIndex(); + m_pCartList->ScrollToSelected(); + } + + m_FocusChange = 0; + } - bool itemsChanged = false; - - int listSize = m_pCartList->GetItemList()->size(); - if (m_DraggedItemIndex != -1) { - if (pressDown && m_DraggedItemIndex < listSize - 1) { - m_IsDragging = true; - itemsChanged = true; - std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex], (*m_pCartList->GetItemList())[m_DraggedItemIndex + 1]); - std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex + 1]->m_ID, (*m_pCartList->GetItemList())[m_DraggedItemIndex]->m_ID); - m_ListItemIndex = ++m_DraggedItemIndex; - m_pCartList->SetSelectedIndex(m_ListItemIndex); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } else if (pressUp && m_DraggedItemIndex > 0) { - m_IsDragging = true; - itemsChanged = true; - std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex], (*m_pCartList->GetItemList())[m_DraggedItemIndex - 1]); - std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex - 1]->m_ID, (*m_pCartList->GetItemList())[m_DraggedItemIndex]->m_ID); - m_ListItemIndex = --m_DraggedItemIndex; - m_pCartList->SetSelectedIndex(m_ListItemIndex); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - } else { - if (pressDown) { - m_ListItemIndex++; - if (m_ListItemIndex >= listSize) { - m_ListItemIndex = listSize - 1; - // If at the end of the list and the player presses down, then switch focus to the BUY button. - m_FocusChange = 1; - m_MenuFocus = OK; - } else { - // Only do list change logic if we actually did change. - m_pCartList->SetSelectedIndex(m_ListItemIndex); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - } else if (pressUp) { - m_ListItemIndex--; - if (m_ListItemIndex < 0) { - m_ListItemIndex = 0; + bool itemsChanged = false; + + int listSize = m_pCartList->GetItemList()->size(); + if (m_DraggedItemIndex != -1) { + if (pressDown && m_DraggedItemIndex < listSize - 1) { + m_IsDragging = true; + itemsChanged = true; + std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex], (*m_pCartList->GetItemList())[m_DraggedItemIndex + 1]); + std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex + 1]->m_ID, (*m_pCartList->GetItemList())[m_DraggedItemIndex]->m_ID); + m_ListItemIndex = ++m_DraggedItemIndex; + m_pCartList->SetSelectedIndex(m_ListItemIndex); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } else if (pressUp && m_DraggedItemIndex > 0) { + m_IsDragging = true; + itemsChanged = true; + std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex], (*m_pCartList->GetItemList())[m_DraggedItemIndex - 1]); + std::swap((*m_pCartList->GetItemList())[m_DraggedItemIndex - 1]->m_ID, (*m_pCartList->GetItemList())[m_DraggedItemIndex]->m_ID); + m_ListItemIndex = --m_DraggedItemIndex; + m_pCartList->SetSelectedIndex(m_ListItemIndex); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + } else { + if (pressDown) { + m_ListItemIndex++; + if (m_ListItemIndex >= listSize) { + m_ListItemIndex = listSize - 1; + // If at the end of the list and the player presses down, then switch focus to the BUY button. + m_FocusChange = 1; + m_MenuFocus = OK; + } else { + // Only do list change logic if we actually did change. + m_pCartList->SetSelectedIndex(m_ListItemIndex); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + } else if (pressUp) { + m_ListItemIndex--; + if (m_ListItemIndex < 0) { + m_ListItemIndex = 0; // If at the top of the list and the player presses up, then switch focus to the CLEAR button. m_FocusChange = 1; m_MenuFocus = MenuFocus::CLEARORDER; - } else { - // Only do list change logic if we actually did change. - m_pCartList->SetSelectedIndex(m_ListItemIndex); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - } - } + } else { + // Only do list change logic if we actually did change. + m_pCartList->SetSelectedIndex(m_ListItemIndex); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + } + } - // Get handle to the currently selected item, if any - GUIListPanel::Item *pItem = m_pCartList->GetItem(m_ListItemIndex); - std::string description = ""; + // Get handle to the currently selected item, if any + GUIListPanel::Item* pItem = m_pCartList->GetItem(m_ListItemIndex); + std::string description = ""; - if (pItem && pItem->m_pEntity) { + if (pItem && pItem->m_pEntity) { description = ((pItem->m_pEntity->GetDescription().empty()) ? "-No Information Found-" : pItem->m_pEntity->GetDescription()) + "\n"; - const Entity *currentItem = pItem->m_pEntity; - const Actor *itemAsActor = dynamic_cast(currentItem); - if (itemAsActor) { + const Entity* currentItem = pItem->m_pEntity; + const Actor* itemAsActor = dynamic_cast(currentItem); + if (itemAsActor) { description += "\nMass: " + (itemAsActor->GetMass() < 0.1F ? "<0.1 kg" : RoundFloatToPrecision(itemAsActor->GetMass(), itemAsActor->GetMass() < 50.0F ? 1 : 0, 3) + " kg"); - int passengerSlotsTaken = itemAsActor->GetPassengerSlots(); - if (passengerSlotsTaken > 1) { - description += "\nPassenger Slots: " + std::to_string(passengerSlotsTaken); - } - } else { - const MovableObject *itemAsMO = dynamic_cast(currentItem); - if (itemAsMO) { + int passengerSlotsTaken = itemAsActor->GetPassengerSlots(); + if (passengerSlotsTaken > 1) { + description += "\nPassenger Slots: " + std::to_string(passengerSlotsTaken); + } + } else { + const MovableObject* itemAsMO = dynamic_cast(currentItem); + if (itemAsMO) { description += "\nMass: " + (itemAsMO->GetMass() < 0.1F ? "<0.1 kg" : RoundFloatToPrecision(itemAsMO->GetMass(), itemAsMO->GetMass() < 50.0F ? 1 : 0, 3) + " kg"); - } - } - } + } + } + } - if (!description.empty()) { - // Show the popup box with the hovered item's description - m_pPopupBox->SetVisible(true); - // Need to add an offset to make it look better and not have the cursor obscure text - m_pPopupBox->SetPositionAbs(m_pCartList->GetXPos() - m_pPopupBox->GetWidth() + 4, m_pCartList->GetYPos() + m_pCartList->GetStackHeight(pItem) - m_pCartList->GetScrollVerticalValue()); - // Make sure the popup box doesn't drop out of sight - if (m_pPopupBox->GetYPos() + m_pPopupBox->GetHeight() > m_pParentBox->GetHeight()) - m_pPopupBox->SetPositionAbs(m_pPopupBox->GetXPos(), m_pParentBox->GetHeight() - m_pPopupBox->GetHeight()); - m_pPopupText->SetHAlignment(GUIFont::Right); - m_pPopupText->SetText(description); - // Resize the box height to fit the text - int newHeight = m_pPopupText->ResizeHeightToFit(); - m_pPopupBox->Resize(m_pPopupBox->GetWidth(), newHeight + 10); - } + if (!description.empty()) { + // Show the popup box with the hovered item's description + m_pPopupBox->SetVisible(true); + // Need to add an offset to make it look better and not have the cursor obscure text + m_pPopupBox->SetPositionAbs(m_pCartList->GetXPos() - m_pPopupBox->GetWidth() + 4, m_pCartList->GetYPos() + m_pCartList->GetStackHeight(pItem) - m_pCartList->GetScrollVerticalValue()); + // Make sure the popup box doesn't drop out of sight + if (m_pPopupBox->GetYPos() + m_pPopupBox->GetHeight() > m_pParentBox->GetHeight()) + m_pPopupBox->SetPositionAbs(m_pPopupBox->GetXPos(), m_pParentBox->GetHeight() - m_pPopupBox->GetHeight()); + m_pPopupText->SetHAlignment(GUIFont::Right); + m_pPopupText->SetText(description); + // Resize the box height to fit the text + int newHeight = m_pPopupText->ResizeHeightToFit(); + m_pPopupBox->Resize(m_pPopupBox->GetWidth(), newHeight + 10); + } - // Fire button removes items from the order list, including equipment on AHumans + // Fire button removes items from the order list, including equipment on AHumans bool isKeyboardControlled = !m_pController->IsMouseControlled() && !m_pController->IsGamepadControlled(); - if (isKeyboardControlled ? (m_pController->IsState(PRESS_FACEBUTTON) && !m_pController->IsState(AIM_SHARP)) : (m_pController->IsState(RELEASE_FACEBUTTON) && !m_IsDragging)) { + if (isKeyboardControlled ? (m_pController->IsState(PRESS_FACEBUTTON) && !m_pController->IsState(AIM_SHARP)) : (m_pController->IsState(RELEASE_FACEBUTTON) && !m_IsDragging)) { if (g_UInputMan.FlagShiftState()) { ClearCartList(); pItem = nullptr; @@ -1616,12 +1506,13 @@ void BuyMenuGUI::Update() if (pItem && pItem->m_pEntity && pItem->m_pEntity->GetClassName() == "AHuman" && g_SettingsMan.SmartBuyMenuNavigationEnabled()) { int lastItemToDelete = m_pCartList->GetItemList()->size() - 1; for (int i = m_ListItemIndex + 1; i != m_pCartList->GetItemList()->size(); i++) { - GUIListPanel::Item *cartItem = m_pCartList->GetItem(i); - if (dynamic_cast(cartItem->m_pEntity)) { + GUIListPanel::Item* cartItem = m_pCartList->GetItem(i); + if (dynamic_cast(cartItem->m_pEntity)) { lastItemToDelete = i - 1; break; } - } for (int i = lastItemToDelete; i > m_ListItemIndex; i--) { + } + for (int i = lastItemToDelete; i > m_ListItemIndex; i--) { m_pCartList->DeleteItem(i); } } @@ -1637,422 +1528,381 @@ void BuyMenuGUI::Update() m_MenuFocus = ORDER; } } - } else if (m_pController->IsState(WEAPON_PICKUP)) { - itemsChanged = true; - DuplicateCartItem(m_ListItemIndex); - } + } else if (m_pController->IsState(WEAPON_PICKUP)) { + itemsChanged = true; + DuplicateCartItem(m_ListItemIndex); + } - if (isKeyboardControlled ? m_pController->IsState(AIM_SHARP) : m_pController->IsState(PRESS_FACEBUTTON)) { - m_DraggedItemIndex = m_pCartList->GetSelectedIndex(); - } else if (m_pController->IsState(RELEASE_FACEBUTTON)) { - m_DraggedItemIndex = -1; - m_IsDragging = false; - } + if (isKeyboardControlled ? m_pController->IsState(AIM_SHARP) : m_pController->IsState(PRESS_FACEBUTTON)) { + m_DraggedItemIndex = m_pCartList->GetSelectedIndex(); + } else if (m_pController->IsState(RELEASE_FACEBUTTON)) { + m_DraggedItemIndex = -1; + m_IsDragging = false; + } - if (itemsChanged) { - UpdateTotalCostLabel(m_pController->GetTeam()); - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + if (itemsChanged) { + UpdateTotalCostLabel(m_pController->GetTeam()); + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); - UpdateItemNestingLevels(); + UpdateItemNestingLevels(); - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - } - } + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + } + } ///////////////////////////////////////// // ORDER CLEAR BUTTON focus - else if (m_MenuFocus == MenuFocus::CLEARORDER) { - if (m_FocusChange) { - m_ClearOrderButton->SetFocus(); - m_FocusChange = 0; - } - if (m_pController->IsState(ControlState::PRESS_FACEBUTTON)) { - ClearCartList(); - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - } - // Switch back focus to the order list if the player presses down - if (pressDown) { - m_MenuFocus = MenuFocus::ORDER; - m_FocusChange = -1; - } else if (pressUp) { - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - } - - ///////////////////////////////////////// - // OK BUTTON focus + else if (m_MenuFocus == MenuFocus::CLEARORDER) { + if (m_FocusChange) { + m_ClearOrderButton->SetFocus(); + m_FocusChange = 0; + } + if (m_pController->IsState(ControlState::PRESS_FACEBUTTON)) { + ClearCartList(); + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + } + // Switch back focus to the order list if the player presses down + if (pressDown) { + m_MenuFocus = MenuFocus::ORDER; + m_FocusChange = -1; + } else if (pressUp) { + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + } - else if (m_MenuFocus == OK) - { - if (m_FocusChange) - { - m_pBuyButton->SetFocus(); - m_FocusChange = 0; - } + ///////////////////////////////////////// + // OK BUTTON focus - if (m_pController->IsState(PRESS_FACEBUTTON)) - { - // Attempt to do the purchase - TryPurchase(); - } + else if (m_MenuFocus == OK) { + if (m_FocusChange) { + m_pBuyButton->SetFocus(); + m_FocusChange = 0; + } - // Switch back focus to the order list if the player presses up - if (pressUp) - { - m_MenuFocus = ORDER; - m_FocusChange = -1; - } - else if (pressDown) - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } + if (m_pController->IsState(PRESS_FACEBUTTON)) { + // Attempt to do the purchase + TryPurchase(); + } - if (m_MenuEnabled == ENABLED) { - if (m_pController->IsState(WEAPON_RELOAD)) { - TryPurchase(); - } else if (m_pController->IsMouseControlled() && (m_pController->IsState(PRESS_PRIMARY) || m_pController->IsState(PRESS_SECONDARY)) && mousePosX > m_pParentBox->GetWidth()) { - if (m_pController->IsState(PRESS_PRIMARY)) { - TryPurchase(); - } else { - SetEnabled(false); - } - } else if (m_pController->IsState(PRESS_SECONDARY) || g_UInputMan.AnyStartPress(false)) { - if (m_SelectingEquipment) { - EnableEquipmentSelection(false); - } else { - SetEnabled(false); - } - } - } + // Switch back focus to the order list if the player presses up + if (pressUp) { + m_MenuFocus = ORDER; + m_FocusChange = -1; + } else if (pressDown) + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + + if (m_MenuEnabled == ENABLED) { + if (m_pController->IsState(WEAPON_RELOAD)) { + TryPurchase(); + } else if (m_pController->IsMouseControlled() && (m_pController->IsState(PRESS_PRIMARY) || m_pController->IsState(PRESS_SECONDARY)) && mousePosX > m_pParentBox->GetWidth()) { + if (m_pController->IsState(PRESS_PRIMARY)) { + TryPurchase(); + } else { + SetEnabled(false); + } + } else if (m_pController->IsState(PRESS_SECONDARY) || g_UInputMan.AnyStartPress(false)) { + if (m_SelectingEquipment) { + EnableEquipmentSelection(false); + } else { + SetEnabled(false); + } + } + } - ////////////////////////////////////////// + ////////////////////////////////////////// // Update the ControlManager m_pGUIController->Update(); - - /////////////////////////////////////// - // Handle events + /////////////////////////////////////// + // Handle events GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { - if (anEvent.GetType() == GUIEvent::Command) - { - // SAVE button clicks - if(anEvent.GetControl() == m_pSaveButton) - { - m_pSaveButton->SetFocus(); - SaveCurrentLoadout(); - m_MenuFocus = SETBUTTONS; -// m_FocusChange = -1; - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + while (m_pGUIController->GetEvent(&anEvent)) { + if (anEvent.GetType() == GUIEvent::Command) { + // SAVE button clicks + if (anEvent.GetControl() == m_pSaveButton) { + m_pSaveButton->SetFocus(); + SaveCurrentLoadout(); + m_MenuFocus = SETBUTTONS; + // m_FocusChange = -1; + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); } - // CLEAR button clicks - if(anEvent.GetControl() == m_pClearButton) - { - m_pClearButton->SetFocus(); + // CLEAR button clicks + if (anEvent.GetControl() == m_pClearButton) { + m_pClearButton->SetFocus(); if (!m_Loadouts.empty()) m_Loadouts.pop_back(); - // Update the list of loadout presets so the removal shows up - CategoryChange(); - // Save new loadout config to file - SaveAllLoadoutsToFile(); - // Set focus back on the clear button (CatChange changed it) - m_pClearButton->SetFocus(); - m_MenuFocus = SETBUTTONS; -// m_FocusChange = -1; - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + // Update the list of loadout presets so the removal shows up + CategoryChange(); + // Save new loadout config to file + SaveAllLoadoutsToFile(); + // Set focus back on the clear button (CatChange changed it) + m_pClearButton->SetFocus(); + m_MenuFocus = SETBUTTONS; + // m_FocusChange = -1; + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); } - // BUY button clicks - if(anEvent.GetControl() == m_pBuyButton) - { - m_pBuyButton->SetFocus(); - TryPurchase(); -// g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + // BUY button clicks + if (anEvent.GetControl() == m_pBuyButton) { + m_pBuyButton->SetFocus(); + TryPurchase(); + // g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); } if (anEvent.GetControl() == m_ClearOrderButton) { ClearCartList(); g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); } - } - else if (anEvent.GetType() == GUIEvent::Notification) - { - ////////////////////////////////////////// + } else if (anEvent.GetType() == GUIEvent::Notification) { + ////////////////////////////////////////// // Clicks on any of the category tabs - for (int cat = 0; cat < CATEGORYCOUNT; ++cat) - { - if(anEvent.GetControl() == m_pCategoryTabs[cat]) - { - // Mouse hovering over - if(anEvent.GetMsg() == GUITab::Hovered) - { - // Just give focus to the categories column - m_MenuFocus = CATEGORIES; - m_pCategoryTabs[cat]->SetFocus(); - } - // Regular click - if(anEvent.GetMsg() == GUITab::Pushed) - { - m_MenuFocus = CATEGORIES; - m_MenuCategory = cat; - m_pCategoryTabs[m_MenuCategory]->SetFocus(); - CategoryChange(); - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - } - } - - ////////////////////////////////////////// + for (int cat = 0; cat < CATEGORYCOUNT; ++cat) { + if (anEvent.GetControl() == m_pCategoryTabs[cat]) { + // Mouse hovering over + if (anEvent.GetMsg() == GUITab::Hovered) { + // Just give focus to the categories column + m_MenuFocus = CATEGORIES; + m_pCategoryTabs[cat]->SetFocus(); + } + // Regular click + if (anEvent.GetMsg() == GUITab::Pushed) { + m_MenuFocus = CATEGORIES; + m_MenuCategory = cat; + m_pCategoryTabs[m_MenuCategory]->SetFocus(); + CategoryChange(); + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + } + } + + ////////////////////////////////////////// // Events on the Shop List - if(anEvent.GetControl() == m_pShopList) - { - if (anEvent.GetMsg() == GUIListBox::MouseDown && (anEvent.GetData() & GUIListBox::MOUSE_LEFT)) - { - m_pShopList->SetFocus(); - m_MenuFocus = ITEMS; - - GUIListPanel::Item *pItem = m_pShopList->GetItem(mousePosX, mousePosY); - - // If a module group list item, toggle its expansion and update the list - if (pItem && pItem->m_ExtraIndex >= 0) - { - // Make appropriate sound - if (!m_aExpandedModules[pItem->m_ExtraIndex]) - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - // Different, maybe? - else - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - // Toggle the expansion of the module group item's items below - m_aExpandedModules[pItem->m_ExtraIndex] = !m_aExpandedModules[pItem->m_ExtraIndex]; - // Re-populate the item list with the new module expansion configuation - CategoryChange(false); - } - // Special case: user clicked on a loadout set, so load it into the menu - else if (pItem && m_MenuCategory == SETS) - { - // Beep if there's an error - if (!DeployLoadout(m_ListItemIndex)) - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - // Normal: only add an item if there's an entity attached to the list item - else if (pItem && pItem->m_pEntity) - { - m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex = m_pShopList->GetSelectedIndex(); - m_pShopList->ScrollToSelected(); - - // Select the craft - if (m_MenuCategory == CRAFT) - { - if (m_pSelectedCraft = dynamic_cast(pItem->m_pEntity)) - { - m_pCraftBox->SetText(pItem->m_Name); - m_pCraftBox->SetRightText(pItem->m_RightText); + if (anEvent.GetControl() == m_pShopList) { + if (anEvent.GetMsg() == GUIListBox::MouseDown && (anEvent.GetData() & GUIListBox::MOUSE_LEFT)) { + m_pShopList->SetFocus(); + m_MenuFocus = ITEMS; + + GUIListPanel::Item* pItem = m_pShopList->GetItem(mousePosX, mousePosY); + + // If a module group list item, toggle its expansion and update the list + if (pItem && pItem->m_ExtraIndex >= 0) { + // Make appropriate sound + if (!m_aExpandedModules[pItem->m_ExtraIndex]) + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + // Different, maybe? + else + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + // Toggle the expansion of the module group item's items below + m_aExpandedModules[pItem->m_ExtraIndex] = !m_aExpandedModules[pItem->m_ExtraIndex]; + // Re-populate the item list with the new module expansion configuation + CategoryChange(false); + } + // Special case: user clicked on a loadout set, so load it into the menu + else if (pItem && m_MenuCategory == SETS) { + // Beep if there's an error + if (!DeployLoadout(m_ListItemIndex)) + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + // Normal: only add an item if there's an entity attached to the list item + else if (pItem && pItem->m_pEntity) { + m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex = m_pShopList->GetSelectedIndex(); + m_pShopList->ScrollToSelected(); + + // Select the craft + if (m_MenuCategory == CRAFT) { + if (m_pSelectedCraft = dynamic_cast(pItem->m_pEntity)) { + m_pCraftBox->SetText(pItem->m_Name); + m_pCraftBox->SetRightText(pItem->m_RightText); m_pCraftNameLabel->SetText(pItem->m_Name); m_pCraftPriceLabel->SetText(pItem->m_RightText); - UpdateTotalPassengersLabel(dynamic_cast(pItem->m_pEntity), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(pItem->m_pEntity), m_pCraftMassLabel); + UpdateTotalPassengersLabel(dynamic_cast(pItem->m_pEntity), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(pItem->m_pEntity), m_pCraftMassLabel); } - } - // Regular ship inventory - else - { - // Gotto make a copy of the bitmap to pass it to the next list - GUIBitmap *pItemBitmap = new AllegroBitmap(dynamic_cast(pItem->m_pBitmap)->GetBitmap()); - - if (m_OwnedItems.size() > 0 || m_OnlyShowOwnedItems) - { - if (GetOwnedItemsAmount(pItem->m_pEntity->GetModuleAndPresetName()) > 0) - { + } + // Regular ship inventory + else { + // Gotto make a copy of the bitmap to pass it to the next list + GUIBitmap* pItemBitmap = new AllegroBitmap(dynamic_cast(pItem->m_pBitmap)->GetBitmap()); + + if (m_OwnedItems.size() > 0 || m_OnlyShowOwnedItems) { + if (GetOwnedItemsAmount(pItem->m_pEntity->GetModuleAndPresetName()) > 0) { AddCartItem(pItem->m_Name, "1 pc", pItemBitmap, pItem->m_pEntity); - } - else - { - if (m_OnlyShowOwnedItems) - { + } else { + if (m_OnlyShowOwnedItems) { if (IsAlwaysAllowedItem(pItem->m_Name)) AddCartItem(pItem->m_Name, pItem->m_RightText, pItemBitmap, pItem->m_pEntity); - } - else - { + } else { AddCartItem(pItem->m_Name, pItem->m_RightText, pItemBitmap, pItem->m_pEntity); } } - } - else - { + } else { AddCartItem(pItem->m_Name, pItem->m_RightText, pItemBitmap, pItem->m_pEntity); } - // If I just selected an AHuman, enable equipment selection mode - if (m_MenuCategory == BODIES && pItem->m_pEntity->GetClassName() == "AHuman") - { - EnableEquipmentSelection(true); - } - } - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - } - // Undo the click deselection if nothing was selected -// else -// m_pShopList->SetSelectedIndex(m_SelectedObjectIndex); - - UpdateTotalCostLabel(m_pController->GetTeam()); - - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + // If I just selected an AHuman, enable equipment selection mode + if (m_MenuCategory == BODIES && pItem->m_pEntity->GetClassName() == "AHuman") { + EnableEquipmentSelection(true); + } + } + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + } + // Undo the click deselection if nothing was selected + // else + // m_pShopList->SetSelectedIndex(m_SelectedObjectIndex); + + UpdateTotalCostLabel(m_pController->GetTeam()); + + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); } - // Mouse moved over the panel, show the popup with item description - else if(anEvent.GetMsg() == GUIListBox::MouseMove) - { - // Mouse is moving within the list, so make it focus on the list - m_pShopList->SetFocus(); - m_MenuFocus = ITEMS; - - // See if it's hovering over any item - GUIListPanel::Item *pItem = m_pShopList->GetItem(mousePosX, mousePosY); - if (pItem) - { - // Don't let mouse movement change the index if it's still hovering inside the same item. - // This is to avoid erratic selection curosr if using both mouse and keyboard to work the menu - if (m_LastHoveredMouseIndex != pItem->m_ID) - { - m_LastHoveredMouseIndex = pItem->m_ID; - - // Play select sound if new index - if (m_ListItemIndex != pItem->m_ID) - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - // Update the seleciton in both the GUI control and our menu - m_pShopList->SetSelectedIndex(m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex = pItem->m_ID); - } - } - } - } - - /////////////////////////////////////////////// - // Events on the Cart List - - else if (anEvent.GetControl() == m_pCartList) - { - if (anEvent.GetMsg() == GUIListBox::MouseUp && !m_IsDragging) { - GUIListPanel::Item *pItem = m_pCartList->GetSelected(); - if (pItem) - { - if (anEvent.GetData() & GUIListBox::MOUSE_LEFT) { - //TODO in future it would be nice to add the concept of a modifier key to Controller, so we can do this for gamepad inputs as well. + // Mouse moved over the panel, show the popup with item description + else if (anEvent.GetMsg() == GUIListBox::MouseMove) { + // Mouse is moving within the list, so make it focus on the list + m_pShopList->SetFocus(); + m_MenuFocus = ITEMS; + + // See if it's hovering over any item + GUIListPanel::Item* pItem = m_pShopList->GetItem(mousePosX, mousePosY); + if (pItem) { + // Don't let mouse movement change the index if it's still hovering inside the same item. + // This is to avoid erratic selection curosr if using both mouse and keyboard to work the menu + if (m_LastHoveredMouseIndex != pItem->m_ID) { + m_LastHoveredMouseIndex = pItem->m_ID; + + // Play select sound if new index + if (m_ListItemIndex != pItem->m_ID) + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + // Update the seleciton in both the GUI control and our menu + m_pShopList->SetSelectedIndex(m_CategoryItemIndex[m_MenuCategory] = m_ListItemIndex = pItem->m_ID); + } + } + } + } + + /////////////////////////////////////////////// + // Events on the Cart List + + else if (anEvent.GetControl() == m_pCartList) { + if (anEvent.GetMsg() == GUIListBox::MouseUp && !m_IsDragging) { + GUIListPanel::Item* pItem = m_pCartList->GetSelected(); + if (pItem) { + if (anEvent.GetData() & GUIListBox::MOUSE_LEFT) { + // TODO in future it would be nice to add the concept of a modifier key to Controller, so we can do this for gamepad inputs as well. if (g_UInputMan.FlagShiftState()) { - ClearCartList(); - pItem = nullptr; - } - - if (pItem && pItem->m_pEntity && pItem->m_pEntity->GetClassName() == "AHuman" && g_SettingsMan.SmartBuyMenuNavigationEnabled()) { - int lastItemToDelete = m_pCartList->GetItemList()->size() - 1; - for (int i = m_ListItemIndex + 1; i != m_pCartList->GetItemList()->size(); i++) { - GUIListPanel::Item *cartItem = m_pCartList->GetItem(i); - if (!cartItem || dynamic_cast(cartItem->m_pEntity)) { - lastItemToDelete = i - 1; - break; - } - } for (int i = lastItemToDelete; i > m_ListItemIndex; i--) { - m_pCartList->DeleteItem(i); - } - } - m_pCartList->DeleteItem(m_ListItemIndex); - // If we're not at the bottom, then select the item in the same place as the one just deleted - if (m_pCartList->GetItemList()->size() > m_ListItemIndex) { - m_pCartList->SetSelectedIndex(m_ListItemIndex); - // If we're not at the top, then move selection up one - } else if (m_ListItemIndex > 0) { - m_pCartList->SetSelectedIndex(--m_ListItemIndex); - // Shift focus back to the item list - } else { - m_MenuFocus = ORDER; - } - } else if (anEvent.GetData() & GUIListBox::MOUSE_MIDDLE) { - DuplicateCartItem(m_ListItemIndex); - } - - UpdateTotalCostLabel(m_pController->GetTeam()); - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); - UpdateItemNestingLevels(); - - g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); - } + ClearCartList(); + pItem = nullptr; + } + + if (pItem && pItem->m_pEntity && pItem->m_pEntity->GetClassName() == "AHuman" && g_SettingsMan.SmartBuyMenuNavigationEnabled()) { + int lastItemToDelete = m_pCartList->GetItemList()->size() - 1; + for (int i = m_ListItemIndex + 1; i != m_pCartList->GetItemList()->size(); i++) { + GUIListPanel::Item* cartItem = m_pCartList->GetItem(i); + if (!cartItem || dynamic_cast(cartItem->m_pEntity)) { + lastItemToDelete = i - 1; + break; + } + } + for (int i = lastItemToDelete; i > m_ListItemIndex; i--) { + m_pCartList->DeleteItem(i); + } + } + m_pCartList->DeleteItem(m_ListItemIndex); + // If we're not at the bottom, then select the item in the same place as the one just deleted + if (m_pCartList->GetItemList()->size() > m_ListItemIndex) { + m_pCartList->SetSelectedIndex(m_ListItemIndex); + // If we're not at the top, then move selection up one + } else if (m_ListItemIndex > 0) { + m_pCartList->SetSelectedIndex(--m_ListItemIndex); + // Shift focus back to the item list + } else { + m_MenuFocus = ORDER; + } + } else if (anEvent.GetData() & GUIListBox::MOUSE_MIDDLE) { + DuplicateCartItem(m_ListItemIndex); + } + + UpdateTotalCostLabel(m_pController->GetTeam()); + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + UpdateItemNestingLevels(); + + g_GUISound.ItemChangeSound()->Play(m_pController->GetPlayer()); + } } - // Mouse moved over the panel, show the popup with item description - else if(anEvent.GetMsg() == GUIListBox::MouseMove) - { - // Mouse is moving within the list, so make it focus on the list - m_pCartList->SetFocus(); - m_MenuFocus = ORDER; - - // See if it's hovering over any item - GUIListPanel::Item *pItem = m_pCartList->GetItem(mousePosX, mousePosY); - if (pItem) - { - // Don't let mouse movement change the index if it's still hovering inside the same item. - // This is to avoid erratic selection curosr if using both mouse and keyboard to work the menu - if (m_LastHoveredMouseIndex != pItem->m_ID) { - if (m_DraggedItemIndex != -1 && m_DraggedItemIndex != pItem->m_ID) { - m_IsDragging = true; - int start = std::min(m_DraggedItemIndex, pItem->m_ID); - int end = std::max(m_DraggedItemIndex, pItem->m_ID); - int direction = pItem->m_ID > m_DraggedItemIndex ? 1 : -1; - for (int i = start; i < end; i++) { - int oldIndex = m_DraggedItemIndex; - if (oldIndex + direction < 0 || oldIndex + direction >= m_pCartList->GetItemList()->size()) { - break; - } - - m_DraggedItemIndex = oldIndex + direction; - std::swap((*m_pCartList->GetItemList())[oldIndex], (*m_pCartList->GetItemList())[oldIndex + direction]); - std::swap((*m_pCartList->GetItemList())[oldIndex + direction]->m_ID, (*m_pCartList->GetItemList())[oldIndex]->m_ID); - } - UpdateItemNestingLevels(); - } - - m_LastHoveredMouseIndex = pItem->m_ID; - // Play select sound if new index - if (m_ListItemIndex != pItem->m_ID) { - g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); - } - - // Update the selection in both the GUI control and our menu - m_pCartList->SetSelectedIndex(m_ListItemIndex = pItem->m_ID); - } - } - } - - if (anEvent.GetMsg() == GUIListBox::MouseDown) { - m_pCartList->SetFocus(); - m_MenuFocus = ORDER; - m_ListItemIndex = m_pCartList->GetSelectedIndex(); - m_pCartList->ScrollToSelected(); - if (anEvent.GetData() & GUIListBox::MOUSE_LEFT) { - m_DraggedItemIndex = m_pCartList->GetSelectedIndex(); - } - } - } - - // We do this down here, outside the m_pCartList control, because if we have a mouse-up event even outside the cart, we should stop dragging. We also check UInputMan in case the mouse is released entirely outside of the buy menu. - if ((anEvent.GetMsg() == GUIListBox::MouseUp && (anEvent.GetData() & GUIListBox::MOUSE_LEFT)) || g_UInputMan.MouseButtonReleased(MouseButtons::MOUSE_LEFT, m_pController->GetPlayer())) { - m_DraggedItemIndex = -1; - m_IsDragging = false; - } - } - } + // Mouse moved over the panel, show the popup with item description + else if (anEvent.GetMsg() == GUIListBox::MouseMove) { + // Mouse is moving within the list, so make it focus on the list + m_pCartList->SetFocus(); + m_MenuFocus = ORDER; + + // See if it's hovering over any item + GUIListPanel::Item* pItem = m_pCartList->GetItem(mousePosX, mousePosY); + if (pItem) { + // Don't let mouse movement change the index if it's still hovering inside the same item. + // This is to avoid erratic selection curosr if using both mouse and keyboard to work the menu + if (m_LastHoveredMouseIndex != pItem->m_ID) { + if (m_DraggedItemIndex != -1 && m_DraggedItemIndex != pItem->m_ID) { + m_IsDragging = true; + int start = std::min(m_DraggedItemIndex, pItem->m_ID); + int end = std::max(m_DraggedItemIndex, pItem->m_ID); + int direction = pItem->m_ID > m_DraggedItemIndex ? 1 : -1; + for (int i = start; i < end; i++) { + int oldIndex = m_DraggedItemIndex; + if (oldIndex + direction < 0 || oldIndex + direction >= m_pCartList->GetItemList()->size()) { + break; + } + + m_DraggedItemIndex = oldIndex + direction; + std::swap((*m_pCartList->GetItemList())[oldIndex], (*m_pCartList->GetItemList())[oldIndex + direction]); + std::swap((*m_pCartList->GetItemList())[oldIndex + direction]->m_ID, (*m_pCartList->GetItemList())[oldIndex]->m_ID); + } + UpdateItemNestingLevels(); + } + + m_LastHoveredMouseIndex = pItem->m_ID; + // Play select sound if new index + if (m_ListItemIndex != pItem->m_ID) { + g_GUISound.SelectionChangeSound()->Play(m_pController->GetPlayer()); + } + + // Update the selection in both the GUI control and our menu + m_pCartList->SetSelectedIndex(m_ListItemIndex = pItem->m_ID); + } + } + } + + if (anEvent.GetMsg() == GUIListBox::MouseDown) { + m_pCartList->SetFocus(); + m_MenuFocus = ORDER; + m_ListItemIndex = m_pCartList->GetSelectedIndex(); + m_pCartList->ScrollToSelected(); + if (anEvent.GetData() & GUIListBox::MOUSE_LEFT) { + m_DraggedItemIndex = m_pCartList->GetSelectedIndex(); + } + } + } + + // We do this down here, outside the m_pCartList control, because if we have a mouse-up event even outside the cart, we should stop dragging. We also check UInputMan in case the mouse is released entirely outside of the buy menu. + if ((anEvent.GetMsg() == GUIListBox::MouseUp && (anEvent.GetData() & GUIListBox::MOUSE_LEFT)) || g_UInputMan.MouseButtonReleased(MouseButtons::MOUSE_LEFT, m_pController->GetPlayer())) { + m_DraggedItemIndex = -1; + m_IsDragging = false; + } + } + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void BuyMenuGUI::Draw(BITMAP *drawBitmap) const { +void BuyMenuGUI::Draw(BITMAP* drawBitmap) const { AllegroScreen drawScreen(drawBitmap); m_pGUIController->Draw(&drawScreen); if (IsEnabled() && m_pController->IsMouseControlled()) { @@ -2119,38 +1969,34 @@ void BuyMenuGUI::FocusChange() ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes sure all things that to happen when category is changed, happens. -void BuyMenuGUI::CategoryChange(bool focusOnCategoryTabs) -{ - // Re-set the GUI manager's focus on the tabs if we're supposed to - // We don't want to do that if we're just refreshing the same category, like in the case of of expanding a module group item - if (focusOnCategoryTabs) - { - m_pCategoryTabs[m_MenuCategory]->SetFocus(); - m_pCategoryTabs[m_MenuCategory]->SetCheck(true); - } - m_pShopList->ClearList(); - - // Hide/show the logo and special sets category buttons, and add all current presets to the list, and we're done. - if (m_MenuCategory == SETS) - { - m_Logo->SetVisible(false); - m_pSaveButton->SetVisible(true); - m_pClearButton->SetVisible(true); - // Add and done! - AddPresetsToItemList(); - return; - } - // Hide the sets buttons otherwise - else - { - m_Logo->SetVisible(true); - m_pSaveButton->SetVisible(false); - m_pClearButton->SetVisible(false); - } +void BuyMenuGUI::CategoryChange(bool focusOnCategoryTabs) { + // Re-set the GUI manager's focus on the tabs if we're supposed to + // We don't want to do that if we're just refreshing the same category, like in the case of of expanding a module group item + if (focusOnCategoryTabs) { + m_pCategoryTabs[m_MenuCategory]->SetFocus(); + m_pCategoryTabs[m_MenuCategory]->SetCheck(true); + } + m_pShopList->ClearList(); + + // Hide/show the logo and special sets category buttons, and add all current presets to the list, and we're done. + if (m_MenuCategory == SETS) { + m_Logo->SetVisible(false); + m_pSaveButton->SetVisible(true); + m_pClearButton->SetVisible(true); + // Add and done! + AddPresetsToItemList(); + return; + } + // Hide the sets buttons otherwise + else { + m_Logo->SetVisible(true); + m_pSaveButton->SetVisible(false); + m_pClearButton->SetVisible(false); + } - // The vector of lists which will be filled with catalog objects, grouped by which data module they were read from - std::vector> catalogList; - std::vector mechaCategoryGroups = { "Actors - Mecha", "Actors - Turrets" }; + // The vector of lists which will be filled with catalog objects, grouped by which data module they were read from + std::vector> catalogList; + std::vector mechaCategoryGroups = {"Actors - Mecha", "Actors - Turrets"}; if (m_MenuCategory == CRAFT) { AddObjectsToItemList(catalogList, "ACRocket"); @@ -2162,142 +2008,123 @@ void BuyMenuGUI::CategoryChange(bool focusOnCategoryTabs) AddObjectsToItemList(catalogList, "AHuman", mechaCategoryGroups, false); AddObjectsToItemList(catalogList, "ACrab", mechaCategoryGroups, false); } else if (m_MenuCategory == TOOLS) { - AddObjectsToItemList(catalogList, "HeldDevice", { "Tools" }); + AddObjectsToItemList(catalogList, "HeldDevice", {"Tools"}); } else if (m_MenuCategory == GUNS) { - AddObjectsToItemList(catalogList, "HDFirearm", { "Weapons" }); + AddObjectsToItemList(catalogList, "HDFirearm", {"Weapons"}); } else if (m_MenuCategory == BOMBS) { - AddObjectsToItemList(catalogList, "ThrownDevice", { "Bombs" }); + AddObjectsToItemList(catalogList, "ThrownDevice", {"Bombs"}); } else if (m_MenuCategory == SHIELDS) { - AddObjectsToItemList(catalogList, "HeldDevice", { "Shields" }); + AddObjectsToItemList(catalogList, "HeldDevice", {"Shields"}); } - SceneObject *pSObject = 0; - const DataModule *pModule = 0; - GUIBitmap *pItemBitmap = 0; - std::list tempList; - for (int moduleID = 0; moduleID < catalogList.size(); ++moduleID) - { - // Don't add an empty module grouping - if (!catalogList[moduleID].empty()) - { - tempList.clear(); - - // Move all valid/desired entities from the module list to the intermediate list - for (std::list::iterator oItr = catalogList[moduleID].begin(); oItr != catalogList[moduleID].end(); ++oItr) - { - pSObject = dynamic_cast(*oItr); - // Only add buyable and non-brain items, unless they are explicitly set to be available. + SceneObject* pSObject = 0; + const DataModule* pModule = 0; + GUIBitmap* pItemBitmap = 0; + std::list tempList; + for (int moduleID = 0; moduleID < catalogList.size(); ++moduleID) { + // Don't add an empty module grouping + if (!catalogList[moduleID].empty()) { + tempList.clear(); + + // Move all valid/desired entities from the module list to the intermediate list + for (std::list::iterator oItr = catalogList[moduleID].begin(); oItr != catalogList[moduleID].end(); ++oItr) { + pSObject = dynamic_cast(*oItr); + // Only add buyable and non-brain items, unless they are explicitly set to be available. if ((pSObject && pSObject->IsBuyable() && !pSObject->IsBuyableInObjectPickerOnly() && !pSObject->IsBuyableInScriptOnly() && !pSObject->IsInGroup("Brains")) || GetOwnedItemsAmount((pSObject)->GetModuleAndPresetName()) > 0 || m_AlwaysAllowedItems.find((pSObject)->GetModuleAndPresetName()) != m_AlwaysAllowedItems.end()) { tempList.push_back(pSObject); } - } - - // Don't add anyhting to the real buy item list if the current module didn't yield any valid items - if (!tempList.empty()) - { - // Add the DataModule separator in the shop list, with appropriate name and perhaps icon? Don't add for first base module - if (moduleID != 0 && (pModule = g_PresetMan.GetDataModule(moduleID))) - { - pItemBitmap = pModule->GetIcon() ? new AllegroBitmap(pModule->GetIcon()) : 0; - // Passing in ownership of the bitmap, making uppercase the name - std::string name = pModule->GetFriendlyName(); - transform(name.begin(), name.end(), name.begin(), ::toupper); - m_pShopList->AddItem(name, m_aExpandedModules[moduleID] ? "-" : "+", pItemBitmap, 0, moduleID); - } - - // If the module is expanded, add all the items within it below - if (moduleID == 0 || m_aExpandedModules[moduleID]) - { - // Transfer from the temp intermediate list to the real gui list - for (std::list::iterator tItr = tempList.begin(); tItr != tempList.end(); ++tItr) - { - // Get a good icon and wrap it, while not passing ownership into the AllegroBitmap - pItemBitmap = new AllegroBitmap((*tItr)->GetGraphicalIcon()); - // Passing in ownership of the bitmap, but not of the pSpriteObj - if (m_OwnedItems.size() > 0 || m_OnlyShowOwnedItems) - { - if (GetOwnedItemsAmount((*tItr)->GetModuleAndPresetName()) > 0) - { - std::string amount = std::to_string(GetOwnedItemsAmount((*tItr)->GetModuleAndPresetName())) + " pcs"; - m_pShopList->AddItem((*tItr)->GetPresetName(), amount , pItemBitmap, *tItr); - } - else - { + } + + // Don't add anyhting to the real buy item list if the current module didn't yield any valid items + if (!tempList.empty()) { + // Add the DataModule separator in the shop list, with appropriate name and perhaps icon? Don't add for first base module + if (moduleID != 0 && (pModule = g_PresetMan.GetDataModule(moduleID))) { + pItemBitmap = pModule->GetIcon() ? new AllegroBitmap(pModule->GetIcon()) : 0; + // Passing in ownership of the bitmap, making uppercase the name + std::string name = pModule->GetFriendlyName(); + transform(name.begin(), name.end(), name.begin(), ::toupper); + m_pShopList->AddItem(name, m_aExpandedModules[moduleID] ? "-" : "+", pItemBitmap, 0, moduleID); + } + + // If the module is expanded, add all the items within it below + if (moduleID == 0 || m_aExpandedModules[moduleID]) { + // Transfer from the temp intermediate list to the real gui list + for (std::list::iterator tItr = tempList.begin(); tItr != tempList.end(); ++tItr) { + // Get a good icon and wrap it, while not passing ownership into the AllegroBitmap + pItemBitmap = new AllegroBitmap((*tItr)->GetGraphicalIcon()); + // Passing in ownership of the bitmap, but not of the pSpriteObj + if (m_OwnedItems.size() > 0 || m_OnlyShowOwnedItems) { + if (GetOwnedItemsAmount((*tItr)->GetModuleAndPresetName()) > 0) { + std::string amount = std::to_string(GetOwnedItemsAmount((*tItr)->GetModuleAndPresetName())) + " pcs"; + m_pShopList->AddItem((*tItr)->GetPresetName(), amount, pItemBitmap, *tItr); + } else { if (!m_OnlyShowOwnedItems) m_pShopList->AddItem((*tItr)->GetPresetName(), (*tItr)->GetGoldValueString(m_NativeTechModule, m_ForeignCostMult), pItemBitmap, *tItr); - else - { + else { if (m_AlwaysAllowedItems.find((*tItr)->GetModuleAndPresetName()) != m_AlwaysAllowedItems.end()) m_pShopList->AddItem((*tItr)->GetPresetName(), (*tItr)->GetGoldValueString(m_NativeTechModule, m_ForeignCostMult), pItemBitmap, *tItr); } } - } - else - { + } else { m_pShopList->AddItem((*tItr)->GetPresetName(), (*tItr)->GetGoldValueString(m_NativeTechModule, m_ForeignCostMult), pItemBitmap, *tItr); } - } - } - } - } - } + } + } + } + } + } - // Set the last saved index for this category so the menu scrolls down to it - m_pShopList->SetSelectedIndex(m_CategoryItemIndex[m_MenuCategory]); - m_ListItemIndex = m_CategoryItemIndex[m_MenuCategory]; - if (focusOnCategoryTabs) - m_pShopList->ScrollToSelected(); + // Set the last saved index for this category so the menu scrolls down to it + m_pShopList->SetSelectedIndex(m_CategoryItemIndex[m_MenuCategory]); + m_ListItemIndex = m_CategoryItemIndex[m_MenuCategory]; + if (focusOnCategoryTabs) + m_pShopList->ScrollToSelected(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: SaveCurrentLoadout ////////////////////////////////////////////////////////////////////////////////////////// // Description: Saves the current loadout into a Set. -void BuyMenuGUI::SaveCurrentLoadout() -{ - Loadout newSet; +void BuyMenuGUI::SaveCurrentLoadout() { + Loadout newSet; - // Abort if there's no cargo to save into the preset - if (!GetOrderList(*(newSet.GetCargoList()))) - return; + // Abort if there's no cargo to save into the preset + if (!GetOrderList(*(newSet.GetCargoList()))) + return; - // Add the ship - newSet.SetDeliveryCraft(dynamic_cast(GetDeliveryCraftPreset())); + // Add the ship + newSet.SetDeliveryCraft(dynamic_cast(GetDeliveryCraftPreset())); - // Add it to the loadouts - m_Loadouts.push_back(newSet); + // Add it to the loadouts + m_Loadouts.push_back(newSet); - // Save the new list of loadouts to file - SaveAllLoadoutsToFile(); + // Save the new list of loadouts to file + SaveAllLoadoutsToFile(); - // Update the list of loadout presets so the new one shows up - CategoryChange(); + // Update the list of loadout presets so the new one shows up + CategoryChange(); - // Set focus back on the save button (CatChange changed it) - m_pSaveButton->SetFocus(); + // Set focus back on the save button (CatChange changed it) + m_pSaveButton->SetFocus(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: DeployLoadout ////////////////////////////////////////////////////////////////////////////////////////// // Description: Loads the loadout set into the cart, replacing whatever's there now. -bool BuyMenuGUI::DeployLoadout(int index) -{ - if (index < 0 || index >= m_Loadouts.size()) - return false; +bool BuyMenuGUI::DeployLoadout(int index) { + if (index < 0 || index >= m_Loadouts.size()) + return false; - // Clear the cart, we're going to refill it with the selected loadout - m_pCartList->ClearList(); + // Clear the cart, we're going to refill it with the selected loadout + m_pCartList->ClearList(); // Check if the craft is available - const ACraft * pCraft = m_Loadouts[index].GetDeliveryCraft(); + const ACraft* pCraft = m_Loadouts[index].GetDeliveryCraft(); - if (pCraft) - { + if (pCraft) { bool craftAvailable = true; if (IsAllowedItem(pCraft->GetModuleAndPresetName())) @@ -2306,8 +2133,7 @@ bool BuyMenuGUI::DeployLoadout(int index) if (IsProhibitedItem(pCraft->GetModuleAndPresetName())) craftAvailable = false; - if (m_OnlyShowOwnedItems && craftAvailable) - { + if (m_OnlyShowOwnedItems && craftAvailable) { if (GetOwnedItemsAmount(pCraft->GetModuleAndPresetName()) > 0) craftAvailable = true; else @@ -2321,14 +2147,13 @@ bool BuyMenuGUI::DeployLoadout(int index) return false; } - // Get and add all the stuff in the selected loadout - std::list *pCargo = m_Loadouts[index].GetCargoList(); - AllegroBitmap *pItemBitmap = 0; - for (std::list::iterator cItr = pCargo->begin(); cItr != pCargo->end(); ++cItr) - { - // Get a good icon and wrap it, while not passing ownership into the AllegroBitmap - pItemBitmap = new AllegroBitmap(const_cast(*cItr)->GetGraphicalIcon()); - // Take into account whether these are native or not, and multiply the cost accordingly + // Get and add all the stuff in the selected loadout + std::list* pCargo = m_Loadouts[index].GetCargoList(); + AllegroBitmap* pItemBitmap = 0; + for (std::list::iterator cItr = pCargo->begin(); cItr != pCargo->end(); ++cItr) { + // Get a good icon and wrap it, while not passing ownership into the AllegroBitmap + pItemBitmap = new AllegroBitmap(const_cast(*cItr)->GetGraphicalIcon()); + // Take into account whether these are native or not, and multiply the cost accordingly bool canAdd = true; if (IsAllowedItem((*cItr)->GetModuleAndPresetName())) @@ -2337,15 +2162,12 @@ bool BuyMenuGUI::DeployLoadout(int index) if (IsProhibitedItem((*cItr)->GetModuleAndPresetName())) canAdd = false; - if (m_OnlyShowOwnedItems && canAdd) - { - if (GetOwnedItemsAmount((*cItr)->GetModuleAndPresetName()) > 0) - { + if (m_OnlyShowOwnedItems && canAdd) { + if (GetOwnedItemsAmount((*cItr)->GetModuleAndPresetName()) > 0) { canAdd = false; // Add manually with pcs counter AddCartItem((*cItr)->GetPresetName(), "1 pc", pItemBitmap, *cItr); - } - else + } else canAdd = false; } @@ -2354,30 +2176,29 @@ bool BuyMenuGUI::DeployLoadout(int index) if (canAdd) AddCartItem((*cItr)->GetPresetName(), (*cItr)->GetGoldValueString(m_NativeTechModule, m_ForeignCostMult), pItemBitmap, *cItr); - } - // Now set the craft to what the loadout specifies, if anything - if (m_Loadouts[index].GetDeliveryCraft()) - { - m_pSelectedCraft = m_Loadouts[index].GetDeliveryCraft(); - // Take into account whether these are native or not, and multiply the cost accordingly - m_pCraftBox->SetText(m_pSelectedCraft->GetPresetName()); - m_pCraftBox->SetRightText(m_pSelectedCraft->GetGoldValueString(m_NativeTechModule, m_ForeignCostMult)); + } + // Now set the craft to what the loadout specifies, if anything + if (m_Loadouts[index].GetDeliveryCraft()) { + m_pSelectedCraft = m_Loadouts[index].GetDeliveryCraft(); + // Take into account whether these are native or not, and multiply the cost accordingly + m_pCraftBox->SetText(m_pSelectedCraft->GetPresetName()); + m_pCraftBox->SetRightText(m_pSelectedCraft->GetGoldValueString(m_NativeTechModule, m_ForeignCostMult)); m_pCraftNameLabel->SetText(m_pSelectedCraft->GetPresetName()); m_pCraftPriceLabel->SetText(m_pSelectedCraft->GetGoldValueString(m_NativeTechModule, m_ForeignCostMult)); - UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); - UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); - } + UpdateTotalPassengersLabel(dynamic_cast(m_pSelectedCraft), m_pCraftPassengersLabel); + UpdateTotalMassLabel(dynamic_cast(m_pSelectedCraft), m_pCraftMassLabel); + } - // Update labels with the new config's values - UpdateTotalCostLabel(); + // Update labels with the new config's values + UpdateTotalCostLabel(); - return true; + return true; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void BuyMenuGUI::AddObjectsToItemList(std::vector> &moduleList, const std::string &type, const std::vector &groups, bool excludeGroups) { +void BuyMenuGUI::AddObjectsToItemList(std::vector>& moduleList, const std::string& type, const std::vector& groups, bool excludeGroups) { while (moduleList.size() < g_PresetMan.GetTotalModuleCount()) { moduleList.emplace_back(); } @@ -2396,14 +2217,11 @@ void BuyMenuGUI::AddObjectsToItemList(std::vector> &moduleLi } // Remove itwms which are not allowed to buy - if (m_AllowedItems.size() > 0) - { - for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) - { - std::list toRemove; - - for (std::list::iterator itr = moduleList[moduleID].begin(); itr != moduleList[moduleID].end(); ++itr) - { + if (m_AllowedItems.size() > 0) { + for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) { + std::list toRemove; + + for (std::list::iterator itr = moduleList[moduleID].begin(); itr != moduleList[moduleID].end(); ++itr) { bool allowed = false; if (m_AllowedItems.find((*itr)->GetModuleAndPresetName()) != m_AllowedItems.end()) @@ -2417,20 +2235,17 @@ void BuyMenuGUI::AddObjectsToItemList(std::vector> &moduleLi } // Remove items from the list - for (std::list::iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr) + for (std::list::iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr) moduleList[moduleID].remove((*itr)); } } // Remove items which are prohibited - if (m_ProhibitedItems.size() > 0) - { - for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) - { - std::list toRemove; - - for (std::list::iterator itr = moduleList[moduleID].begin(); itr != moduleList[moduleID].end(); ++itr) - { + if (m_ProhibitedItems.size() > 0) { + for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) { + std::list toRemove; + + for (std::list::iterator itr = moduleList[moduleID].begin(); itr != moduleList[moduleID].end(); ++itr) { bool allowed = true; if (m_ProhibitedItems.find((*itr)->GetModuleAndPresetName()) != m_ProhibitedItems.end()) @@ -2444,24 +2259,20 @@ void BuyMenuGUI::AddObjectsToItemList(std::vector> &moduleLi } // Remove items from the list - for (std::list::iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr) + for (std::list::iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr) moduleList[moduleID].remove((*itr)); } } // Remove items which are not in stock - if (m_OnlyShowOwnedItems && m_OwnedItems.size() > 0) - { - for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) - { - std::list toRemove; - - for (std::list::iterator itr = moduleList[moduleID].begin(); itr != moduleList[moduleID].end(); ++itr) - { + if (m_OnlyShowOwnedItems && m_OwnedItems.size() > 0) { + for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) { + std::list toRemove; + + for (std::list::iterator itr = moduleList[moduleID].begin(); itr != moduleList[moduleID].end(); ++itr) { bool allowed = false; - for (std::map::iterator itrA = m_OwnedItems.begin(); itrA != m_OwnedItems.end(); ++itrA) - { + for (std::map::iterator itrA = m_OwnedItems.begin(); itrA != m_OwnedItems.end(); ++itrA) { if ((*itr)->GetModuleAndPresetName() == (*itrA).first && (*itrA).second > 0) allowed = true; } @@ -2474,71 +2285,65 @@ void BuyMenuGUI::AddObjectsToItemList(std::vector> &moduleLi } // Remove items from the list - for (std::list::iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr) + for (std::list::iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr) moduleList[moduleID].remove((*itr)); } } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: AddPresetsToItemList ////////////////////////////////////////////////////////////////////////////////////////// // Description: Adds all loadout presets' representations to the item GUI list. -void BuyMenuGUI::AddPresetsToItemList() -{ - GUIBitmap *pItemBitmap = 0; - std::string loadoutLabel; - float loadoutCost; - const Actor *pPassenger = 0; - char costString[256]; - - // Go through all the presets, making intelligible list items from then for the GUI item list - for (std::vector::iterator lItr = m_Loadouts.begin(); lItr != m_Loadouts.end(); ++lItr) - { - loadoutLabel.clear(); - loadoutCost = 0; - pItemBitmap = 0; - pPassenger = 0; +void BuyMenuGUI::AddPresetsToItemList() { + GUIBitmap* pItemBitmap = 0; + std::string loadoutLabel; + float loadoutCost; + const Actor* pPassenger = 0; + char costString[256]; + + // Go through all the presets, making intelligible list items from then for the GUI item list + for (std::vector::iterator lItr = m_Loadouts.begin(); lItr != m_Loadouts.end(); ++lItr) { + loadoutLabel.clear(); + loadoutCost = 0; + pItemBitmap = 0; + pPassenger = 0; // Add preset name at the begining to differentiate loadouts from user-defined presets if ((*lItr).GetPresetName() != "None") loadoutLabel = (*lItr).GetPresetName() + ":\n"; - // Go through the cargo setup of each loadout and encode a meaningful label for the list item - for (std::list::iterator cItr = (*lItr).GetCargoList()->begin(); cItr != (*lItr).GetCargoList()->end(); ++cItr) - { - // If not the first one, add a comma separator to the label - if (cItr != (*lItr).GetCargoList()->begin()) - loadoutLabel += ", "; - // Append the name of the current cargo thing to the label - loadoutLabel += (*cItr)->GetPresetName(); - // Adjust price for foreignness of the items to this player - loadoutCost += (*cItr)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); - if (!pPassenger) - pPassenger = dynamic_cast(*cItr); - } + // Go through the cargo setup of each loadout and encode a meaningful label for the list item + for (std::list::iterator cItr = (*lItr).GetCargoList()->begin(); cItr != (*lItr).GetCargoList()->end(); ++cItr) { + // If not the first one, add a comma separator to the label + if (cItr != (*lItr).GetCargoList()->begin()) + loadoutLabel += ", "; + // Append the name of the current cargo thing to the label + loadoutLabel += (*cItr)->GetPresetName(); + // Adjust price for foreignness of the items to this player + loadoutCost += (*cItr)->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); + if (!pPassenger) + pPassenger = dynamic_cast(*cItr); + } - // Add the ship's cost, if there is one defined - if ((*lItr).GetDeliveryCraft()) - { - loadoutLabel += " via " + (*lItr).GetDeliveryCraft()->GetPresetName(); - // Adjust price for foreignness of the ship to this player - loadoutCost += (*lItr).GetDeliveryCraft()->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); - } + // Add the ship's cost, if there is one defined + if ((*lItr).GetDeliveryCraft()) { + loadoutLabel += " via " + (*lItr).GetDeliveryCraft()->GetPresetName(); + // Adjust price for foreignness of the ship to this player + loadoutCost += (*lItr).GetDeliveryCraft()->GetGoldValue(m_NativeTechModule, m_ForeignCostMult); + } - // Make the cost label - std::snprintf(costString, sizeof(costString), "%.0f", loadoutCost); - // Get a good icon and wrap it, while not passing ownership into the AllegroBitmap - // We're trying to pick the icon of the first passenger, or the first item if there's no passengers in the loadout - pItemBitmap = new AllegroBitmap(pPassenger ? const_cast(pPassenger)->GetGraphicalIcon() : const_cast((*lItr).GetCargoList()->front())->GetGraphicalIcon()); - // Passing in ownership of the bitmap, but not of the pSpriteObj - m_pShopList->AddItem(loadoutLabel, costString, pItemBitmap, 0); - } + // Make the cost label + std::snprintf(costString, sizeof(costString), "%.0f", loadoutCost); + // Get a good icon and wrap it, while not passing ownership into the AllegroBitmap + // We're trying to pick the icon of the first passenger, or the first item if there's no passengers in the loadout + pItemBitmap = new AllegroBitmap(pPassenger ? const_cast(pPassenger)->GetGraphicalIcon() : const_cast((*lItr).GetCargoList()->front())->GetGraphicalIcon()); + // Passing in ownership of the bitmap, but not of the pSpriteObj + m_pShopList->AddItem(loadoutLabel, costString, pItemBitmap, 0); + } } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void BuyMenuGUI::UpdateTotalCostLabel(int whichTeam) { @@ -2546,7 +2351,6 @@ void BuyMenuGUI::UpdateTotalCostLabel(int whichTeam) { m_pCostLabel->SetText(display); } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void BuyMenuGUI::UpdateTotalMassLabel(const ACraft* pCraft, GUILabel* pLabel) const { @@ -2567,7 +2371,6 @@ void BuyMenuGUI::UpdateTotalMassLabel(const ACraft* pCraft, GUILabel* pLabel) co pLabel->SetText(display); } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void BuyMenuGUI::UpdateTotalPassengersLabel(const ACraft* pCraft, GUILabel* pLabel) const { @@ -2588,35 +2391,34 @@ void BuyMenuGUI::UpdateTotalPassengersLabel(const ACraft* pCraft, GUILabel* pLab pLabel->SetText(display); } - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void BuyMenuGUI::TryPurchase() { int player = m_pController->GetPlayer(); - // Switch to the Craft category to give the user a hint - if (!m_pSelectedCraft) - { - m_MenuCategory = CRAFT; - CategoryChange(); - m_FocusChange = -2; - m_MenuFocus = ITEMS; - g_GUISound.UserErrorSound()->Play(player); - // Set the notification blinker - m_BlinkMode = NOCRAFT; - m_BlinkTimer.Reset(); + // Switch to the Craft category to give the user a hint + if (!m_pSelectedCraft) { + m_MenuCategory = CRAFT; + CategoryChange(); + m_FocusChange = -2; + m_MenuFocus = ITEMS; + g_GUISound.UserErrorSound()->Play(player); + // Set the notification blinker + m_BlinkMode = NOCRAFT; + m_BlinkTimer.Reset(); return; - } - // Can't afford it :( - else if (GetTotalOrderCost() > g_ActivityMan.GetActivity()->GetTeamFunds(m_pController->GetTeam())) - { - g_GUISound.UserErrorSound()->Play(player); - // Set the notification blinker - m_BlinkMode = NOFUNDS; - m_BlinkTimer.Reset(); + } + // Can't afford it :( + else if (GetTotalOrderCost() > g_ActivityMan.GetActivity()->GetTeamFunds(m_pController->GetTeam())) { + g_GUISound.UserErrorSound()->Play(player); + // Set the notification blinker + m_BlinkMode = NOFUNDS; + m_BlinkTimer.Reset(); return; } else { - if (m_SelectingEquipment) { EnableEquipmentSelection(false); } - const ACraft * pCraft = dynamic_cast(m_pSelectedCraft); + if (m_SelectingEquipment) { + EnableEquipmentSelection(false); + } + const ACraft* pCraft = dynamic_cast(m_pSelectedCraft); if (pCraft) { // Enforce max mass if (m_EnforceMaxMassConstraint && pCraft->GetMaxInventoryMass() >= 0 && GetTotalOrderMass() > pCraft->GetMaxInventoryMass()) { @@ -2628,8 +2430,7 @@ void BuyMenuGUI::TryPurchase() { } // Enforce max passengers - if (pCraft->GetMaxPassengers() >= 0 && GetTotalOrderPassengers() > pCraft->GetMaxPassengers() && m_EnforceMaxPassengersConstraint) - { + if (pCraft->GetMaxPassengers() >= 0 && GetTotalOrderPassengers() > pCraft->GetMaxPassengers() && m_EnforceMaxPassengersConstraint) { g_GUISound.UserErrorSound()->Play(player); // Set the notification blinker m_BlinkMode = MAXPASSENGERS; @@ -2642,9 +2443,8 @@ void BuyMenuGUI::TryPurchase() { // Only allow purchase if there is a delivery craft and enough funds if (m_pSelectedCraft && std::floor(GetTotalOrderCost()) <= std::floor(g_ActivityMan.GetActivity()->GetTeamFunds(m_pController->GetTeam()))) { m_PurchaseMade = true; - m_DeliveryWidth = static_cast(m_pSelectedCraft)->GetSpriteWidth(); + m_DeliveryWidth = static_cast(m_pSelectedCraft)->GetSpriteWidth(); g_GUISound.PurchaseMadeSound()->Play(player); } } - diff --git a/Source/Menus/BuyMenuGUI.h b/Source/Menus/BuyMenuGUI.h index 399cf9678..626837d48 100644 --- a/Source/Menus/BuyMenuGUI.h +++ b/Source/Menus/BuyMenuGUI.h @@ -10,7 +10,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -21,915 +20,858 @@ struct BITMAP; - -namespace RTE -{ - -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUIBitmap; -class GUILabel; -class SceneObject; -class MovableObject; -class ACraft; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: BuyMenuGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A full menu system that represents a purchasing GUI for Cortex Command -// Parent(s): None. -// Class history: 8/22/2006 BuyMenuGUI Created. - -class BuyMenuGUI { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: BuyMenuGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a BuyMenuGUI object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - BuyMenuGUI() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~BuyMenuGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a BuyMenuGUI object before deletion -// from system memory. -// Arguments: None. - - ~BuyMenuGUI() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the BuyMenuGUI object ready for use. -// Arguments: A poitner to a Controller which will control this Menu. Ownership is -// NOT TRANSFERRED! -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(Controller *pController); - - -////////////////////////////////////////////////////////////////////////////////////////// -// method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire BuyMenuGUI, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the BuyMenuGUI object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadAllLoadoutsFromFile -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads or re-loads all the loadout presets from the appropriate files -// on disk. This will first clear out all current loadout presets! -// Arguments: None. -// Return value: Success or not. - - bool LoadAllLoadoutsFromFile(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveAllLoadoutsToFile -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves all the loadouts to appropriate file on disk. Does NOT save -// any named presets which will be loaded from the standard preset -// loadouts first anyway. -// Arguments: None. -// Return value: Success or not. - - bool SaveAllLoadoutsToFile(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the controller used by this. The ownership of the controller is -// NOT transferred! -// Arguments: The new controller for this menu. Ownership is NOT transferred -// Return value: None. - - void SetController(Controller *pController) { m_pController = pController; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Enables or disables the menu. This will animate it in and out of view. -// Arguments: Whether to enable or disable the menu. -// Return value: None. - - void SetEnabled(bool enable = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the menu is enabled or not. -// Arguments: None. -// Return value: None. - - bool IsEnabled() const { return m_MenuEnabled == ENABLED || m_MenuEnabled == ENABLING; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the menu is at all visible or not. -// Arguments: None. -// Return value: None. - - bool IsVisible() const { return m_MenuEnabled == ENABLED || m_MenuEnabled == ENABLING || m_MenuEnabled == DISABLING; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPosOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where on the screen that this GUI is being drawn to. If upper -// left corner, then 0, 0. This will affect the way the mouse is positioned -// etc. -// Arguments: The new screen position of this entire GUI. - - void SetPosOnScreen(int newPosX, int newPosY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetMetaPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which MetaPlayer uses this menu, if any. -// Arguments: The index of the MetaPlayer that uses this menu. -// Return value: None. - - void SetMetaPlayer(int metaPlayer); - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetMetaPlayer -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets which MetaPlayer uses this menu, if any. -// Arguments: None. -// Return value: Metaplayer who owns this buy menu - - int GetMetaPlayer() const { return m_MetaPlayer; } - - - /// - /// Sets which DataModule ID should be treated as the native tech of the user of this menu. - /// This will also apply the DataModule's faction BuyMenu theme, if applicable. - /// - /// The module ID to set as the native one. 0 means everything is native. - void SetNativeTechModule(int whichModule); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetForeignCostMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the multiplier of the cost of any foreign Tech items. -// Arguments: The scalar multiplier of the costs of foreign Tech items. -// Return value: None. - - void SetForeignCostMultiplier(float newMultiplier) { m_ForeignCostMult = newMultiplier; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetModuleExpanded -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether a data module shown in the item menu should be expanded -// or not. -// Arguments: The module ID to set as expanded. -// Whether should be expanded or not. -// Return value: None. - - void SetModuleExpanded(int whichModule, bool expanded = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PurchaseMade -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether a purchase was made during the last Update. -// Arguments: None. -// Return value: Wheter the BUY button was pressed or not during the last update. - - bool PurchaseMade() const { return m_PurchaseMade; } - - - /// - /// Gets the width of the current delivery craft. - /// - /// The width of the delivery craft, in pixels. - int GetDeliveryWidth() const { return m_DeliveryWidth; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOrderList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return the list of things currently in the purchase order list box. -// Arguments: A reference to a an empty list to fill with the Object:s ordered. -// Ownership of the Object:s is NOT TRANSFERRED! -// Return value: Whetehr any items were put in the list at all. false if there are no -// items in the order listbox. - - bool GetOrderList(std::list &listToFill) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetLoadoutPresets -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return the list of loadouts currently saved as presets. -// Arguments: None. -// Return value: A reference to the list of loadout presets. - - std::vector & GetLoadoutPresets() { return m_Loadouts; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveCurrentLoadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Saves the current loadout into a Set. -// Arguments: None. -// Return value: None. - - void SaveCurrentLoadout(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetDeliveryCraftPreset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return the intended delivery vehicle instance from the order. -// Arguments: None. -// Return value: The poiner to the specified delivery craft instance. Note that this is -// just PresetMan's const pointer, so ownership is NOT transferred! - - const SceneObject * GetDeliveryCraftPreset() { return m_pSelectedCraft; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalCost -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return the total cost of everything listed in the order box. -// Arguments: Whether or not to include delivery cost. -// Return value: The total cost in ounces of gold. - - float GetTotalCost(bool includeDelivery = true) const; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalOrderCost -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return the total cost of everything listed in the order box, including delivery costs. -// Arguments: None. -// Return value: The total cost in ounces of gold. - - float GetTotalOrderCost() const { return GetTotalCost(true); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalCartCost -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return the total cost of everything listed in the order box, excluding delivery costs. -// Arguments: None. -// Return value: The total cost in ounces of gold. - - float GetTotalCartCost() const { return GetTotalCost(false); } - - - /// - /// Return the total mass of all items listed in the order box. - /// - /// The total mass (in kg) of the BuyMenu's cart. - float GetTotalOrderMass() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCraftMass -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return mass of craft used in the order box. -// Arguments: None. -// Return value: The total mass in kg. - - float GetCraftMass(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetTotalOrderPassengers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Return teh total number of passengers in the order box. -// Arguments: None. -// Return value: The total number of passengers. - - int GetTotalOrderPassengers() const; - - /// - /// Enable or disable the equipment selection mode for this BuyMenuGUI. - /// - /// Whether or not equipment selection mode should be enabled. - void EnableEquipmentSelection(bool enabled); - - /// - /// Updates the nesting level for every item in the cart. - /// - void UpdateItemNestingLevels(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Menu each frame -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the menu -// Arguments: The bitmap to draw on. -// Return value: None. - - void Draw(BITMAP *drawBitmap) const; - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnforceMaxPassengersConstraint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether passenger count constraints are enforced by this buy menu. -// Arguments: None. -// Return value: True if passenger constraints are enforced by this menu, false otherwise - - bool EnforceMaxPassengersConstraint() const { return m_EnforceMaxPassengersConstraint; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEnforceMaxPassengersConstraint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether passenger count constraints are enforced by this buy menu. -// Arguments: True to enforce passenger constraints by this menu, false otherwise -// Return value: None. - - void SetEnforceMaxPassengersConstraint(bool enforce) { m_EnforceMaxPassengersConstraint = enforce; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EnforceMaxMassConstraint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether mass constraints are enforced by this buy menu. -// Arguments: True if mass constraints are enforced by this menu, false otherwise -// Return value: None. - - bool EnforceMaxMassConstraint() const { return m_EnforceMaxMassConstraint; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEnforceMaxMassConstraint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets whether mass constraints are enforced by this buy menu. -// Arguments: True to enforce mass constraints by this menu, false otherwise -// Return value: None. - - void SetEnforceMaxMassConstraint(bool enforce) { m_EnforceMaxMassConstraint = enforce; }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddAllowedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an item to the list of allowed items. -// If the list is not empty then everything not in the list is removed from the buy menu -// Items will be removed from the buy menu when it's called, category changed or after a ForceRefresh(). -// Arguments: Full preset name to add. -// Return value: None. - - void AddAllowedItem(std::string presetName) { m_AllowedItems[presetName] = true; }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveAllowedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes an item from the list of allowed items. -// Arguments: Full preset name to remove. -// Return value: None. - - void RemoveAllowedItem(std::string presetName) { m_AllowedItems.erase(presetName); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearAllowedItems -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the list of allowed items -// Arguments: None. -// Return value: None. - - void ClearAllowedItems() { m_AllowedItems.clear(); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsAllowedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns true if the item is in allowed list -// Arguments: Full preset name. -// Return value: None. - - bool IsAllowedItem(std::string presetName) { return m_AllowedItems.find(presetName) != m_AllowedItems.end(); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddAlwaysAllowedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an item to the list of always allowed items. This list overrides all previous constraints. -// Arguments: Full preset name to add. -// Return value: None. - - void AddAlwaysAllowedItem(std::string presetName) { m_AlwaysAllowedItems[presetName] = true; }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveAlwaysAllowedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes an item from the list of always allowed items. -// Arguments: Full preset name to remove. -// Return value: None. - - void RemoveAlwaysAllowedItem(std::string presetName) { m_AlwaysAllowedItems.erase(presetName); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearAlwaysAllowedItems -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the list of allowed items -// Arguments: None. -// Return value: None. - - void ClearAlwaysAllowedItems() { m_AlwaysAllowedItems.clear(); }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsAlwaysAllowedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns true if the item is in always allowed list -// Arguments: Full preset name. -// Return value: None. - - bool IsAlwaysAllowedItem(std::string presetName) { return m_AlwaysAllowedItems.find(presetName) != m_AlwaysAllowedItems.end(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddProhibitedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds an item prohibited to buy from the buy menu. -// The item will be removed from the buy menu when it's called, category changed or after a ForceRefresh(). -// Arguments: Full preset name to add. -// Return value: None. - - void AddProhibitedItem(std::string presetName) { m_ProhibitedItems[presetName] = true; }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveProhibitedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes item from the list of prohibited items -// Arguments: Full preset name to remove. -// Return value: None. - - void RemoveProhibitedItem(std::string presetName) { m_ProhibitedItems.erase(presetName); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearProhibitedItems -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears the list of prohibited items -// Arguments: None. -// Return value: None. - - void ClearProhibitedItems() { m_ProhibitedItems.clear(); }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsProhibitedItem -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns true if the item is in prohibited list -// Arguments: Full preset name. -// Return value: None. - - bool IsProhibitedItem(std::string presetName) { return m_ProhibitedItems.find(presetName) != m_ProhibitedItems.end(); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ForceRefresh -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Forces a refresh update of the list of buy menu items -// Arguments: None. -// Return value: None. - - void ForceRefresh() { CategoryChange(); } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ClearCartList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clear the cart out of items selected for purchase -// Arguments: None. -// Return value: None. - - void ClearCartList(); - - /// - /// Adds an item to the cart. - /// - /// The name shown for the item. - /// The text that is shown right-aligned on the item (typically the cost of the item). - /// The sprite image rendered for the item. This takes ownership! - /// The entity that this item refers to and will create when bought. - /// Extra index for special indexing or reference that the item is associated with. Menu-specific. - void AddCartItem(const std::string &name, const std::string &rightText = "", GUIBitmap *pBitmap = nullptr, const Entity *pEntity = 0, const int extraIndex = -1); - - /// - /// Duplicates an item in the cart. - /// - /// The index of the item to duplicate. - void DuplicateCartItem(const int itemIndex); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadDefaultLoadoutToCart -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads the default loadout to the cart -// Arguments: None. -// Return value: None. - - void LoadDefaultLoadoutToCart() { DeployLoadout(0); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOnlyShowOwnedItems -////////////////////////////////////////////////////////////////////////////////////////// -// Description: If set to true only owned items will be shown in buy menu. Overriden by AlwaysAllowed list. -// Arguments: Value. -// Return value: None. - - void SetOnlyShowOwnedItems(bool value) { m_OnlyShowOwnedItems = value; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOnlyShowOwnedItems -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns whether only owned items will be shown in buy menu. Overriden by AlwaysAllowed list. -// Arguments: None. -// Return value: Whether only owned items will be shown in buy menu. - - bool GetOnlyShowOwnedItems() const { return m_OnlyShowOwnedItems; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetOwnedItemsAmount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the amount of specified items to be owned in this buy menu -// Arguments: Full preset name of item to own. Amount of owned items. -// Return value: None. - - void SetOwnedItemsAmount(std::string presetName, int amount) { m_OwnedItems[presetName] = amount; }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetOwnedItemsAmount -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the amount of specified items owned in this buy menu -// Arguments: Full preset name of item. -// Return value: Amount of owned items. - - int GetOwnedItemsAmount(std::string presetName) { if (m_OwnedItems.find(presetName) != m_OwnedItems.end()) return m_OwnedItems[presetName]; else return 0; }; - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CommitPurchase -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Deducts 1 piece of owned item and return true if purchase can be made or false if the item is out of stock. -// Arguments: Full preset name of item. -// Return value: Whether the purchase can be conducted or the item is out of stock. - - bool CommitPurchase(std::string presetName); +namespace RTE { + + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUIBitmap; + class GUILabel; + class SceneObject; + class MovableObject; + class ACraft; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: BuyMenuGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A full menu system that represents a purchasing GUI for Cortex Command + // Parent(s): None. + // Class history: 8/22/2006 BuyMenuGUI Created. + + class BuyMenuGUI { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: BuyMenuGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a BuyMenuGUI object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + BuyMenuGUI() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~BuyMenuGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a BuyMenuGUI object before deletion + // from system memory. + // Arguments: None. + + ~BuyMenuGUI() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the BuyMenuGUI object ready for use. + // Arguments: A poitner to a Controller which will control this Menu. Ownership is + // NOT TRANSFERRED! + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(Controller* pController); + + ////////////////////////////////////////////////////////////////////////////////////////// + // method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire BuyMenuGUI, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the BuyMenuGUI object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadAllLoadoutsFromFile + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads or re-loads all the loadout presets from the appropriate files + // on disk. This will first clear out all current loadout presets! + // Arguments: None. + // Return value: Success or not. + + bool LoadAllLoadoutsFromFile(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveAllLoadoutsToFile + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves all the loadouts to appropriate file on disk. Does NOT save + // any named presets which will be loaded from the standard preset + // loadouts first anyway. + // Arguments: None. + // Return value: Success or not. + + bool SaveAllLoadoutsToFile(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the controller used by this. The ownership of the controller is + // NOT transferred! + // Arguments: The new controller for this menu. Ownership is NOT transferred + // Return value: None. + + void SetController(Controller* pController) { m_pController = pController; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Enables or disables the menu. This will animate it in and out of view. + // Arguments: Whether to enable or disable the menu. + // Return value: None. + + void SetEnabled(bool enable = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the menu is enabled or not. + // Arguments: None. + // Return value: None. + + bool IsEnabled() const { return m_MenuEnabled == ENABLED || m_MenuEnabled == ENABLING; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the menu is at all visible or not. + // Arguments: None. + // Return value: None. + + bool IsVisible() const { return m_MenuEnabled == ENABLED || m_MenuEnabled == ENABLING || m_MenuEnabled == DISABLING; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPosOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where on the screen that this GUI is being drawn to. If upper + // left corner, then 0, 0. This will affect the way the mouse is positioned + // etc. + // Arguments: The new screen position of this entire GUI. + + void SetPosOnScreen(int newPosX, int newPosY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetMetaPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which MetaPlayer uses this menu, if any. + // Arguments: The index of the MetaPlayer that uses this menu. + // Return value: None. + + void SetMetaPlayer(int metaPlayer); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetMetaPlayer + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets which MetaPlayer uses this menu, if any. + // Arguments: None. + // Return value: Metaplayer who owns this buy menu + + int GetMetaPlayer() const { return m_MetaPlayer; } + + /// + /// Sets which DataModule ID should be treated as the native tech of the user of this menu. + /// This will also apply the DataModule's faction BuyMenu theme, if applicable. + /// + /// The module ID to set as the native one. 0 means everything is native. + void SetNativeTechModule(int whichModule); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetForeignCostMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the multiplier of the cost of any foreign Tech items. + // Arguments: The scalar multiplier of the costs of foreign Tech items. + // Return value: None. + + void SetForeignCostMultiplier(float newMultiplier) { m_ForeignCostMult = newMultiplier; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetModuleExpanded + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether a data module shown in the item menu should be expanded + // or not. + // Arguments: The module ID to set as expanded. + // Whether should be expanded or not. + // Return value: None. + + void SetModuleExpanded(int whichModule, bool expanded = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PurchaseMade + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether a purchase was made during the last Update. + // Arguments: None. + // Return value: Wheter the BUY button was pressed or not during the last update. + + bool PurchaseMade() const { return m_PurchaseMade; } + + /// + /// Gets the width of the current delivery craft. + /// + /// The width of the delivery craft, in pixels. + int GetDeliveryWidth() const { return m_DeliveryWidth; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOrderList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return the list of things currently in the purchase order list box. + // Arguments: A reference to a an empty list to fill with the Object:s ordered. + // Ownership of the Object:s is NOT TRANSFERRED! + // Return value: Whetehr any items were put in the list at all. false if there are no + // items in the order listbox. + + bool GetOrderList(std::list& listToFill) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetLoadoutPresets + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return the list of loadouts currently saved as presets. + // Arguments: None. + // Return value: A reference to the list of loadout presets. + + std::vector& GetLoadoutPresets() { return m_Loadouts; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveCurrentLoadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Saves the current loadout into a Set. + // Arguments: None. + // Return value: None. + + void SaveCurrentLoadout(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetDeliveryCraftPreset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return the intended delivery vehicle instance from the order. + // Arguments: None. + // Return value: The poiner to the specified delivery craft instance. Note that this is + // just PresetMan's const pointer, so ownership is NOT transferred! + + const SceneObject* GetDeliveryCraftPreset() { return m_pSelectedCraft; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalCost + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return the total cost of everything listed in the order box. + // Arguments: Whether or not to include delivery cost. + // Return value: The total cost in ounces of gold. + + float GetTotalCost(bool includeDelivery = true) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalOrderCost + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return the total cost of everything listed in the order box, including delivery costs. + // Arguments: None. + // Return value: The total cost in ounces of gold. + + float GetTotalOrderCost() const { return GetTotalCost(true); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalCartCost + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return the total cost of everything listed in the order box, excluding delivery costs. + // Arguments: None. + // Return value: The total cost in ounces of gold. + + float GetTotalCartCost() const { return GetTotalCost(false); } + + /// + /// Return the total mass of all items listed in the order box. + /// + /// The total mass (in kg) of the BuyMenu's cart. + float GetTotalOrderMass() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCraftMass + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return mass of craft used in the order box. + // Arguments: None. + // Return value: The total mass in kg. + + float GetCraftMass(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetTotalOrderPassengers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Return teh total number of passengers in the order box. + // Arguments: None. + // Return value: The total number of passengers. + + int GetTotalOrderPassengers() const; + + /// + /// Enable or disable the equipment selection mode for this BuyMenuGUI. + /// + /// Whether or not equipment selection mode should be enabled. + void EnableEquipmentSelection(bool enabled); + + /// + /// Updates the nesting level for every item in the cart. + /// + void UpdateItemNestingLevels(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Menu each frame + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the menu + // Arguments: The bitmap to draw on. + // Return value: None. + + void Draw(BITMAP* drawBitmap) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnforceMaxPassengersConstraint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether passenger count constraints are enforced by this buy menu. + // Arguments: None. + // Return value: True if passenger constraints are enforced by this menu, false otherwise + + bool EnforceMaxPassengersConstraint() const { return m_EnforceMaxPassengersConstraint; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEnforceMaxPassengersConstraint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether passenger count constraints are enforced by this buy menu. + // Arguments: True to enforce passenger constraints by this menu, false otherwise + // Return value: None. + + void SetEnforceMaxPassengersConstraint(bool enforce) { m_EnforceMaxPassengersConstraint = enforce; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EnforceMaxMassConstraint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether mass constraints are enforced by this buy menu. + // Arguments: True if mass constraints are enforced by this menu, false otherwise + // Return value: None. + + bool EnforceMaxMassConstraint() const { return m_EnforceMaxMassConstraint; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEnforceMaxMassConstraint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets whether mass constraints are enforced by this buy menu. + // Arguments: True to enforce mass constraints by this menu, false otherwise + // Return value: None. + + void SetEnforceMaxMassConstraint(bool enforce) { m_EnforceMaxMassConstraint = enforce; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddAllowedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an item to the list of allowed items. + // If the list is not empty then everything not in the list is removed from the buy menu + // Items will be removed from the buy menu when it's called, category changed or after a ForceRefresh(). + // Arguments: Full preset name to add. + // Return value: None. + + void AddAllowedItem(std::string presetName) { m_AllowedItems[presetName] = true; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveAllowedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes an item from the list of allowed items. + // Arguments: Full preset name to remove. + // Return value: None. + + void RemoveAllowedItem(std::string presetName) { m_AllowedItems.erase(presetName); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearAllowedItems + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the list of allowed items + // Arguments: None. + // Return value: None. + + void ClearAllowedItems() { m_AllowedItems.clear(); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsAllowedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns true if the item is in allowed list + // Arguments: Full preset name. + // Return value: None. + + bool IsAllowedItem(std::string presetName) { return m_AllowedItems.find(presetName) != m_AllowedItems.end(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddAlwaysAllowedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an item to the list of always allowed items. This list overrides all previous constraints. + // Arguments: Full preset name to add. + // Return value: None. + + void AddAlwaysAllowedItem(std::string presetName) { m_AlwaysAllowedItems[presetName] = true; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveAlwaysAllowedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes an item from the list of always allowed items. + // Arguments: Full preset name to remove. + // Return value: None. + + void RemoveAlwaysAllowedItem(std::string presetName) { m_AlwaysAllowedItems.erase(presetName); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearAlwaysAllowedItems + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the list of allowed items + // Arguments: None. + // Return value: None. + + void ClearAlwaysAllowedItems() { m_AlwaysAllowedItems.clear(); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsAlwaysAllowedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns true if the item is in always allowed list + // Arguments: Full preset name. + // Return value: None. + + bool IsAlwaysAllowedItem(std::string presetName) { return m_AlwaysAllowedItems.find(presetName) != m_AlwaysAllowedItems.end(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddProhibitedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds an item prohibited to buy from the buy menu. + // The item will be removed from the buy menu when it's called, category changed or after a ForceRefresh(). + // Arguments: Full preset name to add. + // Return value: None. + + void AddProhibitedItem(std::string presetName) { m_ProhibitedItems[presetName] = true; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveProhibitedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes item from the list of prohibited items + // Arguments: Full preset name to remove. + // Return value: None. + + void RemoveProhibitedItem(std::string presetName) { m_ProhibitedItems.erase(presetName); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearProhibitedItems + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears the list of prohibited items + // Arguments: None. + // Return value: None. + + void ClearProhibitedItems() { m_ProhibitedItems.clear(); }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsProhibitedItem + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns true if the item is in prohibited list + // Arguments: Full preset name. + // Return value: None. + + bool IsProhibitedItem(std::string presetName) { return m_ProhibitedItems.find(presetName) != m_ProhibitedItems.end(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ForceRefresh + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Forces a refresh update of the list of buy menu items + // Arguments: None. + // Return value: None. + + void ForceRefresh() { CategoryChange(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ClearCartList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clear the cart out of items selected for purchase + // Arguments: None. + // Return value: None. + + void ClearCartList(); + + /// + /// Adds an item to the cart. + /// + /// The name shown for the item. + /// The text that is shown right-aligned on the item (typically the cost of the item). + /// The sprite image rendered for the item. This takes ownership! + /// The entity that this item refers to and will create when bought. + /// Extra index for special indexing or reference that the item is associated with. Menu-specific. + void AddCartItem(const std::string& name, const std::string& rightText = "", GUIBitmap* pBitmap = nullptr, const Entity* pEntity = 0, const int extraIndex = -1); + + /// + /// Duplicates an item in the cart. + /// + /// The index of the item to duplicate. + void DuplicateCartItem(const int itemIndex); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadDefaultLoadoutToCart + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads the default loadout to the cart + // Arguments: None. + // Return value: None. + + void LoadDefaultLoadoutToCart() { DeployLoadout(0); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOnlyShowOwnedItems + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: If set to true only owned items will be shown in buy menu. Overriden by AlwaysAllowed list. + // Arguments: Value. + // Return value: None. + + void SetOnlyShowOwnedItems(bool value) { m_OnlyShowOwnedItems = value; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOnlyShowOwnedItems + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns whether only owned items will be shown in buy menu. Overriden by AlwaysAllowed list. + // Arguments: None. + // Return value: Whether only owned items will be shown in buy menu. + + bool GetOnlyShowOwnedItems() const { return m_OnlyShowOwnedItems; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetOwnedItemsAmount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the amount of specified items to be owned in this buy menu + // Arguments: Full preset name of item to own. Amount of owned items. + // Return value: None. + + void SetOwnedItemsAmount(std::string presetName, int amount) { m_OwnedItems[presetName] = amount; }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetOwnedItemsAmount + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the amount of specified items owned in this buy menu + // Arguments: Full preset name of item. + // Return value: Amount of owned items. + + int GetOwnedItemsAmount(std::string presetName) { + if (m_OwnedItems.find(presetName) != m_OwnedItems.end()) + return m_OwnedItems[presetName]; + else + return 0; + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CommitPurchase + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Deducts 1 piece of owned item and return true if purchase can be made or false if the item is out of stock. + // Arguments: Full preset name of item. + // Return value: Whether the purchase can be conducted or the item is out of stock. + + bool CommitPurchase(std::string presetName); #pragma region Faction Theme Handling - /// - /// Changes the banner image to the one specified. If none is specified, resets it to the default banner image. - /// - /// Path to image to set as banner. - void SetBannerImage(const std::string &imagePath); - - /// - /// Changes the logo image to the one specified. If none is specified, resets it to the default logo image. - /// - /// Path to image to set as logo. - void SetLogoImage(const std::string &imagePath); + /// + /// Changes the banner image to the one specified. If none is specified, resets it to the default banner image. + /// + /// Path to image to set as banner. + void SetBannerImage(const std::string& imagePath); + + /// + /// Changes the logo image to the one specified. If none is specified, resets it to the default logo image. + /// + /// Path to image to set as logo. + void SetLogoImage(const std::string& imagePath); #pragma endregion -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CategoryChange -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes sure all things that to happen when category is changed, happens. -// Arguments: Wheter to change focus to the category tabs or not. -// Return value: None. - - void CategoryChange(bool focusOnCategoryTabs = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DeployLoadout -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Loads the loadout set into the cart, replacing whatever's there now. -// Arguments: The index of the loadout to load. -// Return value: Whether it was loaded successfully or not. - - bool DeployLoadout(int index); - - - /// - /// Adds all objects of a specific type already defined in PresetMan to the current shop/item list. They will be grouped into the different data modules they were read from. - /// - /// Reference to the data module vector of entity lists to add the items to. - /// The name of the class to add all objects of. "" or "All" looks for all. - /// The name of the groups to add all objects of. An empty vector or "All" looks for all. - /// Whether the specified groups should be excluded, meaning all objects NOT associated with the groups will be added. - void AddObjectsToItemList(std::vector> &moduleList, const std::string &type = "", const std::vector &groups = {}, bool excludeGroups = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddPresetsToItemList -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds all loadout presets' representations to the item GUI list. -// Arguments: None. -// Return value: None. - - void AddPresetsToItemList(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateTotalCostLabel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the text of the total cost label to reflect the total cost of -// all the items in teh order box. -// Arguments: The team to display the total funds of. -// Return value: None. - - void UpdateTotalCostLabel(int whichTeam = 0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateTotalMassLabel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the text of the specified label to reflect the total mass of -// all the items in the order box. -// Arguments: Craft to read MaxMass from. Label to update. -// Return value: None. - - void UpdateTotalMassLabel(const ACraft * pCraft, GUILabel * pLabel) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateTotalPassengersLabel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the text of the specified label to reflect the total passenger count of -// all the items in teh order box. -// Arguments: Craft to read MaxPassengers from. Label to update. -// Return value: None. - - void UpdateTotalPassengersLabel(const ACraft * pCraft, GUILabel * pLabel) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TryPurchase -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Attempts to make a purchase with everything already set up. -// Arguments: None. -// Return value: None. - - void TryPurchase(); - - - enum MenuEnabled - { - ENABLING = 0, - ENABLED, - DISABLING, - DISABLED - }; - - enum MenuFocus - { - SETBUTTONS = 0, - CATEGORIES, - ITEMS, - ORDER, - OK, - CLEARORDER, - FOCUSCOUNT - }; - - enum MenuCategory - { - CRAFT = 0, - BODIES, - MECHA, - TOOLS, - GUNS, - BOMBS, - SHIELDS, - SETS, - CATEGORYCOUNT - }; - - enum BlinkMode - { - NOBLINK = 0, - NOFUNDS, - NOCRAFT, - MAXPASSENGERS, - MAXMASS, - BLINKMODECOUNT - }; - - // Controls this Menu. Not owned - Controller *m_pController; - // GUI Screen for use by the in-game GUI - GUIScreen *m_pGUIScreen; - // Input controller - GUIInput *m_pGUIInput; - // The control manager which holds all the controls - GUIControlManager *m_pGUIController; - // Visibility state of each menu - int m_MenuEnabled; - // Focus state - int m_MenuFocus; - // Focus change direction - 0 is non,e negative is back, positive forward - int m_FocusChange; - // Category selection state - int m_MenuCategory; - // Speed at which the menus appear and disappear - float m_MenuSpeed; - // Which item in the currently focused list box we have selected - int m_ListItemIndex; - // Which item we're dragging - int m_DraggedItemIndex; - // Whether we're currently dragging - bool m_IsDragging; - // Which object was last hovered over by the mouse, to avoid repeatedly selecting hte same item over and over when mose only moves a pixel - int m_LastHoveredMouseIndex; - // Which item in each of the categories was last selected, so the scrolling doesn't have to be redone each time user flips back and forth - int m_CategoryItemIndex[CATEGORYCOUNT]; - // Which metaplayer, if any, is using this menu - int m_MetaPlayer; - // The ID of the DataModule that contains the native Tech of the Player using this menu - int m_NativeTechModule; - // The multiplier of costs of any foreign tech items - float m_ForeignCostMult; - // Arry of bools showing which modules that have been expanded in the item list - bool *m_aExpandedModules; - // Notification blink timer - Timer m_BlinkTimer; - // What we're blinking - int m_BlinkMode; - // Measures real time to determine how fast the menu should animate when opening/closing to appear real time to the player - Timer m_MenuTimer; - // Measures the time to when to start repeating inputs when they're held down - Timer m_RepeatStartTimer; - // Measures the interval between input repeats - Timer m_RepeatTimer; - - bool m_SelectingEquipment; //!< Whether or not the menu is in equipment mode. - MenuCategory m_LastVisitedEquipmentTab; //!< The last tab visited while in equipment mode. - MenuCategory m_LastVisitedMainTab; //!< The last tab visited while not in equipment mode. - int m_LastEquipmentScrollPosition; //!< The last scroll position while in equipment mode. - int m_LastMainScrollPosition; //!< The last scroll position while not in equipment mode. - MenuCategory m_FirstMainTab; //!< The first enabled tab when not in equipment mode. - MenuCategory m_LastMainTab; //!< The last enabled tab when not in equipment mode. - MenuCategory m_FirstEquipmentTab; //!< The first enabled tab when in equipment mode. - MenuCategory m_LastEquipmentTab; //!< The last enabled tab when in equipment mode. - - // Collection box of the buy GUIs - GUICollectionBox *m_pParentBox; - // Collection box of the buy popups that contain information about items - GUICollectionBox *m_pPopupBox; - // Label displaying the item popup description - GUILabel *m_pPopupText; - // Top banner - GUICollectionBox *m_Banner; - // Logo label that disappears when the sets category is selected - GUICollectionBox *m_Logo; - // All the radio buttons for the different shop categories - GUITab *m_pCategoryTabs[CATEGORYCOUNT]; - // The Listbox which lists all the shop's items in the currently selected category - GUIListBox *m_pShopList; - // The Listbox which lists all the items currently in the shopping cart or order - GUIListBox *m_pCartList; - // The single-line textbox which shows the selected delivery craft - GUITextBox *m_pCraftBox; - - // Panel with craft parameters - GUICollectionBox *m_pCraftCollectionBox; - - // Selected craft name - GUILabel *m_pCraftNameLabel; - // Selected craft price - GUILabel *m_pCraftPriceLabel; - // Selected craft passenger caption - GUILabel *m_pCraftPassengersCaptionLabel; - // Selected craft passenger count - GUILabel *m_pCraftPassengersLabel; - // Selected craft total mass caption - GUILabel *m_pCraftMassCaptionLabel; - // Selected craft total mass - GUILabel *m_pCraftMassLabel; - - // Label displaying "Delivered On:" - GUILabel *m_pCraftLabel; - // The selected craft instance for delivery - const SceneObject *m_pSelectedCraft; - // Label displaying the total cost - GUILabel *m_pCostLabel; - // The purchasing button - GUIButton *m_pBuyButton; - - GUIButton *m_ClearOrderButton; //!< Button for clearing the cart. - // The save set button - GUIButton *m_pSaveButton; - // The clear set button - GUIButton *m_pClearButton; - // Sets of user-defined loadouts that can be selected quickly. - std::vector m_Loadouts; - // Purchase has been made - bool m_PurchaseMade; - int m_DeliveryWidth; //!< The width of the currently selected delivery craft, which will determine the width of the LZ marker. - // The cursor image shared by all buy menus - static BITMAP *s_pCursor; - - // If true UI won't afford to order a craft with more passengers than allowed by craft - bool m_EnforceMaxPassengersConstraint; - // If true UI won't afford to order a craft with more mass than allowed by craft - bool m_EnforceMaxMassConstraint; - - // Only show items that owned - bool m_OnlyShowOwnedItems; - // If not empty then only shows items present in this list - std::map m_AllowedItems; - // If not empty then items from this list are always shown int he buy menu no matter what other constraints there are - std::map m_AlwaysAllowedItems; - // If not empty then removes items from ths list the buy menu - std::map m_ProhibitedItems; - // A map of owned items, for which the gold will not be deducted when bought - std::map m_OwnedItems; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - static const std::string c_DefaultBannerImagePath; //!< Path to the default banner image. - static const std::string c_DefaultLogoImagePath; //!< Path to the default logo image. - - /// - /// Refresh tab disabled states, so tabs get properly enabled/disabled based on whether or not equipment selection mode is enabled. - /// - void RefreshTabDisabledStates(); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this BuyMenuGUI, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - BuyMenuGUI(const BuyMenuGUI &reference) = delete; - BuyMenuGUI & operator=(const BuyMenuGUI &rhs) = delete; - -}; + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CategoryChange + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes sure all things that to happen when category is changed, happens. + // Arguments: Wheter to change focus to the category tabs or not. + // Return value: None. + + void CategoryChange(bool focusOnCategoryTabs = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DeployLoadout + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Loads the loadout set into the cart, replacing whatever's there now. + // Arguments: The index of the loadout to load. + // Return value: Whether it was loaded successfully or not. + + bool DeployLoadout(int index); + + /// + /// Adds all objects of a specific type already defined in PresetMan to the current shop/item list. They will be grouped into the different data modules they were read from. + /// + /// Reference to the data module vector of entity lists to add the items to. + /// The name of the class to add all objects of. "" or "All" looks for all. + /// The name of the groups to add all objects of. An empty vector or "All" looks for all. + /// Whether the specified groups should be excluded, meaning all objects NOT associated with the groups will be added. + void AddObjectsToItemList(std::vector>& moduleList, const std::string& type = "", const std::vector& groups = {}, bool excludeGroups = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddPresetsToItemList + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds all loadout presets' representations to the item GUI list. + // Arguments: None. + // Return value: None. + + void AddPresetsToItemList(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateTotalCostLabel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the text of the total cost label to reflect the total cost of + // all the items in teh order box. + // Arguments: The team to display the total funds of. + // Return value: None. + + void UpdateTotalCostLabel(int whichTeam = 0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateTotalMassLabel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the text of the specified label to reflect the total mass of + // all the items in the order box. + // Arguments: Craft to read MaxMass from. Label to update. + // Return value: None. + + void UpdateTotalMassLabel(const ACraft* pCraft, GUILabel* pLabel) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateTotalPassengersLabel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the text of the specified label to reflect the total passenger count of + // all the items in teh order box. + // Arguments: Craft to read MaxPassengers from. Label to update. + // Return value: None. + + void UpdateTotalPassengersLabel(const ACraft* pCraft, GUILabel* pLabel) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TryPurchase + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Attempts to make a purchase with everything already set up. + // Arguments: None. + // Return value: None. + + void TryPurchase(); + + enum MenuEnabled { + ENABLING = 0, + ENABLED, + DISABLING, + DISABLED + }; + + enum MenuFocus { + SETBUTTONS = 0, + CATEGORIES, + ITEMS, + ORDER, + OK, + CLEARORDER, + FOCUSCOUNT + }; + + enum MenuCategory { + CRAFT = 0, + BODIES, + MECHA, + TOOLS, + GUNS, + BOMBS, + SHIELDS, + SETS, + CATEGORYCOUNT + }; + + enum BlinkMode { + NOBLINK = 0, + NOFUNDS, + NOCRAFT, + MAXPASSENGERS, + MAXMASS, + BLINKMODECOUNT + }; + + // Controls this Menu. Not owned + Controller* m_pController; + // GUI Screen for use by the in-game GUI + GUIScreen* m_pGUIScreen; + // Input controller + GUIInput* m_pGUIInput; + // The control manager which holds all the controls + GUIControlManager* m_pGUIController; + // Visibility state of each menu + int m_MenuEnabled; + // Focus state + int m_MenuFocus; + // Focus change direction - 0 is non,e negative is back, positive forward + int m_FocusChange; + // Category selection state + int m_MenuCategory; + // Speed at which the menus appear and disappear + float m_MenuSpeed; + // Which item in the currently focused list box we have selected + int m_ListItemIndex; + // Which item we're dragging + int m_DraggedItemIndex; + // Whether we're currently dragging + bool m_IsDragging; + // Which object was last hovered over by the mouse, to avoid repeatedly selecting hte same item over and over when mose only moves a pixel + int m_LastHoveredMouseIndex; + // Which item in each of the categories was last selected, so the scrolling doesn't have to be redone each time user flips back and forth + int m_CategoryItemIndex[CATEGORYCOUNT]; + // Which metaplayer, if any, is using this menu + int m_MetaPlayer; + // The ID of the DataModule that contains the native Tech of the Player using this menu + int m_NativeTechModule; + // The multiplier of costs of any foreign tech items + float m_ForeignCostMult; + // Arry of bools showing which modules that have been expanded in the item list + bool* m_aExpandedModules; + // Notification blink timer + Timer m_BlinkTimer; + // What we're blinking + int m_BlinkMode; + // Measures real time to determine how fast the menu should animate when opening/closing to appear real time to the player + Timer m_MenuTimer; + // Measures the time to when to start repeating inputs when they're held down + Timer m_RepeatStartTimer; + // Measures the interval between input repeats + Timer m_RepeatTimer; + + bool m_SelectingEquipment; //!< Whether or not the menu is in equipment mode. + MenuCategory m_LastVisitedEquipmentTab; //!< The last tab visited while in equipment mode. + MenuCategory m_LastVisitedMainTab; //!< The last tab visited while not in equipment mode. + int m_LastEquipmentScrollPosition; //!< The last scroll position while in equipment mode. + int m_LastMainScrollPosition; //!< The last scroll position while not in equipment mode. + MenuCategory m_FirstMainTab; //!< The first enabled tab when not in equipment mode. + MenuCategory m_LastMainTab; //!< The last enabled tab when not in equipment mode. + MenuCategory m_FirstEquipmentTab; //!< The first enabled tab when in equipment mode. + MenuCategory m_LastEquipmentTab; //!< The last enabled tab when in equipment mode. + + // Collection box of the buy GUIs + GUICollectionBox* m_pParentBox; + // Collection box of the buy popups that contain information about items + GUICollectionBox* m_pPopupBox; + // Label displaying the item popup description + GUILabel* m_pPopupText; + // Top banner + GUICollectionBox* m_Banner; + // Logo label that disappears when the sets category is selected + GUICollectionBox* m_Logo; + // All the radio buttons for the different shop categories + GUITab* m_pCategoryTabs[CATEGORYCOUNT]; + // The Listbox which lists all the shop's items in the currently selected category + GUIListBox* m_pShopList; + // The Listbox which lists all the items currently in the shopping cart or order + GUIListBox* m_pCartList; + // The single-line textbox which shows the selected delivery craft + GUITextBox* m_pCraftBox; + + // Panel with craft parameters + GUICollectionBox* m_pCraftCollectionBox; + + // Selected craft name + GUILabel* m_pCraftNameLabel; + // Selected craft price + GUILabel* m_pCraftPriceLabel; + // Selected craft passenger caption + GUILabel* m_pCraftPassengersCaptionLabel; + // Selected craft passenger count + GUILabel* m_pCraftPassengersLabel; + // Selected craft total mass caption + GUILabel* m_pCraftMassCaptionLabel; + // Selected craft total mass + GUILabel* m_pCraftMassLabel; + + // Label displaying "Delivered On:" + GUILabel* m_pCraftLabel; + // The selected craft instance for delivery + const SceneObject* m_pSelectedCraft; + // Label displaying the total cost + GUILabel* m_pCostLabel; + // The purchasing button + GUIButton* m_pBuyButton; + + GUIButton* m_ClearOrderButton; //!< Button for clearing the cart. + // The save set button + GUIButton* m_pSaveButton; + // The clear set button + GUIButton* m_pClearButton; + // Sets of user-defined loadouts that can be selected quickly. + std::vector m_Loadouts; + // Purchase has been made + bool m_PurchaseMade; + int m_DeliveryWidth; //!< The width of the currently selected delivery craft, which will determine the width of the LZ marker. + // The cursor image shared by all buy menus + static BITMAP* s_pCursor; + + // If true UI won't afford to order a craft with more passengers than allowed by craft + bool m_EnforceMaxPassengersConstraint; + // If true UI won't afford to order a craft with more mass than allowed by craft + bool m_EnforceMaxMassConstraint; + + // Only show items that owned + bool m_OnlyShowOwnedItems; + // If not empty then only shows items present in this list + std::map m_AllowedItems; + // If not empty then items from this list are always shown int he buy menu no matter what other constraints there are + std::map m_AlwaysAllowedItems; + // If not empty then removes items from ths list the buy menu + std::map m_ProhibitedItems; + // A map of owned items, for which the gold will not be deducted when bought + std::map m_OwnedItems; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_DefaultBannerImagePath; //!< Path to the default banner image. + static const std::string c_DefaultLogoImagePath; //!< Path to the default logo image. + + /// + /// Refresh tab disabled states, so tabs get properly enabled/disabled based on whether or not equipment selection mode is enabled. + /// + void RefreshTabDisabledStates(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this BuyMenuGUI, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + BuyMenuGUI(const BuyMenuGUI& reference) = delete; + BuyMenuGUI& operator=(const BuyMenuGUI& rhs) = delete; + }; } // namespace RTE -#endif // File +#endif // File diff --git a/Source/Menus/GibEditorGUI.cpp b/Source/Menus/GibEditorGUI.cpp index a690bb7c9..89a9c464e 100644 --- a/Source/Menus/GibEditorGUI.cpp +++ b/Source/Menus/GibEditorGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -39,108 +38,102 @@ using namespace RTE; // Description: Clears all the member variables of this GibEditorGUI, effectively // resetting the members of this abstraction level only. -void GibEditorGUI::Clear() -{ - m_pController = 0; - m_EditMade = false; - m_EditorGUIMode = PICKINGGIB; - m_PreviousMode = ADDINGGIB; - m_pObjectToLoad = 0; - m_BlinkTimer.Reset(); - m_BlinkMode = NOBLINK; - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); +void GibEditorGUI::Clear() { + m_pController = 0; + m_EditMade = false; + m_EditorGUIMode = PICKINGGIB; + m_PreviousMode = ADDINGGIB; + m_pObjectToLoad = 0; + m_BlinkTimer.Reset(); + m_BlinkMode = NOBLINK; + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); m_PieMenu = nullptr; - m_pPicker = 0; - m_GridSnapping = false; - m_pZoomSource = 0; - m_ZoomFactor = 1; - m_CursorPos.Reset(); - m_CursorOffset.Reset(); - m_CursorInAir = true; - m_FacingLeft = false; - m_PlacedGibs.clear(); - m_pCurrentGib = 0; - m_GibListOrder = -1; - m_DrawCurrentGib = true; - m_pObjectToBlink = 0; + m_pPicker = 0; + m_GridSnapping = false; + m_pZoomSource = 0; + m_ZoomFactor = 1; + m_CursorPos.Reset(); + m_CursorOffset.Reset(); + m_CursorInAir = true; + m_FacingLeft = false; + m_PlacedGibs.clear(); + m_pCurrentGib = 0; + m_GibListOrder = -1; + m_DrawCurrentGib = true; + m_pObjectToBlink = 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the GibEditorGUI object ready for use. -int GibEditorGUI::Create(Controller *pController, int whichModuleSpace) -{ - RTEAssert(pController, "No controller sent to GibEditorGUI on creation!"); - m_pController = pController; +int GibEditorGUI::Create(Controller* pController, int whichModuleSpace) { + RTEAssert(pController, "No controller sent to GibEditorGUI on creation!"); + m_pController = pController; - if (m_PieMenu) { m_PieMenu = nullptr; } - m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", "Gib Editor Pie Menu")->Clone())); + if (m_PieMenu) { + m_PieMenu = nullptr; + } + m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", "Gib Editor Pie Menu")->Clone())); m_PieMenu->SetMenuController(pController); - // Allocate and (re)create the Editor GUIs - if (!m_pPicker) - m_pPicker = new ObjectPickerGUI(); - else - m_pPicker->Reset(); - // Only show MovableObject:s as valid gibs to be placed - m_pPicker->Create(pController, whichModuleSpace, "MovableObject"); + // Allocate and (re)create the Editor GUIs + if (!m_pPicker) + m_pPicker = new ObjectPickerGUI(); + else + m_pPicker->Reset(); + // Only show MovableObject:s as valid gibs to be placed + m_pPicker->Create(pController, whichModuleSpace, "MovableObject"); - // Intermediate zooming bitmap - m_pZoomSource = create_bitmap_ex(8, 64, 64); + // Intermediate zooming bitmap + m_pZoomSource = create_bitmap_ex(8, 64, 64); - // Cursor init - m_CursorPos = g_SceneMan.GetSceneDim() / 2; + // Cursor init + m_CursorPos = g_SceneMan.GetSceneDim() / 2; - // Set initial focus, category list, and label settings - m_EditorGUIMode = PICKINGGIB; - m_pCurrentGib = 0; + // Set initial focus, category list, and label settings + m_EditorGUIMode = PICKINGGIB; + m_pCurrentGib = 0; - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); - return 0; + return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the GibEditorGUI object. -void GibEditorGUI::Destroy() -{ - delete m_pPicker; +void GibEditorGUI::Destroy() { + delete m_pPicker; - destroy_bitmap(m_pZoomSource); + destroy_bitmap(m_pZoomSource); - for (std::list::iterator gItr = m_PlacedGibs.begin(); gItr != m_PlacedGibs.end(); ++gItr) - delete (*gItr); + for (std::list::iterator gItr = m_PlacedGibs.begin(); gItr != m_PlacedGibs.end(); ++gItr) + delete (*gItr); - delete m_pCurrentGib; + delete m_pCurrentGib; - Clear(); + Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetController ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the controller used by this. The ownership of the controller is // NOT transferred! -void GibEditorGUI::SetController(Controller *pController) -{ - m_pController = pController; +void GibEditorGUI::SetController(Controller* pController) { + m_pController = pController; m_PieMenu->SetMenuController(pController); - m_pPicker->SetController(pController); + m_pPicker->SetController(pController); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetPosOnScreen ////////////////////////////////////////////////////////////////////////////////////////// @@ -148,146 +141,145 @@ void GibEditorGUI::SetController(Controller *pController) // left corner, then 0, 0. This will affect the way the mouse is positioned // etc. -void GibEditorGUI::SetPosOnScreen(int newPosX, int newPosY) -{ - m_pPicker->SetPosOnScreen(newPosX, newPosY); +void GibEditorGUI::SetPosOnScreen(int newPosX, int newPosY) { + m_pPicker->SetPosOnScreen(newPosX, newPosY); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetActivatedPieSlice ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gets any Pie menu slice command activated last update. PieSlice::SliceType GibEditorGUI::GetActivatedPieSlice() const { - return m_PieMenu->GetPieCommand(); + return m_PieMenu->GetPieCommand(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetModuleSpace ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets which DataModule space to be picking objects from. If -1, then // let the player pick from all loaded modules. -void GibEditorGUI::SetModuleSpace(int moduleSpaceID) -{ - m_pPicker->SetModuleSpace(moduleSpaceID); +void GibEditorGUI::SetModuleSpace(int moduleSpaceID) { + m_pPicker->SetModuleSpace(moduleSpaceID); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Update ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void GibEditorGUI::Update() -{ - // Update the user controller -// m_pController->Update(); - - m_pObjectToLoad = 0; - m_EditMade = false; - m_pObjectToBlink = 0; - - //////////////////////////////////////////// - // Blinking logic -/* - if (m_BlinkMode == OBJECTBLINK) - { - m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); - } - else if (m_BlinkMode == NOCRAFT) - { - bool blink = m_BlinkTimer.AlternateSim(250); - m_pCraftLabel->SetVisible(blink); - m_pCraftBox->SetVisible(blink); - } - - // Time out the blinker - if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) - { - m_pCostLabel->SetVisible(true); - m_pCraftLabel->SetVisible(true); - m_pCraftBox->SetVisible(true); - m_BlinkMode = NOBLINK; - } -*/ - ///////////////////////////////////////////// - // Repeating input logic - - bool pressLeft = m_pController->IsState(PRESS_LEFT); - bool pressRight = m_pController->IsState(PRESS_RIGHT); - bool pressUp = m_pController->IsState(PRESS_UP); - bool pressDown = m_pController->IsState(PRESS_DOWN); - - // If no direction is held down, then cancel the repeating - if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) - { - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - } - - // Check if any direction has been held for the starting amount of time to get into repeat mode - if (m_RepeatStartTimer.IsPastRealMS(200)) - { - // Check for the repeat interval - if (m_RepeatTimer.IsPastRealMS(50)) - { - if (m_pController->IsState(MOVE_RIGHT)) - pressRight = true; - else if (m_pController->IsState(MOVE_LEFT)) - pressLeft = true; - - if (m_pController->IsState(MOVE_UP)) - pressUp = true; - else if (m_pController->IsState(MOVE_DOWN)) - pressDown = true; - - m_RepeatTimer.Reset(); - } - } - - /////////////////////////////////////////////// - // Analog cursor input - - Vector analogInput; - if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) - analogInput = m_pController->GetAnalogMove(); -// else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) -// analogInput = m_pController->GetAnalogAim(); - - ///////////////////////////////////////////// - // PIE MENU +void GibEditorGUI::Update() { + // Update the user controller + // m_pController->Update(); + + m_pObjectToLoad = 0; + m_EditMade = false; + m_pObjectToBlink = 0; + + //////////////////////////////////////////// + // Blinking logic + /* + if (m_BlinkMode == OBJECTBLINK) + { + m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); + } + else if (m_BlinkMode == NOCRAFT) + { + bool blink = m_BlinkTimer.AlternateSim(250); + m_pCraftLabel->SetVisible(blink); + m_pCraftBox->SetVisible(blink); + } + + // Time out the blinker + if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) + { + m_pCostLabel->SetVisible(true); + m_pCraftLabel->SetVisible(true); + m_pCraftBox->SetVisible(true); + m_BlinkMode = NOBLINK; + } + */ + ///////////////////////////////////////////// + // Repeating input logic + + bool pressLeft = m_pController->IsState(PRESS_LEFT); + bool pressRight = m_pController->IsState(PRESS_RIGHT); + bool pressUp = m_pController->IsState(PRESS_UP); + bool pressDown = m_pController->IsState(PRESS_DOWN); + + // If no direction is held down, then cancel the repeating + if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) { + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + } + + // Check if any direction has been held for the starting amount of time to get into repeat mode + if (m_RepeatStartTimer.IsPastRealMS(200)) { + // Check for the repeat interval + if (m_RepeatTimer.IsPastRealMS(50)) { + if (m_pController->IsState(MOVE_RIGHT)) + pressRight = true; + else if (m_pController->IsState(MOVE_LEFT)) + pressLeft = true; + + if (m_pController->IsState(MOVE_UP)) + pressUp = true; + else if (m_pController->IsState(MOVE_DOWN)) + pressDown = true; + + m_RepeatTimer.Reset(); + } + } + + /////////////////////////////////////////////// + // Analog cursor input + + Vector analogInput; + if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) + analogInput = m_pController->GetAnalogMove(); + // else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) + // analogInput = m_pController->GetAnalogAim(); + + ///////////////////////////////////////////// + // PIE MENU m_PieMenu->Update(); - if (PieSlice *zoomInSlice = m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorZoomIn)) { zoomInSlice->SetEnabled(m_ZoomFactor < MAXZOOMFACTOR); } - if (PieSlice *zoomOutSlice = m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorZoomOut)) { zoomOutSlice->SetEnabled(m_ZoomFactor > MINZOOMFACTOR); } + if (PieSlice* zoomInSlice = m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorZoomIn)) { + zoomInSlice->SetEnabled(m_ZoomFactor < MAXZOOMFACTOR); + } + if (PieSlice* zoomOutSlice = m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorZoomOut)) { + zoomOutSlice->SetEnabled(m_ZoomFactor > MINZOOMFACTOR); + } - // Show the pie menu only when the secondary button is held down - if (m_pController->IsState(PRESS_SECONDARY) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGGIB) { + // Show the pie menu only when the secondary button is held down + if (m_pController->IsState(PRESS_SECONDARY) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGGIB) { m_PieMenu->SetPos(m_GridSnapping ? g_SceneMan.SnapPosition(m_CursorPos) : m_CursorPos); m_PieMenu->SetEnabled(true); - std::array infrontAndBehindPieSlices = { m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorInFront), m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorBehind) }; - for (PieSlice *pieSlice : infrontAndBehindPieSlices) { - if (pieSlice) { pieSlice->SetEnabled(m_EditorGUIMode == ADDINGGIB); } + std::array infrontAndBehindPieSlices = {m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorInFront), m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorBehind)}; + for (PieSlice* pieSlice: infrontAndBehindPieSlices) { + if (pieSlice) { + pieSlice->SetEnabled(m_EditorGUIMode == ADDINGGIB); + } } - } + } - if (!m_pController->IsState(PIE_MENU_ACTIVE) || m_EditorGUIMode == INACTIVE || m_EditorGUIMode == PICKINGGIB) { m_PieMenu->SetEnabled(false); } + if (!m_pController->IsState(PIE_MENU_ACTIVE) || m_EditorGUIMode == INACTIVE || m_EditorGUIMode == PICKINGGIB) { + m_PieMenu->SetEnabled(false); + } - /////////////////////////////////////// - // Handle pie menu selections + /////////////////////////////////////// + // Handle pie menu selections - if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { + if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorPick) { m_EditorGUIMode = PICKINGGIB; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorLoad) { - // Set up the picker to pick an MOSRotating to load - m_EditorGUIMode = PICKOBJECTTOLOAD; - m_pPicker->ShowOnlyType("MOSRotating"); + // Set up the picker to pick an MOSRotating to load + m_EditorGUIMode = PICKOBJECTTOLOAD; + m_pPicker->ShowOnlyType("MOSRotating"); } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorMove) { m_EditorGUIMode = MOVINGGIB; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorRemove) { @@ -299,581 +291,510 @@ void GibEditorGUI::Update() } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorZoomOut && m_ZoomFactor > MINZOOMFACTOR) { m_ZoomFactor--; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorInFront) { - m_PreviousMode = m_EditorGUIMode; - m_EditorGUIMode = PLACEINFRONT; - } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorBehind) { - m_PreviousMode = m_EditorGUIMode; - m_EditorGUIMode = PLACEBEHIND; - } - } - - ////////////////////////////////////////// - // Picker logic - - // Enable or disable the picker - m_pPicker->SetEnabled(m_EditorGUIMode == PICKOBJECTTOLOAD || m_EditorGUIMode == PICKINGGIB); - - // Update the picker GUI - m_pPicker->Update(); - - // Picking something to load into the editor - if (m_EditorGUIMode == PICKOBJECTTOLOAD) - { - g_FrameMan.ClearScreenText(); - g_FrameMan.SetScreenText("Select an object to LOAD into the gib editor ->", 0, 333); - - // Picked something! - if (m_pPicker->ObjectPicked() && !m_pPicker->IsEnabled()) - { - m_pObjectToLoad = dynamic_cast(m_pPicker->ObjectPicked()); - // Set picker back to showing all valid gib types - if (m_pObjectToLoad) - { - m_pPicker->ShowOnlyType("MovableObject"); - g_FrameMan.ClearScreenText(); - } - } - } - // Picking an object to place as a gib in currently edited object - else if (m_EditorGUIMode == PICKINGGIB) - { - g_FrameMan.SetScreenText("Select a new Gib object to add onto the edited object ->"); - - if (m_pPicker->ObjectPicked()) - { - // Assign a copy of the picked object to be the currently held one. - delete m_pCurrentGib; - if (m_pCurrentGib = dynamic_cast(m_pPicker->ObjectPicked()->Clone())) - { - // Disable any controller, if an actor - Actor *pActor = dynamic_cast(m_pCurrentGib); - if (pActor) - pActor->GetController()->SetDisabled(true); - // Set the list order to be at the end so new objects are added there - m_GibListOrder = -1; - // Update the object - m_pCurrentGib->Update(); - // If done picking, revert to moving object mode - if (m_pPicker->DonePicking()) - { - m_EditorGUIMode = ADDINGGIB; - } - } - } - } - - if (!m_pPicker->IsVisible()) - g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - ///////////////////////////////////// - // ADDING GIB MODE - - if (m_EditorGUIMode == ADDINGGIB && !m_PieMenu->IsEnabled()) - { - g_FrameMan.SetScreenText("Click to ADD a new gib to the edited object - Drag to place with precision", 0); - - m_DrawCurrentGib = true; - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput * 8; - // Re-enable snapping only when the cursor is moved again -// m_GridSnapping = true; - } - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - // Re-enable snapping only when the cursor is moved again -// m_GridSnapping = true; - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= SCENESNAPSIZE; - if (pressRight) - m_CursorPos.m_X += SCENESNAPSIZE; - if (pressDown) - m_CursorPos.m_Y += SCENESNAPSIZE; - if (pressLeft) - m_CursorPos.m_X -= SCENESNAPSIZE; - // Re-enable snapping only when the cursor is moved again -// if (pressUp || pressRight || pressDown || pressLeft) -// m_GridSnapping = true; - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - - // Mousewheel is used as shortcut for getting next and prev items in teh picker's object list - if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(ControlState::ACTOR_NEXT)) - { - // Assign a copy of the next picked object to be the currently held one. - const SceneObject *pNewObject = m_pPicker->GetPrevObject(); - if (pNewObject) - { - delete m_pCurrentGib; - m_pCurrentGib = dynamic_cast(pNewObject->Clone()); - // Disable any controller, if an actor - Actor *pActor = dynamic_cast(m_pCurrentGib); - if (pActor) - pActor->GetController()->SetDisabled(true); - // Update the object - m_pCurrentGib->Update(); - } - } - else if (m_pController->IsState(SCROLL_DOWN) || m_pController->IsState(ControlState::ACTOR_PREV)) - { - // Assign a copy of the next picked object to be the currently held one. - const SceneObject *pNewObject = m_pPicker->GetNextObject(); - if (pNewObject) - { - delete m_pCurrentGib; - m_pCurrentGib = dynamic_cast(pNewObject->Clone()); - // Disable any controller, if an actor - Actor *pActor = dynamic_cast(m_pCurrentGib); - if (pActor) - pActor->GetController()->SetDisabled(true); - // Update the object - m_pCurrentGib->Update(); - } - } - - // Start the timer when the button is first pressed, and when the picker has deactivated - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - m_BlinkTimer.Reset(); - m_EditorGUIMode = PLACINGGIB; - m_PreviousMode = ADDINGGIB; - g_GUISound.PlacementBlip()->Play(); - } - } - - ///////////////////////////////////////////////////////////// - // PLACING MODE - - else if (m_EditorGUIMode == PLACINGGIB) - { - if (m_PreviousMode == MOVINGGIB) - g_FrameMan.SetScreenText("Click and drag on a placed gib to MOVE it - Click quickly to DETACH", 0); - else - g_FrameMan.SetScreenText("Click to ADD a new gib to the edited object - Drag to place with precision", 0); - - m_DrawCurrentGib = true; - - // Freeze when first pressing down and grid snapping is still engaged - if (!(m_pController->IsState(PRIMARY_ACTION) && m_GridSnapping)) - { - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput; - m_FacingLeft = analogInput.m_X < 0 || (m_FacingLeft && analogInput.m_X == 0); - } - // Try the mouse - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - m_FacingLeft = m_pController->GetMouseMovement().m_X < 0 || (m_FacingLeft && m_pController->GetMouseMovement().m_X == 0); - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= 1; - if (pressRight) - { - m_CursorPos.m_X += 1; - m_FacingLeft = false; - } - if (pressDown) - m_CursorPos.m_Y += 1; - if (pressLeft) - { - m_CursorPos.m_X -= 1; - m_FacingLeft = true; - } - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - } - - // Disable snapping after a small interval of holding down the button, to avoid unintentional nudges when just placing on the grid - if (m_pController->IsState(PRIMARY_ACTION) && m_BlinkTimer.IsPastRealMS(333) && m_GridSnapping) - { - m_GridSnapping = false; - m_CursorPos = g_SceneMan.SnapPosition(m_CursorPos); - } - - if (m_pController->IsState(RELEASE_PRIMARY)) - - // Cancel placing if secondary button is pressed - if (m_pController->IsState(PRESS_SECONDARY) || m_pController->IsState(PIE_MENU_ACTIVE)) - { - m_EditorGUIMode = m_PreviousMode; - } - // If previous mode was moving, tear the gib loose if the button is released to soo - else if (m_PreviousMode == MOVINGGIB && m_pController->IsState(RELEASE_PRIMARY) && !m_BlinkTimer.IsPastRealMS(150)) - { - m_EditorGUIMode = ADDINGGIB; - } - // Only place if the picker and pie menus are completely out of view, to avoid immediate placing after picking - else if (m_pCurrentGib && m_pController->IsState(RELEASE_PRIMARY) && !m_pPicker->IsVisible()) - { - m_pCurrentGib->Update(); - - // Add to the placed objects list - AddPlacedObject(dynamic_cast(m_pCurrentGib->Clone()), m_GibListOrder); - // Increment the list order so we place over last placed item - if (m_GibListOrder >= 0) - m_GibListOrder++; - g_GUISound.PlacementThud()->Play(); -// g_GUISound.PlacementGravel()->Play(); - m_EditMade = true; - -// TEMP REMOVE WEHN YOU CLEAN UP THE ABOVE HARDCODED BRAIN PLACEMENT - if (m_EditorGUIMode != PICKINGGIB) -// TEMP REMOVE ABOVE - // Go back to previous mode - m_EditorGUIMode = m_PreviousMode; - } - - // Set the facing of AHumans based on right/left cursor movements - AHuman *pAHuman = dynamic_cast(m_pCurrentGib); - if (pAHuman) - pAHuman->SetHFlipped(m_FacingLeft); - } - - ///////////////////////////////////////////////////////////// - // POINTING AT MODES - - else if ((m_EditorGUIMode == MOVINGGIB || m_EditorGUIMode == DELETINGGIB || m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) && !m_PieMenu->IsEnabled()) - { - m_DrawCurrentGib = false; - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - m_CursorPos += analogInput * 4; - else if (!m_pController->GetMouseMovement().IsZero()) - m_CursorPos += m_pController->GetMouseMovement() / 2; - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= 1; - if (pressRight) - m_CursorPos.m_X += 1; - if (pressDown) - m_CursorPos.m_Y += 1; - if (pressLeft) - m_CursorPos.m_X -= 1; - } - - ///////////////////////////////// - // MOVING GIB MODE - - if (m_EditorGUIMode == MOVINGGIB) - { - g_FrameMan.SetScreenText("Click and drag on a placed gib to MOVE it - Click quickly to DETACH", 0); - - // Pick an object under the cursor and start moving it - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - const MovableObject *pPicked = PickPlacedObject(m_CursorPos, &m_GibListOrder); - if (pPicked) - { - // Grab the position and a copy of the the object itself before killing it from the scene - m_pCurrentGib = dynamic_cast(pPicked->Clone()); - m_CursorOffset = m_CursorPos - m_pCurrentGib->GetPos(); - RemovePlacedObject(m_GibListOrder); - m_EditMade = true; - - // Go to placing mode to move it around - m_EditorGUIMode = PLACINGGIB; - m_PreviousMode = MOVINGGIB; - m_BlinkTimer.Reset(); - g_GUISound.PlacementBlip()->Play(); - g_GUISound.PlacementGravel()->Play(); - } - else - g_GUISound.UserErrorSound()->Play(); - } - } - - //////////////////////////// - // REMOVING GIB MODE - - else if (m_EditorGUIMode == DELETINGGIB) - { - g_FrameMan.SetScreenText("Click and hold to select an object - release to DELETE it", 0); - - // When primary is held down, pick object and show which one will be nuked if released - if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) - { - m_pObjectToBlink = PickPlacedObject(m_CursorPos); - } - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - if (PickPlacedObject(m_CursorPos, &m_GibListOrder)) - { - // Nuke it! - RemovePlacedObject(m_GibListOrder); - m_EditMade = true; -// TODO: Add awesome destruction sound here - } - else - g_GUISound.UserErrorSound()->Play(); - } - } - - ///////////////////////////////////// - // PLACE IN FRONT AND BEHIND OF MODES - - else if (m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) - { - if (m_EditorGUIMode == PLACEINFRONT) - g_FrameMan.SetScreenText("Click an object to place the next one IN FRONT of it", 0); - else if (m_EditorGUIMode == PLACEBEHIND) - g_FrameMan.SetScreenText("Click an object to place the next one BEHIND it", 0); - - // When primary is held down, pick object and show which one will be nuked if released - if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) - { - m_pObjectToBlink = PickPlacedObject(m_CursorPos); - } - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - if (PickPlacedObject(m_CursorPos, &m_GibListOrder)) - { - // Adjust the next list order to be in front if applicable (it's automatically behind if same order index) - if (m_EditorGUIMode == PLACEINFRONT) - m_GibListOrder++; - - // Go back to previous mode - m_EditorGUIMode = m_PreviousMode; - } - else - g_GUISound.UserErrorSound()->Play(); - } - } - } - - // Remove cursor offset if not applicable anymore - if (m_EditorGUIMode != PLACINGGIB) - m_CursorOffset.Reset(); - - // Keep the cursor position within the world - g_SceneMan.ForceBounds(m_CursorPos); -// TODO: make setscrolltarget with 'sloppy' target - // Scroll to the cursor's scene position - g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - // Apply the cursor position to the currently held object - if (m_pCurrentGib && m_DrawCurrentGib) - { + m_PreviousMode = m_EditorGUIMode; + m_EditorGUIMode = PLACEINFRONT; + } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorBehind) { + m_PreviousMode = m_EditorGUIMode; + m_EditorGUIMode = PLACEBEHIND; + } + } + + ////////////////////////////////////////// + // Picker logic + + // Enable or disable the picker + m_pPicker->SetEnabled(m_EditorGUIMode == PICKOBJECTTOLOAD || m_EditorGUIMode == PICKINGGIB); + + // Update the picker GUI + m_pPicker->Update(); + + // Picking something to load into the editor + if (m_EditorGUIMode == PICKOBJECTTOLOAD) { + g_FrameMan.ClearScreenText(); + g_FrameMan.SetScreenText("Select an object to LOAD into the gib editor ->", 0, 333); + + // Picked something! + if (m_pPicker->ObjectPicked() && !m_pPicker->IsEnabled()) { + m_pObjectToLoad = dynamic_cast(m_pPicker->ObjectPicked()); + // Set picker back to showing all valid gib types + if (m_pObjectToLoad) { + m_pPicker->ShowOnlyType("MovableObject"); + g_FrameMan.ClearScreenText(); + } + } + } + // Picking an object to place as a gib in currently edited object + else if (m_EditorGUIMode == PICKINGGIB) { + g_FrameMan.SetScreenText("Select a new Gib object to add onto the edited object ->"); + + if (m_pPicker->ObjectPicked()) { + // Assign a copy of the picked object to be the currently held one. + delete m_pCurrentGib; + if (m_pCurrentGib = dynamic_cast(m_pPicker->ObjectPicked()->Clone())) { + // Disable any controller, if an actor + Actor* pActor = dynamic_cast(m_pCurrentGib); + if (pActor) + pActor->GetController()->SetDisabled(true); + // Set the list order to be at the end so new objects are added there + m_GibListOrder = -1; + // Update the object + m_pCurrentGib->Update(); + // If done picking, revert to moving object mode + if (m_pPicker->DonePicking()) { + m_EditorGUIMode = ADDINGGIB; + } + } + } + } + + if (!m_pPicker->IsVisible()) + g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + ///////////////////////////////////// + // ADDING GIB MODE + + if (m_EditorGUIMode == ADDINGGIB && !m_PieMenu->IsEnabled()) { + g_FrameMan.SetScreenText("Click to ADD a new gib to the edited object - Drag to place with precision", 0); + + m_DrawCurrentGib = true; + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) { + m_CursorPos += analogInput * 8; + // Re-enable snapping only when the cursor is moved again + // m_GridSnapping = true; + } else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + // Re-enable snapping only when the cursor is moved again + // m_GridSnapping = true; + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= SCENESNAPSIZE; + if (pressRight) + m_CursorPos.m_X += SCENESNAPSIZE; + if (pressDown) + m_CursorPos.m_Y += SCENESNAPSIZE; + if (pressLeft) + m_CursorPos.m_X -= SCENESNAPSIZE; + // Re-enable snapping only when the cursor is moved again + // if (pressUp || pressRight || pressDown || pressLeft) + // m_GridSnapping = true; + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + + // Mousewheel is used as shortcut for getting next and prev items in teh picker's object list + if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(ControlState::ACTOR_NEXT)) { + // Assign a copy of the next picked object to be the currently held one. + const SceneObject* pNewObject = m_pPicker->GetPrevObject(); + if (pNewObject) { + delete m_pCurrentGib; + m_pCurrentGib = dynamic_cast(pNewObject->Clone()); + // Disable any controller, if an actor + Actor* pActor = dynamic_cast(m_pCurrentGib); + if (pActor) + pActor->GetController()->SetDisabled(true); + // Update the object + m_pCurrentGib->Update(); + } + } else if (m_pController->IsState(SCROLL_DOWN) || m_pController->IsState(ControlState::ACTOR_PREV)) { + // Assign a copy of the next picked object to be the currently held one. + const SceneObject* pNewObject = m_pPicker->GetNextObject(); + if (pNewObject) { + delete m_pCurrentGib; + m_pCurrentGib = dynamic_cast(pNewObject->Clone()); + // Disable any controller, if an actor + Actor* pActor = dynamic_cast(m_pCurrentGib); + if (pActor) + pActor->GetController()->SetDisabled(true); + // Update the object + m_pCurrentGib->Update(); + } + } + + // Start the timer when the button is first pressed, and when the picker has deactivated + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + m_BlinkTimer.Reset(); + m_EditorGUIMode = PLACINGGIB; + m_PreviousMode = ADDINGGIB; + g_GUISound.PlacementBlip()->Play(); + } + } + + ///////////////////////////////////////////////////////////// + // PLACING MODE + + else if (m_EditorGUIMode == PLACINGGIB) { + if (m_PreviousMode == MOVINGGIB) + g_FrameMan.SetScreenText("Click and drag on a placed gib to MOVE it - Click quickly to DETACH", 0); + else + g_FrameMan.SetScreenText("Click to ADD a new gib to the edited object - Drag to place with precision", 0); + + m_DrawCurrentGib = true; + + // Freeze when first pressing down and grid snapping is still engaged + if (!(m_pController->IsState(PRIMARY_ACTION) && m_GridSnapping)) { + if (!analogInput.IsZero()) { + m_CursorPos += analogInput; + m_FacingLeft = analogInput.m_X < 0 || (m_FacingLeft && analogInput.m_X == 0); + } + // Try the mouse + else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + m_FacingLeft = m_pController->GetMouseMovement().m_X < 0 || (m_FacingLeft && m_pController->GetMouseMovement().m_X == 0); + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= 1; + if (pressRight) { + m_CursorPos.m_X += 1; + m_FacingLeft = false; + } + if (pressDown) + m_CursorPos.m_Y += 1; + if (pressLeft) { + m_CursorPos.m_X -= 1; + m_FacingLeft = true; + } + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + } + + // Disable snapping after a small interval of holding down the button, to avoid unintentional nudges when just placing on the grid + if (m_pController->IsState(PRIMARY_ACTION) && m_BlinkTimer.IsPastRealMS(333) && m_GridSnapping) { + m_GridSnapping = false; + m_CursorPos = g_SceneMan.SnapPosition(m_CursorPos); + } + + if (m_pController->IsState(RELEASE_PRIMARY)) + + // Cancel placing if secondary button is pressed + if (m_pController->IsState(PRESS_SECONDARY) || m_pController->IsState(PIE_MENU_ACTIVE)) { + m_EditorGUIMode = m_PreviousMode; + } + // If previous mode was moving, tear the gib loose if the button is released to soo + else if (m_PreviousMode == MOVINGGIB && m_pController->IsState(RELEASE_PRIMARY) && !m_BlinkTimer.IsPastRealMS(150)) { + m_EditorGUIMode = ADDINGGIB; + } + // Only place if the picker and pie menus are completely out of view, to avoid immediate placing after picking + else if (m_pCurrentGib && m_pController->IsState(RELEASE_PRIMARY) && !m_pPicker->IsVisible()) { + m_pCurrentGib->Update(); + + // Add to the placed objects list + AddPlacedObject(dynamic_cast(m_pCurrentGib->Clone()), m_GibListOrder); + // Increment the list order so we place over last placed item + if (m_GibListOrder >= 0) + m_GibListOrder++; + g_GUISound.PlacementThud()->Play(); + // g_GUISound.PlacementGravel()->Play(); + m_EditMade = true; + + // TEMP REMOVE WEHN YOU CLEAN UP THE ABOVE HARDCODED BRAIN PLACEMENT + if (m_EditorGUIMode != PICKINGGIB) + // TEMP REMOVE ABOVE + // Go back to previous mode + m_EditorGUIMode = m_PreviousMode; + } + + // Set the facing of AHumans based on right/left cursor movements + AHuman* pAHuman = dynamic_cast(m_pCurrentGib); + if (pAHuman) + pAHuman->SetHFlipped(m_FacingLeft); + } + + ///////////////////////////////////////////////////////////// + // POINTING AT MODES + + else if ((m_EditorGUIMode == MOVINGGIB || m_EditorGUIMode == DELETINGGIB || m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) && !m_PieMenu->IsEnabled()) { + m_DrawCurrentGib = false; + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) + m_CursorPos += analogInput * 4; + else if (!m_pController->GetMouseMovement().IsZero()) + m_CursorPos += m_pController->GetMouseMovement() / 2; + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= 1; + if (pressRight) + m_CursorPos.m_X += 1; + if (pressDown) + m_CursorPos.m_Y += 1; + if (pressLeft) + m_CursorPos.m_X -= 1; + } + + ///////////////////////////////// + // MOVING GIB MODE + + if (m_EditorGUIMode == MOVINGGIB) { + g_FrameMan.SetScreenText("Click and drag on a placed gib to MOVE it - Click quickly to DETACH", 0); + + // Pick an object under the cursor and start moving it + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + const MovableObject* pPicked = PickPlacedObject(m_CursorPos, &m_GibListOrder); + if (pPicked) { + // Grab the position and a copy of the the object itself before killing it from the scene + m_pCurrentGib = dynamic_cast(pPicked->Clone()); + m_CursorOffset = m_CursorPos - m_pCurrentGib->GetPos(); + RemovePlacedObject(m_GibListOrder); + m_EditMade = true; + + // Go to placing mode to move it around + m_EditorGUIMode = PLACINGGIB; + m_PreviousMode = MOVINGGIB; + m_BlinkTimer.Reset(); + g_GUISound.PlacementBlip()->Play(); + g_GUISound.PlacementGravel()->Play(); + } else + g_GUISound.UserErrorSound()->Play(); + } + } + + //////////////////////////// + // REMOVING GIB MODE + + else if (m_EditorGUIMode == DELETINGGIB) { + g_FrameMan.SetScreenText("Click and hold to select an object - release to DELETE it", 0); + + // When primary is held down, pick object and show which one will be nuked if released + if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) { + m_pObjectToBlink = PickPlacedObject(m_CursorPos); + } else if (m_pController->IsState(RELEASE_PRIMARY)) { + if (PickPlacedObject(m_CursorPos, &m_GibListOrder)) { + // Nuke it! + RemovePlacedObject(m_GibListOrder); + m_EditMade = true; + // TODO: Add awesome destruction sound here + } else + g_GUISound.UserErrorSound()->Play(); + } + } + + ///////////////////////////////////// + // PLACE IN FRONT AND BEHIND OF MODES + + else if (m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) { + if (m_EditorGUIMode == PLACEINFRONT) + g_FrameMan.SetScreenText("Click an object to place the next one IN FRONT of it", 0); + else if (m_EditorGUIMode == PLACEBEHIND) + g_FrameMan.SetScreenText("Click an object to place the next one BEHIND it", 0); + + // When primary is held down, pick object and show which one will be nuked if released + if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) { + m_pObjectToBlink = PickPlacedObject(m_CursorPos); + } else if (m_pController->IsState(RELEASE_PRIMARY)) { + if (PickPlacedObject(m_CursorPos, &m_GibListOrder)) { + // Adjust the next list order to be in front if applicable (it's automatically behind if same order index) + if (m_EditorGUIMode == PLACEINFRONT) + m_GibListOrder++; + + // Go back to previous mode + m_EditorGUIMode = m_PreviousMode; + } else + g_GUISound.UserErrorSound()->Play(); + } + } + } + + // Remove cursor offset if not applicable anymore + if (m_EditorGUIMode != PLACINGGIB) + m_CursorOffset.Reset(); + + // Keep the cursor position within the world + g_SceneMan.ForceBounds(m_CursorPos); + // TODO: make setscrolltarget with 'sloppy' target + // Scroll to the cursor's scene position + g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + // Apply the cursor position to the currently held object + if (m_pCurrentGib && m_DrawCurrentGib) { Vector gibPos = g_SceneMan.SnapPosition(m_CursorPos - m_CursorOffset, m_GridSnapping); gibPos.SetX(static_cast(gibPos.m_X)); gibPos.SetY(static_cast(gibPos.m_Y)); - m_pCurrentGib->SetPos(gibPos); - m_pCurrentGib->Update(); - } + m_pCurrentGib->SetPos(gibPos); + m_pCurrentGib->Update(); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the menu -void GibEditorGUI::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) const -{ - // Done, so don't draw the UI - if (m_EditorGUIMode == DONEEDITING) - return; - - // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene - int i = 0; - for (std::list::const_iterator itr = m_PlacedGibs.begin(); itr != m_PlacedGibs.end(); ++itr, ++i) - { - // Draw the currently held object into the order of the list if it is to be placed inside - if (m_pCurrentGib && m_DrawCurrentGib && i == m_GibListOrder) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGGIB ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - m_pCurrentGib->Draw(pTargetBitmap, targetPos, g_DrawTrans); - Actor *pActor = dynamic_cast(m_pCurrentGib); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - - // Blink trans if we are supposed to blink this one - if ((*itr) == m_pObjectToBlink) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); - } - else - (*itr)->Draw(pTargetBitmap, targetPos); - - // Draw basic HUD if an actor - Actor *pActor = dynamic_cast(*itr); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - - // Draw picking object crosshairs and not the selected object - if (!m_DrawCurrentGib) - { - Vector center = m_CursorPos - targetPos; - putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); - } - // If the held object will be placed at the end of the list, draw it last to the scene, transperent blinking - else if (m_pCurrentGib && (m_GibListOrder < 0 || m_GibListOrder == m_PlacedGibs.size())) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGGIB ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - m_pCurrentGib->Draw(pTargetBitmap, targetPos, g_DrawTrans); - Actor *pActor = dynamic_cast(m_pCurrentGib); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - - // Draw the zoom window, if active - if (m_ZoomFactor > 1) - { - Vector sourceCenter = m_CursorPos - targetPos; - - // Make sure the source is within the target bitmap - int halfWidth = m_pZoomSource->w / 2; - if (sourceCenter.m_X - halfWidth < 0) - sourceCenter.m_X = halfWidth; - else if (sourceCenter.m_X + halfWidth >= pTargetBitmap->w) - sourceCenter.m_X = pTargetBitmap->w - halfWidth; - int halfHeight = m_pZoomSource->w / 2; - if (sourceCenter.m_Y - halfHeight < 0) - sourceCenter.m_Y = halfHeight; - else if (sourceCenter.m_Y + halfHeight >= pTargetBitmap->h) - sourceCenter.m_Y = pTargetBitmap->h - halfHeight; - - // Copy to the intermediate source bitmap - blit(pTargetBitmap, m_pZoomSource, sourceCenter.m_X - halfWidth, sourceCenter.m_Y - halfHeight, 0, 0, m_pZoomSource->w, m_pZoomSource->h); - - - Vector zoomedCenter = m_CursorPos - targetPos; - - // Make sure the zoomed view is within the target bitmap - halfWidth = (m_pZoomSource->w / 2) * m_ZoomFactor; - if (zoomedCenter.m_X - halfWidth < 0) - zoomedCenter.m_X = halfWidth; - else if (zoomedCenter.m_X + halfWidth >= pTargetBitmap->w) - zoomedCenter.m_X = pTargetBitmap->w - halfWidth; - halfHeight = (m_pZoomSource->w / 2) * m_ZoomFactor; - if (zoomedCenter.m_Y - halfHeight < 0) - zoomedCenter.m_Y = halfHeight; - else if (zoomedCenter.m_Y + halfHeight >= pTargetBitmap->h) - zoomedCenter.m_Y = pTargetBitmap->h - halfHeight; - - // Then draw right back but stretched to the target - stretch_blit(m_pZoomSource, pTargetBitmap, 0, 0, m_pZoomSource->w, m_pZoomSource->h, zoomedCenter.m_X - halfWidth, zoomedCenter.m_Y - halfHeight, m_pZoomSource->w * m_ZoomFactor, m_pZoomSource->h * m_ZoomFactor); - rect(pTargetBitmap, zoomedCenter.m_X - halfWidth, zoomedCenter.m_Y - halfHeight, zoomedCenter.m_X + halfWidth - 1, zoomedCenter.m_Y + halfHeight - 1, g_YellowGlowColor); - } - - m_pPicker->Draw(pTargetBitmap); - - // Draw the pie menu +void GibEditorGUI::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) const { + // Done, so don't draw the UI + if (m_EditorGUIMode == DONEEDITING) + return; + + // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene + int i = 0; + for (std::list::const_iterator itr = m_PlacedGibs.begin(); itr != m_PlacedGibs.end(); ++itr, ++i) { + // Draw the currently held object into the order of the list if it is to be placed inside + if (m_pCurrentGib && m_DrawCurrentGib && i == m_GibListOrder) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGGIB ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + m_pCurrentGib->Draw(pTargetBitmap, targetPos, g_DrawTrans); + Actor* pActor = dynamic_cast(m_pCurrentGib); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + + // Blink trans if we are supposed to blink this one + if ((*itr) == m_pObjectToBlink) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); + } else + (*itr)->Draw(pTargetBitmap, targetPos); + + // Draw basic HUD if an actor + Actor* pActor = dynamic_cast(*itr); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + + // Draw picking object crosshairs and not the selected object + if (!m_DrawCurrentGib) { + Vector center = m_CursorPos - targetPos; + putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); + } + // If the held object will be placed at the end of the list, draw it last to the scene, transperent blinking + else if (m_pCurrentGib && (m_GibListOrder < 0 || m_GibListOrder == m_PlacedGibs.size())) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGGIB ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + m_pCurrentGib->Draw(pTargetBitmap, targetPos, g_DrawTrans); + Actor* pActor = dynamic_cast(m_pCurrentGib); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + + // Draw the zoom window, if active + if (m_ZoomFactor > 1) { + Vector sourceCenter = m_CursorPos - targetPos; + + // Make sure the source is within the target bitmap + int halfWidth = m_pZoomSource->w / 2; + if (sourceCenter.m_X - halfWidth < 0) + sourceCenter.m_X = halfWidth; + else if (sourceCenter.m_X + halfWidth >= pTargetBitmap->w) + sourceCenter.m_X = pTargetBitmap->w - halfWidth; + int halfHeight = m_pZoomSource->w / 2; + if (sourceCenter.m_Y - halfHeight < 0) + sourceCenter.m_Y = halfHeight; + else if (sourceCenter.m_Y + halfHeight >= pTargetBitmap->h) + sourceCenter.m_Y = pTargetBitmap->h - halfHeight; + + // Copy to the intermediate source bitmap + blit(pTargetBitmap, m_pZoomSource, sourceCenter.m_X - halfWidth, sourceCenter.m_Y - halfHeight, 0, 0, m_pZoomSource->w, m_pZoomSource->h); + + Vector zoomedCenter = m_CursorPos - targetPos; + + // Make sure the zoomed view is within the target bitmap + halfWidth = (m_pZoomSource->w / 2) * m_ZoomFactor; + if (zoomedCenter.m_X - halfWidth < 0) + zoomedCenter.m_X = halfWidth; + else if (zoomedCenter.m_X + halfWidth >= pTargetBitmap->w) + zoomedCenter.m_X = pTargetBitmap->w - halfWidth; + halfHeight = (m_pZoomSource->w / 2) * m_ZoomFactor; + if (zoomedCenter.m_Y - halfHeight < 0) + zoomedCenter.m_Y = halfHeight; + else if (zoomedCenter.m_Y + halfHeight >= pTargetBitmap->h) + zoomedCenter.m_Y = pTargetBitmap->h - halfHeight; + + // Then draw right back but stretched to the target + stretch_blit(m_pZoomSource, pTargetBitmap, 0, 0, m_pZoomSource->w, m_pZoomSource->h, zoomedCenter.m_X - halfWidth, zoomedCenter.m_Y - halfHeight, m_pZoomSource->w * m_ZoomFactor, m_pZoomSource->h * m_ZoomFactor); + rect(pTargetBitmap, zoomedCenter.m_X - halfWidth, zoomedCenter.m_Y - halfHeight, zoomedCenter.m_X + halfWidth - 1, zoomedCenter.m_Y + halfHeight - 1, g_YellowGlowColor); + } + + m_pPicker->Draw(pTargetBitmap); + + // Draw the pie menu m_PieMenu->Draw(pTargetBitmap, targetPos); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: AddPlacedObject ////////////////////////////////////////////////////////////////////////////////////////// // Description: Adds a MovableObject to be placed in this scene. Ownership IS transferred! -void GibEditorGUI::AddPlacedObject(MovableObject *pObjectToAdd, int listOrder) -{ - if (!pObjectToAdd) - return; - - if (listOrder < 0 || listOrder >= m_PlacedGibs.size()) - m_PlacedGibs.push_back(pObjectToAdd); - else - { - // Find the spot - std::list::iterator itr = m_PlacedGibs.begin(); - for (int i = 0; i != listOrder && itr != m_PlacedGibs.end(); ++i, ++itr) - ; - - // Put 'er in - m_PlacedGibs.insert(itr, pObjectToAdd); - } +void GibEditorGUI::AddPlacedObject(MovableObject* pObjectToAdd, int listOrder) { + if (!pObjectToAdd) + return; + + if (listOrder < 0 || listOrder >= m_PlacedGibs.size()) + m_PlacedGibs.push_back(pObjectToAdd); + else { + // Find the spot + std::list::iterator itr = m_PlacedGibs.begin(); + for (int i = 0; i != listOrder && itr != m_PlacedGibs.end(); ++i, ++itr) + ; + + // Put 'er in + m_PlacedGibs.insert(itr, pObjectToAdd); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: RemovePlacedObject ////////////////////////////////////////////////////////////////////////////////////////// // Description: Removes a MovableObject placed in this scene. -void GibEditorGUI::RemovePlacedObject(int whichToRemove) -{ - if (m_PlacedGibs.empty()) - return; - - if (whichToRemove < 0 || whichToRemove >= m_PlacedGibs.size()) - { - delete m_PlacedGibs.back(); - m_PlacedGibs.pop_back(); - } - else - { - // Find the spot - std::list::iterator itr = m_PlacedGibs.begin(); - for (int i = 0; i != whichToRemove && itr != m_PlacedGibs.end(); ++i, ++itr) - ; - - delete (*itr); - m_PlacedGibs.erase(itr); - } +void GibEditorGUI::RemovePlacedObject(int whichToRemove) { + if (m_PlacedGibs.empty()) + return; + + if (whichToRemove < 0 || whichToRemove >= m_PlacedGibs.size()) { + delete m_PlacedGibs.back(); + m_PlacedGibs.pop_back(); + } else { + // Find the spot + std::list::iterator itr = m_PlacedGibs.begin(); + for (int i = 0; i != whichToRemove && itr != m_PlacedGibs.end(); ++i, ++itr) + ; + + delete (*itr); + m_PlacedGibs.erase(itr); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: PickPlacedObject ////////////////////////////////////////////////////////////////////////////////////////// // Description: Returns the last placed object that graphically overlaps an absolute // point in the scene. -const MovableObject * GibEditorGUI::PickPlacedObject(Vector &scenePoint, int *pListOrderPlace) const -{ - // REVERSE! - int i = m_PlacedGibs.size() - 1; - for (std::list::const_reverse_iterator itr = m_PlacedGibs.rbegin(); itr != m_PlacedGibs.rend(); ++itr, --i) - { - if ((*itr)->IsOnScenePoint(scenePoint)) - { - if (pListOrderPlace) - *pListOrderPlace = i; - return *itr; - } - } - - if (pListOrderPlace) - *pListOrderPlace = -1; - return 0; -} +const MovableObject* GibEditorGUI::PickPlacedObject(Vector& scenePoint, int* pListOrderPlace) const { + // REVERSE! + int i = m_PlacedGibs.size() - 1; + for (std::list::const_reverse_iterator itr = m_PlacedGibs.rbegin(); itr != m_PlacedGibs.rend(); ++itr, --i) { + if ((*itr)->IsOnScenePoint(scenePoint)) { + if (pListOrderPlace) + *pListOrderPlace = i; + return *itr; + } + } + if (pListOrderPlace) + *pListOrderPlace = -1; + return 0; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePlacedObjects @@ -881,10 +802,8 @@ const MovableObject * GibEditorGUI::PickPlacedObject(Vector &scenePoint, int *pL // Description: Updated the objects in the placed scene objects list of this. This is // mostly for the editor to represent the items correctly. -void GibEditorGUI::UpdatePlacedObjects() -{ - for (std::list::iterator itr = m_PlacedGibs.begin(); itr != m_PlacedGibs.end(); ++itr) - { - (*itr)->Update(); - } -} \ No newline at end of file +void GibEditorGUI::UpdatePlacedObjects() { + for (std::list::iterator itr = m_PlacedGibs.begin(); itr != m_PlacedGibs.end(); ++itr) { + (*itr)->Update(); + } +} diff --git a/Source/Menus/GibEditorGUI.h b/Source/Menus/GibEditorGUI.h index fd15e09e5..2727042c4 100644 --- a/Source/Menus/GibEditorGUI.h +++ b/Source/Menus/GibEditorGUI.h @@ -10,7 +10,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -22,387 +21,351 @@ struct BITMAP; - -namespace RTE -{ - -class MovableObject; -class MOSRotating; -class ObjectPickerGUI; -class PieMenu; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: GibEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A placement part of the gib editor which manages the pie menu and picker. -// Parent(s): None. -// Class history: 9/16/2007 GibEditorGUI Created. - -class GibEditorGUI { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - // Different modes of this editor - enum EditorGUIMode - { - INACTIVE = 0, - PICKOBJECTTOLOAD, - PICKINGGIB, - ADDINGGIB, - PLACINGGIB, - MOVINGGIB, - DELETINGGIB, - PLACEINFRONT, - PLACEBEHIND, - DONEEDITING, - EDITORGUIMODECOUNT - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: GibEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a GibEditorGUI object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - GibEditorGUI() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~GibEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a GibEditorGUI object before deletion -// from system memory. -// Arguments: None. - - ~GibEditorGUI() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the GibEditorGUI object ready for use. -// Arguments: A poitner to a Controller which will control this Menu. Ownership is -// NOT TRANSFERRED! -// Which module space that this eidtor will be able to pick objects from. -// -1 means all modules. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(Controller *pController, int whichModuleSpace = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire GibEditorGUI, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the GibEditorGUI object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the controller used by this. The ownership of the controller is -// NOT transferred! -// Arguments: The new controller for this menu. Ownership is NOT transferred -// Return value: None. - - void SetController(Controller *pController); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPosOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where on the screen that this GUI is being drawn to. If upper -// left corner, then 0, 0. This will affect the way the mouse is positioned -// etc. -// Arguments: The new screen position of this entire GUI. - - void SetPosOnScreen(int newPosX, int newPosY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCursorPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the absolute scene coordinates of the cursor of this Editor. -// Arguments: The new cursor position in absolute scene units. -// Return value: None. - - void SetCursorPos(const Vector &newCursorPos) { m_CursorPos = newCursorPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCurrentGib -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the new Object to be held at the gib cursor of this Editor. Ownership -// IS transferred! -// Arguments: The new Object to be held by the cursor. Ownership IS transferred! -// Return value: None. - - void SetCurrentGib(MovableObject *pNewGibObject) { m_pCurrentGib = pNewGibObject; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActivatedPieSlice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets any Pie menu slice command activated last update. -// Arguments: None. -// Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. - - PieSlice::SliceType GetActivatedPieSlice() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlacedGibs -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the list of already placed gibs of the currently edited object. -// Ownership of neither list not objects IS NOT transferred! -// Arguments: None. -// Return value: The current list of placed gibs. OWNERSHIP IS NOT TRANSFERRED! - - std::list * GetPlacedGibs() { return &m_PlacedGibs; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentGib -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the currently held Object in the cursor of this Editor. Ownership -// IS NOT transferred! -// Arguments: None. -// Return value: The currently held object, if any. OWNERSHIP IS NOT TRANSFERRED! - - const MovableObject * GetCurrentGib() { return m_pCurrentGib; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetObjectToLoad -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns a refernece instance of an object if it has been picked to be -// loaded into the editor. Ownership is NOT transferred. -// Arguments: None. -// Return value: Reference instance of the picked object to be loaded. 0 if nothing. OWNERSHIP IS NOT TRANSFERRED! -// was picked since last update. - - const MOSRotating * GetObjectToLoad() { return m_pObjectToLoad; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which DataModule space to be picking objects from. If -1, then -// let the player pick from all loaded modules. -// Arguments: The ID of the module to let the player pick objects from. All official -// modules' objects will alwayws be presented, in addition to the one -// passed in here. -// Return value: None. - - void SetModuleSpace(int moduleSpaceID = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EditMade -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether an edit on the scene was made in the last Update. -// Arguments: None. -// Return value: Whether any edit was made. - - bool EditMade() const { return m_EditMade; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Menu each frame -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the editor -// Arguments: The bitmap to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AddPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Adds a MovableObject to be placed in the editor. Ownership IS transferred! -// Arguments: The MovableOjbect instace to add, OIT! -// Where in the list the object should be inserted. -1 means at the end -// of the list. -// Return value: None. - - void AddPlacedObject(MovableObject *pObjectToAdd, int listOrder = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemovePlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a MovableObject placed in this editor. -// Arguments: The list order number of the object to remove. If -1, the last one is removed. -// Return value: None. - - void RemovePlacedObject(int whichToRemove = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PickPlacedObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Returns the last placed object that graphically overlaps an absolute -// point in the scene. Note that the placed object don't really exist in -// the scene, but in the editor. Their own Pos's are used. -// Arguments: The point in absolute scene coordinates that will be used to pick the -// last placed MovableObject which overlaps it. -// An int which will be filled out with the order place of any found object -// in the list. if nothing is found, it will get a value of -1. -// Return value: The last hit MovableObject, if any. Ownership is NOT transferred! - - const MovableObject * PickPlacedObject(Vector &scenePoint, int *pListOrderPlace = 0) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePlacedObjects -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updated the objects in the placed scene objects list of this. This is -// mostly for the editor to represent the items correctly. -// Arguments: None. -// Return value: None. - - void UpdatePlacedObjects(); - - - enum BlinkMode - { - NOBLINK = 0, - OBJECTBLINKON, - OBJECTBLINKOFF, - BLINKMODECOUNT - }; - - // Controller which conrols this menu. Not owned - Controller *m_pController; - // Whether an editor was made to the Scene in the last Update - bool m_EditMade; - // The current mode of the whole GUI. See EditorGUIMode enum. - EditorGUIMode m_EditorGUIMode; - // The previous mode of the whole GUI, to go back to when the current mode is done in some cases - EditorGUIMode m_PreviousMode; - // The ref instance picked to be loaded into the editor from the picker. 0 if none has been yet. Not owned. - const MOSRotating *m_pObjectToLoad; - // Notification blink timer - Timer m_BlinkTimer; - // What we're blinking - int m_BlinkMode; - // Measures the time to when to start repeating inputs when they're held down - Timer m_RepeatStartTimer; - // Measures the interval between input repeats - Timer m_RepeatTimer; - - std::unique_ptr m_PieMenu; //!< The PieMenu for this GibEditorGUI. - // The object picker - ObjectPickerGUI *m_pPicker; - // Grid snapping enabled - bool m_GridSnapping; - // The zooming bitmaps owned by this; source gets the area from the screen, destination is the zoomed in view - BITMAP *m_pZoomSource; - // The zoom factor of the magnifying window. 0 means no zoom window - int m_ZoomFactor; - // Current cursor position, in absolute scene coordinates - Vector m_CursorPos; - // The offset from the current object's position to the cursor, if any - Vector m_CursorOffset; - // Cursor position in free air, or over something - bool m_CursorInAir; - // Gib facing left or not when placing - bool m_FacingLeft; - // List of all the gibs currently placed on the edited object. - // They are proxies of the actual gib list of the edited object, and are OWNED by editor. - std::list m_PlacedGibs; - // Currently held object to place as a gib. This is what is attached to the cursor and will be placed when the fire button is pressed - // OWNED by this. - MovableObject *m_pCurrentGib; - // Where in the scene's list order the next object should be placed. If -1, then place at the end of the list. - int m_GibListOrder; - // Whether to draw the currently held object - bool m_DrawCurrentGib; - // Currently placed scene object to make blink when drawing it. NOT OWNED. - const MovableObject *m_pObjectToBlink; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this GibEditorGUI, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - GibEditorGUI(const GibEditorGUI &reference) = delete; - GibEditorGUI & operator=(const GibEditorGUI &rhs) = delete; - -}; +namespace RTE { + + class MovableObject; + class MOSRotating; + class ObjectPickerGUI; + class PieMenu; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: GibEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A placement part of the gib editor which manages the pie menu and picker. + // Parent(s): None. + // Class history: 9/16/2007 GibEditorGUI Created. + + class GibEditorGUI { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + // Different modes of this editor + enum EditorGUIMode { + INACTIVE = 0, + PICKOBJECTTOLOAD, + PICKINGGIB, + ADDINGGIB, + PLACINGGIB, + MOVINGGIB, + DELETINGGIB, + PLACEINFRONT, + PLACEBEHIND, + DONEEDITING, + EDITORGUIMODECOUNT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: GibEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a GibEditorGUI object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + GibEditorGUI() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~GibEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a GibEditorGUI object before deletion + // from system memory. + // Arguments: None. + + ~GibEditorGUI() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the GibEditorGUI object ready for use. + // Arguments: A poitner to a Controller which will control this Menu. Ownership is + // NOT TRANSFERRED! + // Which module space that this eidtor will be able to pick objects from. + // -1 means all modules. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(Controller* pController, int whichModuleSpace = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire GibEditorGUI, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the GibEditorGUI object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the controller used by this. The ownership of the controller is + // NOT transferred! + // Arguments: The new controller for this menu. Ownership is NOT transferred + // Return value: None. + + void SetController(Controller* pController); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPosOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where on the screen that this GUI is being drawn to. If upper + // left corner, then 0, 0. This will affect the way the mouse is positioned + // etc. + // Arguments: The new screen position of this entire GUI. + + void SetPosOnScreen(int newPosX, int newPosY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCursorPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the absolute scene coordinates of the cursor of this Editor. + // Arguments: The new cursor position in absolute scene units. + // Return value: None. + + void SetCursorPos(const Vector& newCursorPos) { m_CursorPos = newCursorPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCurrentGib + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the new Object to be held at the gib cursor of this Editor. Ownership + // IS transferred! + // Arguments: The new Object to be held by the cursor. Ownership IS transferred! + // Return value: None. + + void SetCurrentGib(MovableObject* pNewGibObject) { m_pCurrentGib = pNewGibObject; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActivatedPieSlice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets any Pie menu slice command activated last update. + // Arguments: None. + // Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. + + PieSlice::SliceType GetActivatedPieSlice() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlacedGibs + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the list of already placed gibs of the currently edited object. + // Ownership of neither list not objects IS NOT transferred! + // Arguments: None. + // Return value: The current list of placed gibs. OWNERSHIP IS NOT TRANSFERRED! + + std::list* GetPlacedGibs() { return &m_PlacedGibs; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentGib + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the currently held Object in the cursor of this Editor. Ownership + // IS NOT transferred! + // Arguments: None. + // Return value: The currently held object, if any. OWNERSHIP IS NOT TRANSFERRED! + + const MovableObject* GetCurrentGib() { return m_pCurrentGib; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetObjectToLoad + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns a refernece instance of an object if it has been picked to be + // loaded into the editor. Ownership is NOT transferred. + // Arguments: None. + // Return value: Reference instance of the picked object to be loaded. 0 if nothing. OWNERSHIP IS NOT TRANSFERRED! + // was picked since last update. + + const MOSRotating* GetObjectToLoad() { return m_pObjectToLoad; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which DataModule space to be picking objects from. If -1, then + // let the player pick from all loaded modules. + // Arguments: The ID of the module to let the player pick objects from. All official + // modules' objects will alwayws be presented, in addition to the one + // passed in here. + // Return value: None. + + void SetModuleSpace(int moduleSpaceID = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EditMade + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether an edit on the scene was made in the last Update. + // Arguments: None. + // Return value: Whether any edit was made. + + bool EditMade() const { return m_EditMade; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Menu each frame + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the editor + // Arguments: The bitmap to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AddPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Adds a MovableObject to be placed in the editor. Ownership IS transferred! + // Arguments: The MovableOjbect instace to add, OIT! + // Where in the list the object should be inserted. -1 means at the end + // of the list. + // Return value: None. + + void AddPlacedObject(MovableObject* pObjectToAdd, int listOrder = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemovePlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a MovableObject placed in this editor. + // Arguments: The list order number of the object to remove. If -1, the last one is removed. + // Return value: None. + + void RemovePlacedObject(int whichToRemove = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PickPlacedObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Returns the last placed object that graphically overlaps an absolute + // point in the scene. Note that the placed object don't really exist in + // the scene, but in the editor. Their own Pos's are used. + // Arguments: The point in absolute scene coordinates that will be used to pick the + // last placed MovableObject which overlaps it. + // An int which will be filled out with the order place of any found object + // in the list. if nothing is found, it will get a value of -1. + // Return value: The last hit MovableObject, if any. Ownership is NOT transferred! + + const MovableObject* PickPlacedObject(Vector& scenePoint, int* pListOrderPlace = 0) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePlacedObjects + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updated the objects in the placed scene objects list of this. This is + // mostly for the editor to represent the items correctly. + // Arguments: None. + // Return value: None. + + void UpdatePlacedObjects(); + + enum BlinkMode { + NOBLINK = 0, + OBJECTBLINKON, + OBJECTBLINKOFF, + BLINKMODECOUNT + }; + + // Controller which conrols this menu. Not owned + Controller* m_pController; + // Whether an editor was made to the Scene in the last Update + bool m_EditMade; + // The current mode of the whole GUI. See EditorGUIMode enum. + EditorGUIMode m_EditorGUIMode; + // The previous mode of the whole GUI, to go back to when the current mode is done in some cases + EditorGUIMode m_PreviousMode; + // The ref instance picked to be loaded into the editor from the picker. 0 if none has been yet. Not owned. + const MOSRotating* m_pObjectToLoad; + // Notification blink timer + Timer m_BlinkTimer; + // What we're blinking + int m_BlinkMode; + // Measures the time to when to start repeating inputs when they're held down + Timer m_RepeatStartTimer; + // Measures the interval between input repeats + Timer m_RepeatTimer; + + std::unique_ptr m_PieMenu; //!< The PieMenu for this GibEditorGUI. + // The object picker + ObjectPickerGUI* m_pPicker; + // Grid snapping enabled + bool m_GridSnapping; + // The zooming bitmaps owned by this; source gets the area from the screen, destination is the zoomed in view + BITMAP* m_pZoomSource; + // The zoom factor of the magnifying window. 0 means no zoom window + int m_ZoomFactor; + // Current cursor position, in absolute scene coordinates + Vector m_CursorPos; + // The offset from the current object's position to the cursor, if any + Vector m_CursorOffset; + // Cursor position in free air, or over something + bool m_CursorInAir; + // Gib facing left or not when placing + bool m_FacingLeft; + // List of all the gibs currently placed on the edited object. + // They are proxies of the actual gib list of the edited object, and are OWNED by editor. + std::list m_PlacedGibs; + // Currently held object to place as a gib. This is what is attached to the cursor and will be placed when the fire button is pressed + // OWNED by this. + MovableObject* m_pCurrentGib; + // Where in the scene's list order the next object should be placed. If -1, then place at the end of the list. + int m_GibListOrder; + // Whether to draw the currently held object + bool m_DrawCurrentGib; + // Currently placed scene object to make blink when drawing it. NOT OWNED. + const MovableObject* m_pObjectToBlink; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this GibEditorGUI, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + GibEditorGUI(const GibEditorGUI& reference) = delete; + GibEditorGUI& operator=(const GibEditorGUI& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Menus/InventoryMenuGUI.cpp b/Source/Menus/InventoryMenuGUI.cpp index db53148ea..1021e0ca5 100644 --- a/Source/Menus/InventoryMenuGUI.cpp +++ b/Source/Menus/InventoryMenuGUI.cpp @@ -28,14 +28,14 @@ namespace RTE { const Vector InventoryMenuGUI::c_CarouselBoxSizeStep = (c_CarouselBoxMaxSize - c_CarouselBoxMinSize) / (c_ItemsPerRow / 2); const int InventoryMenuGUI::c_CarouselBoxCornerRadius = ((c_CarouselBoxMaxSize.GetFloorIntY() - c_CarouselBoxMinSize.GetFloorIntY()) / 2) - 1; - BITMAP *InventoryMenuGUI::s_CursorBitmap = nullptr; + BITMAP* InventoryMenuGUI::s_CursorBitmap = nullptr; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::CarouselItemBox::GetIconsAndMass(std::vector &itemIcons, float &totalItemMass, const std::vector> *equippedItems) const { + void InventoryMenuGUI::CarouselItemBox::GetIconsAndMass(std::vector& itemIcons, float& totalItemMass, const std::vector>* equippedItems) const { if (IsForEquippedItems) { itemIcons.reserve(equippedItems->size()); - for (const auto &[equippedItem, offhandEquippedItem] : *equippedItems) { + for (const auto& [equippedItem, offhandEquippedItem]: *equippedItems) { if (equippedItem && equippedItem->GetUniqueID() != 0) { itemIcons.emplace_back(equippedItem->GetGraphicalIcon()); totalItemMass += equippedItem->GetMass(); @@ -51,7 +51,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::Clear() { m_SmallFont = nullptr; @@ -78,7 +78,7 @@ namespace RTE { m_CarouselAnimationDirection = CarouselAnimationDirection::None; m_CarouselAnimationTimer.Reset(); m_CarouselAnimationTimer.SetRealTimeLimitMS(200); - for (std::unique_ptr &carouselItemBox : m_CarouselItemBoxes) { + for (std::unique_ptr& carouselItemBox: m_CarouselItemBoxes) { carouselItemBox = nullptr; } m_CarouselExitingItemBox.reset(); @@ -123,14 +123,18 @@ namespace RTE { m_GUIInventoryItemsScrollbar = nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int InventoryMenuGUI::Create(Controller *activityPlayerController, Actor *inventoryActor, MenuMode menuMode) { + int InventoryMenuGUI::Create(Controller* activityPlayerController, Actor* inventoryActor, MenuMode menuMode) { RTEAssert(activityPlayerController, "No controller sent to InventoryMenuGUI on creation!"); RTEAssert(c_ItemsPerRow % 2 == 1, "Don't you dare use an even number of items per inventory row, you filthy animal!"); - if (!m_SmallFont) { m_SmallFont = g_FrameMan.GetSmallFont(); } - if (!m_LargeFont) { m_LargeFont = g_FrameMan.GetLargeFont(); } + if (!m_SmallFont) { + m_SmallFont = g_FrameMan.GetSmallFont(); + } + if (!m_LargeFont) { + m_LargeFont = g_FrameMan.GetLargeFont(); + } m_MenuController = activityPlayerController; SetInventoryActor(inventoryActor); @@ -144,7 +148,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::Destroy() { destroy_bitmap(m_CarouselBitmap.release()); @@ -153,10 +157,10 @@ namespace RTE { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int InventoryMenuGUI::SetupCarouselMode() { - for (std::unique_ptr &carouselItemBox : m_CarouselItemBoxes) { + for (std::unique_ptr& carouselItemBox: m_CarouselItemBoxes) { carouselItemBox = std::make_unique(); carouselItemBox->IsForEquippedItems = false; } @@ -188,17 +192,23 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int InventoryMenuGUI::SetupFullOrTransferMode() { - if (!m_GUIControlManager) { m_GUIControlManager = std::make_unique(); } - if (!m_GUIScreen) { m_GUIScreen = std::make_unique(g_FrameMan.GetBackBuffer8()); } - if (!m_GUIInput) { m_GUIInput = std::make_unique(m_MenuController->GetPlayer()); } + if (!m_GUIControlManager) { + m_GUIControlManager = std::make_unique(); + } + if (!m_GUIScreen) { + m_GUIScreen = std::make_unique(g_FrameMan.GetBackBuffer8()); + } + if (!m_GUIInput) { + m_GUIInput = std::make_unique(m_MenuController->GetPlayer()); + } RTEAssert(m_GUIControlManager->Create(m_GUIScreen.get(), m_GUIInput.get(), "Base.rte/GUIs/Skins", "InventoryMenuSkin.ini"), "Failed to create InventoryMenuGUI GUIControlManager and load it from Base.rte/GUIs/Skins/Menus/InventoryMenuSkin.ini"); - //TODO When this is split into 2 classes, full mode should use the fonts from its gui control manager while transfer mode, will need to get its fonts from FrameMan. May be good for the ingame menu base class to have these font pointers, even if some subclasses set em up in different ways. - //if (!m_SmallFont) { m_SmallFont = m_GUIControlManager->GetSkin()->GetFont("FontSmall.png"); } - //if (!m_LargeFont) { m_LargeFont = m_GUIControlManager->GetSkin()->GetFont("FontLarge.png"); } + // TODO When this is split into 2 classes, full mode should use the fonts from its gui control manager while transfer mode, will need to get its fonts from FrameMan. May be good for the ingame menu base class to have these font pointers, even if some subclasses set em up in different ways. + // if (!m_SmallFont) { m_SmallFont = m_GUIControlManager->GetSkin()->GetFont("FontSmall.png"); } + // if (!m_LargeFont) { m_LargeFont = m_GUIControlManager->GetSkin()->GetFont("FontLarge.png"); } m_GUIControlManager->Load("Base.rte/GUIs/InventoryMenuGUI.ini"); m_GUIControlManager->EnableMouse(m_MenuController->IsMouseControlled()); @@ -208,40 +218,40 @@ namespace RTE { } if (g_FrameMan.IsInMultiplayerMode()) { - dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_FrameMan.GetPlayerFrameBufferWidth(m_MenuController->GetPlayer()), g_FrameMan.GetPlayerFrameBufferHeight(m_MenuController->GetPlayer())); + dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_FrameMan.GetPlayerFrameBufferWidth(m_MenuController->GetPlayer()), g_FrameMan.GetPlayerFrameBufferHeight(m_MenuController->GetPlayer())); } else { - dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); } - m_GUITopLevelBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBox_InventoryMenuGUI")); + m_GUITopLevelBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBox_InventoryMenuGUI")); m_GUITopLevelBox->SetPositionAbs(g_FrameMan.GetPlayerFrameBufferWidth(m_MenuController->GetPlayer()), 0); m_GUITopLevelBoxFullSize.SetXY(static_cast(m_GUITopLevelBox->GetWidth()), static_cast(m_GUITopLevelBox->GetHeight())); - m_GUIInformationText = dynamic_cast(m_GUIControlManager->GetControl("Label_InformationText")); - m_GUIInformationToggleButton = dynamic_cast(m_GUIControlManager->GetControl("Button_InformationToggle")); + m_GUIInformationText = dynamic_cast(m_GUIControlManager->GetControl("Label_InformationText")); + m_GUIInformationToggleButton = dynamic_cast(m_GUIControlManager->GetControl("Button_InformationToggle")); m_GUIInformationToggleButton->SetText(""); - m_GUIInformationToggleButtonIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Information")); + m_GUIInformationToggleButtonIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Information")); - m_GUIEquippedItemsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBox_EquippedItems")); - m_GUISwapSetButton = dynamic_cast(m_GUIControlManager->GetControl("Button_SwapSet")); + m_GUIEquippedItemsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBox_EquippedItems")); + m_GUISwapSetButton = dynamic_cast(m_GUIControlManager->GetControl("Button_SwapSet")); m_GUISwapSetButton->SetEnabled(false); m_GUISwapSetButton->SetVisible(false); - m_GUIEquippedItemButton = dynamic_cast(m_GUIControlManager->GetControl("Button_EquippedItem")); + m_GUIEquippedItemButton = dynamic_cast(m_GUIControlManager->GetControl("Button_EquippedItem")); m_GUIEquippedItemButton->SetHorizontalOverflowScroll(true); - m_GUIOffhandEquippedItemButton = dynamic_cast(m_GUIControlManager->GetControl("Button_OffhandEquippedItem")); + m_GUIOffhandEquippedItemButton = dynamic_cast(m_GUIControlManager->GetControl("Button_OffhandEquippedItem")); m_GUIOffhandEquippedItemButton->SetHorizontalOverflowScroll(true); - m_GUIReloadButton = dynamic_cast(m_GUIControlManager->GetControl("Button_Reload")); + m_GUIReloadButton = dynamic_cast(m_GUIControlManager->GetControl("Button_Reload")); m_GUIReloadButton->SetText(""); - m_GUIReloadButtonIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Refresh")); - m_GUIDropButton = dynamic_cast(m_GUIControlManager->GetControl("Button_Drop")); + m_GUIReloadButtonIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Refresh")); + m_GUIDropButton = dynamic_cast(m_GUIControlManager->GetControl("Button_Drop")); m_GUIDropButton->SetText(""); - m_GUIDropButtonIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Drop")); + m_GUIDropButtonIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Drop")); - m_GUIInventoryItemsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBox_InventoryItems")); - m_GUIInventoryItemsScrollbar = dynamic_cast(m_GUIControlManager->GetControl("Scrollbar_InventoryItems")); + m_GUIInventoryItemsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBox_InventoryItems")); + m_GUIInventoryItemsScrollbar = dynamic_cast(m_GUIControlManager->GetControl("Scrollbar_InventoryItems")); m_GUIInventoryItemsScrollbar->SetValue(0); m_GUIInventoryItemsScrollbar->SetMinimum(0); - GUIButton *inventoryItemButtonTemplate = dynamic_cast(m_GUIControlManager->GetControl("Button_InventoryItemTemplate")); + GUIButton* inventoryItemButtonTemplate = dynamic_cast(m_GUIControlManager->GetControl("Button_InventoryItemTemplate")); inventoryItemButtonTemplate->SetEnabled(false); inventoryItemButtonTemplate->SetVisible(false); @@ -253,11 +263,11 @@ namespace RTE { std::string emptyButtonText = "> <"; inventoryItemButtonProperties.AddVariable("Text", emptyButtonText); inventoryItemButtonProperties.AddVariable("HorizontalOverflowScroll", true); - std::pair itemButtonPair; + std::pair itemButtonPair; for (int i = 0; i < c_FullViewPageItemLimit; i++) { inventoryItemButtonProperties.AddVariable("Name", std::to_string(i)); - itemButtonPair = {nullptr, dynamic_cast(m_GUIControlManager->AddControl(&inventoryItemButtonProperties))}; + itemButtonPair = {nullptr, dynamic_cast(m_GUIControlManager->AddControl(&inventoryItemButtonProperties))}; itemButtonPair.second->SetPositionRel(inventoryItemButtonTemplate->GetRelXPos() + ((i % c_ItemsPerRow) * inventoryItemButtonTemplate->GetWidth()), inventoryItemButtonTemplate->GetRelYPos() + ((i / c_ItemsPerRow) * inventoryItemButtonTemplate->GetHeight())); m_GUIInventoryItemButtons.emplace_back(itemButtonPair); } @@ -265,18 +275,20 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::SetInventoryActor(Actor *newInventoryActor) { + void InventoryMenuGUI::SetInventoryActor(Actor* newInventoryActor) { m_InventoryActor = newInventoryActor; if (m_InventoryActor) { - m_InventoryActorIsHuman = dynamic_cast(m_InventoryActor); + m_InventoryActorIsHuman = dynamic_cast(m_InventoryActor); - if (g_SceneMan.ShortestDistance(m_CenterPos, m_InventoryActor->GetCPUPos(), g_SceneMan.SceneWrapsX()).GetMagnitude() > 2.0F) { m_CenterPos = m_InventoryActor->GetCPUPos(); } + if (g_SceneMan.ShortestDistance(m_CenterPos, m_InventoryActor->GetCPUPos(), g_SceneMan.SceneWrapsX()).GetMagnitude() > 2.0F) { + m_CenterPos = m_InventoryActor->GetCPUPos(); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::SetEnabled(bool enable) { if (!m_MenuController || !m_InventoryActor) { @@ -293,17 +305,19 @@ namespace RTE { m_NonMousePreviousEquippedItemsBoxButton = nullptr; m_NonMousePreviousInventoryItemsBoxButton = nullptr; m_NonMousePreviousReloadOrDropButton = nullptr; - if (m_NonMouseHighlightedButton) { m_NonMouseHighlightedButton->OnMouseLeave(0, 0, 0, 0); } - for (const auto &[inventoryItem, inventoryItemButton] : m_GUIInventoryItemButtons) { + if (m_NonMouseHighlightedButton) { + m_NonMouseHighlightedButton->OnMouseLeave(0, 0, 0, 0); + } + for (const auto& [inventoryItem, inventoryItemButton]: m_GUIInventoryItemButtons) { inventoryItemButton->OnMouseLeave(0, 0, 0, 0); } - SoundContainer *soundToPlay = enable ? g_GUISound.EnterMenuSound() : g_GUISound.ExitMenuSound(); + SoundContainer* soundToPlay = enable ? g_GUISound.EnterMenuSound() : g_GUISound.ExitMenuSound(); soundToPlay->Play(); } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool InventoryMenuGUI::EnableIfNotEmpty() { bool shouldEnable = !m_InventoryActorEquippedItems.empty() || (m_InventoryActor && !m_InventoryActor->IsInventoryEmpty()); @@ -311,7 +325,7 @@ namespace RTE { return shouldEnable; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::ClearSelectedItem() { if (m_GUISelectedItem) { @@ -320,12 +334,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::SetSelectedItem(GUIButton *selectedItemButton, MovableObject *selectedItemObject, int inventoryIndex, int equippedItemIndex, bool isBeingDragged) { - if (!selectedItemButton || !selectedItemObject || (inventoryIndex < 0 && equippedItemIndex < 0)) { ClearSelectedItem(); } + void InventoryMenuGUI::SetSelectedItem(GUIButton* selectedItemButton, MovableObject* selectedItemObject, int inventoryIndex, int equippedItemIndex, bool isBeingDragged) { + if (!selectedItemButton || !selectedItemObject || (inventoryIndex < 0 && equippedItemIndex < 0)) { + ClearSelectedItem(); + } - if (!m_GUISelectedItem) { m_GUISelectedItem = std::make_unique(); } + if (!m_GUISelectedItem) { + m_GUISelectedItem = std::make_unique(); + } m_GUISelectedItem->Button = selectedItemButton; m_GUISelectedItem->Object = selectedItemObject; m_GUISelectedItem->InventoryIndex = inventoryIndex; @@ -334,7 +352,7 @@ namespace RTE { m_GUISelectedItem->DragHoldCount = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::Update() { if (IsEnabled() && (!m_MenuController || !m_InventoryActor || !g_MovableMan.ValidMO(m_InventoryActor))) { @@ -343,15 +361,19 @@ namespace RTE { } if (IsEnablingOrDisabling() && m_EnableDisableAnimationTimer.IsPastRealTimeLimit()) { m_EnabledState = (m_EnabledState == EnabledState::Enabling) ? EnabledState::Enabled : EnabledState::Disabled; - //Note gui size setting is handled here rather than in Full Mode updating so it can be made to only happen once when things are fully enabled, instead of setting over-and-over and potentially triggering extra redrawing. - if (m_EnabledState == EnabledState::Enabled && m_MenuMode != MenuMode::Carousel) { m_GUITopLevelBox->SetSize(m_GUITopLevelBoxFullSize.GetFloorIntX(), m_GUITopLevelBoxFullSize.GetFloorIntY()); } + // Note gui size setting is handled here rather than in Full Mode updating so it can be made to only happen once when things are fully enabled, instead of setting over-and-over and potentially triggering extra redrawing. + if (m_EnabledState == EnabledState::Enabled && m_MenuMode != MenuMode::Carousel) { + m_GUITopLevelBox->SetSize(m_GUITopLevelBoxFullSize.GetFloorIntX(), m_GUITopLevelBoxFullSize.GetFloorIntY()); + } } if (m_InventoryActor && g_MovableMan.ValidMO(m_InventoryActor)) { - if (const AHuman *inventoryActorAsAHuman = (m_InventoryActorIsHuman ? dynamic_cast(m_InventoryActor) : nullptr)) { + if (const AHuman* inventoryActorAsAHuman = (m_InventoryActorIsHuman ? dynamic_cast(m_InventoryActor) : nullptr)) { m_InventoryActorEquippedItems.clear(); m_InventoryActorEquippedItems.reserve(1); - if (inventoryActorAsAHuman->GetEquippedItem() || inventoryActorAsAHuman->GetEquippedBGItem()) { m_InventoryActorEquippedItems.push_back({inventoryActorAsAHuman->GetEquippedItem(), inventoryActorAsAHuman->GetEquippedBGItem()}); } + if (inventoryActorAsAHuman->GetEquippedItem() || inventoryActorAsAHuman->GetEquippedBGItem()) { + m_InventoryActorEquippedItems.push_back({inventoryActorAsAHuman->GetEquippedItem(), inventoryActorAsAHuman->GetEquippedBGItem()}); + } } else if (!m_InventoryActorEquippedItems.empty()) { m_InventoryActorEquippedItems.clear(); } @@ -380,9 +402,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::Draw(BITMAP *targetBitmap, const Vector &targetPos) const { + void InventoryMenuGUI::Draw(BITMAP* targetBitmap, const Vector& targetPos) const { Vector drawPos = m_CenterPos - targetPos; switch (m_MenuMode) { @@ -407,28 +429,30 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::UpdateCarouselMode() { - if (!CarouselModeReadyForUse()) { SetupCarouselMode(); } + if (!CarouselModeReadyForUse()) { + SetupCarouselMode(); + } - for (const std::unique_ptr &carouselItemBox : m_CarouselItemBoxes) { + for (const std::unique_ptr& carouselItemBox: m_CarouselItemBoxes) { carouselItemBox->Item = nullptr; } - const std::deque *inventory = m_InventoryActor->GetInventory(); + const std::deque* inventory = m_InventoryActor->GetInventory(); if (inventory && !inventory->empty()) { int leftSideItemCount = std::min(static_cast(std::floor(static_cast(inventory->size()) / 2)), c_ItemsPerRow / 2); int rightSideItemCount = std::min(static_cast(std::ceil(static_cast(inventory->size()) / 2)), c_ItemsPerRow / 2 + (m_InventoryActorEquippedItems.empty() ? 1 : 0)); int carouselIndex = 0; - std::vector temporaryLeftSideItemsForProperOrdering; + std::vector temporaryLeftSideItemsForProperOrdering; temporaryLeftSideItemsForProperOrdering.reserve(leftSideItemCount); if (leftSideItemCount > 0) { - std::for_each(inventory->crbegin(), inventory->crbegin() + leftSideItemCount, [&temporaryLeftSideItemsForProperOrdering](MovableObject *carouselItem) { + std::for_each(inventory->crbegin(), inventory->crbegin() + leftSideItemCount, [&temporaryLeftSideItemsForProperOrdering](MovableObject* carouselItem) { temporaryLeftSideItemsForProperOrdering.emplace_back(carouselItem); }); } - std::for_each(temporaryLeftSideItemsForProperOrdering.crbegin(), temporaryLeftSideItemsForProperOrdering.crend(), [this, &carouselIndex, &leftSideItemCount](MovableObject *carouselItem) { + std::for_each(temporaryLeftSideItemsForProperOrdering.crbegin(), temporaryLeftSideItemsForProperOrdering.crend(), [this, &carouselIndex, &leftSideItemCount](MovableObject* carouselItem) { m_CarouselItemBoxes.at(carouselIndex + (c_ItemsPerRow / 2) - leftSideItemCount)->Item = carouselItem; m_CarouselItemBoxes.at(carouselIndex)->IsForEquippedItems = false; carouselIndex++; @@ -439,7 +463,7 @@ namespace RTE { carouselIndex++; } if (rightSideItemCount > 0) { - std::for_each(inventory->cbegin(), inventory->cbegin() + rightSideItemCount, [this, &carouselIndex](MovableObject *carouselItem) { + std::for_each(inventory->cbegin(), inventory->cbegin() + rightSideItemCount, [this, &carouselIndex](MovableObject* carouselItem) { m_CarouselItemBoxes.at(carouselIndex)->Item = carouselItem; m_CarouselItemBoxes.at(carouselIndex)->IsForEquippedItems = false; carouselIndex++; @@ -464,7 +488,7 @@ namespace RTE { UpdateCarouselItemBoxSizesAndPositions(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::UpdateCarouselItemBoxSizesAndPositions() { float halfMassFontHeight = static_cast(m_SmallFont->GetFontHeight() / 2); @@ -476,7 +500,7 @@ namespace RTE { /// /// Lambda to do all the repetitive boilerplate of setting up a carousel item box. /// - auto SetupCarouselItemBox = [this, &halfMassFontHeight, &carouselIndex, &carouselAnimationProgress, ¤tBoxHorizontalOffset](const std::unique_ptr &carouselItemBox, bool leftSideRoundedAndBordered, bool rightSideRoundedAndBordered) { + auto SetupCarouselItemBox = [this, &halfMassFontHeight, &carouselIndex, &carouselAnimationProgress, ¤tBoxHorizontalOffset](const std::unique_ptr& carouselItemBox, bool leftSideRoundedAndBordered, bool rightSideRoundedAndBordered) { carouselItemBox->CurrentSize = carouselItemBox->FullSize; if (carouselIndex == -1) { carouselItemBox->CurrentSize += c_CarouselBoxSizeStep * (1.0F - carouselAnimationProgress); @@ -500,7 +524,7 @@ namespace RTE { SetupCarouselItemBox(m_CarouselExitingItemBox, true, false); } - for (const std::unique_ptr &carouselItemBox : m_CarouselItemBoxes) { + for (const std::unique_ptr& carouselItemBox: m_CarouselItemBoxes) { if (carouselIndex == 0 && m_CarouselAnimationDirection == CarouselAnimationDirection::Right && directionalAnimationProgress == 0.0F) { carouselIndex++; continue; @@ -522,15 +546,19 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::UpdateFullMode() { - if (!FullOrTransferModeReadyForUse()) { SetupFullOrTransferMode(); } + if (!FullOrTransferModeReadyForUse()) { + SetupFullOrTransferMode(); + } if (!m_GUIShowEmptyRows) { int numberOfRowsToShow = static_cast(std::ceil(static_cast(std::min(c_FullViewPageItemLimit, m_InventoryActor->GetInventorySize())) / static_cast(c_ItemsPerRow))); int expectedInventoryHeight = m_GUIInventoryItemButtons[0].second->GetHeight() * numberOfRowsToShow; - if (numberOfRowsToShow * c_ItemsPerRow < c_FullViewPageItemLimit) { expectedInventoryHeight -= 1; } + if (numberOfRowsToShow * c_ItemsPerRow < c_FullViewPageItemLimit) { + expectedInventoryHeight -= 1; + } if (m_GUIInventoryItemsBox->GetHeight() != expectedInventoryHeight) { int inventoryItemsBoxPreviousHeight = m_GUIInventoryItemsBox->GetHeight(); m_GUIInventoryItemsBox->SetSize(m_GUIInventoryItemsBox->GetWidth(), expectedInventoryHeight); @@ -541,7 +569,7 @@ namespace RTE { UpdateFullModeEquippedItemButtons(); - const std::deque *inventory = m_InventoryActor->GetInventory(); + const std::deque* inventory = m_InventoryActor->GetInventory(); UpdateFullModeScrollbar(inventory); @@ -560,8 +588,10 @@ namespace RTE { if (m_GUISelectedItem) { m_GUISelectedItem->Button->OnGainFocus(); - if (m_GUISelectedItem->DragWasHeldForLongEnough()) { m_GUIInformationToggleButton->SetEnabled(false); } - if (const HDFirearm *selectedItemAsFirearm = dynamic_cast(m_GUISelectedItem->Object)) { + if (m_GUISelectedItem->DragWasHeldForLongEnough()) { + m_GUIInformationToggleButton->SetEnabled(false); + } + if (const HDFirearm* selectedItemAsFirearm = dynamic_cast(m_GUISelectedItem->Object)) { m_GUIReloadButton->SetEnabled(!selectedItemAsFirearm->IsFull()); } else { m_GUIReloadButton->SetEnabled(false); @@ -569,13 +599,13 @@ namespace RTE { m_GUIDropButton->SetEnabled(true); } else { m_GUIReloadButton->SetEnabled(false); - for (const auto[equippedItem, offhandEquippedItem] : m_InventoryActorEquippedItems) { - const HDFirearm *equippedItemAsFirearm = dynamic_cast(equippedItem); + for (const auto [equippedItem, offhandEquippedItem]: m_InventoryActorEquippedItems) { + const HDFirearm* equippedItemAsFirearm = dynamic_cast(equippedItem); if (equippedItemAsFirearm && !equippedItemAsFirearm->IsFull()) { m_GUIReloadButton->SetEnabled(true); break; } - const HDFirearm *offhandEquippedItemAsFirearm = dynamic_cast(offhandEquippedItem); + const HDFirearm* offhandEquippedItemAsFirearm = dynamic_cast(offhandEquippedItem); if (offhandEquippedItemAsFirearm && !offhandEquippedItemAsFirearm->IsFull()) { m_GUIReloadButton->SetEnabled(true); break; @@ -589,11 +619,11 @@ namespace RTE { UpdateFullModeNonItemButtonIconsAndHighlightWidths(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::UpdateFullModeEquippedItemButtons() { - const MovableObject *equippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).first : nullptr; - const MovableObject *offhandEquippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).second : nullptr; + const MovableObject* equippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).first : nullptr; + const MovableObject* offhandEquippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).second : nullptr; m_GUIEquippedItemButton->SetEnabled(equippedItem); if (m_GUISelectedItem && m_GUISelectedItem->Button == m_GUIEquippedItemButton && m_GUISelectedItem->DragWasHeldForLongEnough()) { @@ -615,7 +645,7 @@ namespace RTE { m_GUIOffhandEquippedItemButton->SetIconAndText(nullptr, "> <"); } - bool showOffhandButton = offhandEquippedItem || (dynamic_cast(equippedItem) && dynamic_cast(equippedItem)->IsOneHanded()); + bool showOffhandButton = offhandEquippedItem || (dynamic_cast(equippedItem) && dynamic_cast(equippedItem)->IsOneHanded()); if (showOffhandButton && !m_GUIOffhandEquippedItemButton->GetVisible()) { m_GUIEquippedItemButton->Resize(m_GUIEquippedItemButton->GetWidth() / 2, m_GUIEquippedItemButton->GetHeight()); m_GUIOffhandEquippedItemButton->SetVisible(true); @@ -625,9 +655,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::UpdateFullModeScrollbar(const std::deque *inventory) { + void InventoryMenuGUI::UpdateFullModeScrollbar(const std::deque* inventory) { if (inventory->size() > c_FullViewPageItemLimit) { m_GUIInventoryItemsScrollbar->SetMaximum(static_cast(std::ceil(static_cast(inventory->size() - c_FullViewPageItemLimit) / static_cast(c_ItemsPerRow))) + 1); if (!m_GUIInventoryItemsScrollbar->GetVisible()) { @@ -654,13 +684,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::UpdateFullModeInventoryItemButtons(const std::deque *inventory) { + void InventoryMenuGUI::UpdateFullModeInventoryItemButtons(const std::deque* inventory) { int startIndex = m_GUIInventoryItemsScrollbar->GetValue() * c_ItemsPerRow; int lastPopulatedIndex = static_cast(inventory->size() - 1); - GUIButton *itemButton; - MovableObject *inventoryItem; + GUIButton* itemButton; + MovableObject* inventoryItem; for (int i = startIndex; (i - startIndex) < c_FullViewPageItemLimit; i++) { itemButton = m_GUIInventoryItemButtons.at(i - startIndex).second; if (i <= lastPopulatedIndex) { @@ -685,13 +715,15 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::UpdateFullModeInformationText(const std::deque *inventory) { + void InventoryMenuGUI::UpdateFullModeInformationText(const std::deque* inventory) { if (!m_GUIShowInformationText && m_GUIInformationText->GetVisible()) { m_GUIInformationText->SetVisible(false); } else if (m_GUIShowInformationText) { - if (!m_GUIInformationText->GetVisible()) { m_GUIInformationText->SetVisible(true); } + if (!m_GUIInformationText->GetVisible()) { + m_GUIInformationText->SetVisible(true); + } std::string informationText; if (m_GUISelectedItem) { @@ -708,7 +740,7 @@ namespace RTE { } else { if (m_GUIDisplayOnly) { informationText = ">> DISPLAY ONLY <<"; - } else if (m_InventoryActorEquippedItems.empty() && inventory->empty()) { + } else if (m_InventoryActorEquippedItems.empty() && inventory->empty()) { informationText = "No items to display."; } else { informationText = m_MenuController->IsMouseControlled() ? "Click an item to interact with it. You can also click and hold to drag items." : "Press an item to interact with it."; @@ -718,16 +750,15 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::UpdateFullModeNonItemButtonIconsAndHighlightWidths() { - std::vector> buttonsToCheckIconsFor = { - { m_GUIInformationToggleButton, m_GUIInformationToggleButtonIcon }, - { m_GUIReloadButton, m_GUIReloadButtonIcon }, - { m_GUIDropButton, m_GUIDropButtonIcon } - }; + std::vector> buttonsToCheckIconsFor = { + {m_GUIInformationToggleButton, m_GUIInformationToggleButtonIcon}, + {m_GUIReloadButton, m_GUIReloadButtonIcon}, + {m_GUIDropButton, m_GUIDropButtonIcon}}; - for (const auto &[button, icon] : buttonsToCheckIconsFor) { + for (const auto& [button, icon]: buttonsToCheckIconsFor) { if (icon) { if (button->IsEnabled()) { button->SetIcon((button->HasFocus() || button->IsMousedOver() || button->IsPushed()) ? icon->GetBitmaps8()[1] : icon->GetBitmaps8()[0]); @@ -746,13 +777,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::UpdateTransferMode() { - //TODO Make Transfer mode + // TODO Make Transfer mode } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::HandleInput() { if (m_MenuController->IsState(ControlState::PRESS_SECONDARY)) { @@ -760,7 +791,7 @@ namespace RTE { return; } - //TODO Maybe add support for other click types, e.g. if player right clicks on an item when they have one selected, we can call some custom lua function, so you can do custom stuff like combining items or whatever + // TODO Maybe add support for other click types, e.g. if player right clicks on an item when they have one selected, we can call some custom lua function, so you can do custom stuff like combining items or whatever if (m_MenuController->IsMouseControlled()) { if (HandleMouseInput()) { return; @@ -769,10 +800,12 @@ namespace RTE { HandleNonMouseInput(); } - if (m_GUISelectedItem && m_MenuController->IsState(ControlState::WEAPON_DROP)) { DropSelectedItem(); } + if (m_GUISelectedItem && m_MenuController->IsState(ControlState::WEAPON_DROP)) { + DropSelectedItem(); + } GUIEvent guiEvent; - const GUIControl *guiControl; + const GUIControl* guiControl; while (m_GUIControlManager->GetEvent(&guiEvent)) { guiControl = guiEvent.GetControl(); if (guiEvent.GetType() == GUIEvent::Notification && guiEvent.GetMsg() == GUIButton::Focused) { @@ -787,7 +820,7 @@ namespace RTE { m_GUIInformationToggleButton->OnLoseFocus(); } else if (guiControl == m_GUIEquippedItemButton) { int equippedItemButtonIndexToUse = 0; - if (const AHuman *inventoryActorAsAHuman = (m_InventoryActorIsHuman ? dynamic_cast(m_InventoryActor) : nullptr); inventoryActorAsAHuman && !inventoryActorAsAHuman->GetFGArm() && !inventoryActorAsAHuman->GetEquippedBGItem()) { + if (const AHuman* inventoryActorAsAHuman = (m_InventoryActorIsHuman ? dynamic_cast(m_InventoryActor) : nullptr); inventoryActorAsAHuman && !inventoryActorAsAHuman->GetFGArm() && !inventoryActorAsAHuman->GetEquippedBGItem()) { equippedItemButtonIndexToUse = 1; } HandleItemButtonPressOrHold(m_GUIEquippedItemButton, m_InventoryActorEquippedItems.empty() ? nullptr : m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).first, equippedItemButtonIndexToUse, buttonHeld); @@ -799,15 +832,17 @@ namespace RTE { } else if (!buttonHeld && guiControl == m_GUIDropButton) { DropSelectedItem(); } else { - for (const auto &[inventoryObject, inventoryItemButton] : m_GUIInventoryItemButtons) { - if (guiControl == inventoryItemButton) { HandleItemButtonPressOrHold(inventoryItemButton, inventoryObject, -1, buttonHeld); } + for (const auto& [inventoryObject, inventoryItemButton]: m_GUIInventoryItemButtons) { + if (guiControl == inventoryItemButton) { + HandleItemButtonPressOrHold(inventoryItemButton, inventoryObject, -1, buttonHeld); + } } } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool InventoryMenuGUI::HandleMouseInput() { int mouseX; @@ -818,21 +853,35 @@ namespace RTE { if (m_GUIInventoryItemsScrollbar->GetVisible()) { int mouseWheelChange = m_MenuController->IsState(ControlState::SCROLL_UP) ? -1 : (m_MenuController->IsState(ControlState::SCROLL_DOWN) ? 1 : 0); - if (mouseWheelChange != 0) { m_GUIInventoryItemsScrollbar->SetValue(std::clamp(m_GUIInventoryItemsScrollbar->GetValue() + mouseWheelChange, m_GUIInventoryItemsScrollbar->GetMinimum(), m_GUIInventoryItemsScrollbar->GetMaximum())); } + if (mouseWheelChange != 0) { + m_GUIInventoryItemsScrollbar->SetValue(std::clamp(m_GUIInventoryItemsScrollbar->GetValue() + mouseWheelChange, m_GUIInventoryItemsScrollbar->GetMinimum(), m_GUIInventoryItemsScrollbar->GetMaximum())); + } } if (m_GUISelectedItem && m_GUISelectedItem->IsBeingDragged) { if (!m_GUISelectedItem->DragWasHeldForLongEnough()) { m_GUISelectedItem->DragHoldCount++; - if (m_GUISelectedItem->DragWasHeldForLongEnough()) { g_GUISound.ItemChangeSound()->Play(m_MenuController->GetPlayer()); } + if (m_GUISelectedItem->DragWasHeldForLongEnough()) { + g_GUISound.ItemChangeSound()->Play(m_MenuController->GetPlayer()); + } } - if (m_GUIEquippedItemButton->IsPushed() && !m_GUIEquippedItemButton->PointInside(mouseX, mouseY)) { m_GUIEquippedItemButton->SetPushed(false); } - if (m_GUIOffhandEquippedItemButton->IsPushed() && !m_GUIOffhandEquippedItemButton->PointInside(mouseX, mouseY)) { m_GUIOffhandEquippedItemButton->SetPushed(false); } - if (m_GUIReloadButton->IsPushed() && !m_GUIReloadButton->PointInside(mouseX, mouseY)) { m_GUIReloadButton->SetPushed(false); } - if (m_GUIDropButton->IsPushed() && !m_GUIDropButton->PointInside(mouseX, mouseY)) { m_GUIDropButton->SetPushed(false); } - for (const auto &[unused, inventoryItemButton] : m_GUIInventoryItemButtons) { - if (inventoryItemButton->IsPushed() && !inventoryItemButton->PointInside(mouseX, mouseY)) { inventoryItemButton->SetPushed(false); } + if (m_GUIEquippedItemButton->IsPushed() && !m_GUIEquippedItemButton->PointInside(mouseX, mouseY)) { + m_GUIEquippedItemButton->SetPushed(false); + } + if (m_GUIOffhandEquippedItemButton->IsPushed() && !m_GUIOffhandEquippedItemButton->PointInside(mouseX, mouseY)) { + m_GUIOffhandEquippedItemButton->SetPushed(false); + } + if (m_GUIReloadButton->IsPushed() && !m_GUIReloadButton->PointInside(mouseX, mouseY)) { + m_GUIReloadButton->SetPushed(false); + } + if (m_GUIDropButton->IsPushed() && !m_GUIDropButton->PointInside(mouseX, mouseY)) { + m_GUIDropButton->SetPushed(false); + } + for (const auto& [unused, inventoryItemButton]: m_GUIInventoryItemButtons) { + if (inventoryItemButton->IsPushed() && !inventoryItemButton->PointInside(mouseX, mouseY)) { + inventoryItemButton->SetPushed(false); + } } int mouseEvents[3]; @@ -856,7 +905,7 @@ namespace RTE { g_GUISound.SelectionChangeSound()->Play(m_MenuController->GetPlayer()); } else if (mouseReleased) { int equippedItemButtonIndexToUse = 0; - if (const AHuman *inventoryActorAsAHuman = (m_InventoryActorIsHuman ? dynamic_cast(m_InventoryActor) : nullptr); inventoryActorAsAHuman && !inventoryActorAsAHuman->GetFGArm() && !inventoryActorAsAHuman->GetEquippedBGItem()) { + if (const AHuman* inventoryActorAsAHuman = (m_InventoryActorIsHuman ? dynamic_cast(m_InventoryActor) : nullptr); inventoryActorAsAHuman && !inventoryActorAsAHuman->GetFGArm() && !inventoryActorAsAHuman->GetEquippedBGItem()) { equippedItemButtonIndexToUse = 1; } HandleItemButtonPressOrHold(m_GUIEquippedItemButton, m_InventoryActorEquippedItems.empty() ? nullptr : m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).first, equippedItemButtonIndexToUse); @@ -893,7 +942,7 @@ namespace RTE { m_GUIDropButton->SetPushed(false); } } else { - for (const auto &[inventoryObject, inventoryItemButton] : m_GUIInventoryItemButtons) { + for (const auto& [inventoryObject, inventoryItemButton]: m_GUIInventoryItemButtons) { if (inventoryItemButton->PointInside(mouseX, mouseY)) { if (mouseHeld && !inventoryItemButton->IsPushed()) { inventoryItemButton->SetPushed(true); @@ -919,11 +968,15 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InventoryMenuGUI::HandleNonMouseInput() { - if (!m_NonMouseHighlightedButton || !m_NonMouseHighlightedButton->GetVisible() || (!m_GUIShowEmptyRows && m_NonMouseHighlightedButton->GetParent() == m_GUIInventoryItemsBox && m_InventoryActor->IsInventoryEmpty())) { m_NonMouseHighlightedButton = m_GUIEquippedItemButton; } - if (!m_NonMouseHighlightedButton->IsMousedOver()) { m_NonMouseHighlightedButton->OnMouseEnter(0, 0, 0, 0); } + if (!m_NonMouseHighlightedButton || !m_NonMouseHighlightedButton->GetVisible() || (!m_GUIShowEmptyRows && m_NonMouseHighlightedButton->GetParent() == m_GUIInventoryItemsBox && m_InventoryActor->IsInventoryEmpty())) { + m_NonMouseHighlightedButton = m_GUIEquippedItemButton; + } + if (!m_NonMouseHighlightedButton->IsMousedOver()) { + m_NonMouseHighlightedButton->OnMouseEnter(0, 0, 0, 0); + } if (m_MenuController->IsState(ControlState::PRESS_PRIMARY)) { if (m_NonMouseHighlightedButton->IsEnabled()) { @@ -936,7 +989,7 @@ namespace RTE { } } - GUIButton *nextButtonToHighlight = nullptr; + GUIButton* nextButtonToHighlight = nullptr; Directions pressedDirection = GetNonMouseButtonControllerMovement(); switch (pressedDirection) { case Directions::Up: @@ -969,7 +1022,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Directions InventoryMenuGUI::GetNonMouseButtonControllerMovement() { bool pressUp = m_MenuController->IsState(ControlState::PRESS_UP) || m_MenuController->IsState(ControlState::SCROLL_UP); @@ -1004,10 +1057,10 @@ namespace RTE { return Directions::None; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIButton * InventoryMenuGUI::HandleNonMouseUpInput() { - GUIButton *nextButtonToHighlight = nullptr; + GUIButton* InventoryMenuGUI::HandleNonMouseUpInput() { + GUIButton* nextButtonToHighlight = nullptr; if (m_NonMouseHighlightedButton == m_GUIDropButton) { nextButtonToHighlight = m_GUIReloadButton; @@ -1039,10 +1092,10 @@ namespace RTE { return nextButtonToHighlight; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIButton * InventoryMenuGUI::HandleNonMouseDownInput() { - GUIButton *nextButtonToHighlight = nullptr; + GUIButton* InventoryMenuGUI::HandleNonMouseDownInput() { + GUIButton* nextButtonToHighlight = nullptr; if (!m_InventoryActor->IsInventoryEmpty() && (m_NonMouseHighlightedButton == m_GUISwapSetButton || m_NonMouseHighlightedButton == m_GUIEquippedItemButton || m_NonMouseHighlightedButton == m_GUIOffhandEquippedItemButton || m_NonMouseHighlightedButton == m_GUIDropButton || m_NonMouseHighlightedButton == m_GUIInformationToggleButton)) { nextButtonToHighlight = m_NonMousePreviousInventoryItemsBoxButton; @@ -1078,10 +1131,10 @@ namespace RTE { return nextButtonToHighlight; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIButton * InventoryMenuGUI::HandleNonMouseLeftInput() { - GUIButton *nextButtonToHighlight = nullptr; + GUIButton* InventoryMenuGUI::HandleNonMouseLeftInput() { + GUIButton* nextButtonToHighlight = nullptr; if (m_NonMouseHighlightedButton->GetParent() == m_GUIInventoryItemsBox) { try { @@ -1104,15 +1157,17 @@ namespace RTE { } else if (m_NonMouseHighlightedButton == m_GUIInformationToggleButton) { nextButtonToHighlight = m_NonMousePreviousReloadOrDropButton ? m_NonMousePreviousReloadOrDropButton : m_GUIReloadButton; } - if (nextButtonToHighlight) { m_NonMousePreviousInventoryItemsBoxButton = nullptr; } + if (nextButtonToHighlight) { + m_NonMousePreviousInventoryItemsBoxButton = nullptr; + } } return nextButtonToHighlight; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUIButton * InventoryMenuGUI::HandleNonMouseRightInput() { - GUIButton *nextButtonToHighlight = nullptr; + GUIButton* InventoryMenuGUI::HandleNonMouseRightInput() { + GUIButton* nextButtonToHighlight = nullptr; if (m_NonMouseHighlightedButton->GetParent() == m_GUIInventoryItemsBox) { try { @@ -1122,7 +1177,9 @@ namespace RTE { nextButtonToHighlight = m_GUIInventoryItemButtons.at(highlightedButtonIndex - c_ItemsPerRow + 1).second; } else { int numberOfVisibleButtons = m_GUIShowEmptyRows ? c_FullViewPageItemLimit : c_ItemsPerRow * static_cast(std::ceil(static_cast(std::min(c_FullViewPageItemLimit, m_InventoryActor->GetInventorySize())) / static_cast(c_ItemsPerRow))); - if (highlightedButtonIndex + 1 < numberOfVisibleButtons) { nextButtonToHighlight = m_GUIInventoryItemButtons.at(highlightedButtonIndex + 1).second; } + if (highlightedButtonIndex + 1 < numberOfVisibleButtons) { + nextButtonToHighlight = m_GUIInventoryItemButtons.at(highlightedButtonIndex + 1).second; + } m_NonMousePreviousEquippedItemsBoxButton = nullptr; } } catch (std::invalid_argument) { @@ -1140,18 +1197,20 @@ namespace RTE { } else if (m_NonMouseHighlightedButton == m_GUIReloadButton || m_NonMouseHighlightedButton == m_GUIDropButton) { nextButtonToHighlight = m_GUIInformationToggleButton; } - if (nextButtonToHighlight) { m_NonMousePreviousInventoryItemsBoxButton = nullptr; } + if (nextButtonToHighlight) { + m_NonMousePreviousInventoryItemsBoxButton = nullptr; + } } return nextButtonToHighlight; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::HandleItemButtonPressOrHold(GUIButton *pressedButton, MovableObject *buttonObject, int buttonEquippedItemIndex, bool buttonHeld) { + void InventoryMenuGUI::HandleItemButtonPressOrHold(GUIButton* pressedButton, MovableObject* buttonObject, int buttonEquippedItemIndex, bool buttonHeld) { if (buttonHeld && m_GUISelectedItem) { return; } - if ((buttonEquippedItemIndex == 1 && m_GUISelectedItem && !m_GUISelectedItem->Object->HasObjectInGroup("Shields") && !dynamic_cast(m_GUISelectedItem->Object)->IsDualWieldable()) || (m_GUISelectedItem && m_GUISelectedItem->EquippedItemIndex == 1 && buttonObject && !buttonObject->HasObjectInGroup("Shields") && !dynamic_cast(buttonObject)->IsDualWieldable())) { + if ((buttonEquippedItemIndex == 1 && m_GUISelectedItem && !m_GUISelectedItem->Object->HasObjectInGroup("Shields") && !dynamic_cast(m_GUISelectedItem->Object)->IsDualWieldable()) || (m_GUISelectedItem && m_GUISelectedItem->EquippedItemIndex == 1 && buttonObject && !buttonObject->HasObjectInGroup("Shields") && !dynamic_cast(buttonObject)->IsDualWieldable())) { g_GUISound.UserErrorSound()->Play(m_MenuController->GetPlayer()); return; } @@ -1166,7 +1225,9 @@ namespace RTE { } if (m_GUISelectedItem == nullptr) { - if (!buttonHeld) { g_GUISound.ItemChangeSound()->Play(m_MenuController->GetPlayer()); } + if (!buttonHeld) { + g_GUISound.ItemChangeSound()->Play(m_MenuController->GetPlayer()); + } if (buttonEquippedItemIndex > -1) { SetSelectedItem(pressedButton, buttonObject, -1, pressedButtonItemIndex, buttonHeld); } else { @@ -1178,17 +1239,17 @@ namespace RTE { } else { if (m_GUISelectedItem->EquippedItemIndex > -1) { if (buttonEquippedItemIndex > -1) { - Arm *selectedItemArm = dynamic_cast(m_GUISelectedItem->Object->GetParent()); - Arm *buttonObjectArm = selectedItemArm && buttonObject ? dynamic_cast(buttonObject->GetParent()) : nullptr; + Arm* selectedItemArm = dynamic_cast(m_GUISelectedItem->Object->GetParent()); + Arm* buttonObjectArm = selectedItemArm && buttonObject ? dynamic_cast(buttonObject->GetParent()) : nullptr; if (!buttonObject) { - const AHuman *inventoryActorAsAHuman = dynamic_cast(m_InventoryActor); + const AHuman* inventoryActorAsAHuman = dynamic_cast(m_InventoryActor); buttonObjectArm = buttonEquippedItemIndex == 0 ? inventoryActorAsAHuman->GetFGArm() : inventoryActorAsAHuman->GetBGArm(); } - if (selectedItemArm && buttonObjectArm && dynamic_cast(buttonObject) && dynamic_cast(m_GUISelectedItem->Object)) { + if (selectedItemArm && buttonObjectArm && dynamic_cast(buttonObject) && dynamic_cast(m_GUISelectedItem->Object)) { selectedItemArm->RemoveAttachable(selectedItemArm->GetHeldDevice()); buttonObjectArm->RemoveAttachable(buttonObjectArm->GetHeldDevice()); - selectedItemArm->SetHeldDevice(dynamic_cast(buttonObject)); - buttonObjectArm->SetHeldDevice(dynamic_cast(m_GUISelectedItem->Object)); + selectedItemArm->SetHeldDevice(dynamic_cast(buttonObject)); + buttonObjectArm->SetHeldDevice(dynamic_cast(m_GUISelectedItem->Object)); m_InventoryActor->GetDeviceSwitchSound()->Play(m_MenuController->GetPlayer()); } else { g_GUISound.UserErrorSound()->Play(m_MenuController->GetPlayer()); @@ -1213,7 +1274,7 @@ namespace RTE { pressedButton->OnLoseFocus(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool InventoryMenuGUI::SwapEquippedItemAndInventoryItem(int equippedItemIndex, int inventoryItemIndex) { if (!m_InventoryActorIsHuman) { @@ -1221,11 +1282,11 @@ namespace RTE { return false; } - AHuman *inventoryActorAsAHuman = dynamic_cast(m_InventoryActor); - MovableObject *equippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() && !m_InventoryActorEquippedItems.empty() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).first : nullptr; - MovableObject *offhandEquippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() && !m_InventoryActorEquippedItems.empty() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).second : nullptr; + AHuman* inventoryActorAsAHuman = dynamic_cast(m_InventoryActor); + MovableObject* equippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() && !m_InventoryActorEquippedItems.empty() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).first : nullptr; + MovableObject* offhandEquippedItem = m_GUIInventoryActorCurrentEquipmentSetIndex < m_InventoryActorEquippedItems.size() && !m_InventoryActorEquippedItems.empty() ? m_InventoryActorEquippedItems.at(m_GUIInventoryActorCurrentEquipmentSetIndex).second : nullptr; - const HeldDevice *inventoryItemToSwapIn = inventoryItemIndex < m_InventoryActor->GetInventorySize() ? dynamic_cast(m_InventoryActor->GetInventory()->at(inventoryItemIndex)) : nullptr; + const HeldDevice* inventoryItemToSwapIn = inventoryItemIndex < m_InventoryActor->GetInventorySize() ? dynamic_cast(m_InventoryActor->GetInventory()->at(inventoryItemIndex)) : nullptr; if (!inventoryItemToSwapIn && inventoryItemIndex < m_InventoryActor->GetInventorySize()) { g_GUISound.UserErrorSound()->Play(m_MenuController->GetPlayer()); return false; @@ -1233,15 +1294,15 @@ namespace RTE { bool inventoryItemCanGoInOffhand = !inventoryItemToSwapIn || inventoryItemToSwapIn->IsDualWieldable() || inventoryItemToSwapIn->HasObjectInGroup("Shields"); equippedItemIndex = !inventoryItemCanGoInOffhand || !inventoryActorAsAHuman->GetBGArm() ? 0 : equippedItemIndex; - MovableObject *equippedItemToSwapOut = equippedItemIndex == 0 ? equippedItem : offhandEquippedItem; + MovableObject* equippedItemToSwapOut = equippedItemIndex == 0 ? equippedItem : offhandEquippedItem; if (equippedItemIndex == 0 && !inventoryActorAsAHuman->GetFGArm()) { g_GUISound.UserErrorSound()->Play(m_MenuController->GetPlayer()); return false; } - Arm *equippedItemArm = equippedItemIndex == 0 ? inventoryActorAsAHuman->GetFGArm() : inventoryActorAsAHuman->GetBGArm(); - equippedItemArm->SetHeldDevice(dynamic_cast(m_InventoryActor->SetInventoryItemAtIndex(equippedItemArm->RemoveAttachable(equippedItemArm->GetHeldDevice()), inventoryItemIndex))); + Arm* equippedItemArm = equippedItemIndex == 0 ? inventoryActorAsAHuman->GetFGArm() : inventoryActorAsAHuman->GetBGArm(); + equippedItemArm->SetHeldDevice(dynamic_cast(m_InventoryActor->SetInventoryItemAtIndex(equippedItemArm->RemoveAttachable(equippedItemArm->GetHeldDevice()), inventoryItemIndex))); equippedItemArm->SetHandPos(m_InventoryActor->GetPos() + m_InventoryActor->GetHolsterOffset().GetXFlipped(m_InventoryActor->IsHFlipped())); if (!inventoryItemCanGoInOffhand && offhandEquippedItem) { m_InventoryActor->AddInventoryItem(inventoryActorAsAHuman->GetBGArm()->RemoveAttachable(inventoryActorAsAHuman->GetBGArm()->GetHeldDevice())); @@ -1251,16 +1312,16 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::ReloadSelectedItem() { //for a in MovableMan.Actors do print(ToAHuman(a).EquippedBGItem:SetOneHanded(true)) end + void InventoryMenuGUI::ReloadSelectedItem() { // for a in MovableMan.Actors do print(ToAHuman(a).EquippedBGItem:SetOneHanded(true)) end if (!m_InventoryActorIsHuman) { return; } - AHuman *inventoryActorAsAHuman = dynamic_cast(m_InventoryActor); + AHuman* inventoryActorAsAHuman = dynamic_cast(m_InventoryActor); if (m_GUISelectedItem == nullptr) { inventoryActorAsAHuman->ReloadFirearms(); - } else if (const HDFirearm *selectedItemObjectAsFirearm = dynamic_cast(m_GUISelectedItem->Object)) { + } else if (const HDFirearm* selectedItemObjectAsFirearm = dynamic_cast(m_GUISelectedItem->Object)) { bool selectedItemIsEquipped = m_GUISelectedItem->EquippedItemIndex > -1; if (!selectedItemIsEquipped) { int equippedItemIndexToUse = inventoryActorAsAHuman->GetFGArm() ? 0 : 1; @@ -1276,10 +1337,10 @@ namespace RTE { m_GUIReloadButton->OnLoseFocus(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::DropSelectedItem(const Vector *dropDirection) { - auto LaunchInventoryItem = [this, &dropDirection](MovableObject *itemToLaunch) { + void InventoryMenuGUI::DropSelectedItem(const Vector* dropDirection) { + auto LaunchInventoryItem = [this, &dropDirection](MovableObject* itemToLaunch) { Vector itemPosition = m_InventoryActor->GetPos(); Vector throwForce(0.75F + (0.25F * RandomNum()), 0); if (dropDirection && dropDirection->MagnitudeIsGreaterThan(0.5F)) { @@ -1301,7 +1362,7 @@ namespace RTE { }; if (m_GUISelectedItem->EquippedItemIndex > -1) { - Attachable *itemToLaunch = dynamic_cast(m_GUISelectedItem->Object->GetParent())->RemoveAttachable(dynamic_cast(m_GUISelectedItem->Object->GetParent())->GetHeldDevice()); + Attachable* itemToLaunch = dynamic_cast(m_GUISelectedItem->Object->GetParent())->RemoveAttachable(dynamic_cast(m_GUISelectedItem->Object->GetParent())->GetHeldDevice()); if (itemToLaunch) { LaunchInventoryItem(itemToLaunch); } @@ -1313,15 +1374,15 @@ namespace RTE { m_GUIDropButton->OnLoseFocus(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::DrawCarouselMode(BITMAP *targetBitmap, const Vector &drawPos) const { + void InventoryMenuGUI::DrawCarouselMode(BITMAP* targetBitmap, const Vector& drawPos) const { clear_to_color(m_CarouselBitmap.get(), g_MaskColor); clear_to_color(m_CarouselBGBitmap.get(), g_MaskColor); AllegroBitmap carouselAllegroBitmap(m_CarouselBitmap.get()); float enableDisableProgress = static_cast(m_EnableDisableAnimationTimer.RealTimeLimitProgress()); - for (const std::unique_ptr &carouselItemBox : m_CarouselItemBoxes) { + for (const std::unique_ptr& carouselItemBox: m_CarouselItemBoxes) { if ((carouselItemBox->Item && carouselItemBox->Item->GetUniqueID() != 0) || (carouselItemBox->IsForEquippedItems && !m_InventoryActorEquippedItems.empty())) { DrawCarouselItemBoxBackground(*carouselItemBox); DrawCarouselItemBoxForeground(*carouselItemBox, &carouselAllegroBitmap); @@ -1352,23 +1413,25 @@ namespace RTE { bool hasDrawnAtLeastOnce = false; std::list wrappedRectangles; g_SceneMan.WrapRect(IntRect(drawPos.GetFloorIntX(), drawPos.GetFloorIntY(), drawPos.GetFloorIntX() + m_CarouselBitmap->w, drawPos.GetFloorIntY() + m_CarouselBitmap->h), wrappedRectangles); - for (const IntRect &wrappedRectangle : wrappedRectangles) { + for (const IntRect& wrappedRectangle: wrappedRectangles) { if (m_CarouselBackgroundTransparent && !g_FrameMan.IsInMultiplayerMode()) { g_FrameMan.SetTransTableFromPreset(TransparencyPreset::MoreTrans); draw_trans_sprite(targetBitmap, m_CarouselBGBitmap.get(), wrappedRectangle.m_Left - m_CarouselBGBitmap->w / 2, wrappedRectangle.m_Top - m_CarouselBGBitmap->h / 2); draw_sprite(targetBitmap, m_CarouselBitmap.get(), wrappedRectangle.m_Left - m_CarouselBitmap->w / 2, wrappedRectangle.m_Top - m_CarouselBitmap->h / 2); } else { - if (!hasDrawnAtLeastOnce) { draw_sprite(m_CarouselBGBitmap.get(), m_CarouselBitmap.get(), 0, 0); } + if (!hasDrawnAtLeastOnce) { + draw_sprite(m_CarouselBGBitmap.get(), m_CarouselBitmap.get(), 0, 0); + } draw_sprite(targetBitmap, m_CarouselBGBitmap.get(), wrappedRectangle.m_Left - m_CarouselBGBitmap->w / 2, wrappedRectangle.m_Top - m_CarouselBGBitmap->h / 2); } hasDrawnAtLeastOnce = true; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::DrawCarouselItemBoxBackground(const CarouselItemBox &itemBoxToDraw) const { - auto DrawBox = [](BITMAP *targetBitmap, const Vector &boxTopLeftCorner, const Vector &boxBottomRightCorner, int color, bool roundedLeftSide, bool roundedRightSide) { + void InventoryMenuGUI::DrawCarouselItemBoxBackground(const CarouselItemBox& itemBoxToDraw) const { + auto DrawBox = [](BITMAP* targetBitmap, const Vector& boxTopLeftCorner, const Vector& boxBottomRightCorner, int color, bool roundedLeftSide, bool roundedRightSide) { if (roundedLeftSide) { circlefill(targetBitmap, boxTopLeftCorner.GetFloorIntX() + c_CarouselBoxCornerRadius, boxTopLeftCorner.GetFloorIntY() + c_CarouselBoxCornerRadius, c_CarouselBoxCornerRadius, color); circlefill(targetBitmap, boxTopLeftCorner.GetFloorIntX() + c_CarouselBoxCornerRadius, boxBottomRightCorner.GetFloorIntY() - c_CarouselBoxCornerRadius, c_CarouselBoxCornerRadius, color); @@ -1389,28 +1452,32 @@ namespace RTE { DrawBox(m_CarouselBGBitmap.get(), itemBoxToDraw.Pos + (itemBoxToDraw.RoundedAndBorderedSides.first ? m_CarouselBackgroundBoxBorderSize : Vector(0, m_CarouselBackgroundBoxBorderSize.GetY())), itemBoxToDraw.Pos + itemBoxToDraw.CurrentSize - spriteZeroIndexSizeOffset - (itemBoxToDraw.RoundedAndBorderedSides.second ? m_CarouselBackgroundBoxBorderSize : Vector(0, m_CarouselBackgroundBoxBorderSize.GetY())), m_CarouselBackgroundBoxColor, itemBoxToDraw.RoundedAndBorderedSides.first, itemBoxToDraw.RoundedAndBorderedSides.second); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::DrawCarouselItemBoxForeground(const CarouselItemBox &itemBoxToDraw, AllegroBitmap *carouselAllegroBitmap) const { - std::vector itemIcons; + void InventoryMenuGUI::DrawCarouselItemBoxForeground(const CarouselItemBox& itemBoxToDraw, AllegroBitmap* carouselAllegroBitmap) const { + std::vector itemIcons; float totalItemMass = 0; itemBoxToDraw.GetIconsAndMass(itemIcons, totalItemMass, &m_InventoryActorEquippedItems); Vector spriteZeroIndexSizeOffset(1, 1); Vector multiItemDrawOffset = Vector(c_MultipleItemInBoxOffset * static_cast(itemIcons.size() - 1), -c_MultipleItemInBoxOffset * static_cast(itemIcons.size() - 1)); Vector iconMaxSize = itemBoxToDraw.CurrentSize - Vector(c_MinimumItemPadding * 2, c_MinimumItemPadding * 2) - spriteZeroIndexSizeOffset; - if (itemBoxToDraw.RoundedAndBorderedSides.first) { iconMaxSize.SetX(iconMaxSize.GetX() - m_CarouselBackgroundBoxBorderSize.GetX()); } - if (itemBoxToDraw.RoundedAndBorderedSides.second) { iconMaxSize.SetX(iconMaxSize.GetX() - m_CarouselBackgroundBoxBorderSize.GetX()); } - std::for_each(itemIcons.crbegin(), itemIcons.crend(), [this, &itemBoxToDraw, &multiItemDrawOffset, &iconMaxSize](BITMAP *iconToDraw) { + if (itemBoxToDraw.RoundedAndBorderedSides.first) { + iconMaxSize.SetX(iconMaxSize.GetX() - m_CarouselBackgroundBoxBorderSize.GetX()); + } + if (itemBoxToDraw.RoundedAndBorderedSides.second) { + iconMaxSize.SetX(iconMaxSize.GetX() - m_CarouselBackgroundBoxBorderSize.GetX()); + } + std::for_each(itemIcons.crbegin(), itemIcons.crend(), [this, &itemBoxToDraw, &multiItemDrawOffset, &iconMaxSize](BITMAP* iconToDraw) { if (iconToDraw) { float stretchRatio = std::max(static_cast(iconToDraw->w - 1 + (multiItemDrawOffset.GetFloorIntX() / 2)) / iconMaxSize.GetX(), static_cast(iconToDraw->h - 1 + (multiItemDrawOffset.GetFloorIntY() / 2)) / iconMaxSize.GetY()); if (stretchRatio > 1.0F) { float stretchedWidth = static_cast(iconToDraw->w) / stretchRatio; float stretchedHeight = static_cast(iconToDraw->h) / stretchRatio; stretch_sprite(m_CarouselBitmap.get(), iconToDraw, - itemBoxToDraw.IconCenterPosition.GetFloorIntX() - static_cast(itemBoxToDraw.RoundedAndBorderedSides.first ? std::floor(stretchedWidth / 2.0F) : std::ceil(stretchedWidth / 2.0F)) + multiItemDrawOffset.GetFloorIntX() + (itemBoxToDraw.RoundedAndBorderedSides.first ? m_CarouselBackgroundBoxBorderSize.GetFloorIntX() / 2 : 0) - (itemBoxToDraw.RoundedAndBorderedSides.second ? m_CarouselBackgroundBoxBorderSize.GetFloorIntX() / 2 : 0), - itemBoxToDraw.IconCenterPosition.GetFloorIntY() - static_cast(stretchedHeight / 2.0F) + multiItemDrawOffset.GetFloorIntY(), - static_cast(itemBoxToDraw.RoundedAndBorderedSides.first ? std::ceil(stretchedWidth) : std::floor(stretchedWidth)), static_cast(stretchedHeight)); + itemBoxToDraw.IconCenterPosition.GetFloorIntX() - static_cast(itemBoxToDraw.RoundedAndBorderedSides.first ? std::floor(stretchedWidth / 2.0F) : std::ceil(stretchedWidth / 2.0F)) + multiItemDrawOffset.GetFloorIntX() + (itemBoxToDraw.RoundedAndBorderedSides.first ? m_CarouselBackgroundBoxBorderSize.GetFloorIntX() / 2 : 0) - (itemBoxToDraw.RoundedAndBorderedSides.second ? m_CarouselBackgroundBoxBorderSize.GetFloorIntX() / 2 : 0), + itemBoxToDraw.IconCenterPosition.GetFloorIntY() - static_cast(stretchedHeight / 2.0F) + multiItemDrawOffset.GetFloorIntY(), + static_cast(itemBoxToDraw.RoundedAndBorderedSides.first ? std::ceil(stretchedWidth) : std::floor(stretchedWidth)), static_cast(stretchedHeight)); } else { draw_sprite(m_CarouselBitmap.get(), iconToDraw, itemBoxToDraw.IconCenterPosition.GetFloorIntX() - (iconToDraw->w / 2) + multiItemDrawOffset.GetFloorIntX(), itemBoxToDraw.IconCenterPosition.GetFloorIntY() - (iconToDraw->h / 2) + multiItemDrawOffset.GetFloorIntY()); } @@ -1422,14 +1489,16 @@ namespace RTE { m_SmallFont->DrawAligned(carouselAllegroBitmap, itemBoxToDraw.IconCenterPosition.GetFloorIntX(), itemBoxToDraw.IconCenterPosition.GetFloorIntY() - ((itemBoxToDraw.CurrentSize.GetFloorIntY() + m_SmallFont->GetFontHeight()) / 2) + 1, massString.c_str(), GUIFont::Centre); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void InventoryMenuGUI::DrawFullMode(BITMAP *targetBitmap, const Vector &drawPos) const { + void InventoryMenuGUI::DrawFullMode(BITMAP* targetBitmap, const Vector& drawPos) const { m_GUITopLevelBox->SetPositionAbs(drawPos.GetFloorIntX(), drawPos.GetFloorIntY()); if (IsEnablingOrDisabling()) { float enableDisableProgress = static_cast(m_EnableDisableAnimationTimer.RealTimeLimitProgress()); - if (m_EnabledState == EnabledState::Disabling) { enableDisableProgress = 1.0F - enableDisableProgress; } + if (m_EnabledState == EnabledState::Disabling) { + enableDisableProgress = 1.0F - enableDisableProgress; + } m_GUITopLevelBox->SetSize(static_cast(m_GUITopLevelBoxFullSize.GetX() * enableDisableProgress), static_cast(m_GUITopLevelBoxFullSize.GetY() * enableDisableProgress)); m_GUITopLevelBox->SetPositionAbs(m_GUITopLevelBox->GetXPos() + ((m_GUITopLevelBoxFullSize.GetFloorIntX() - m_GUITopLevelBox->GetWidth()) / 2), m_GUITopLevelBox->GetYPos() + ((m_GUITopLevelBoxFullSize.GetFloorIntY() - m_GUITopLevelBox->GetHeight()) / 2)); } @@ -1438,11 +1507,11 @@ namespace RTE { m_GUIControlManager->Draw(&guiScreen); if (IsEnabled() && !m_GUIDisplayOnly && m_MenuController->IsMouseControlled()) { if (m_GUISelectedItem && m_GUISelectedItem->DragWasHeldForLongEnough()) { - BITMAP *selectedObjectIcon = m_GUISelectedItem->Object->GetGraphicalIcon(); + BITMAP* selectedObjectIcon = m_GUISelectedItem->Object->GetGraphicalIcon(); draw_sprite(targetBitmap, selectedObjectIcon, m_GUICursorPos.GetFloorIntX() - (selectedObjectIcon->w / 2), m_GUICursorPos.GetFloorIntY() - (selectedObjectIcon->h / 2)); } else { draw_sprite(targetBitmap, s_CursorBitmap, m_GUICursorPos.GetFloorIntX(), m_GUICursorPos.GetFloorIntY()); } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/InventoryMenuGUI.h b/Source/Menus/InventoryMenuGUI.h index af1801960..30c6783a8 100644 --- a/Source/Menus/InventoryMenuGUI.h +++ b/Source/Menus/InventoryMenuGUI.h @@ -28,11 +28,14 @@ namespace RTE { class InventoryMenuGUI { public: - /// /// Enumeration for the modes an InventoryMenuGUI can have. /// - enum class MenuMode { Carousel, Full, Transfer }; + enum class MenuMode { + Carousel, + Full, + Transfer + }; #pragma region Creation /// @@ -47,7 +50,7 @@ namespace RTE { /// The Actor whose inventory this GUI will display. Ownership is NOT transferred! /// The mode this menu should use when it's enabled. Defaults to Carousel. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(Controller *activityPlayerController, Actor *inventoryActor = nullptr, MenuMode menuMode = MenuMode::Carousel); + int Create(Controller* activityPlayerController, Actor* inventoryActor = nullptr, MenuMode menuMode = MenuMode::Carousel); #pragma endregion #pragma region Destruction @@ -67,19 +70,19 @@ namespace RTE { /// Sets the controller used by this. The ownership of the controller is NOT transferred! /// /// The new controller for this menu. Ownership is NOT transferred! - void SetController(Controller *controller) { m_MenuController = controller; } + void SetController(Controller* controller) { m_MenuController = controller; } /// /// Gets the Actor whose inventory this GUI will display. The ownership of the Actor is NOT transferred! /// /// The Actor whose inventory this GUI will display. Ownership is NOT transferred! - const Actor * GetInventoryActor() const { return m_InventoryActor; } + const Actor* GetInventoryActor() const { return m_InventoryActor; } /// /// Sets the Actor whose inventory this GUI will display. The ownership of the Actor is NOT transferred! /// /// The new Actor whose inventory this GUI will display. Ownership is NOT transferred! - void SetInventoryActor(Actor *newInventoryActor); + void SetInventoryActor(Actor* newInventoryActor); /// /// Gets the MenuMode this InventoryMenuGUI is currently in. @@ -145,7 +148,7 @@ namespace RTE { /// The index of this selected item in the displayed inventory. -1 means the item is not in the inventory. /// The index of this selected item in the vector of equipped items. -1 means the item is not in the inventory. /// Whether or not the selected item is being dragged. - void SetSelectedItem(GUIButton *selectedItemButton, MovableObject *selectedItemObject, int inventoryIndex, int equippedItemIndex, bool isBeingDragged); + void SetSelectedItem(GUIButton* selectedItemButton, MovableObject* selectedItemObject, int inventoryIndex, int equippedItemIndex, bool isBeingDragged); #pragma endregion #pragma region Updating @@ -159,16 +162,15 @@ namespace RTE { /// /// A pointer to a BITMAP to draw on. Generally a screen BITMAP. /// The absolute position of the target bitmap's upper left corner in the scene. - void Draw(BITMAP *targetBitmap, const Vector &targetPos = Vector()) const; + void Draw(BITMAP* targetBitmap, const Vector& targetPos = Vector()) const; #pragma endregion private: - /// /// A struct containing all information required to drawn and animate a carousel item box in Carousel MenuMode. /// struct CarouselItemBox { - MovableObject *Item; //!< A pointer to the item being displayed in the CarouselItemBox. + MovableObject* Item; //!< A pointer to the item being displayed in the CarouselItemBox. bool IsForEquippedItems; //!< Whether or not this CarouselItemBox is for displaying equipped items. Vector FullSize; //!< The full size for this CarouselItemBox when it's not animating. Vector CurrentSize; //!< The current size of this CarouselItemBox. @@ -183,15 +185,15 @@ namespace RTE { /// A vector of Bitmaps to be filled in with the icon(s) for this CarouselItemBox's item(s). /// A float to be filled in with the total mass of this CarouselItemBox's item(s). /// A pointer to the vector of sets of equipped items to be used if the CarouselItemBox IsForEquippedItem. - void GetIconsAndMass(std::vector &itemIcons, float &totalItemMass, const std::vector> *equippedItems) const; + void GetIconsAndMass(std::vector& itemIcons, float& totalItemMass, const std::vector>* equippedItems) const; }; /// /// A struct containing all information required to describe a selected item in Full/Transfer MenuMode. /// struct GUISelectedItem { - GUIButton *Button; //!< A pointer to the button for this GUISelectedItem. - MovableObject *Object; //!< A pointer to the MovableObject for this GUISelectedItem. Should always match up with what the Button is displaying. + GUIButton* Button; //!< A pointer to the button for this GUISelectedItem. + MovableObject* Object; //!< A pointer to the MovableObject for this GUISelectedItem. Should always match up with what the Button is displaying. int InventoryIndex; //!< The index in the InventoryItemsBox that this GUISelectedItem is for. Either this or the EquippedItemIndex must have a value. int EquippedItemIndex; //!< The index in the EquippedItemIndex that this GUISelectedItem is for. Either this or the InventoryIndex must have a value. bool IsBeingDragged; //!< Whether or not the GUISelectedItem is currently being dragged. @@ -207,12 +209,21 @@ namespace RTE { /// /// Enumeration for enabled states when enabling/disabling the InventoryMenuGUI. /// - enum class EnabledState { Enabling, Enabled, Disabling, Disabled }; + enum class EnabledState { + Enabling, + Enabled, + Disabling, + Disabled + }; /// /// Enumeration for which direction an inventory is being swapped in. /// - enum class CarouselAnimationDirection { Left = -1, None, Right}; + enum class CarouselAnimationDirection { + Left = -1, + None, + Right + }; static constexpr int c_ItemsPerRow = 5; //!< The number of items per row of the inventory display. MUST be an odd number. Used in all MenuModes. static constexpr int c_MinimumItemPadding = 1; //!< The padding between item icons and their containing boxes. Items will have at least this much padding on all sides. Used in all MenuModes. @@ -227,13 +238,13 @@ namespace RTE { static constexpr int c_FullViewPageItemLimit = c_ItemsPerRow * 3; //!< The default number of rows in the full inventory display. Used in Full/Transfer MenuModes. static constexpr int c_FullMenuVerticalOffset = 50; //!< How high above its target the full GUI will be. Used in Full/Transfer MenuModes. - static BITMAP *s_CursorBitmap; //!< The cursor image shared by all GUIs. + static BITMAP* s_CursorBitmap; //!< The cursor image shared by all GUIs. - GUIFont *m_SmallFont; //!< A pointer to the small font from FrameMan. Not owned here. - GUIFont *m_LargeFont; //!< A pointer to the large font from FrameMan. Not owned here. + GUIFont* m_SmallFont; //!< A pointer to the small font from FrameMan. Not owned here. + GUIFont* m_LargeFont; //!< A pointer to the large font from FrameMan. Not owned here. - Controller *m_MenuController; //!< The Controller which controls this menu. - Actor *m_InventoryActor; //!< The Actor whose inventory this GUI will display. + Controller* m_MenuController; //!< The Controller which controls this menu. + Actor* m_InventoryActor; //!< The Actor whose inventory this GUI will display. MenuMode m_MenuMode; //!< The mode this menu is in. See MenuMode enum for more details. Vector m_CenterPos; //!< The center position of this menu in the scene. @@ -241,7 +252,7 @@ namespace RTE { Timer m_EnableDisableAnimationTimer; //!< Timer for progressing enabling/disabling animations. bool m_InventoryActorIsHuman; //!< Whether the Actor whose inventory this GUI will display is an AHuman. - std::vector> m_InventoryActorEquippedItems; //!< A vector of pairs of pointers to the equipped item and equipped offhand item of the Actor whose inventory this GUI will display, if applicable. Pointers are NOT owned. + std::vector> m_InventoryActorEquippedItems; //!< A vector of pairs of pointers to the equipped item and equipped offhand item of the Actor whose inventory this GUI will display, if applicable. Pointers are NOT owned. bool m_CarouselDrawEmptyBoxes; //!< Whether or not the carousel should draw empty item boxes. Used in Carousel MenuMode. bool m_CarouselBackgroundTransparent; //!< Whether or not the carousel's background should be drawn transparently. Used in Carousel MenuMode. @@ -265,18 +276,18 @@ namespace RTE { Timer m_GUIRepeatStartTimer; //!< Measures the time to when to start repeating inputs when they're held down. Used in Full/Transfer MenuModes. Timer m_GUIRepeatTimer; //!< Measures the interval between input repeats. Used in Full/Transfer MenuModes. - GUIButton *m_NonMouseHighlightedButton; //!< A pointer to the GUIButton currently highlighted by the keyboard or gamepad. - //TODO These previous buttons should be cleaned up when InventoryMenuGUI is refactored. Requirements were unclear so this is more complicated than it needs to be, these 3 can be consolidated into 2 or 1 variable, and the code handling them can be simplified a bit. - GUIButton *m_NonMousePreviousEquippedItemsBoxButton; //!< A pointer to the last GUIButton in the EquippedItemsBox that was highlighted by the keyboard or gamepad. - GUIButton *m_NonMousePreviousInventoryItemsBoxButton; //!< A pointer to the last GUIButton in the InventoryItemsBox that was highlighted by the keyboard or gamepad. - GUIButton *m_NonMousePreviousReloadOrDropButton; //!< A pointer to whichever of the reload or drop GUIButtons was last highlighted by the keyboard or gamepad. + GUIButton* m_NonMouseHighlightedButton; //!< A pointer to the GUIButton currently highlighted by the keyboard or gamepad. + // TODO These previous buttons should be cleaned up when InventoryMenuGUI is refactored. Requirements were unclear so this is more complicated than it needs to be, these 3 can be consolidated into 2 or 1 variable, and the code handling them can be simplified a bit. + GUIButton* m_NonMousePreviousEquippedItemsBoxButton; //!< A pointer to the last GUIButton in the EquippedItemsBox that was highlighted by the keyboard or gamepad. + GUIButton* m_NonMousePreviousInventoryItemsBoxButton; //!< A pointer to the last GUIButton in the InventoryItemsBox that was highlighted by the keyboard or gamepad. + GUIButton* m_NonMousePreviousReloadOrDropButton; //!< A pointer to whichever of the reload or drop GUIButtons was last highlighted by the keyboard or gamepad. Vector m_GUITopLevelBoxFullSize; //!< A Vector holding the full size of the top level box for enabling/disabling animations. bool m_GUIShowInformationText; //!< Whether or information text explaining how to use the menu should be showing. - const Icon *m_GUIInformationToggleButtonIcon; //!< A pointer to the PresetMan pie icon for information, used here for the information toggle button. Not Owned here. - const Icon *m_GUIReloadButtonIcon; //!< A pointer to the PresetMan pie icon for reloading, used here for the reload button. Not Owned here. - const Icon *m_GUIDropButtonIcon; //!< A pointer to the PresetMan pie icon for dropping items, used here for the drop button. Not Owned here. - std::vector> m_GUIInventoryItemButtons; //!< A vector of pairs of MovableObject pointers and GUIButton pointers, connecting inventory GUIButtons to their corresponding MovableObjects. + const Icon* m_GUIInformationToggleButtonIcon; //!< A pointer to the PresetMan pie icon for information, used here for the information toggle button. Not Owned here. + const Icon* m_GUIReloadButtonIcon; //!< A pointer to the PresetMan pie icon for reloading, used here for the reload button. Not Owned here. + const Icon* m_GUIDropButtonIcon; //!< A pointer to the PresetMan pie icon for dropping items, used here for the drop button. Not Owned here. + std::vector> m_GUIInventoryItemButtons; //!< A vector of pairs of MovableObject pointers and GUIButton pointers, connecting inventory GUIButtons to their corresponding MovableObjects. /// /// GUI elements that make up the full mode InventoryMenuGUI. @@ -284,17 +295,17 @@ namespace RTE { std::unique_ptr m_GUIControlManager; std::unique_ptr m_GUIScreen; std::unique_ptr m_GUIInput; - GUICollectionBox *m_GUITopLevelBox; - GUILabel *m_GUIInformationText; - GUIButton *m_GUIInformationToggleButton; - GUICollectionBox *m_GUIEquippedItemsBox; - GUIButton *m_GUISwapSetButton; - GUIButton *m_GUIEquippedItemButton; - GUIButton *m_GUIOffhandEquippedItemButton; - GUIButton *m_GUIReloadButton; - GUIButton *m_GUIDropButton; - GUICollectionBox *m_GUIInventoryItemsBox; - GUIScrollbar *m_GUIInventoryItemsScrollbar; + GUICollectionBox* m_GUITopLevelBox; + GUILabel* m_GUIInformationText; + GUIButton* m_GUIInformationToggleButton; + GUICollectionBox* m_GUIEquippedItemsBox; + GUIButton* m_GUISwapSetButton; + GUIButton* m_GUIEquippedItemButton; + GUIButton* m_GUIOffhandEquippedItemButton; + GUIButton* m_GUIReloadButton; + GUIButton* m_GUIDropButton; + GUICollectionBox* m_GUIInventoryItemsBox; + GUIScrollbar* m_GUIInventoryItemsScrollbar; #pragma region Create Breakdown /// @@ -347,19 +358,19 @@ namespace RTE { /// Handles hiding and showing the scrollbar, and calculating everything related to it in Full MenuMode. /// /// A pointer to the inventory this InventoryMenuGUI is displaying. - void UpdateFullModeScrollbar(const std::deque *inventory); + void UpdateFullModeScrollbar(const std::deque* inventory); /// /// Handles content and enabled status for inventory item buttons in Full MenuMode. Does not deal with button input. /// /// A pointer to the inventory this InventoryMenuGUI is displaying. - void UpdateFullModeInventoryItemButtons(const std::deque *inventory); + void UpdateFullModeInventoryItemButtons(const std::deque* inventory); /// /// Handles everything for displaying information text in Full MenuMode. /// /// A pointer to the inventory this InventoryMenuGUI is displaying. - void UpdateFullModeInformationText(const std::deque *inventory); + void UpdateFullModeInformationText(const std::deque* inventory); /// /// Handles updating icons and widths to support higlighting, for non-item buttons in Full MenuMode. @@ -399,25 +410,25 @@ namespace RTE { /// Breakdown of HandleNonMouseInput for handling pressing/holding up. /// /// The next button to highlight, based on input handling. - GUIButton * HandleNonMouseUpInput(); + GUIButton* HandleNonMouseUpInput(); /// /// Breakdown of HandleNonMouseInput for handling pressing/holding down. /// /// The next button to highlight, based on input handling. - GUIButton * HandleNonMouseDownInput(); + GUIButton* HandleNonMouseDownInput(); /// /// Breakdown of HandleNonMouseInput for handling pressing/holding left. /// /// The next button to highlight, based on input handling. - GUIButton * HandleNonMouseLeftInput(); + GUIButton* HandleNonMouseLeftInput(); /// /// Breakdown of HandleNonMouseInput for handling pressing/holding right. /// /// The next button to highlight, based on input handling. - GUIButton * HandleNonMouseRightInput(); + GUIButton* HandleNonMouseRightInput(); /// /// Handles item button press command events from the GUIControls of this InventoryMenuGUI by selecting/de-selecting the corresponding item. @@ -426,15 +437,15 @@ namespace RTE { /// A pointer to the MovableObject the GUIButton represents. /// The index of this button in the vector of equipped items if applicable. The default value of -1 means it's not an equipped item. /// Whether or not the button was held. - void HandleItemButtonPressOrHold(GUIButton *pressedButton, MovableObject *buttonObject, int buttonEquippedItemIndex = -1, bool buttonHeld = false); + void HandleItemButtonPressOrHold(GUIButton* pressedButton, MovableObject* buttonObject, int buttonEquippedItemIndex = -1, bool buttonHeld = false); #pragma endregion #pragma region GUI Button Actions - //TODO implement swap mode + // TODO implement swap mode /// /// Handles set swap button press command events from the GUIControls of this InventoryMenuGUI. /// - //void SwapEquippedItemSet() {} + // void SwapEquippedItemSet() {} /// /// Swaps the equipped item at the given equipped item index with one in the inventory Actor's inventory at the given inventory item index. @@ -454,7 +465,7 @@ namespace RTE { /// Drops the selected item, rotating its drop velocity in the direction of the passed in dropDirection Vector. /// /// A pointer to a Vector containing the direction the selected item should be dropped in. Nullptr means standard dropping will be used. - void DropSelectedItem(const Vector *dropDirection = nullptr); + void DropSelectedItem(const Vector* dropDirection = nullptr); #pragma endregion #pragma region Draw Breakdown @@ -463,27 +474,27 @@ namespace RTE { /// /// A pointer to a BITMAP to draw on. Generally a screen BITMAP. /// The position at which to draw the carousel. - void DrawCarouselMode(BITMAP *targetBitmap, const Vector &drawPos) const; + void DrawCarouselMode(BITMAP* targetBitmap, const Vector& drawPos) const; /// /// Draws the InventoryMenuGUI when it's in Full MenuMode. /// /// A pointer to a BITMAP to draw on. Generally a screen BITMAP. /// The position at which to draw the GUI. - void DrawFullMode(BITMAP *targetBitmap, const Vector &drawPos) const; + void DrawFullMode(BITMAP* targetBitmap, const Vector& drawPos) const; /// /// Draws the specified CarouselItemBox's background to the carousel background Bitmap. /// /// The CarouselItemBox to draw. - void DrawCarouselItemBoxBackground(const CarouselItemBox &itemBoxToDraw) const; + void DrawCarouselItemBoxBackground(const CarouselItemBox& itemBoxToDraw) const; /// /// Draws the specified CarouselItemBox's item(s) and mass text to the carousel Bitmap. /// /// The CarouselItemBox to draw. /// An AllegroBitmap of the bitmap the CarouselItemBox should draw its foreground to. Used for drawing mass strings, and predefined to avoid needless creation. - void DrawCarouselItemBoxForeground(const CarouselItemBox &itemBoxToDraw, AllegroBitmap *carouselAllegroBitmap) const; + void DrawCarouselItemBoxForeground(const CarouselItemBox& itemBoxToDraw, AllegroBitmap* carouselAllegroBitmap) const; #pragma endregion /// @@ -492,8 +503,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - InventoryMenuGUI(const InventoryMenuGUI &reference) = delete; - InventoryMenuGUI & operator=(const InventoryMenuGUI &rhs) = delete; + InventoryMenuGUI(const InventoryMenuGUI& reference) = delete; + InventoryMenuGUI& operator=(const InventoryMenuGUI& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Menus/LoadingScreen.cpp b/Source/Menus/LoadingScreen.cpp index 0e6fa6e22..06a6efe3f 100644 --- a/Source/Menus/LoadingScreen.cpp +++ b/Source/Menus/LoadingScreen.cpp @@ -14,7 +14,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LoadingScreen::Clear() { m_LoadingLogWriter = nullptr; @@ -24,9 +24,9 @@ namespace RTE { m_ProgressListboxPosY = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LoadingScreen::Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool progressReportDisabled) { + void LoadingScreen::Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool progressReportDisabled) { GUIControlManager loadingScreenManager; RTEAssert(loadingScreenManager.Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "LoadingScreenSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/LoadingScreenSkin.ini"); loadingScreenManager.Load("Base.rte/GUIs/LoadingGUI.ini"); @@ -59,14 +59,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LoadingScreen::CreateLoadingSplash(int xOffset) { if (m_LoadingSplashBitmap) { destroy_bitmap(m_LoadingSplashBitmap); m_LoadingSplashBitmap = nullptr; } - const BITMAP *backbuffer = g_FrameMan.GetBackBuffer32(); + const BITMAP* backbuffer = g_FrameMan.GetBackBuffer32(); m_LoadingSplashBitmap = create_bitmap_ex(FrameMan::c_BPP, backbuffer->w, backbuffer->h); clear_bitmap(m_LoadingSplashBitmap); @@ -79,14 +79,16 @@ namespace RTE { loadingSplash.Draw(m_LoadingSplashBitmap, loadingSplashTargetBox); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LoadingScreen::CreateProgressReportListbox(GUIControlManager *parentControlManager) { - dynamic_cast(parentControlManager->GetControl("root"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); - GUIListBox *listBox = dynamic_cast(parentControlManager->GetControl("ProgressBox")); + void LoadingScreen::CreateProgressReportListbox(GUIControlManager* parentControlManager) { + dynamic_cast(parentControlManager->GetControl("root"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + GUIListBox* listBox = dynamic_cast(parentControlManager->GetControl("ProgressBox")); // Make the box a bit bigger if there's room in higher, HD resolutions. - if (g_WindowMan.GetResX() >= c_DefaultResX) { listBox->Resize((g_WindowMan.GetResX() / 3) - 12, listBox->GetHeight()); } + if (g_WindowMan.GetResX() >= c_DefaultResX) { + listBox->Resize((g_WindowMan.GetResX() / 3) - 12, listBox->GetHeight()); + } listBox->SetPositionRel(g_WindowMan.GetResX() - listBox->GetWidth() - 12, (g_WindowMan.GetResY() / 2) - (listBox->GetHeight() / 2)); listBox->ClearList(); @@ -102,7 +104,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LoadingScreen::Destroy() { destroy_bitmap(m_LoadingSplashBitmap); @@ -112,15 +114,21 @@ namespace RTE { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LoadingScreen::LoadingSplashProgressReport(const std::string &reportString, bool newItem) { - if (System::IsLoggingToCLI()) { System::PrintLoadingToCLI(reportString, newItem); } + void LoadingScreen::LoadingSplashProgressReport(const std::string& reportString, bool newItem) { + if (System::IsLoggingToCLI()) { + System::PrintLoadingToCLI(reportString, newItem); + } if (newItem) { // Write out the last line to the log file before starting a new one and scroll the bitmap upwards. - if (g_LoadingScreen.m_LoadingLogWriter) { g_LoadingScreen.m_LoadingLogWriter->NewLineString(reportString, false); } - if (g_LoadingScreen.m_ProgressListboxBitmap) { blit(g_LoadingScreen.m_ProgressListboxBitmap, g_LoadingScreen.m_ProgressListboxBitmap, 2, 12, 2, 2, g_LoadingScreen.m_ProgressListboxBitmap->w - 3, g_LoadingScreen.m_ProgressListboxBitmap->h - 12); } + if (g_LoadingScreen.m_LoadingLogWriter) { + g_LoadingScreen.m_LoadingLogWriter->NewLineString(reportString, false); + } + if (g_LoadingScreen.m_ProgressListboxBitmap) { + blit(g_LoadingScreen.m_ProgressListboxBitmap, g_LoadingScreen.m_ProgressListboxBitmap, 2, 12, 2, 2, g_LoadingScreen.m_ProgressListboxBitmap->w - 3, g_LoadingScreen.m_ProgressListboxBitmap->h - 12); + } } if (g_LoadingScreen.m_ProgressListboxBitmap) { @@ -141,9 +149,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LoadingScreen::DrawLoadingSplash() { draw_sprite(g_FrameMan.GetBackBuffer32(), m_LoadingSplashBitmap, 0, 0); } -} +} // namespace RTE diff --git a/Source/Menus/LoadingScreen.h b/Source/Menus/LoadingScreen.h index 2486610f8..68d15faf4 100644 --- a/Source/Menus/LoadingScreen.h +++ b/Source/Menus/LoadingScreen.h @@ -18,7 +18,6 @@ namespace RTE { class LoadingScreen : public Singleton { public: - #pragma region Creation /// /// Constructor method used to instantiate a LoadingScreen object in system memory. @@ -31,7 +30,7 @@ namespace RTE { /// Pointer to a GUIScreen interface that will be used by this LoadingScreen's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this LoadingScreen's GUIControlManager. Ownership is NOT transferred! /// Whether the loading screen progress report is disabled meaning GUI elements and adjustments relevant to it can be skipped. - void Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool progressReportDisabled); + void Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool progressReportDisabled); /// /// Creates the loading splash screen and draws the composed frame to the LoadingSplashBitmap. @@ -44,7 +43,7 @@ namespace RTE { /// As it turned out, a massive amount of time is spent updating the GUI control and flipping the frame buffers. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this LoadingScreen. Ownership is NOT transferred! - void CreateProgressReportListbox(GUIControlManager *parentControlManager); + void CreateProgressReportListbox(GUIControlManager* parentControlManager); #pragma endregion #pragma region Destruction @@ -60,7 +59,7 @@ namespace RTE { /// /// The string to print in the report and log. /// Whether to start a new line in the log writer and to scroll the bitmap. - static void LoadingSplashProgressReport(const std::string &reportString, bool newItem = false); + static void LoadingSplashProgressReport(const std::string& reportString, bool newItem = false); /// /// Draws the loading splash to the screen. @@ -69,11 +68,10 @@ namespace RTE { #pragma endregion private: - std::unique_ptr m_LoadingLogWriter; //!< The Writer that generates the loading log. - BITMAP *m_LoadingSplashBitmap; //!< BITMAP that is used for drawing the splash screen. - BITMAP *m_ProgressListboxBitmap; //!< BITMAP that the progress report will be drawn into. + BITMAP* m_LoadingSplashBitmap; //!< BITMAP that is used for drawing the splash screen. + BITMAP* m_ProgressListboxBitmap; //!< BITMAP that the progress report will be drawn into. int m_ProgressListboxPosX; //!< Position of the progress report box on X axis. int m_ProgressListboxPosY; //!< Position of the progress report box on Y axis. @@ -83,8 +81,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - LoadingScreen(const LoadingScreen &reference) = delete; - LoadingScreen &operator=(const LoadingScreen &rhs) = delete; + LoadingScreen(const LoadingScreen& reference) = delete; + LoadingScreen& operator=(const LoadingScreen& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/MainMenuGUI.cpp b/Source/Menus/MainMenuGUI.cpp index 11c69ccbe..7582440fe 100644 --- a/Source/Menus/MainMenuGUI.cpp +++ b/Source/Menus/MainMenuGUI.cpp @@ -20,7 +20,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::Clear() { m_RootBoxMaxWidth = 0; @@ -54,9 +54,9 @@ namespace RTE { m_MainScreenPrevHoveredButtonIndex = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MainMenuGUI::Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput) { + void MainMenuGUI::Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput) { m_MainMenuScreenGUIControlManager = std::make_unique(); RTEAssert(m_MainMenuScreenGUIControlManager->Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "MainMenuScreenSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuScreenSkin.ini"); m_MainMenuScreenGUIControlManager->Load("Base.rte/GUIs/MainMenuGUI.ini"); @@ -67,10 +67,10 @@ namespace RTE { m_RootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); - GUICollectionBox *mainScreenRootBox = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("root")); + GUICollectionBox* mainScreenRootBox = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("root")); mainScreenRootBox->Resize(m_RootBoxMaxWidth, mainScreenRootBox->GetHeight()); - GUICollectionBox *subMenuScreenRootBox = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("root")); + GUICollectionBox* subMenuScreenRootBox = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("root")); subMenuScreenRootBox->Resize(m_RootBoxMaxWidth, g_WindowMan.GetResY()); m_MainMenuButtons[MenuButton::BackToMainButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonBackToMain")); @@ -90,22 +90,22 @@ namespace RTE { SetActiveMenuScreen(g_WindowMan.ResolutionChanged() ? MenuScreen::SettingsScreen : MenuScreen::MainScreen, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::CreateMainScreen() { - m_MainMenuScreens[MenuScreen::MainScreen] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("MainScreen")); + m_MainMenuScreens[MenuScreen::MainScreen] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("MainScreen")); m_MainMenuScreens[MenuScreen::MainScreen]->CenterInParent(true, false); - m_MainMenuButtons[MenuButton::MetaGameButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToMetaGame")); - m_MainMenuButtons[MenuButton::ScenarioButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToSkirmish")); - m_MainMenuButtons[MenuButton::MultiplayerButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToMultiplayer")); + m_MainMenuButtons[MenuButton::MetaGameButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToMetaGame")); + m_MainMenuButtons[MenuButton::ScenarioButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToSkirmish")); + m_MainMenuButtons[MenuButton::MultiplayerButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToMultiplayer")); m_MainMenuButtons[MenuButton::SaveOrLoadGameButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonSaveOrLoadGame")); - m_MainMenuButtons[MenuButton::SettingsButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToOptions")); - m_MainMenuButtons[MenuButton::ModManagerButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToModManager")); - m_MainMenuButtons[MenuButton::EditorsButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToEditor")); - m_MainMenuButtons[MenuButton::CreditsButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToCreds")); - m_MainMenuButtons[MenuButton::QuitButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonQuit")); - m_MainMenuButtons[MenuButton::ResumeButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonResume")); + m_MainMenuButtons[MenuButton::SettingsButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToOptions")); + m_MainMenuButtons[MenuButton::ModManagerButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToModManager")); + m_MainMenuButtons[MenuButton::EditorsButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToEditor")); + m_MainMenuButtons[MenuButton::CreditsButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonMainToCreds")); + m_MainMenuButtons[MenuButton::QuitButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonQuit")); + m_MainMenuButtons[MenuButton::ResumeButton] = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("ButtonResume")); for (int mainScreenButton = MenuButton::MetaGameButton; mainScreenButton <= MenuButton::ResumeButton; ++mainScreenButton) { m_MainMenuButtons.at(mainScreenButton)->CenterInParent(true, false); @@ -118,49 +118,49 @@ namespace RTE { m_MainMenuButtons.at(mainScreenButton)->SetText(m_MainScreenButtonUnhoveredText.at(mainScreenButton)); } - m_VersionLabel = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("VersionLabel")); + m_VersionLabel = dynamic_cast(m_MainMenuScreenGUIControlManager->GetControl("VersionLabel")); m_VersionLabel->SetText("Community Project\nv" + c_GameVersion.str()); m_VersionLabel->SetPositionAbs(10, g_WindowMan.GetResY() - m_VersionLabel->GetTextHeight() - 5); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::CreateMetaGameNoticeScreen() { - m_MainMenuScreens[MenuScreen::MetaGameNoticeScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("MetaScreen")); + m_MainMenuScreens[MenuScreen::MetaGameNoticeScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("MetaScreen")); m_MainMenuScreens[MenuScreen::MetaGameNoticeScreen]->CenterInParent(true, false); - m_MainMenuButtons[MenuButton::PlayTutorialButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonTutorial")); - m_MainMenuButtons[MenuButton::MetaGameContinueButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonContinue")); + m_MainMenuButtons[MenuButton::PlayTutorialButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonTutorial")); + m_MainMenuButtons[MenuButton::MetaGameContinueButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonContinue")); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::CreateEditorsScreen() { - m_MainMenuScreens[MenuScreen::EditorScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("EditorScreen")); + m_MainMenuScreens[MenuScreen::EditorScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("EditorScreen")); m_MainMenuScreens[MenuScreen::EditorScreen]->CenterInParent(true, false); - m_MainMenuButtons[MenuButton::SceneEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonSceneEditor")); - m_MainMenuButtons[MenuButton::AreaEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonAreaEditor")); - m_MainMenuButtons[MenuButton::AssemblyEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonAssemblyEditor")); - m_MainMenuButtons[MenuButton::GibEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonGibPlacement")); - m_MainMenuButtons[MenuButton::ActorEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonActorEditor")); + m_MainMenuButtons[MenuButton::SceneEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonSceneEditor")); + m_MainMenuButtons[MenuButton::AreaEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonAreaEditor")); + m_MainMenuButtons[MenuButton::AssemblyEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonAssemblyEditor")); + m_MainMenuButtons[MenuButton::GibEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonGibPlacement")); + m_MainMenuButtons[MenuButton::ActorEditorButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("ButtonActorEditor")); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::CreateCreditsScreen() { - m_MainMenuScreens[MenuScreen::CreditsScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("CreditsScreen")); + m_MainMenuScreens[MenuScreen::CreditsScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("CreditsScreen")); m_MainMenuScreens[MenuScreen::CreditsScreen]->Resize(m_MainMenuScreens[MenuScreen::CreditsScreen]->GetWidth(), g_WindowMan.GetResY()); m_MainMenuScreens[MenuScreen::CreditsScreen]->CenterInParent(true, false); - m_CreditsScrollPanel = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("CreditsPanel")); + m_CreditsScrollPanel = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("CreditsPanel")); m_CreditsScrollPanel->Resize(m_CreditsScrollPanel->GetWidth(), g_WindowMan.GetResY() - m_CreditsScrollPanel->GetYPos() - 50); - m_CreditsTextLabel = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("CreditsLabel")); + m_CreditsTextLabel = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("CreditsLabel")); // TODO: Get Unicode going! // Hack here to change the special characters over 128 in the ANSI ASCII table to match our font files - for (char &stringChar : s_CreditsText) { + for (char& stringChar: s_CreditsText) { if (stringChar == -60) { stringChar = static_cast(142); //'Ä' } else if (stringChar == -42) { @@ -173,26 +173,28 @@ namespace RTE { m_CreditsTextLabel->ResizeHeightToFit(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::CreateQuitScreen() { - m_MainMenuScreens[MenuScreen::QuitScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("QuitConfirmBox")); + m_MainMenuScreens[MenuScreen::QuitScreen] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("QuitConfirmBox")); m_MainMenuScreens[MenuScreen::QuitScreen]->CenterInParent(true, false); - m_MainMenuButtons[MenuButton::QuitConfirmButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("QuitConfirmButton")); - m_MainMenuButtons[MenuButton::QuitCancelButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("QuitCancelButton")); + m_MainMenuButtons[MenuButton::QuitConfirmButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("QuitConfirmButton")); + m_MainMenuButtons[MenuButton::QuitCancelButton] = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("QuitCancelButton")); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::HideAllScreens() { - for (GUICollectionBox *menuScreen : m_MainMenuScreens) { - if (menuScreen) { menuScreen->SetVisible(false); } + for (GUICollectionBox* menuScreen: m_MainMenuScreens) { + if (menuScreen) { + menuScreen->SetVisible(false); + } } m_MenuScreenChange = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::SetActiveMenuScreen(MenuScreen screenToShow, bool playButtonPressSound) { if (screenToShow != m_ActiveMenuScreen) { @@ -205,13 +207,13 @@ namespace RTE { m_SaveLoadMenu->Refresh(); } - if (playButtonPressSound) { - g_GUISound.ButtonPressSound()->Play(); + if (playButtonPressSound) { + g_GUISound.ButtonPressSound()->Play(); } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::ShowMainScreen() { m_VersionLabel->SetVisible(true); @@ -225,7 +227,7 @@ namespace RTE { m_MenuScreenChange = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::ShowMetaGameNoticeScreen() { m_MainMenuScreens[MenuScreen::MetaGameNoticeScreen]->SetVisible(true); @@ -234,14 +236,13 @@ namespace RTE { m_MainMenuButtons[MenuButton::BackToMainButton]->SetVisible(true); m_MainMenuButtons[MenuButton::BackToMainButton]->SetPositionAbs((m_RootBoxMaxWidth - m_MainMenuButtons[MenuButton::BackToMainButton]->GetWidth()) / 2, m_MainMenuButtons[MenuButton::MetaGameContinueButton]->GetYPos() + 25); - GUILabel *metaNoticeLabel = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("MetaLabel")); + GUILabel* metaNoticeLabel = dynamic_cast(m_SubMenuScreenGUIControlManager->GetControl("MetaLabel")); std::string metaNotice = { - "- A T T E N T I O N -\n\n" - "Please note that Conquest mode is very INCOMPLETE and flawed, and the Cortex Command Community Project team will be remaking it from the ground-up in future. " - "For now though, it's fully playable, and you can absolutely enjoy playing it with the A.I. and/or up to three friends. Alternatively, check out Void Wanderers on cccp.mod.io!\n\n" - "Also, if you have not yet played Cortex Command, we recommend you first try the tutorial:" - }; + "- A T T E N T I O N -\n\n" + "Please note that Conquest mode is very INCOMPLETE and flawed, and the Cortex Command Community Project team will be remaking it from the ground-up in future. " + "For now though, it's fully playable, and you can absolutely enjoy playing it with the A.I. and/or up to three friends. Alternatively, check out Void Wanderers on cccp.mod.io!\n\n" + "Also, if you have not yet played Cortex Command, we recommend you first try the tutorial:"}; metaNoticeLabel->SetText(metaNotice); metaNoticeLabel->SetVisible(true); @@ -251,7 +252,7 @@ namespace RTE { m_MenuScreenChange = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::ShowEditorsScreen() { m_MainMenuScreens[MenuScreen::EditorScreen]->SetVisible(true); @@ -263,7 +264,7 @@ namespace RTE { m_MenuScreenChange = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::ShowCreditsScreen() { m_MainMenuScreens[MenuScreen::CreditsScreen]->SetVisible(true); @@ -280,7 +281,7 @@ namespace RTE { m_MenuScreenChange = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::ShowQuitScreenOrQuit() { if (m_ActiveMenuScreen != MenuScreen::QuitScreen && g_ActivityMan.GetActivity() && (g_ActivityMan.GetActivity()->GetActivityState() == Activity::Running || g_ActivityMan.GetActivity()->GetActivityState() == Activity::Editing)) { @@ -292,7 +293,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::ShowAndBlinkResumeButton() { if (!m_MainMenuButtons[MenuButton::ResumeButton]->GetVisible()) { @@ -310,7 +311,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MainMenuGUI::RollCredits() { int scrollDuration = m_CreditsTextLabel->GetHeight() * 50; @@ -324,7 +325,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MainMenuGUI::MainMenuUpdateResult MainMenuGUI::Update() { m_UpdateResult = MainMenuUpdateResult::NoEvent; @@ -337,12 +338,16 @@ namespace RTE { switch (m_ActiveMenuScreen) { case MenuScreen::MainScreen: - if (m_MenuScreenChange) { ShowMainScreen(); } + if (m_MenuScreenChange) { + ShowMainScreen(); + } backToMainMenu = HandleInputEvents(); ShowAndBlinkResumeButton(); break; case MenuScreen::MetaGameNoticeScreen: - if (m_MenuScreenChange) { ShowMetaGameNoticeScreen(); } + if (m_MenuScreenChange) { + ShowMetaGameNoticeScreen(); + } backToMainMenu = HandleInputEvents(); break; case MenuScreen::SaveOrLoadGameScreen: @@ -356,11 +361,15 @@ namespace RTE { backToMainMenu = m_ModManagerMenu->HandleInputEvents(); break; case MenuScreen::EditorScreen: - if (m_MenuScreenChange) { ShowEditorsScreen(); } + if (m_MenuScreenChange) { + ShowEditorsScreen(); + } backToMainMenu = HandleInputEvents(); break; case MenuScreen::CreditsScreen: - if (m_MenuScreenChange) { ShowCreditsScreen(); } + if (m_MenuScreenChange) { + ShowCreditsScreen(); + } backToMainMenu = RollCredits() ? true : HandleInputEvents(); break; case MenuScreen::QuitScreen: @@ -372,17 +381,21 @@ namespace RTE { } HandleBackNavigation(backToMainMenu); - if (m_UpdateResult == MainMenuUpdateResult::ActivityStarted || m_UpdateResult == MainMenuUpdateResult::ActivityResumed) { m_MainMenuButtons[MenuButton::ResumeButton]->SetVisible(false); } + if (m_UpdateResult == MainMenuUpdateResult::ActivityStarted || m_UpdateResult == MainMenuUpdateResult::ActivityResumed) { + m_MainMenuButtons[MenuButton::ResumeButton]->SetVisible(false); + } return m_UpdateResult; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::HandleBackNavigation(bool backButtonPressed) { if ((!m_ActiveDialogBox || m_ActiveDialogBox == m_MainMenuScreens[MenuScreen::QuitScreen]) && (backButtonPressed || g_UInputMan.KeyPressed(SDLK_ESCAPE))) { if (m_ActiveMenuScreen != MenuScreen::MainScreen) { if (m_ActiveMenuScreen == MenuScreen::SettingsScreen || m_ActiveMenuScreen == MenuScreen::ModManagerScreen) { - if (m_ActiveMenuScreen == MenuScreen::SettingsScreen) { m_SettingsMenu->RefreshActiveSettingsMenuScreen(); } + if (m_ActiveMenuScreen == MenuScreen::SettingsScreen) { + m_SettingsMenu->RefreshActiveSettingsMenuScreen(); + } g_SettingsMan.UpdateSettingsFile(); } else if (m_ActiveMenuScreen == MenuScreen::CreditsScreen) { m_UpdateResult = MainMenuUpdateResult::BackToMainFromCredits; @@ -398,14 +411,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MainMenuGUI::HandleInputEvents() { if (m_ActiveMenuScreen == MenuScreen::MainScreen) { int mouseX = 0; int mouseY = 0; m_ActiveGUIControlManager->GetManager()->GetInputController()->GetMousePosition(&mouseX, &mouseY); - UpdateMainScreenHoveredButton(dynamic_cast(m_MainMenuScreenGUIControlManager->GetControlUnderPoint(mouseX, mouseY, m_MainMenuScreens[MenuScreen::MainScreen], 1))); + UpdateMainScreenHoveredButton(dynamic_cast(m_MainMenuScreenGUIControlManager->GetControlUnderPoint(mouseX, mouseY, m_MainMenuScreens[MenuScreen::MainScreen], 1))); } m_ActiveGUIControlManager->Update(); @@ -431,14 +444,16 @@ namespace RTE { default: break; } - } else if (guiEvent.GetType() == GUIEvent::Notification && (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl()))) { g_GUISound.SelectionChangeSound()->Play(); } + } else if (guiEvent.GetType() == GUIEvent::Notification && (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl()))) { + g_GUISound.SelectionChangeSound()->Play(); + } } return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MainMenuGUI::HandleMainScreenInputEvents(const GUIControl *guiEventControl) { + void MainMenuGUI::HandleMainScreenInputEvents(const GUIControl* guiEventControl) { if (guiEventControl == m_MainMenuButtons[MenuButton::MetaGameButton]) { if (!m_MetaGameNoticeShown) { SetActiveMenuScreen(MenuScreen::MetaGameNoticeScreen); @@ -471,9 +486,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MainMenuGUI::HandleMetaGameNoticeScreenInputEvents(const GUIControl *guiEventControl) { + void MainMenuGUI::HandleMetaGameNoticeScreenInputEvents(const GUIControl* guiEventControl) { if (guiEventControl == m_MainMenuButtons[MenuButton::PlayTutorialButton]) { m_UpdateResult = MainMenuUpdateResult::ActivityStarted; SetActiveMenuScreen(MenuScreen::MainScreen); @@ -483,9 +498,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MainMenuGUI::HandleEditorsScreenInputEvents(const GUIControl *guiEventControl) { + void MainMenuGUI::HandleEditorsScreenInputEvents(const GUIControl* guiEventControl) { std::string editorToStart; if (guiEventControl == m_MainMenuButtons[MenuButton::SceneEditorButton]) { editorToStart = "SceneEditor"; @@ -506,9 +521,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MainMenuGUI::HandleQuitScreenInputEvents(const GUIControl *guiEventControl) { + void MainMenuGUI::HandleQuitScreenInputEvents(const GUIControl* guiEventControl) { if (guiEventControl == m_MainMenuButtons[MenuButton::QuitConfirmButton]) { m_UpdateResult = MainMenuUpdateResult::Quit; g_GUISound.ButtonPressSound()->Play(); @@ -517,16 +532,20 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void MainMenuGUI::UpdateMainScreenHoveredButton(const GUIButton *hoveredButton) { + void MainMenuGUI::UpdateMainScreenHoveredButton(const GUIButton* hoveredButton) { int hoveredButtonIndex = -1; if (hoveredButton) { hoveredButtonIndex = std::distance(m_MainMenuButtons.begin(), std::find(m_MainMenuButtons.begin(), m_MainMenuButtons.end(), hoveredButton)); - if (hoveredButton != m_MainScreenHoveredButton) { m_MainMenuButtons.at(hoveredButtonIndex)->SetText(m_MainScreenButtonHoveredText.at(hoveredButtonIndex)); } + if (hoveredButton != m_MainScreenHoveredButton) { + m_MainMenuButtons.at(hoveredButtonIndex)->SetText(m_MainScreenButtonHoveredText.at(hoveredButtonIndex)); + } m_MainScreenHoveredButton = m_MainMenuButtons.at(hoveredButtonIndex); } - if (!hoveredButton || hoveredButtonIndex != m_MainScreenPrevHoveredButtonIndex) { m_MainMenuButtons.at(m_MainScreenPrevHoveredButtonIndex)->SetText(m_MainScreenButtonUnhoveredText.at(m_MainScreenPrevHoveredButtonIndex)); } + if (!hoveredButton || hoveredButtonIndex != m_MainScreenPrevHoveredButtonIndex) { + m_MainMenuButtons.at(m_MainScreenPrevHoveredButtonIndex)->SetText(m_MainScreenButtonUnhoveredText.at(m_MainScreenPrevHoveredButtonIndex)); + } if (hoveredButtonIndex >= 0) { m_MainScreenPrevHoveredButtonIndex = hoveredButtonIndex; @@ -535,7 +554,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MainMenuGUI::Draw() { // Early return to avoid single frame flicker when title screen goes into transition from the meta notice screen to meta config screen. @@ -564,4 +583,4 @@ namespace RTE { } m_ActiveGUIControlManager->DrawMouse(); } -} +} // namespace RTE diff --git a/Source/Menus/MainMenuGUI.h b/Source/Menus/MainMenuGUI.h index 18e036321..43583e215 100644 --- a/Source/Menus/MainMenuGUI.h +++ b/Source/Menus/MainMenuGUI.h @@ -23,7 +23,6 @@ namespace RTE { class MainMenuGUI { public: - /// /// Enumeration for the results of the MainMenuGUI input and event update. /// @@ -44,14 +43,17 @@ namespace RTE { /// /// Pointer to a GUIScreen interface that will be used by this MainMenuGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this MainMenuGUI's GUIControlManager. Ownership is NOT transferred! - MainMenuGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput) { Clear(); Create(guiScreen, guiInput); } + MainMenuGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput) { + Clear(); + Create(guiScreen, guiInput); + } /// /// Makes the MainMenuGUI object ready for use. /// /// Pointer to a GUIScreen interface that will be used by this MainMenuGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this MainMenuGUI's GUIControlManager. Ownership is NOT transferred! - void Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput); + void Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput); #pragma endregion #pragma region Concrete Methods @@ -68,7 +70,6 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for the different sub-menu screens of the main menu. /// @@ -115,8 +116,8 @@ namespace RTE { std::unique_ptr m_MainMenuScreenGUIControlManager; //!< The GUIControlManager which owns all the GUIControls of the MainMenuGUI main screen. Alternative to changing skins at runtime which is expensive, since the main screen now has a unique skin. std::unique_ptr m_SubMenuScreenGUIControlManager; //!< The GUIControlManager which owns all the GUIControls of the MainMenuGUI sub-menus. - GUIControlManager *m_ActiveGUIControlManager; //!< The GUIControlManager that is currently being updated and drawn to the screen. - GUICollectionBox *m_ActiveDialogBox; // The currently active GUICollectionBox in any of the main or sub-menu screens that acts as a dialog box and requires drawing an overlay. + GUIControlManager* m_ActiveGUIControlManager; //!< The GUIControlManager that is currently being updated and drawn to the screen. + GUICollectionBox* m_ActiveDialogBox; // The currently active GUICollectionBox in any of the main or sub-menu screens that acts as a dialog box and requires drawing an overlay. MenuScreen m_ActiveMenuScreen; //!< The currently active menu screen that is being updated and drawn to the screen. See MenuScreen enumeration. MainMenuUpdateResult m_UpdateResult; //!< The result of the MainMenuGUI update. See MainMenuUpdateResult enumeration. @@ -134,17 +135,17 @@ namespace RTE { // Right now the way this works is the font graphic has different character visuals for uppercase and lowercase and the visual change happens by applying the appropriate case string when hovering/unhovering. std::array m_MainScreenButtonHoveredText; //!< Array containing uppercase strings of the main screen buttons text that are used to display the larger font when a button is hovered over. std::array m_MainScreenButtonUnhoveredText; //!< Array containing lowercase strings of the main menu screen buttons text that are used to display the smaller font when a button is not hovered over. - GUIButton *m_MainScreenHoveredButton; //!< The currently hovered main screen button. + GUIButton* m_MainScreenHoveredButton; //!< The currently hovered main screen button. int m_MainScreenPrevHoveredButtonIndex; //!< The index of the previously hovered main screen button in the main menu button array. /// /// GUI elements that compose the main menu screen. /// - GUILabel *m_VersionLabel; - GUILabel *m_CreditsTextLabel; - GUICollectionBox *m_CreditsScrollPanel; - std::array m_MainMenuScreens; - std::array m_MainMenuButtons; + GUILabel* m_VersionLabel; + GUILabel* m_CreditsTextLabel; + GUICollectionBox* m_CreditsScrollPanel; + std::array m_MainMenuScreens; + std::array m_MainMenuButtons; #pragma region Create Breakdown /// @@ -240,31 +241,31 @@ namespace RTE { /// Handles the player interaction with the main screen GUI elements. /// /// Pointer to the GUI element that the player interacted with. - void HandleMainScreenInputEvents(const GUIControl *guiEventControl); + void HandleMainScreenInputEvents(const GUIControl* guiEventControl); /// /// Handles the player interaction with the MetaGame notice screen GUI elements. /// /// Pointer to the GUI element that the player interacted with. - void HandleMetaGameNoticeScreenInputEvents(const GUIControl *guiEventControl); + void HandleMetaGameNoticeScreenInputEvents(const GUIControl* guiEventControl); /// /// Handles the player interaction with the editor selection screen GUI elements. /// /// Pointer to the GUI element that the player interacted with. - void HandleEditorsScreenInputEvents(const GUIControl *guiEventControl); + void HandleEditorsScreenInputEvents(const GUIControl* guiEventControl); /// /// Handles the player interaction with the quit screen GUI elements. /// /// Pointer to the GUI element that the player interacted with. - void HandleQuitScreenInputEvents(const GUIControl *guiEventControl); + void HandleQuitScreenInputEvents(const GUIControl* guiEventControl); /// /// Updates the currently hovered main screen button text to give the hovered visual and updates the previously hovered button to remove the hovered visual. /// /// Pointer to the currently hovered main screen button, if any. Acquired by GUIControlManager::GetControlUnderPoint. - void UpdateMainScreenHoveredButton(const GUIButton *hoveredButton); + void UpdateMainScreenHoveredButton(const GUIButton* hoveredButton); #pragma endregion /// @@ -273,8 +274,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - MainMenuGUI(const MainMenuGUI &reference) = delete; - MainMenuGUI & operator=(const MainMenuGUI &rhs) = delete; + MainMenuGUI(const MainMenuGUI& reference) = delete; + MainMenuGUI& operator=(const MainMenuGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/MetagameGUI.cpp b/Source/Menus/MetagameGUI.cpp index 8074c06f0..a62c667d2 100644 --- a/Source/Menus/MetagameGUI.cpp +++ b/Source/Menus/MetagameGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -61,92 +60,77 @@ using namespace RTE; #define STARTGOLDMIN 2000 #define STARTGOLDMAX 8000 #define BRAINPOOLMAX 20 -#define BRAINGOLDVALUE 4000//1250 +#define BRAINGOLDVALUE 4000 // 1250 #define BATTLEPAD 10 #define BRAINOVERLAP 2 - const std::string MetagameGUI::c_ClassName = "MetagameGUI"; - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws a neat animation over a site to show it changing team ownership. -void MetagameGUI::SiteTarget::Draw(BITMAP *drawBitmap) const -{ - if (!drawBitmap) - return; - - // Draw the appropriate growing geometric figure around the location, growing - if (m_Style == SiteTarget::CROSSHAIRSSHRINK) - { - float radius = LERP(0.0, 1.0, 200, 10, m_AnimProgress); - float lineLen = LERP(0.0, 1.0, 60, 10, m_AnimProgress); - float rotation = 0;//LERP(0.0, 1.0, -c_EighthPI, 0.0, m_AnimProgress); - Vector inner; - Vector outer; - - // Draw all the crosshair lines, being rotated - for (int i = 0; i < 4; ++i) - { - inner.SetXY(radius, 0); - outer.SetXY(radius + lineLen, 0); - inner.RadRotate(rotation + (c_HalfPI * i)); - outer.RadRotate(rotation + (c_HalfPI * i)); - DrawGlowLine(drawBitmap, m_CenterPos + inner, m_CenterPos + outer, m_Color); - } - } - else if (m_Style == SiteTarget::CROSSHAIRSGROW) - { - float radius = LERP(0.0, 1.0, 10, 200, m_AnimProgress); - float lineLen = LERP(0.0, 1.0, 10, 60, m_AnimProgress); - float rotation = 0;//LERP(0.0, 1.0, -c_EighthPI, 0.0, m_AnimProgress); - Vector inner; - Vector outer; - - // Draw all the crosshair lines, being rotated - for (int i = 0; i < 4; ++i) - { - inner.SetXY(radius, 0); - outer.SetXY(radius + lineLen, 0); - inner.RadRotate(rotation + (c_HalfPI * i)); - outer.RadRotate(rotation + (c_HalfPI * i)); - DrawGlowLine(drawBitmap, m_CenterPos + inner, m_CenterPos + outer, m_Color); - } - } - else if (m_Style == SiteTarget::CIRCLESHRINK) - { - float radius = LERP(0.0, 1.0, 24, 6, m_AnimProgress); - int blendAmount = LERP(0.0, 1.0, 0, 255, m_AnimProgress);// + 15 * NormalRand(); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - circle(drawBitmap, m_CenterPos.m_X, m_CenterPos.m_Y, radius, m_Color); - } - else if (m_Style == SiteTarget::CIRCLEGROW) - { - float radius = LERP(0.0, 1.0, 6, 24, m_AnimProgress); - int blendAmount = LERP(0.0, 1.0, 255, 0, m_AnimProgress);// + 15 * NormalRand(); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - circle(drawBitmap, m_CenterPos.m_X, m_CenterPos.m_Y, radius, m_Color); - } - else if (m_Style == SiteTarget::SQUARESHRINK) - { - float radius = LERP(0.0, 1.0, 24, 6, m_AnimProgress); - int blendAmount = LERP(0.0, 1.0, 0, 255, m_AnimProgress);// + 15 * NormalRand(); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - rect(drawBitmap, m_CenterPos.m_X - radius, m_CenterPos.m_Y - radius, m_CenterPos.m_X + radius, m_CenterPos.m_Y + radius, m_Color); - } - // Default - else// if (m_Style == SiteTarget::SQUAREGROW) - { - float radius = LERP(0.0, 1.0, 6, 24, m_AnimProgress); - int blendAmount = LERP(0.0, 1.0, 255, 0, m_AnimProgress);// + 15 * NormalRand(); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - rect(drawBitmap, m_CenterPos.m_X - radius, m_CenterPos.m_Y - radius, m_CenterPos.m_X + radius, m_CenterPos.m_Y + radius, m_Color); - } -} +void MetagameGUI::SiteTarget::Draw(BITMAP* drawBitmap) const { + if (!drawBitmap) + return; + // Draw the appropriate growing geometric figure around the location, growing + if (m_Style == SiteTarget::CROSSHAIRSSHRINK) { + float radius = LERP(0.0, 1.0, 200, 10, m_AnimProgress); + float lineLen = LERP(0.0, 1.0, 60, 10, m_AnimProgress); + float rotation = 0; // LERP(0.0, 1.0, -c_EighthPI, 0.0, m_AnimProgress); + Vector inner; + Vector outer; + + // Draw all the crosshair lines, being rotated + for (int i = 0; i < 4; ++i) { + inner.SetXY(radius, 0); + outer.SetXY(radius + lineLen, 0); + inner.RadRotate(rotation + (c_HalfPI * i)); + outer.RadRotate(rotation + (c_HalfPI * i)); + DrawGlowLine(drawBitmap, m_CenterPos + inner, m_CenterPos + outer, m_Color); + } + } else if (m_Style == SiteTarget::CROSSHAIRSGROW) { + float radius = LERP(0.0, 1.0, 10, 200, m_AnimProgress); + float lineLen = LERP(0.0, 1.0, 10, 60, m_AnimProgress); + float rotation = 0; // LERP(0.0, 1.0, -c_EighthPI, 0.0, m_AnimProgress); + Vector inner; + Vector outer; + + // Draw all the crosshair lines, being rotated + for (int i = 0; i < 4; ++i) { + inner.SetXY(radius, 0); + outer.SetXY(radius + lineLen, 0); + inner.RadRotate(rotation + (c_HalfPI * i)); + outer.RadRotate(rotation + (c_HalfPI * i)); + DrawGlowLine(drawBitmap, m_CenterPos + inner, m_CenterPos + outer, m_Color); + } + } else if (m_Style == SiteTarget::CIRCLESHRINK) { + float radius = LERP(0.0, 1.0, 24, 6, m_AnimProgress); + int blendAmount = LERP(0.0, 1.0, 0, 255, m_AnimProgress); // + 15 * NormalRand(); + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + circle(drawBitmap, m_CenterPos.m_X, m_CenterPos.m_Y, radius, m_Color); + } else if (m_Style == SiteTarget::CIRCLEGROW) { + float radius = LERP(0.0, 1.0, 6, 24, m_AnimProgress); + int blendAmount = LERP(0.0, 1.0, 255, 0, m_AnimProgress); // + 15 * NormalRand(); + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + circle(drawBitmap, m_CenterPos.m_X, m_CenterPos.m_Y, radius, m_Color); + } else if (m_Style == SiteTarget::SQUARESHRINK) { + float radius = LERP(0.0, 1.0, 24, 6, m_AnimProgress); + int blendAmount = LERP(0.0, 1.0, 0, 255, m_AnimProgress); // + 15 * NormalRand(); + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + rect(drawBitmap, m_CenterPos.m_X - radius, m_CenterPos.m_Y - radius, m_CenterPos.m_X + radius, m_CenterPos.m_Y + radius, m_Color); + } + // Default + else // if (m_Style == SiteTarget::SQUAREGROW) + { + float radius = LERP(0.0, 1.0, 6, 24, m_AnimProgress); + int blendAmount = LERP(0.0, 1.0, 255, 0, m_AnimProgress); // + 15 * NormalRand(); + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + rect(drawBitmap, m_CenterPos.m_X - radius, m_CenterPos.m_Y - radius, m_CenterPos.m_X + radius, m_CenterPos.m_Y + radius, m_Color); + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: Clear @@ -154,182 +138,178 @@ void MetagameGUI::SiteTarget::Draw(BITMAP *drawBitmap) const // Description: Clears all the member variables of this MetagameGUI, effectively // resetting the members of this abstraction level only. -void MetagameGUI::Clear() -{ +void MetagameGUI::Clear() { m_RootBoxMaxWidth = 0; - m_pController = 0; - m_pGUIScreen = 0; - m_pGUIInput = 0; - m_pGUIController = 0; - m_MenuEnabled = ENABLED; - m_MenuScreen = NEWDIALOG; - m_ScreenChange = true; - m_SceneFocus = 0; - m_FocusChange = 0; - m_MenuSpeed = 0.3; - m_BlinkTimer.Reset(); - m_BlinkMode = NOBLINK; - - m_pBannerRedTop = 0; - m_pBannerRedBottom = 0; - m_pBannerYellowTop = 0; - m_pBannerYellowBottom = 0; - - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - m_AnimTimer3.Reset(); - - m_AnimMode = 0; - m_AnimModeChange = false; - m_AnimModeDuration = 2000; - m_AnimMetaPlayer = Players::NoPlayer; - m_AnimDefenseTeam = Activity::NoTeam; - m_AnimActivityChange = false; - Scene *m_pAnimScene = 0; - m_AnimRatio = 0; - m_AnimProgress = 0; - m_AnimTotalFunds = 0; - m_AnimFundsMax = 0; - m_AnimFundsMin = 0; - m_AnimBuildCount = 0; - m_AnimIncomeLine = 0; - m_AnimIncomeLineChange = false; - m_AnimActionLine = 0; - m_AnimActionLineChange = false; - m_AnimSegment = 0; - m_AnimCountStart = 0; - m_AnimCountCurrent = 0; - m_AnimCountEnd = 0; - m_LineConnected = false; - - m_IncomeSiteLines.clear(); - m_ActivePlayerIncomeLines = -1; - m_ActionMeterDrawOverride = false; - m_NewSiteIndicators.clear(); - m_SiteSwitchIndicators.clear(); - - m_PlanetCenter.Reset(); - m_PlanetRadius = 240.0f; - - m_pGameMessageLabel = 0; - - m_pToolTipBox = 0; - m_pToolTipText = 0; - m_ToolTipTimer.Reset(); - m_pHoveredControl = 0; - - for (int iscreen = 0; iscreen < SCREENCOUNT; ++iscreen) - m_apScreenBox[iscreen] = 0; - for (int button = 0; button < METABUTTONCOUNT; ++button) - m_apMetaButton[button] = 0; - - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - m_apPlayerBox[metaPlayer] = 0; - m_apPlayerTeamBox[metaPlayer] = 0; - m_apPlayerTeamActionBox[metaPlayer] = 0; - m_apPlayerBarLabel[metaPlayer] = 0; - m_apPlayerBrainTravelLabel[metaPlayer] = 0; - m_aBattleFunds[metaPlayer] = 0; - m_aBattleAttacker[metaPlayer] = false; - m_aAnimDestroyed[metaPlayer] = false; - m_aBrainIconPos[metaPlayer].Reset(); - m_aQuadTakenBy[metaPlayer] = Players::NoPlayer; - m_apBrainPoolLabel[metaPlayer] = 0; - m_apFundsChangeLabel[metaPlayer] = 0; - m_apBrainChangeLabel[metaPlayer] = 0; - m_apFundsChangeTimer[metaPlayer].Reset(); - m_apBrainsChangeTimer[metaPlayer].Reset(); - - m_apPlayerControlButton[metaPlayer] = 0; - m_apPlayerTeamSelect[metaPlayer] = 0; - m_apPlayerTechSelect[metaPlayer] = 0; - m_apPlayerHandicap[metaPlayer] = 0; - m_apPlayerNameBox[metaPlayer] = 0; + m_pController = 0; + m_pGUIScreen = 0; + m_pGUIInput = 0; + m_pGUIController = 0; + m_MenuEnabled = ENABLED; + m_MenuScreen = NEWDIALOG; + m_ScreenChange = true; + m_SceneFocus = 0; + m_FocusChange = 0; + m_MenuSpeed = 0.3; + m_BlinkTimer.Reset(); + m_BlinkMode = NOBLINK; + + m_pBannerRedTop = 0; + m_pBannerRedBottom = 0; + m_pBannerYellowTop = 0; + m_pBannerYellowBottom = 0; + + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + m_AnimTimer3.Reset(); + + m_AnimMode = 0; + m_AnimModeChange = false; + m_AnimModeDuration = 2000; + m_AnimMetaPlayer = Players::NoPlayer; + m_AnimDefenseTeam = Activity::NoTeam; + m_AnimActivityChange = false; + Scene* m_pAnimScene = 0; + m_AnimRatio = 0; + m_AnimProgress = 0; + m_AnimTotalFunds = 0; + m_AnimFundsMax = 0; + m_AnimFundsMin = 0; + m_AnimBuildCount = 0; + m_AnimIncomeLine = 0; + m_AnimIncomeLineChange = false; + m_AnimActionLine = 0; + m_AnimActionLineChange = false; + m_AnimSegment = 0; + m_AnimCountStart = 0; + m_AnimCountCurrent = 0; + m_AnimCountEnd = 0; + m_LineConnected = false; + + m_IncomeSiteLines.clear(); + m_ActivePlayerIncomeLines = -1; + m_ActionMeterDrawOverride = false; + m_NewSiteIndicators.clear(); + m_SiteSwitchIndicators.clear(); + + m_PlanetCenter.Reset(); + m_PlanetRadius = 240.0f; + + m_pGameMessageLabel = 0; + + m_pToolTipBox = 0; + m_pToolTipText = 0; + m_ToolTipTimer.Reset(); + m_pHoveredControl = 0; + + for (int iscreen = 0; iscreen < SCREENCOUNT; ++iscreen) + m_apScreenBox[iscreen] = 0; + for (int button = 0; button < METABUTTONCOUNT; ++button) + m_apMetaButton[button] = 0; + + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + m_apPlayerBox[metaPlayer] = 0; + m_apPlayerTeamBox[metaPlayer] = 0; + m_apPlayerTeamActionBox[metaPlayer] = 0; + m_apPlayerBarLabel[metaPlayer] = 0; + m_apPlayerBrainTravelLabel[metaPlayer] = 0; + m_aBattleFunds[metaPlayer] = 0; + m_aBattleAttacker[metaPlayer] = false; + m_aAnimDestroyed[metaPlayer] = false; + m_aBrainIconPos[metaPlayer].Reset(); + m_aQuadTakenBy[metaPlayer] = Players::NoPlayer; + m_apBrainPoolLabel[metaPlayer] = 0; + m_apFundsChangeLabel[metaPlayer] = 0; + m_apBrainChangeLabel[metaPlayer] = 0; + m_apFundsChangeTimer[metaPlayer].Reset(); + m_apBrainsChangeTimer[metaPlayer].Reset(); + + m_apPlayerControlButton[metaPlayer] = 0; + m_apPlayerTeamSelect[metaPlayer] = 0; + m_apPlayerTechSelect[metaPlayer] = 0; + m_apPlayerHandicap[metaPlayer] = 0; + m_apPlayerNameBox[metaPlayer] = 0; m_apPlayerAISkillSlider[metaPlayer] = 0; m_apPlayerAISkillLabel[metaPlayer] = 0; - m_aStationIncomeLineIndices[metaPlayer] = -1; - m_aBrainSaleIncomeLineIndices[metaPlayer] = -1; - m_ActionSiteLines[metaPlayer].clear(); - } - - m_PrevMousePos.Reset(); - - m_pConfirmationBox = 0; - m_pConfirmationLabel = 0; - m_pConfirmationButton = 0; - - m_pPhaseBox = 0; - m_pPhaseLabel = 0; - m_PreTurn = false; - m_BattleToResume = false; - m_PostBattleReview = false; - m_BattleCausedOwnershipChange = false; - m_PreBattleTeamOwnership = Activity::NoTeam; - - m_pScenePlanetLabel = 0; - m_pSceneInfoPopup = 0; - m_pSceneCloseButton = 0; - m_pSceneNameLabel = 0; - m_pSceneOwnerTeam = 0; - m_pSceneResidentsLabel = 0; - m_pSceneInfoLabel = 0; - m_pSceneBudgetLabel = 0; - m_pSceneBudgetSlider = 0; - m_pSceneBudgetBar = 0; - m_pAutoDesignCheckbox = 0; - m_pScanInfoLabel = 0; - - m_pDraggedBox = 0; - m_EngageDrag = false; - m_pHoveredScene = 0; - m_pSelectedScene = 0; - m_pPlayingScene = 0; - - m_pSizeLabel = 0; - m_pSizeSlider = 0; - m_pDifficultyLabel = 0; - m_pDifficultySlider = 0; - m_pGoldLabel = 0; - m_pGoldSlider = 0; - m_pLengthLabel = 0; - m_pLengthSlider = 0; - m_pErrorLabel = 0; - - m_NewSaveBox = 0; - m_pSavesToOverwriteCombo = 0; - m_pSavesToLoadCombo = 0; - m_pSaveInfoLabel = 0; - m_pLoadInfoLabel = 0; - m_pSelectedGameToLoad = 0; - - m_ContinuePhase = false; - m_ActivityRestarted = false; - m_ActivityResumed = false; - m_StartFunds = 1600; - m_CPUPlayer = -1; - m_StartDifficulty = Activity::MediumDifficulty; - m_BackToMain = false; - m_Quit = false; + m_aStationIncomeLineIndices[metaPlayer] = -1; + m_aBrainSaleIncomeLineIndices[metaPlayer] = -1; + m_ActionSiteLines[metaPlayer].clear(); + } + + m_PrevMousePos.Reset(); + + m_pConfirmationBox = 0; + m_pConfirmationLabel = 0; + m_pConfirmationButton = 0; + + m_pPhaseBox = 0; + m_pPhaseLabel = 0; + m_PreTurn = false; + m_BattleToResume = false; + m_PostBattleReview = false; + m_BattleCausedOwnershipChange = false; + m_PreBattleTeamOwnership = Activity::NoTeam; + + m_pScenePlanetLabel = 0; + m_pSceneInfoPopup = 0; + m_pSceneCloseButton = 0; + m_pSceneNameLabel = 0; + m_pSceneOwnerTeam = 0; + m_pSceneResidentsLabel = 0; + m_pSceneInfoLabel = 0; + m_pSceneBudgetLabel = 0; + m_pSceneBudgetSlider = 0; + m_pSceneBudgetBar = 0; + m_pAutoDesignCheckbox = 0; + m_pScanInfoLabel = 0; + + m_pDraggedBox = 0; + m_EngageDrag = false; + m_pHoveredScene = 0; + m_pSelectedScene = 0; + m_pPlayingScene = 0; + + m_pSizeLabel = 0; + m_pSizeSlider = 0; + m_pDifficultyLabel = 0; + m_pDifficultySlider = 0; + m_pGoldLabel = 0; + m_pGoldSlider = 0; + m_pLengthLabel = 0; + m_pLengthSlider = 0; + m_pErrorLabel = 0; + + m_NewSaveBox = 0; + m_pSavesToOverwriteCombo = 0; + m_pSavesToLoadCombo = 0; + m_pSaveInfoLabel = 0; + m_pLoadInfoLabel = 0; + m_pSelectedGameToLoad = 0; + + m_ContinuePhase = false; + m_ActivityRestarted = false; + m_ActivityResumed = false; + m_StartFunds = 1600; + m_CPUPlayer = -1; + m_StartDifficulty = Activity::MediumDifficulty; + m_BackToMain = false; + m_Quit = false; m_StationPosOnOrbit.Reset(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetToStartNewGame ////////////////////////////////////////////////////////////////////////////////////////// // Description: Resets internal state of GUI to show 'Start new campaign' screen // Arguments: None. // Return value: None. -void MetagameGUI::SetToStartNewGame() -{ +void MetagameGUI::SetToStartNewGame() { g_MetaMan.SetSuspend(true); HideAllScreens(); UpdatePlayerSetup(); - //UpdatePlayerBars(); + // UpdatePlayerBars(); SwitchToScreen(MetagameGUI::NEWDIALOG); } @@ -338,278 +318,271 @@ void MetagameGUI::SetToStartNewGame() ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the MetagameGUI object ready for use. -int MetagameGUI::Create() -{ - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - m_ActionSiteLines[metaPlayer].clear(); - // The relevant onces will be enabled again in update - m_apPlayerBox[metaPlayer]->SetVisible(false); - // Clear out the team flag Icons; they will be re-set on next update - m_apPlayerTeamBox[metaPlayer]->SetDrawImage(0); - m_apPlayerTeamActionBox[metaPlayer]->SetDrawImage(0); - m_apBrainPoolLabel[metaPlayer]->SetVisible(false); - } - - return 0; -} +int MetagameGUI::Create() { + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + m_ActionSiteLines[metaPlayer].clear(); + // The relevant onces will be enabled again in update + m_apPlayerBox[metaPlayer]->SetVisible(false); + // Clear out the team flag Icons; they will be re-set on next update + m_apPlayerTeamBox[metaPlayer]->SetDrawImage(0); + m_apPlayerTeamActionBox[metaPlayer]->SetDrawImage(0); + m_apBrainPoolLabel[metaPlayer]->SetVisible(false); + } + return 0; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the MetagameGUI object ready for use. -int MetagameGUI::Create(Controller *pController) -{ - RTEAssert(pController, "No controller sent to MetagameGUI on creation!"); - m_pController = pController; +int MetagameGUI::Create(Controller* pController) { + RTEAssert(pController, "No controller sent to MetagameGUI on creation!"); + m_pController = pController; - char str[256]; + char str[256]; - if (!m_pGUIScreen) - m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer32()); - if (!m_pGUIInput) - m_pGUIInput = new GUIInputWrapper(-1, true); - if (!m_pGUIController) - m_pGUIController = new GUIControlManager(); + if (!m_pGUIScreen) + m_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer32()); + if (!m_pGUIInput) + m_pGUIInput = new GUIInputWrapper(-1, true); + if (!m_pGUIController) + m_pGUIController = new GUIControlManager(); if (!m_pGUIController->Create(m_pGUIScreen, m_pGUIInput, "Base.rte/GUIs/Skins/Menus", "MainMenuSubMenuSkin.ini")) { RTEAbort("Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuSubMenuSkin.ini"); } - m_pGUIController->Load("Base.rte/GUIs/MetagameGUI.ini"); + m_pGUIController->Load("Base.rte/GUIs/MetagameGUI.ini"); m_RootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); - // Make sure we have convenient points to the containing GUI colleciton boxes that we will manipulate the positions of - GUICollectionBox *pRootBox = m_apScreenBox[ROOTBOX] = dynamic_cast(m_pGUIController->GetControl("root")); - // Make the root box fill the screen -// pRootBox->SetPositionAbs((g_WindowMan.GetResX() - pRootBox->GetWidth()) / 2, 0);// (g_WindowMan.GetResY() - pRootBox->GetHeight()) / 2); - pRootBox->SetDrawBackground(false); - pRootBox->Resize(m_RootBoxMaxWidth, g_WindowMan.GetResY()); - - m_pBannerRedTop = new GUIBanner(); - m_pBannerRedBottom = new GUIBanner(); - m_pBannerYellowTop = new GUIBanner(); - m_pBannerYellowBottom = new GUIBanner(); - m_pBannerRedTop->Create("Base.rte/GUIs/Fonts/BannerFontRedReg.png", "Base.rte/GUIs/Fonts/BannerFontRedBlur.png", 32); - m_pBannerRedBottom->Create("Base.rte/GUIs/Fonts/BannerFontRedReg.png", "Base.rte/GUIs/Fonts/BannerFontRedBlur.png", 32); - m_pBannerYellowTop->Create("Base.rte/GUIs/Fonts/BannerFontYellowReg.png", "Base.rte/GUIs/Fonts/BannerFontYellowBlur.png", 32); - m_pBannerYellowBottom->Create("Base.rte/GUIs/Fonts/BannerFontYellowReg.png", "Base.rte/GUIs/Fonts/BannerFontYellowBlur.png", 32); - - // General game message label - m_pGameMessageLabel = dynamic_cast(m_pGUIController->GetControl("GameMessageLabel")); - m_pGameMessageLabel->CenterInParent(true, false); - m_pGameMessageLabel->SetPositionAbs(m_pGameMessageLabel->GetXPos(), 0); - m_pGameMessageLabel->SetVisible(false); - - // ToolTip box - m_pToolTipBox = dynamic_cast(m_pGUIController->GetControl("ToolTipBox")); - m_pToolTipText = dynamic_cast(m_pGUIController->GetControl("ToolTipLabel")); - m_pToolTipBox->SetDrawType(GUICollectionBox::Panel); - m_pToolTipBox->SetDrawBackground(true); - // Never enable the popup, because it steals focus and cuases other windows to think teh cursor left them - m_pToolTipBox->SetEnabled(false); - m_pToolTipBox->SetVisible(false); - // Set the font - m_pToolTipText->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); - - // Make sure we have convenient points to the containing GUI colleciton boxes that we will manipulate the positions of - m_apScreenBox[NEWDIALOG] = dynamic_cast(m_pGUIController->GetControl("NewGameDialog")); - m_apScreenBox[LOADDIALOG] = dynamic_cast(m_pGUIController->GetControl("LoadDialog")); - m_apScreenBox[SAVEDIALOG] = dynamic_cast(m_pGUIController->GetControl("SaveDialog")); - m_apScreenBox[MENUDIALOG] = dynamic_cast(m_pGUIController->GetControl("GameMenu")); - m_apScreenBox[STATSDIALOG] = dynamic_cast(m_pGUIController->GetControl("GameStatsBox")); - m_apScreenBox[SCENEINFOBOX] = dynamic_cast(m_pGUIController->GetControl("SceneInfoBox")); - - // Center most of the main boxes in the root box - m_apScreenBox[NEWDIALOG]->CenterInParent(true, true); - m_apScreenBox[LOADDIALOG]->CenterInParent(true, true); - m_apScreenBox[SAVEDIALOG]->CenterInParent(true, true); - m_apScreenBox[MENUDIALOG]->CenterInParent(true, true); - m_apScreenBox[STATSDIALOG]->CenterInParent(true, true); - - // Buttons which will be altered - m_apMetaButton[CONFIRM] = dynamic_cast(m_pGUIController->GetControl("ConfirmButton")); - m_apMetaButton[P1CONTROL] = dynamic_cast(m_pGUIController->GetControl("P1ControlButton")); - m_apMetaButton[P2CONTROL] = dynamic_cast(m_pGUIController->GetControl("P2ControlButton")); - m_apMetaButton[P3CONTROL] = dynamic_cast(m_pGUIController->GetControl("P3ControlButton")); - m_apMetaButton[P4CONTROL] = dynamic_cast(m_pGUIController->GetControl("P4ControlButton")); - m_apMetaButton[STARTNEW] = dynamic_cast(m_pGUIController->GetControl("StartButton")); - m_apMetaButton[LOADNOW] = dynamic_cast(m_pGUIController->GetControl("LoadButton")); - m_apMetaButton[SAVENOW] = dynamic_cast(m_pGUIController->GetControl("SaveButton")); - m_apMetaButton[CONTINUE] = dynamic_cast(m_pGUIController->GetControl("ContinueButton")); - m_apMetaButton[SCENEACTION] = dynamic_cast(m_pGUIController->GetControl("SceneActionButton")); - m_apMetaButton[DESIGNBASE] = dynamic_cast(m_pGUIController->GetControl("DesignBaseButton")); - m_apMetaButton[SCANNOW] = dynamic_cast(m_pGUIController->GetControl("ScanNowButton")); - m_apMetaButton[SCANLATER] = dynamic_cast(m_pGUIController->GetControl("ScanLaterButton")); - - // Confirmation box - m_pConfirmationBox = dynamic_cast(m_pGUIController->GetControl("ConfirmDialog")); - m_pConfirmationLabel = dynamic_cast(m_pGUIController->GetControl("ConfirmLabel")); - m_pConfirmationButton = dynamic_cast(m_pGUIController->GetControl("ConfirmButton")); - m_pConfirmationBox->CenterInParent(true, true); - m_pConfirmationBox->SetVisible(false); - - // Floating player bars - m_apPlayerBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1Bar")); - m_apPlayerBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2Bar")); - m_apPlayerBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3Bar")); - m_apPlayerBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4Bar")); - m_apPlayerTeamBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1Team")); - m_apPlayerTeamBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2Team")); - m_apPlayerTeamBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3Team")); - m_apPlayerTeamBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4Team")); - m_apPlayerBarLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1FundsLabel")); - m_apPlayerBarLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2FundsLabel")); - m_apPlayerBarLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3FundsLabel")); - m_apPlayerBarLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4FundsLabel")); - m_apBrainPoolLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1BrainLabel")); - m_apBrainPoolLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2BrainLabel")); - m_apBrainPoolLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3BrainLabel")); - m_apBrainPoolLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4BrainLabel")); - m_apFundsChangeLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1FundsChangeLabel")); - m_apFundsChangeLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2FundsChangeLabel")); - m_apFundsChangeLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3FundsChangeLabel")); - m_apFundsChangeLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4FundsChangeLabel")); - m_apBrainChangeLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1BrainChangeLabel")); - m_apBrainChangeLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2BrainChangeLabel")); - m_apBrainChangeLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3BrainChangeLabel")); - m_apBrainChangeLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4BrainChangeLabel")); - - // Battle site display - m_apPlayerTeamActionBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1TeamAction")); - m_apPlayerTeamActionBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2TeamAction")); - m_apPlayerTeamActionBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3TeamAction")); - m_apPlayerTeamActionBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4TeamAction")); - m_apPlayerBrainTravelLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1BrainTravelLabel")); - m_apPlayerBrainTravelLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2BrainTravelLabel")); - m_apPlayerBrainTravelLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3BrainTravelLabel")); - m_apPlayerBrainTravelLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4BrainTravelLabel")); - - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - m_apBrainPoolLabel[metaPlayer]->SetVisible(false); - m_apBrainPoolLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - // Tuck these away so they don't interfere with dragging etc - m_apFundsChangeLabel[metaPlayer]->SetVisible(false); - m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - m_apBrainChangeLabel[metaPlayer]->SetVisible(false); - m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - - // Hide the battle display initially - m_apPlayerTeamActionBox[metaPlayer]->SetVisible(false); - m_apPlayerTeamActionBox[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - m_apPlayerBrainTravelLabel[metaPlayer]->SetVisible(false); - m_apPlayerBrainTravelLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - } - - // Phase info box - m_pPhaseBox = dynamic_cast(m_pGUIController->GetControl("PhaseBox")); - m_pPhaseLabel = dynamic_cast(m_pGUIController->GetControl("PhaseLabel")); - // Just get the menu button temporarily so we can set the custom menu icon - if (GUIButton *pMenuButton = dynamic_cast(m_pGUIController->GetControl("OpenMenuButton"))) - { - std::snprintf(str, sizeof(str), "%c", -22); - pMenuButton->SetText(std::string(str)); - } - - // Planet mouseover scene label - m_pScenePlanetLabel = dynamic_cast(m_pGUIController->GetControl("ScenePlanetLabel")); - m_pScenePlanetLabel->SetVisible(false); - - // Scene Info Box - m_pSceneInfoPopup = dynamic_cast(m_pGUIController->GetControl("SceneInfoBox")); - m_pSceneCloseButton = dynamic_cast(m_pGUIController->GetControl("SceneCloseButton")); - m_pSceneNameLabel = dynamic_cast(m_pGUIController->GetControl("SceneNameLabel")); - m_pSceneOwnerTeam = dynamic_cast(m_pGUIController->GetControl("SceneOwnerTeam")); - m_pSceneResidentsLabel = dynamic_cast(m_pGUIController->GetControl("SceneResidentsLabel")); - m_pSceneInfoLabel = dynamic_cast(m_pGUIController->GetControl("SceneInfoLabel")); - m_pSceneInfoLabel->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); - m_pSceneInfoPopup->SetVisible(false); - m_pSceneBudgetLabel = dynamic_cast(m_pGUIController->GetControl("SceneBudgetLabel")); - m_pSceneBudgetSlider = dynamic_cast(m_pGUIController->GetControl("SceneBudgetSlider")); - m_pSceneBudgetBar = dynamic_cast(m_pGUIController->GetControl("SceneBudgetBar")); - m_pSceneBudgetBar->SetDrawColor(makecol(55, 5, 10)); - m_pAutoDesignCheckbox = dynamic_cast(m_pGUIController->GetControl("AutoDesignCheckbox")); - m_pScanInfoLabel = dynamic_cast(m_pGUIController->GetControl("ScanInfoLabel")); - - // Set initial focus, category list, and label settings - m_ScreenChange = true; - m_FocusChange = 1; -// CategoryChange(); - - // New Game Dialog - m_pSizeLabel = dynamic_cast(m_pGUIController->GetControl("SizeLabel")); - m_pSizeSlider = dynamic_cast(m_pGUIController->GetControl("SizeSlider")); - m_pDifficultyLabel = dynamic_cast(m_pGUIController->GetControl("DifficultyLabel")); - m_pDifficultySlider = dynamic_cast(m_pGUIController->GetControl("DifficultySlider")); - m_pGoldLabel = dynamic_cast(m_pGUIController->GetControl("GoldLabel")); - m_pGoldSlider = dynamic_cast(m_pGUIController->GetControl("GoldSlider")); - m_pLengthLabel = dynamic_cast(m_pGUIController->GetControl("LengthLabel")); - m_pLengthSlider = dynamic_cast(m_pGUIController->GetControl("LengthSlider")); - m_pErrorLabel = dynamic_cast(m_pGUIController->GetControl("StartErrorLabel")); - m_apPlayerControlButton[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1ControlButton")); - m_apPlayerControlButton[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2ControlButton")); - m_apPlayerControlButton[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3ControlButton")); - m_apPlayerControlButton[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4ControlButton")); - m_apPlayerTeamSelect[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1TeamCombo")); - m_apPlayerTeamSelect[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2TeamCombo")); - m_apPlayerTeamSelect[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3TeamCombo")); - m_apPlayerTeamSelect[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4TeamCombo")); - m_apPlayerTechSelect[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1TechCombo")); - m_apPlayerTechSelect[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2TechCombo")); - m_apPlayerTechSelect[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3TechCombo")); - m_apPlayerTechSelect[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4TechCombo")); - m_apPlayerHandicap[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1HCCombo")); - m_apPlayerHandicap[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2HCCombo")); - m_apPlayerHandicap[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3HCCombo")); - m_apPlayerHandicap[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4HCCombo")); - m_apPlayerNameBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1NameText")); - m_apPlayerNameBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2NameText")); - m_apPlayerNameBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3NameText")); - m_apPlayerNameBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4NameText")); - m_apPlayerAISkillSlider[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1AISkillSlider")); - m_apPlayerAISkillSlider[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2AISkillSlider")); - m_apPlayerAISkillSlider[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3AISkillSlider")); - m_apPlayerAISkillSlider[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4AISkillSlider")); - m_apPlayerAISkillLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1AISkillLabel")); - m_apPlayerAISkillLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2AISkillLabel")); - m_apPlayerAISkillLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3AISkillLabel")); - m_apPlayerAISkillLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4AISkillLabel")); + // Make sure we have convenient points to the containing GUI colleciton boxes that we will manipulate the positions of + GUICollectionBox* pRootBox = m_apScreenBox[ROOTBOX] = dynamic_cast(m_pGUIController->GetControl("root")); + // Make the root box fill the screen + // pRootBox->SetPositionAbs((g_WindowMan.GetResX() - pRootBox->GetWidth()) / 2, 0);// (g_WindowMan.GetResY() - pRootBox->GetHeight()) / 2); + pRootBox->SetDrawBackground(false); + pRootBox->Resize(m_RootBoxMaxWidth, g_WindowMan.GetResY()); + + m_pBannerRedTop = new GUIBanner(); + m_pBannerRedBottom = new GUIBanner(); + m_pBannerYellowTop = new GUIBanner(); + m_pBannerYellowBottom = new GUIBanner(); + m_pBannerRedTop->Create("Base.rte/GUIs/Fonts/BannerFontRedReg.png", "Base.rte/GUIs/Fonts/BannerFontRedBlur.png", 32); + m_pBannerRedBottom->Create("Base.rte/GUIs/Fonts/BannerFontRedReg.png", "Base.rte/GUIs/Fonts/BannerFontRedBlur.png", 32); + m_pBannerYellowTop->Create("Base.rte/GUIs/Fonts/BannerFontYellowReg.png", "Base.rte/GUIs/Fonts/BannerFontYellowBlur.png", 32); + m_pBannerYellowBottom->Create("Base.rte/GUIs/Fonts/BannerFontYellowReg.png", "Base.rte/GUIs/Fonts/BannerFontYellowBlur.png", 32); + + // General game message label + m_pGameMessageLabel = dynamic_cast(m_pGUIController->GetControl("GameMessageLabel")); + m_pGameMessageLabel->CenterInParent(true, false); + m_pGameMessageLabel->SetPositionAbs(m_pGameMessageLabel->GetXPos(), 0); + m_pGameMessageLabel->SetVisible(false); + + // ToolTip box + m_pToolTipBox = dynamic_cast(m_pGUIController->GetControl("ToolTipBox")); + m_pToolTipText = dynamic_cast(m_pGUIController->GetControl("ToolTipLabel")); + m_pToolTipBox->SetDrawType(GUICollectionBox::Panel); + m_pToolTipBox->SetDrawBackground(true); + // Never enable the popup, because it steals focus and cuases other windows to think teh cursor left them + m_pToolTipBox->SetEnabled(false); + m_pToolTipBox->SetVisible(false); + // Set the font + m_pToolTipText->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); + + // Make sure we have convenient points to the containing GUI colleciton boxes that we will manipulate the positions of + m_apScreenBox[NEWDIALOG] = dynamic_cast(m_pGUIController->GetControl("NewGameDialog")); + m_apScreenBox[LOADDIALOG] = dynamic_cast(m_pGUIController->GetControl("LoadDialog")); + m_apScreenBox[SAVEDIALOG] = dynamic_cast(m_pGUIController->GetControl("SaveDialog")); + m_apScreenBox[MENUDIALOG] = dynamic_cast(m_pGUIController->GetControl("GameMenu")); + m_apScreenBox[STATSDIALOG] = dynamic_cast(m_pGUIController->GetControl("GameStatsBox")); + m_apScreenBox[SCENEINFOBOX] = dynamic_cast(m_pGUIController->GetControl("SceneInfoBox")); + + // Center most of the main boxes in the root box + m_apScreenBox[NEWDIALOG]->CenterInParent(true, true); + m_apScreenBox[LOADDIALOG]->CenterInParent(true, true); + m_apScreenBox[SAVEDIALOG]->CenterInParent(true, true); + m_apScreenBox[MENUDIALOG]->CenterInParent(true, true); + m_apScreenBox[STATSDIALOG]->CenterInParent(true, true); + + // Buttons which will be altered + m_apMetaButton[CONFIRM] = dynamic_cast(m_pGUIController->GetControl("ConfirmButton")); + m_apMetaButton[P1CONTROL] = dynamic_cast(m_pGUIController->GetControl("P1ControlButton")); + m_apMetaButton[P2CONTROL] = dynamic_cast(m_pGUIController->GetControl("P2ControlButton")); + m_apMetaButton[P3CONTROL] = dynamic_cast(m_pGUIController->GetControl("P3ControlButton")); + m_apMetaButton[P4CONTROL] = dynamic_cast(m_pGUIController->GetControl("P4ControlButton")); + m_apMetaButton[STARTNEW] = dynamic_cast(m_pGUIController->GetControl("StartButton")); + m_apMetaButton[LOADNOW] = dynamic_cast(m_pGUIController->GetControl("LoadButton")); + m_apMetaButton[SAVENOW] = dynamic_cast(m_pGUIController->GetControl("SaveButton")); + m_apMetaButton[CONTINUE] = dynamic_cast(m_pGUIController->GetControl("ContinueButton")); + m_apMetaButton[SCENEACTION] = dynamic_cast(m_pGUIController->GetControl("SceneActionButton")); + m_apMetaButton[DESIGNBASE] = dynamic_cast(m_pGUIController->GetControl("DesignBaseButton")); + m_apMetaButton[SCANNOW] = dynamic_cast(m_pGUIController->GetControl("ScanNowButton")); + m_apMetaButton[SCANLATER] = dynamic_cast(m_pGUIController->GetControl("ScanLaterButton")); + + // Confirmation box + m_pConfirmationBox = dynamic_cast(m_pGUIController->GetControl("ConfirmDialog")); + m_pConfirmationLabel = dynamic_cast(m_pGUIController->GetControl("ConfirmLabel")); + m_pConfirmationButton = dynamic_cast(m_pGUIController->GetControl("ConfirmButton")); + m_pConfirmationBox->CenterInParent(true, true); + m_pConfirmationBox->SetVisible(false); + + // Floating player bars + m_apPlayerBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1Bar")); + m_apPlayerBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2Bar")); + m_apPlayerBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3Bar")); + m_apPlayerBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4Bar")); + m_apPlayerTeamBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1Team")); + m_apPlayerTeamBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2Team")); + m_apPlayerTeamBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3Team")); + m_apPlayerTeamBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4Team")); + m_apPlayerBarLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1FundsLabel")); + m_apPlayerBarLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2FundsLabel")); + m_apPlayerBarLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3FundsLabel")); + m_apPlayerBarLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4FundsLabel")); + m_apBrainPoolLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1BrainLabel")); + m_apBrainPoolLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2BrainLabel")); + m_apBrainPoolLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3BrainLabel")); + m_apBrainPoolLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4BrainLabel")); + m_apFundsChangeLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1FundsChangeLabel")); + m_apFundsChangeLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2FundsChangeLabel")); + m_apFundsChangeLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3FundsChangeLabel")); + m_apFundsChangeLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4FundsChangeLabel")); + m_apBrainChangeLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1BrainChangeLabel")); + m_apBrainChangeLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2BrainChangeLabel")); + m_apBrainChangeLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3BrainChangeLabel")); + m_apBrainChangeLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4BrainChangeLabel")); + + // Battle site display + m_apPlayerTeamActionBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1TeamAction")); + m_apPlayerTeamActionBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2TeamAction")); + m_apPlayerTeamActionBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3TeamAction")); + m_apPlayerTeamActionBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4TeamAction")); + m_apPlayerBrainTravelLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1BrainTravelLabel")); + m_apPlayerBrainTravelLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2BrainTravelLabel")); + m_apPlayerBrainTravelLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3BrainTravelLabel")); + m_apPlayerBrainTravelLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4BrainTravelLabel")); + + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + m_apBrainPoolLabel[metaPlayer]->SetVisible(false); + m_apBrainPoolLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + // Tuck these away so they don't interfere with dragging etc + m_apFundsChangeLabel[metaPlayer]->SetVisible(false); + m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + m_apBrainChangeLabel[metaPlayer]->SetVisible(false); + m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + + // Hide the battle display initially + m_apPlayerTeamActionBox[metaPlayer]->SetVisible(false); + m_apPlayerTeamActionBox[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + m_apPlayerBrainTravelLabel[metaPlayer]->SetVisible(false); + m_apPlayerBrainTravelLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + } + + // Phase info box + m_pPhaseBox = dynamic_cast(m_pGUIController->GetControl("PhaseBox")); + m_pPhaseLabel = dynamic_cast(m_pGUIController->GetControl("PhaseLabel")); + // Just get the menu button temporarily so we can set the custom menu icon + if (GUIButton* pMenuButton = dynamic_cast(m_pGUIController->GetControl("OpenMenuButton"))) { + std::snprintf(str, sizeof(str), "%c", -22); + pMenuButton->SetText(std::string(str)); + } + + // Planet mouseover scene label + m_pScenePlanetLabel = dynamic_cast(m_pGUIController->GetControl("ScenePlanetLabel")); + m_pScenePlanetLabel->SetVisible(false); + + // Scene Info Box + m_pSceneInfoPopup = dynamic_cast(m_pGUIController->GetControl("SceneInfoBox")); + m_pSceneCloseButton = dynamic_cast(m_pGUIController->GetControl("SceneCloseButton")); + m_pSceneNameLabel = dynamic_cast(m_pGUIController->GetControl("SceneNameLabel")); + m_pSceneOwnerTeam = dynamic_cast(m_pGUIController->GetControl("SceneOwnerTeam")); + m_pSceneResidentsLabel = dynamic_cast(m_pGUIController->GetControl("SceneResidentsLabel")); + m_pSceneInfoLabel = dynamic_cast(m_pGUIController->GetControl("SceneInfoLabel")); + m_pSceneInfoLabel->SetFont(m_pGUIController->GetSkin()->GetFont("FontSmall.png")); + m_pSceneInfoPopup->SetVisible(false); + m_pSceneBudgetLabel = dynamic_cast(m_pGUIController->GetControl("SceneBudgetLabel")); + m_pSceneBudgetSlider = dynamic_cast(m_pGUIController->GetControl("SceneBudgetSlider")); + m_pSceneBudgetBar = dynamic_cast(m_pGUIController->GetControl("SceneBudgetBar")); + m_pSceneBudgetBar->SetDrawColor(makecol(55, 5, 10)); + m_pAutoDesignCheckbox = dynamic_cast(m_pGUIController->GetControl("AutoDesignCheckbox")); + m_pScanInfoLabel = dynamic_cast(m_pGUIController->GetControl("ScanInfoLabel")); + + // Set initial focus, category list, and label settings + m_ScreenChange = true; + m_FocusChange = 1; + // CategoryChange(); + + // New Game Dialog + m_pSizeLabel = dynamic_cast(m_pGUIController->GetControl("SizeLabel")); + m_pSizeSlider = dynamic_cast(m_pGUIController->GetControl("SizeSlider")); + m_pDifficultyLabel = dynamic_cast(m_pGUIController->GetControl("DifficultyLabel")); + m_pDifficultySlider = dynamic_cast(m_pGUIController->GetControl("DifficultySlider")); + m_pGoldLabel = dynamic_cast(m_pGUIController->GetControl("GoldLabel")); + m_pGoldSlider = dynamic_cast(m_pGUIController->GetControl("GoldSlider")); + m_pLengthLabel = dynamic_cast(m_pGUIController->GetControl("LengthLabel")); + m_pLengthSlider = dynamic_cast(m_pGUIController->GetControl("LengthSlider")); + m_pErrorLabel = dynamic_cast(m_pGUIController->GetControl("StartErrorLabel")); + m_apPlayerControlButton[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1ControlButton")); + m_apPlayerControlButton[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2ControlButton")); + m_apPlayerControlButton[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3ControlButton")); + m_apPlayerControlButton[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4ControlButton")); + m_apPlayerTeamSelect[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1TeamCombo")); + m_apPlayerTeamSelect[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2TeamCombo")); + m_apPlayerTeamSelect[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3TeamCombo")); + m_apPlayerTeamSelect[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4TeamCombo")); + m_apPlayerTechSelect[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1TechCombo")); + m_apPlayerTechSelect[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2TechCombo")); + m_apPlayerTechSelect[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3TechCombo")); + m_apPlayerTechSelect[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4TechCombo")); + m_apPlayerHandicap[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1HCCombo")); + m_apPlayerHandicap[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2HCCombo")); + m_apPlayerHandicap[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3HCCombo")); + m_apPlayerHandicap[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4HCCombo")); + m_apPlayerNameBox[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1NameText")); + m_apPlayerNameBox[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2NameText")); + m_apPlayerNameBox[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3NameText")); + m_apPlayerNameBox[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4NameText")); + m_apPlayerAISkillSlider[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1AISkillSlider")); + m_apPlayerAISkillSlider[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2AISkillSlider")); + m_apPlayerAISkillSlider[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3AISkillSlider")); + m_apPlayerAISkillSlider[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4AISkillSlider")); + m_apPlayerAISkillLabel[Players::PlayerOne] = dynamic_cast(m_pGUIController->GetControl("P1AISkillLabel")); + m_apPlayerAISkillLabel[Players::PlayerTwo] = dynamic_cast(m_pGUIController->GetControl("P2AISkillLabel")); + m_apPlayerAISkillLabel[Players::PlayerThree] = dynamic_cast(m_pGUIController->GetControl("P3AISkillLabel")); + m_apPlayerAISkillLabel[Players::PlayerFour] = dynamic_cast(m_pGUIController->GetControl("P4AISkillLabel")); m_apPlayerControlButton[Players::PlayerOne]->SetText("Human"); -// m_apPlayerControlButton[Players::PlayerTwo]->SetText("Human"); - m_apPlayerControlButton[Players::PlayerTwo]->SetText("A.I."); - m_apPlayerNameBox[Players::PlayerOne]->SetText("Player 1"); - m_apPlayerNameBox[Players::PlayerTwo]->SetText("Player 2"); - m_apPlayerNameBox[Players::PlayerThree]->SetText("Player 3"); - m_apPlayerNameBox[Players::PlayerFour]->SetText("Player 4"); - - // Add the handicap options to the dropdowns - // Prepare the brain icon - std::snprintf(str, sizeof(str), "%c", -48); - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +5", "", 0, 0, -1); - m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +3", "", 0, 0, -1); - m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +1", "", 0, 0, -1); - m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +-", "", 0, 0, -1); - m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " -1", "", 0, 0, -1); - m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " -3", "", 0, 0, -1); - m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " -5", "", 0, 0, -1); - - // Preselect the 0 handicap - m_apPlayerHandicap[metaPlayer]->SetSelectedIndex(3); - // Make the lists be scrolled to the top when they are initially dropped -// m_apPlayerHandicap[metaPlayer]->GetListPanel()->ScrollToTop(); - } - - // Save and Load Dialogs - m_NewSaveBox = dynamic_cast(m_pGUIController->GetControl("NewSaveText")); - m_pSavesToOverwriteCombo = dynamic_cast(m_pGUIController->GetControl("OverwriteList")); - m_pSavesToLoadCombo = dynamic_cast(m_pGUIController->GetControl("LoadList")); - m_pSaveInfoLabel = dynamic_cast(m_pGUIController->GetControl("SavedGameStats")); - m_pLoadInfoLabel = dynamic_cast(m_pGUIController->GetControl("LoadStats")); + // m_apPlayerControlButton[Players::PlayerTwo]->SetText("Human"); + m_apPlayerControlButton[Players::PlayerTwo]->SetText("A.I."); + m_apPlayerNameBox[Players::PlayerOne]->SetText("Player 1"); + m_apPlayerNameBox[Players::PlayerTwo]->SetText("Player 2"); + m_apPlayerNameBox[Players::PlayerThree]->SetText("Player 3"); + m_apPlayerNameBox[Players::PlayerFour]->SetText("Player 4"); + + // Add the handicap options to the dropdowns + // Prepare the brain icon + std::snprintf(str, sizeof(str), "%c", -48); + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +5", "", 0, 0, -1); + m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +3", "", 0, 0, -1); + m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +1", "", 0, 0, -1); + m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " +-", "", 0, 0, -1); + m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " -1", "", 0, 0, -1); + m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " -3", "", 0, 0, -1); + m_apPlayerHandicap[metaPlayer]->GetListPanel()->AddItem(std::string(str) + " -5", "", 0, 0, -1); + + // Preselect the 0 handicap + m_apPlayerHandicap[metaPlayer]->SetSelectedIndex(3); + // Make the lists be scrolled to the top when they are initially dropped + // m_apPlayerHandicap[metaPlayer]->GetListPanel()->ScrollToTop(); + } + + // Save and Load Dialogs + m_NewSaveBox = dynamic_cast(m_pGUIController->GetControl("NewSaveText")); + m_pSavesToOverwriteCombo = dynamic_cast(m_pGUIController->GetControl("OverwriteList")); + m_pSavesToLoadCombo = dynamic_cast(m_pGUIController->GetControl("LoadList")); + m_pSaveInfoLabel = dynamic_cast(m_pGUIController->GetControl("SavedGameStats")); + m_pLoadInfoLabel = dynamic_cast(m_pGUIController->GetControl("LoadStats")); for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { m_apPlayerTeamSelect[player]->ClearList(); @@ -620,14 +593,14 @@ int MetagameGUI::Create(Controller *pController) m_apPlayerTeamSelect[player]->SetDropDownStyle(GUIComboBox::DropDownList); } - // Special height for the last one so it doesn't fly out of the dialog box - m_apPlayerTeamSelect[Players::PlayerFour]->SetDropHeight(40); - m_apPlayerTechSelect[Players::PlayerFour]->SetDropHeight(40); - m_apPlayerHandicap[Players::PlayerFour]->SetDropHeight(40); + // Special height for the last one so it doesn't fly out of the dialog box + m_apPlayerTeamSelect[Players::PlayerFour]->SetDropHeight(40); + m_apPlayerTechSelect[Players::PlayerFour]->SetDropHeight(40); + m_apPlayerHandicap[Players::PlayerFour]->SetDropHeight(40); - // Put the new game dialog in order - UpdatePlayerSetup(); - UpdateGameSizeLabels(); + // Put the new game dialog in order + UpdatePlayerSetup(); + UpdateGameSizeLabels(); UpdateAISkillSliders(Players::PlayerOne); UpdateAISkillSliders(Players::PlayerTwo); @@ -636,21 +609,19 @@ int MetagameGUI::Create(Controller *pController) MoveLocationsIntoTheScreen(); - // Hide all screens, the appropriate screen will reappear on next update - HideAllScreens(); - return 0; + // Hide all screens, the appropriate screen will reappear on next update + HideAllScreens(); + return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: MoveLocationsIntoTheScreen ////////////////////////////////////////////////////////////////////////////////////////// // Description: Moves any locations closer to the center of the planet if they were left out -void MetagameGUI::MoveLocationsIntoTheScreen() -{ - //Clear offsets - for (std::vector::iterator pItr = g_MetaMan.m_Scenes.begin(); pItr != g_MetaMan.m_Scenes.end(); ++pItr) - (*pItr)->SetLocationOffset(Vector(0,0)); +void MetagameGUI::MoveLocationsIntoTheScreen() { + // Clear offsets + for (std::vector::iterator pItr = g_MetaMan.m_Scenes.begin(); pItr != g_MetaMan.m_Scenes.end(); ++pItr) + (*pItr)->SetLocationOffset(Vector(0, 0)); // We need to calculate planet center manually because m_PlanetCenter reflects coords of moving planet // which is outside the screen when this is called first time @@ -659,14 +630,12 @@ void MetagameGUI::MoveLocationsIntoTheScreen() if (!m_PlanetCenter.IsZero()) planetCenter = m_PlanetCenter; - //Move out-of-screen scenes closer to the middle of the planet if we have planet info - for (std::vector::iterator pItr = g_MetaMan.m_Scenes.begin(); pItr != g_MetaMan.m_Scenes.end(); ++pItr) - { + // Move out-of-screen scenes closer to the middle of the planet if we have planet info + for (std::vector::iterator pItr = g_MetaMan.m_Scenes.begin(); pItr != g_MetaMan.m_Scenes.end(); ++pItr) { float y = planetCenter.GetY() + (*pItr)->GetLocation().GetY(); // Do not touch scenes outside the planet, they might be hidden intentionally - if (abs((*pItr)->GetLocation().GetY()) < m_PlanetRadius + 100 && abs((*pItr)->GetLocation().GetX()) < m_PlanetRadius + 100) - { + if (abs((*pItr)->GetLocation().GetY()) < m_PlanetRadius + 100 && abs((*pItr)->GetLocation().GetX()) < m_PlanetRadius + 100) { if (y < 10) (*pItr)->SetLocationOffset(Vector(0, -y + 14)); @@ -676,24 +645,19 @@ void MetagameGUI::MoveLocationsIntoTheScreen() } // Add offsets to reveal overlapping scenes if any - for (std::vector::iterator pItr = g_MetaMan.m_Scenes.begin(); pItr != g_MetaMan.m_Scenes.end(); ++pItr) - { + for (std::vector::iterator pItr = g_MetaMan.m_Scenes.begin(); pItr != g_MetaMan.m_Scenes.end(); ++pItr) { bool isOverlapped = false; - do - { + do { isOverlapped = false; // Find overlapping scene dot - for (std::vector::iterator pItr2 = g_MetaMan.m_Scenes.begin(); pItr2 != g_MetaMan.m_Scenes.end(); ++pItr2) - { - if ((*pItr) != (*pItr2)) - { + for (std::vector::iterator pItr2 = g_MetaMan.m_Scenes.begin(); pItr2 != g_MetaMan.m_Scenes.end(); ++pItr2) { + if ((*pItr) != (*pItr2)) { Vector pos1 = (*pItr)->GetLocation() + (*pItr)->GetLocationOffset(); Vector pos2 = (*pItr2)->GetLocation() + (*pItr2)->GetLocationOffset(); - if ((pos1 - pos2).MagnitudeIsLessThan(8.0F)) - { + if ((pos1 - pos2).MagnitudeIsLessThan(8.0F)) { isOverlapped = true; break; } @@ -709,12 +673,10 @@ void MetagameGUI::MoveLocationsIntoTheScreen() if (isOverlapped) (*pItr)->SetLocationOffset((*pItr)->GetLocationOffset() + offsetIncrement); - } - while (isOverlapped); + } while (isOverlapped); } } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: ReadProperty ////////////////////////////////////////////////////////////////////////////////////////// @@ -723,49 +685,47 @@ void MetagameGUI::MoveLocationsIntoTheScreen() // is called. If the property isn't recognized by any of the base classes, // false is returned, and the Reader's position is untouched. -int MetagameGUI::ReadProperty(const std::string_view &propName, Reader &reader) -{ - Vector tempPos; - - StartPropertyList(return Serializable::ReadProperty(propName, reader)); - - MatchProperty("P1BoxPos", - { - reader >> tempPos; - m_apPlayerBox[Players::PlayerOne]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); - }); - MatchProperty("P2BoxPos", - { - reader >> tempPos; - m_apPlayerBox[Players::PlayerTwo]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); - }); - MatchProperty("P3BoxPos", - { - reader >> tempPos; - m_apPlayerBox[Players::PlayerThree]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); - }); - MatchProperty("P4BoxPos", - { - reader >> tempPos; - m_apPlayerBox[Players::PlayerFour]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); - }); - MatchProperty("PhaseBoxPos", - { - reader >> tempPos; - m_pPhaseBox->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); - }); - - EndPropertyList; +int MetagameGUI::ReadProperty(const std::string_view& propName, Reader& reader) { + Vector tempPos; + + StartPropertyList(return Serializable::ReadProperty(propName, reader)); + + MatchProperty("P1BoxPos", + { + reader >> tempPos; + m_apPlayerBox[Players::PlayerOne]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); + }); + MatchProperty("P2BoxPos", + { + reader >> tempPos; + m_apPlayerBox[Players::PlayerTwo]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); + }); + MatchProperty("P3BoxPos", + { + reader >> tempPos; + m_apPlayerBox[Players::PlayerThree]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); + }); + MatchProperty("P4BoxPos", + { + reader >> tempPos; + m_apPlayerBox[Players::PlayerFour]->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); + }); + MatchProperty("PhaseBoxPos", + { + reader >> tempPos; + m_pPhaseBox->SetPositionAbs(tempPos.GetFloorIntX(), tempPos.GetFloorIntY()); + }); + + EndPropertyList; } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual method: Save ////////////////////////////////////////////////////////////////////////////////////////// // Description: Saves the complete state of this MetagameGUI to an output stream for // later recreation with Create(Reader &reader); -int MetagameGUI::Save(Writer &writer) const { +int MetagameGUI::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("P1BoxPos", Vector(m_apPlayerBox[Players::PlayerOne]->GetXPos(), m_apPlayerBox[Players::PlayerOne]->GetYPos())); @@ -778,55 +738,46 @@ int MetagameGUI::Save(Writer &writer) const { return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the MetagameGUI object. -void MetagameGUI::Destroy() -{ - delete m_pGUIController; - delete m_pGUIInput; - delete m_pGUIScreen; +void MetagameGUI::Destroy() { + delete m_pGUIController; + delete m_pGUIInput; + delete m_pGUIScreen; - delete m_pBannerRedTop; - delete m_pBannerRedBottom; - delete m_pBannerYellowTop; - delete m_pBannerYellowBottom; + delete m_pBannerRedTop; + delete m_pBannerRedBottom; + delete m_pBannerYellowTop; + delete m_pBannerYellowBottom; - Clear(); + Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetGUIControlManager ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gets the GUIControlManager owned and used by this. -GUIControlManager * MetagameGUI::GetGUIControlManager() -{ - return m_pGUIController; +GUIControlManager* MetagameGUI::GetGUIControlManager() { + return m_pGUIController; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetEnabled ////////////////////////////////////////////////////////////////////////////////////////// // Description: Enables or disables the menu. This will animate it in and out of view. -void MetagameGUI::SetEnabled(bool enable) -{ - if (enable && m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) - { - m_MenuEnabled = ENABLING; - g_GUISound.EnterMenuSound()->Play(); - } - else if (!enable && m_MenuEnabled != DISABLED && m_MenuEnabled != DISABLING) - { - m_MenuEnabled = DISABLING; - g_GUISound.ExitMenuSound()->Play(); - } +void MetagameGUI::SetEnabled(bool enable) { + if (enable && m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) { + m_MenuEnabled = ENABLING; + g_GUISound.EnterMenuSound()->Play(); + } else if (!enable && m_MenuEnabled != DISABLED && m_MenuEnabled != DISABLING) { + m_MenuEnabled = DISABLING; + g_GUISound.ExitMenuSound()->Play(); + } // Populate the tech comboboxes with the available tech modules for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { @@ -834,7 +785,7 @@ void MetagameGUI::SetEnabled(bool enable) m_apPlayerTechSelect[team]->SetSelectedIndex(0); } for (int moduleID = 0; moduleID < g_PresetMan.GetTotalModuleCount(); ++moduleID) { - if (const DataModule *dataModule = g_PresetMan.GetDataModule(moduleID)) { + if (const DataModule* dataModule = g_PresetMan.GetDataModule(moduleID)) { if (dataModule->IsFaction()) { for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { m_apPlayerTechSelect[team]->GetListPanel()->AddItem(dataModule->GetFriendlyName(), "", nullptr, nullptr, moduleID); @@ -844,214 +795,196 @@ void MetagameGUI::SetEnabled(bool enable) } } - std::list flagList; + std::list flagList; g_PresetMan.GetAllOfGroup(flagList, "Flags", "Icon"); for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - for (std::list::iterator itr = flagList.begin(); itr != flagList.end(); ++itr) { - if (const Icon *pIcon = dynamic_cast(*itr)) { m_apPlayerTeamSelect[player]->AddItem("", "", new AllegroBitmap(pIcon->GetBitmaps32()[0]), pIcon); } + for (std::list::iterator itr = flagList.begin(); itr != flagList.end(); ++itr) { + if (const Icon* pIcon = dynamic_cast(*itr)) { + m_apPlayerTeamSelect[player]->AddItem("", "", new AllegroBitmap(pIcon->GetBitmaps32()[0]), pIcon); + } } } - if (m_apPlayerTeamSelect[Players::PlayerOne]->GetSelectedIndex() < 0) { m_apPlayerTeamSelect[Players::PlayerOne]->SetSelectedIndex(0); } + if (m_apPlayerTeamSelect[Players::PlayerOne]->GetSelectedIndex() < 0) { + m_apPlayerTeamSelect[Players::PlayerOne]->SetSelectedIndex(0); + } - m_ScreenChange = true; + m_ScreenChange = true; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SelectScene ////////////////////////////////////////////////////////////////////////////////////////// // Description: Tries to select a specifically named scene on the metagame field. -void MetagameGUI::SelectScene(Scene *pScene) -{ - m_pSelectedScene = pScene; - - // Update the budget slider - if (m_pSelectedScene) - { - // If during a player's round phase, show and set the budget slider to reflect the newly selected scene's setting - if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - { - int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; - - // If owned by this player's team, make the budget slider represent the currently set setting of this Scene - if (m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer)) - { - m_pSceneBudgetSlider->SetValue(std::floor((m_pSelectedScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()) / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); - } - // Owned by enemy player, so show the attack budget set up for this scene - else if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) - { - if (m_pSelectedScene->GetPresetName() == g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName()) - m_pSceneBudgetSlider->SetValue(std::floor((g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget() / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); - // Not the current target, so set slider to 0. It will set the new budget as - else - m_pSceneBudgetSlider->SetValue(0); - } - // Unowned site, so set up expedition budget (same so far) - else - { - if (m_pSelectedScene->GetPresetName() == g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName()) - m_pSceneBudgetSlider->SetValue(std::floor((g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget() / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); - // Not the current target, so set slider to 0. It will set the new budget as - else - m_pSceneBudgetSlider->SetValue(0); - } - } - - UpdateScenesBox(true); - } -} +void MetagameGUI::SelectScene(Scene* pScene) { + m_pSelectedScene = pScene; + + // Update the budget slider + if (m_pSelectedScene) { + // If during a player's round phase, show and set the budget slider to reflect the newly selected scene's setting + if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) { + int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; + + // If owned by this player's team, make the budget slider represent the currently set setting of this Scene + if (m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer)) { + m_pSceneBudgetSlider->SetValue(std::floor((m_pSelectedScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()) / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); + } + // Owned by enemy player, so show the attack budget set up for this scene + else if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) { + if (m_pSelectedScene->GetPresetName() == g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName()) + m_pSceneBudgetSlider->SetValue(std::floor((g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget() / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); + // Not the current target, so set slider to 0. It will set the new budget as + else + m_pSceneBudgetSlider->SetValue(0); + } + // Unowned site, so set up expedition budget (same so far) + else { + if (m_pSelectedScene->GetPresetName() == g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName()) + m_pSceneBudgetSlider->SetValue(std::floor((g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget() / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); + // Not the current target, so set slider to 0. It will set the new budget as + else + m_pSceneBudgetSlider->SetValue(0); + } + } + UpdateScenesBox(true); + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: SelectScene ////////////////////////////////////////////////////////////////////////////////////////// // Description: Tries to select a specifically named scene on the metagame field. -bool MetagameGUI::SelectScene(std::string sceneName) -{ - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Only allow selection if the Scene is revealed yet! - if ((*sItr)->GetPresetName() == sceneName && (*sItr)->IsRevealed()) - { - SelectScene(*sItr); - return true; - } - } - - return false; -} +bool MetagameGUI::SelectScene(std::string sceneName) { + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Only allow selection if the Scene is revealed yet! + if ((*sItr)->GetPresetName() == sceneName && (*sItr)->IsRevealed()) { + SelectScene(*sItr); + return true; + } + } + return false; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: SwitchToScreen ////////////////////////////////////////////////////////////////////////////////////////// // Description: Switches to showing a specific menu screen/mode. -void MetagameGUI::SwitchToScreen(int newScreen) -{ - RTEAssert(newScreen >= ROOTBOX && newScreen < SCREENCOUNT, "Tried to switch to an out of bounds screen!"); +void MetagameGUI::SwitchToScreen(int newScreen) { + RTEAssert(newScreen >= ROOTBOX && newScreen < SCREENCOUNT, "Tried to switch to an out of bounds screen!"); - // Hide all previously shown screens - HideAllScreens(); + // Hide all previously shown screens + HideAllScreens(); - m_MenuScreen = newScreen; - m_ScreenChange = true; + m_MenuScreen = newScreen; + m_ScreenChange = true; - // Show the selected screen! - m_apScreenBox[m_MenuScreen]->SetVisible(true); + // Show the selected screen! + m_apScreenBox[m_MenuScreen]->SetVisible(true); - // Suspend game depending on which screen it is - g_MetaMan.SetSuspend(m_MenuScreen != ROOTBOX && m_MenuScreen != STATSDIALOG && m_MenuScreen != SCENEINFOBOX); + // Suspend game depending on which screen it is + g_MetaMan.SetSuspend(m_MenuScreen != ROOTBOX && m_MenuScreen != STATSDIALOG && m_MenuScreen != SCENEINFOBOX); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetRoundName ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes a round number into a nice friendly text string. "ONE" for 1 etc -std::string MetagameGUI::GetRoundName(int roundNumber) -{ - if (roundNumber < 12) - { - if (roundNumber == 0) - return "ONE"; - else if (roundNumber == 1) - return "TWO"; - else if (roundNumber == 2) - return "THREE"; - else if (roundNumber == 3) - return "FOUR"; - else if (roundNumber == 4) - return "FIVE"; - else if (roundNumber == 5) - return "SIX"; - else if (roundNumber == 6) - return "SEVEN"; - else if (roundNumber == 7) - return "EIGHT"; - else if (roundNumber == 8) - return "NINE"; - else if (roundNumber == 9) - return "TEN"; - else if (roundNumber == 10) - return "ELEVEN"; - else if (roundNumber == 11) - return "TWELVE"; - } - char numStr[8]; - std::snprintf(numStr, sizeof(numStr), "%d", roundNumber + 1); - return std::string(numStr); +std::string MetagameGUI::GetRoundName(int roundNumber) { + if (roundNumber < 12) { + if (roundNumber == 0) + return "ONE"; + else if (roundNumber == 1) + return "TWO"; + else if (roundNumber == 2) + return "THREE"; + else if (roundNumber == 3) + return "FOUR"; + else if (roundNumber == 4) + return "FIVE"; + else if (roundNumber == 5) + return "SIX"; + else if (roundNumber == 6) + return "SEVEN"; + else if (roundNumber == 7) + return "EIGHT"; + else if (roundNumber == 8) + return "NINE"; + else if (roundNumber == 9) + return "TEN"; + else if (roundNumber == 10) + return "ELEVEN"; + else if (roundNumber == 11) + return "TWELVE"; + } + char numStr[8]; + std::snprintf(numStr, sizeof(numStr), "%d", roundNumber + 1); + return std::string(numStr); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: StartNewGame ////////////////////////////////////////////////////////////////////////////////////////// // Description: Attempts to start a new Metagame using the settings set in the // New Game dialog box. -bool MetagameGUI::StartNewGame() -{ - // Prepare the UI for the game intro/start - UpdatePlayerSetup(); - HideAllScreens(); - m_IncomeSiteLines.clear(); - m_NewSiteIndicators.clear(); - m_SiteSwitchIndicators.clear(); - - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - g_MetaMan.m_TeamIcons[team].Reset(); - - // Create the MetaPlayer:s based on the settings in the dialog box - char str[256]; - g_MetaMan.m_Players.clear(); - g_MetaMan.m_TeamCount = 0; +bool MetagameGUI::StartNewGame() { + // Prepare the UI for the game intro/start + UpdatePlayerSetup(); + HideAllScreens(); + m_IncomeSiteLines.clear(); + m_NewSiteIndicators.clear(); + m_SiteSwitchIndicators.clear(); + + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) + g_MetaMan.m_TeamIcons[team].Reset(); + + // Create the MetaPlayer:s based on the settings in the dialog box + char str[256]; + g_MetaMan.m_Players.clear(); + g_MetaMan.m_TeamCount = 0; g_MetaMan.m_Difficulty = m_pDifficultySlider->GetValue(); m_StartDifficulty = m_pDifficultySlider->GetValue(); - const Icon *pTeamIcon = 0; + const Icon* pTeamIcon = 0; - //Clear metaman's AI skill to defaults + // Clear metaman's AI skill to defaults for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; team++) g_MetaMan.m_TeamAISkill[team] = Activity::DefaultSkill; - // Starting gold amount is common to all - int startGold = STARTGOLDMIN + ((STARTGOLDMAX - STARTGOLDMIN) * (float)m_pGoldSlider->GetValue() / 100.0); - - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - m_ActionSiteLines[player].clear(); - // clear the flag icons on the floating player bars; they will be set on next update in UpdatePlayerBars() - m_apPlayerTeamBox[player]->SetDrawType(GUICollectionBox::Image); - m_apPlayerTeamBox[player]->SetDrawImage(0); - // Same for the players' team flags that appear around the battle sites - m_apPlayerTeamActionBox[player]->SetDrawType(GUICollectionBox::Image); - m_apPlayerTeamActionBox[player]->SetDrawImage(0); - - // Found an active player - if (m_apPlayerControlButton[player]->GetText() != "None") - { - // Disallow empty player name strings - if (m_apPlayerNameBox[player]->GetText() == "") - { - std::snprintf(str, sizeof(str), "Player %d", player); - m_apPlayerNameBox[player]->SetText(str); - } - - // Set up the new player and add it - MetaPlayer newPlayer; - newPlayer.SetName(m_apPlayerNameBox[player]->GetText()); - // Set the in-game control mapping of this metagame player - newPlayer.m_InGamePlayer = player; - // Whether this is a human or AI player - newPlayer.SetHuman(m_apPlayerControlButton[player]->GetText() == "Human"); + // Starting gold amount is common to all + int startGold = STARTGOLDMIN + ((STARTGOLDMAX - STARTGOLDMIN) * (float)m_pGoldSlider->GetValue() / 100.0); + + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + m_ActionSiteLines[player].clear(); + // clear the flag icons on the floating player bars; they will be set on next update in UpdatePlayerBars() + m_apPlayerTeamBox[player]->SetDrawType(GUICollectionBox::Image); + m_apPlayerTeamBox[player]->SetDrawImage(0); + // Same for the players' team flags that appear around the battle sites + m_apPlayerTeamActionBox[player]->SetDrawType(GUICollectionBox::Image); + m_apPlayerTeamActionBox[player]->SetDrawImage(0); + + // Found an active player + if (m_apPlayerControlButton[player]->GetText() != "None") { + // Disallow empty player name strings + if (m_apPlayerNameBox[player]->GetText() == "") { + std::snprintf(str, sizeof(str), "Player %d", player); + m_apPlayerNameBox[player]->SetText(str); + } + + // Set up the new player and add it + MetaPlayer newPlayer; + newPlayer.SetName(m_apPlayerNameBox[player]->GetText()); + // Set the in-game control mapping of this metagame player + newPlayer.m_InGamePlayer = player; + // Whether this is a human or AI player + newPlayer.SetHuman(m_apPlayerControlButton[player]->GetText() == "Human"); // Set native cost multypliiers according to difficulty - if (!newPlayer.IsHuman()) - { + if (!newPlayer.IsHuman()) { if (g_MetaMan.m_Difficulty < Activity::CakeDifficulty) newPlayer.SetNativeCostMultiplier(1.2); else if (g_MetaMan.m_Difficulty < Activity::EasyDifficulty) @@ -1066,42 +999,39 @@ bool MetagameGUI::StartNewGame() newPlayer.SetNativeCostMultiplier(0.40); } -// TODO: Add the control scheme icons to the newgame dialog for clarity - - // Get the chosen team icon - if (m_apPlayerTeamSelect[player]->GetSelectedItem()) - pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity); - // Just get the first one if nothing is selected - else if (m_apPlayerTeamSelect[player]->GetCount() > 0) - pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetItem(0)->m_pEntity); - - // See if the player is designated to a new team or one that has already been created - bool newTeam = true; - for (int team = Activity::TeamOne; team < g_MetaMan.m_TeamCount; ++team) - { - // Join existing team! - if (pTeamIcon->GetPresetName() == g_MetaMan.m_TeamIcons[team].GetPresetName()) - { - newPlayer.SetTeam(team); - newTeam = false; - break; - } - } - - // If we didn't find that the team we were designated already exists, then create it - if (newTeam) - { - // Set the team of the new player - newPlayer.SetTeam(g_MetaMan.m_TeamCount); + // TODO: Add the control scheme icons to the newgame dialog for clarity + + // Get the chosen team icon + if (m_apPlayerTeamSelect[player]->GetSelectedItem()) + pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity); + // Just get the first one if nothing is selected + else if (m_apPlayerTeamSelect[player]->GetCount() > 0) + pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetItem(0)->m_pEntity); + + // See if the player is designated to a new team or one that has already been created + bool newTeam = true; + for (int team = Activity::TeamOne; team < g_MetaMan.m_TeamCount; ++team) { + // Join existing team! + if (pTeamIcon->GetPresetName() == g_MetaMan.m_TeamIcons[team].GetPresetName()) { + newPlayer.SetTeam(team); + newTeam = false; + break; + } + } + + // If we didn't find that the team we were designated already exists, then create it + if (newTeam) { + // Set the team of the new player + newPlayer.SetTeam(g_MetaMan.m_TeamCount); // Set AI Skill level g_MetaMan.m_TeamAISkill[g_MetaMan.m_TeamCount] = m_apPlayerAISkillSlider[player]->GetValue(); - // Set the new team icon - g_MetaMan.m_TeamIcons[g_MetaMan.m_TeamCount] = *pTeamIcon; - // Increase the team count - g_MetaMan.m_TeamCount++; - } + // Set the new team icon + g_MetaMan.m_TeamIcons[g_MetaMan.m_TeamCount] = *pTeamIcon; + // Increase the team count + g_MetaMan.m_TeamCount++; + } - if (const GUIListPanel::Item *selectedTech = m_apPlayerTechSelect[player]->GetSelectedItem()) { + if (const GUIListPanel::Item* selectedTech = m_apPlayerTechSelect[player]->GetSelectedItem()) { // If the "random" selection, choose one from the list of loaded techs. if (m_apPlayerTechSelect[player]->GetSelectedIndex() <= 0) { int randomSelection = 0; @@ -1112,79 +1042,81 @@ bool MetagameGUI::StartNewGame() randomSelection = RandomNum(1, m_apPlayerTechSelect[player]->GetListPanel()->GetItemList()->size() - 1); ok = true; for (int p = 0; p < player; p++) { - if (randomSelection == m_apPlayerTechSelect[p]->GetSelectedIndex()) { ok = false; } + if (randomSelection == m_apPlayerTechSelect[p]->GetSelectedIndex()) { + ok = false; + } } } selectedTech = m_apPlayerTechSelect[player]->GetItem(randomSelection); } - if (selectedTech) { newPlayer.m_NativeTechModule = selectedTech->m_ExtraIndex; } - } - - // Set the starting brains for this player - // Start with the baseline setting - newPlayer.m_BrainPool = m_pLengthSlider->GetValue(); - // Baseline can never be 0 - newPlayer.m_BrainPool = MAX(newPlayer.m_BrainPool, 1); - // Apply the handicap! - if (m_apPlayerHandicap[player]->GetSelectedIndex() == 0) - newPlayer.m_BrainPool += 5; - else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 1) - newPlayer.m_BrainPool += 3; - else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 2) - newPlayer.m_BrainPool += 1; - else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 4) - newPlayer.m_BrainPool -= 1; - else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 5) - newPlayer.m_BrainPool -= 3; - else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 6) - newPlayer.m_BrainPool -= 5; - // Give at least ONE brain! - newPlayer.m_BrainPool = MAX(newPlayer.m_BrainPool, 1); - - // Starting gold amount; common to all - newPlayer.m_Funds = startGold; - - g_MetaMan.m_Players.push_back(newPlayer); - - m_apPlayerTeamSelect[player]->SetVisible(false); - m_apPlayerTechSelect[player]->SetVisible(false); - m_apPlayerNameBox[player]->SetVisible(false); + if (selectedTech) { + newPlayer.m_NativeTechModule = selectedTech->m_ExtraIndex; + } + } + + // Set the starting brains for this player + // Start with the baseline setting + newPlayer.m_BrainPool = m_pLengthSlider->GetValue(); + // Baseline can never be 0 + newPlayer.m_BrainPool = MAX(newPlayer.m_BrainPool, 1); + // Apply the handicap! + if (m_apPlayerHandicap[player]->GetSelectedIndex() == 0) + newPlayer.m_BrainPool += 5; + else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 1) + newPlayer.m_BrainPool += 3; + else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 2) + newPlayer.m_BrainPool += 1; + else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 4) + newPlayer.m_BrainPool -= 1; + else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 5) + newPlayer.m_BrainPool -= 3; + else if (m_apPlayerHandicap[player]->GetSelectedIndex() == 6) + newPlayer.m_BrainPool -= 5; + // Give at least ONE brain! + newPlayer.m_BrainPool = MAX(newPlayer.m_BrainPool, 1); + + // Starting gold amount; common to all + newPlayer.m_Funds = startGold; + + g_MetaMan.m_Players.push_back(newPlayer); + + m_apPlayerTeamSelect[player]->SetVisible(false); + m_apPlayerTechSelect[player]->SetVisible(false); + m_apPlayerNameBox[player]->SetVisible(false); m_apPlayerAISkillSlider[player]->SetVisible(false); m_apPlayerAISkillLabel[player]->SetVisible(false); - m_aBattleFunds[player] = 0; - m_aBattleAttacker[player] = false; - m_aAnimDestroyed[player] = false; - m_aBrainIconPos[player].Reset(); - continue; - } - } - - // Arrange all the floating UI elements neatly, depending on number of playing players - m_apPlayerBox[Players::PlayerOne]->SetPositionRel(20, 30); - m_apPlayerBox[Players::PlayerTwo]->SetPositionRel(20, m_apScreenBox[ROOTBOX]->GetHeight() - m_apPlayerBox[Players::PlayerTwo]->GetHeight() - 30); - m_apPlayerBox[Players::PlayerThree]->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_apPlayerBox[Players::PlayerThree]->GetWidth() - 20, m_apScreenBox[ROOTBOX]->GetHeight() - m_apPlayerBox[Players::PlayerThree]->GetHeight() - 30); - m_apPlayerBox[Players::PlayerFour]->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_apPlayerBox[Players::PlayerFour]->GetWidth() - 20, 30); - UpdatePlayerBars(); - - // Place Scene Info popup in convenient position - if (g_MetaMan.m_Players.size() <= 3) - m_pSceneInfoPopup->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_pSceneInfoPopup->GetWidth() - 16, 16); - else - m_pSceneInfoPopup->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_pSceneInfoPopup->GetWidth() - 16, 110); - - // If two or fewer players, place phase box in lower right corner of screen, otherwise center bottom - if (g_MetaMan.m_Players.size() <= 2) - m_pPhaseBox->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_pPhaseBox->GetWidth() - 10, m_apScreenBox[ROOTBOX]->GetHeight() - m_pPhaseBox->GetHeight() - 40); - else - m_pPhaseBox->SetPositionRel((m_apScreenBox[ROOTBOX]->GetWidth() / 2) - (m_pPhaseBox->GetWidth() / 2), m_apScreenBox[ROOTBOX]->GetHeight() - m_pPhaseBox->GetHeight() - 10); - - - // Start game of specified size! - g_MetaMan.NewGame(m_pSizeSlider->GetValue()); - - return true; -} + m_aBattleFunds[player] = 0; + m_aBattleAttacker[player] = false; + m_aAnimDestroyed[player] = false; + m_aBrainIconPos[player].Reset(); + continue; + } + } + // Arrange all the floating UI elements neatly, depending on number of playing players + m_apPlayerBox[Players::PlayerOne]->SetPositionRel(20, 30); + m_apPlayerBox[Players::PlayerTwo]->SetPositionRel(20, m_apScreenBox[ROOTBOX]->GetHeight() - m_apPlayerBox[Players::PlayerTwo]->GetHeight() - 30); + m_apPlayerBox[Players::PlayerThree]->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_apPlayerBox[Players::PlayerThree]->GetWidth() - 20, m_apScreenBox[ROOTBOX]->GetHeight() - m_apPlayerBox[Players::PlayerThree]->GetHeight() - 30); + m_apPlayerBox[Players::PlayerFour]->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_apPlayerBox[Players::PlayerFour]->GetWidth() - 20, 30); + UpdatePlayerBars(); + + // Place Scene Info popup in convenient position + if (g_MetaMan.m_Players.size() <= 3) + m_pSceneInfoPopup->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_pSceneInfoPopup->GetWidth() - 16, 16); + else + m_pSceneInfoPopup->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_pSceneInfoPopup->GetWidth() - 16, 110); + + // If two or fewer players, place phase box in lower right corner of screen, otherwise center bottom + if (g_MetaMan.m_Players.size() <= 2) + m_pPhaseBox->SetPositionRel(m_apScreenBox[ROOTBOX]->GetWidth() - m_pPhaseBox->GetWidth() - 10, m_apScreenBox[ROOTBOX]->GetHeight() - m_pPhaseBox->GetHeight() - 40); + else + m_pPhaseBox->SetPositionRel((m_apScreenBox[ROOTBOX]->GetWidth() / 2) - (m_pPhaseBox->GetWidth() / 2), m_apScreenBox[ROOTBOX]->GetHeight() - m_pPhaseBox->GetHeight() - 10); + + // Start game of specified size! + g_MetaMan.NewGame(m_pSizeSlider->GetValue()); + + return true; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: LoadGame @@ -1192,114 +1124,107 @@ bool MetagameGUI::StartNewGame() // Description: Attempts to load a Metagame from disk using the settings set in the // Load Game dialog box. -bool MetagameGUI::LoadGame() -{ - // Get the MetaSave to load from the previously temporarily saved combobox selection - if (m_pSelectedGameToLoad) - { - const MetaSave *saveToLoad = dynamic_cast(m_pSelectedGameToLoad); - if (saveToLoad) - { - if (g_MetaMan.Load(saveToLoad) < 0) - { - g_ConsoleMan.PrintString("ERROR: Failed to load Metagame '" + saveToLoad->GetPresetName() + "' from " + saveToLoad->GetSavePath()); - return false; - } +bool MetagameGUI::LoadGame() { + // Get the MetaSave to load from the previously temporarily saved combobox selection + if (m_pSelectedGameToLoad) { + const MetaSave* saveToLoad = dynamic_cast(m_pSelectedGameToLoad); + if (saveToLoad) { + if (g_MetaMan.Load(saveToLoad) < 0) { + g_ConsoleMan.PrintString("ERROR: Failed to load Metagame '" + saveToLoad->GetPresetName() + "' from " + saveToLoad->GetSavePath()); + return false; + } // Reconstruct income site lines without changing funds UpdateIncomeCounting(true); - // Reconstruct the player action lines - they are important! - for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - UpdatePlayerActionLines(metaPlayer); + // Reconstruct the player action lines - they are important! + for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) + UpdatePlayerActionLines(metaPlayer); - // Re-init some other GUI elements - UpdatePlayerBars(); - UpdateScenesBox(true); + // Re-init some other GUI elements + UpdatePlayerBars(); + UpdateScenesBox(true); - // Make sure GUI boxes are on the screen; save game might have been made on wonky resolution - for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - KeepBoxOnScreen(m_apPlayerBox[metaPlayer], 30); - KeepBoxOnScreen(m_pPhaseBox, 30); - KeepBoxOnScreen(m_pSceneInfoPopup, 30); + // Make sure GUI boxes are on the screen; save game might have been made on wonky resolution + for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) + KeepBoxOnScreen(m_apPlayerBox[metaPlayer], 30); + KeepBoxOnScreen(m_pPhaseBox, 30); + KeepBoxOnScreen(m_pSceneInfoPopup, 30); - // Reset some special state vars - m_PostBattleReview = false; - m_BattleCausedOwnershipChange = false; + // Reset some special state vars + m_PostBattleReview = false; + m_BattleCausedOwnershipChange = false; - //Move locations back to screen if they are not visible + // Move locations back to screen if they are not visible MoveLocationsIntoTheScreen(); - g_ConsoleMan.PrintString("Successfully loaded Metagame '" + saveToLoad->GetPresetName() + "' from " + saveToLoad->GetSavePath()); - m_ContinuePhase = false; - return true; - } - } + g_ConsoleMan.PrintString("Successfully loaded Metagame '" + saveToLoad->GetPresetName() + "' from " + saveToLoad->GetSavePath()); + m_ContinuePhase = false; + return true; + } + } - g_ConsoleMan.PrintString("ERROR: Failed to load the Metagame"); - return false; + g_ConsoleMan.PrintString("ERROR: Failed to load the Metagame"); + return false; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SaveGame ////////////////////////////////////////////////////////////////////////////////////////// // Description: Attempts to save a Metagame to disk using the settings set in the // Save Game dialog box. -bool MetagameGUI::SaveGame(std::string saveName, std::string savePath, bool resaveSceneData) -{ - const std::string fullSavePath = g_PresetMan.GetFullModulePath(savePath); - // If specified, first load all bitmap data of all Scenes in the current Metagame that have once saved em, so we can re-save them to the new files - if (resaveSceneData) - g_MetaMan.LoadSceneData(); - - // Set the GameName of the MetaGame to be the save name - g_MetaMan.m_GameName = saveName; - - // Save any loaded scene data FIRST, so that all the paths of ContentFiles get updated to the actual save location first, - // which may have been changed due to the saveName being different than before. - g_MetaMan.SaveSceneData(METASAVEPATH + saveName); - - // Whichever new or existing, create a writer with the path - Writer metaWriter(fullSavePath.c_str()); - // Now that all the updated data files have been written to disk and their paths updated, send the MetaMan state for actual writing to an ini - if (g_MetaMan.Save(metaWriter) < 0) - return false; - - // Clear out the scene data again so we're not keeping it in memory unnecessarily - if (resaveSceneData) - g_MetaMan.ClearSceneData(); - - // After successful save, update the corresponding preset to reflect the newly saved game - // Create a new MetaSave preset that will hold the runtime info of this new save (so it shows up as something we can overwrite later this same runtime) - MetaSave newSave; - // This will automatically set all internal members to represent what MetaMan's current state is - newSave.Create(fullSavePath); - newSave.SetPresetName(saveName); - - // Now add or update the actual Preset - g_PresetMan.AddEntityPreset(&newSave, g_PresetMan.GetModuleID(METASAVEMODULENAME), true, std::string(METASAVEPATH) + "Index.ini"); - - // Now write out the index file of all MetaSaves so the new save is found on next runtime - Writer indexWriter((std::string(METASAVEPATH) + "Index.ini").c_str()); - indexWriter.ObjectStart("DataModule"); - indexWriter.NewPropertyWithValue("ModuleName", "Metagame Saves"); - // Get the current list of all MetaSave Preset:s, including the new one we just saved - std::list saveList; - g_PresetMan.GetAllOfType(saveList, "MetaSave"); - // Go through the list and add their names to the combo box - for (const Entity *saveListEntry : saveList) { - indexWriter.NewPropertyWithValue("AddMetaSave", saveListEntry); - } - indexWriter.ObjectEnd(); - - // Report to console - g_ConsoleMan.PrintString("Successfully saved Metagame '" + saveName + "' to " + savePath); - - return true; -} +bool MetagameGUI::SaveGame(std::string saveName, std::string savePath, bool resaveSceneData) { + const std::string fullSavePath = g_PresetMan.GetFullModulePath(savePath); + // If specified, first load all bitmap data of all Scenes in the current Metagame that have once saved em, so we can re-save them to the new files + if (resaveSceneData) + g_MetaMan.LoadSceneData(); + + // Set the GameName of the MetaGame to be the save name + g_MetaMan.m_GameName = saveName; + + // Save any loaded scene data FIRST, so that all the paths of ContentFiles get updated to the actual save location first, + // which may have been changed due to the saveName being different than before. + g_MetaMan.SaveSceneData(METASAVEPATH + saveName); + + // Whichever new or existing, create a writer with the path + Writer metaWriter(fullSavePath.c_str()); + // Now that all the updated data files have been written to disk and their paths updated, send the MetaMan state for actual writing to an ini + if (g_MetaMan.Save(metaWriter) < 0) + return false; + + // Clear out the scene data again so we're not keeping it in memory unnecessarily + if (resaveSceneData) + g_MetaMan.ClearSceneData(); + + // After successful save, update the corresponding preset to reflect the newly saved game + // Create a new MetaSave preset that will hold the runtime info of this new save (so it shows up as something we can overwrite later this same runtime) + MetaSave newSave; + // This will automatically set all internal members to represent what MetaMan's current state is + newSave.Create(fullSavePath); + newSave.SetPresetName(saveName); + + // Now add or update the actual Preset + g_PresetMan.AddEntityPreset(&newSave, g_PresetMan.GetModuleID(METASAVEMODULENAME), true, std::string(METASAVEPATH) + "Index.ini"); + + // Now write out the index file of all MetaSaves so the new save is found on next runtime + Writer indexWriter((std::string(METASAVEPATH) + "Index.ini").c_str()); + indexWriter.ObjectStart("DataModule"); + indexWriter.NewPropertyWithValue("ModuleName", "Metagame Saves"); + // Get the current list of all MetaSave Preset:s, including the new one we just saved + std::list saveList; + g_PresetMan.GetAllOfType(saveList, "MetaSave"); + // Go through the list and add their names to the combo box + for (const Entity* saveListEntry: saveList) { + indexWriter.NewPropertyWithValue("AddMetaSave", saveListEntry); + } + indexWriter.ObjectEnd(); + // Report to console + g_ConsoleMan.PrintString("Successfully saved Metagame '" + saveName + "' to " + savePath); + + return true; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: SaveGameFromDialog @@ -1307,38 +1232,34 @@ bool MetagameGUI::SaveGame(std::string saveName, std::string savePath, bool resa // Description: Attempts to save a Metagame to disk using the settings set in the // Save Game dialog box. -bool MetagameGUI::SaveGameFromDialog() -{ - std::string saveName; - std::string savePath; - - // Determine whether we have a new save file or one chosen from the list to overwrite - // User wrote in a new save file/folder to use, so go ahead and create it - if (!m_NewSaveBox->GetText().empty()) - { - saveName = m_NewSaveBox->GetText(); - savePath = METASAVEPATH + m_NewSaveBox->GetText() + ".ini"; - } - // A game was selected to be overwritten, so extract its path and save to it - else if (m_pSavesToOverwriteCombo->GetSelectedItem()) - { - saveName = m_pSavesToOverwriteCombo->GetSelectedItem()->m_Name; - const MetaSave *pSave = dynamic_cast(m_pSavesToOverwriteCombo->GetSelectedItem()->m_pEntity); - if (pSave) - savePath = pSave->GetSavePath(); - // Fall back on just doing a new save with that name - else - savePath = METASAVEPATH + m_NewSaveBox->GetText() + ".ini"; - } - // Coulnd't find a valid name selected by the player?? (GUI problem) - else - { - g_ConsoleMan.PrintString("ERROR: Could not save Metagame, because no valid save name was specified?"); - return false; - } - - // First load all bitmap data of all Scenes in the current Metagame that have once saved em, so we can re-save them to the new files - return SaveGame(saveName, savePath, true); +bool MetagameGUI::SaveGameFromDialog() { + std::string saveName; + std::string savePath; + + // Determine whether we have a new save file or one chosen from the list to overwrite + // User wrote in a new save file/folder to use, so go ahead and create it + if (!m_NewSaveBox->GetText().empty()) { + saveName = m_NewSaveBox->GetText(); + savePath = METASAVEPATH + m_NewSaveBox->GetText() + ".ini"; + } + // A game was selected to be overwritten, so extract its path and save to it + else if (m_pSavesToOverwriteCombo->GetSelectedItem()) { + saveName = m_pSavesToOverwriteCombo->GetSelectedItem()->m_Name; + const MetaSave* pSave = dynamic_cast(m_pSavesToOverwriteCombo->GetSelectedItem()->m_pEntity); + if (pSave) + savePath = pSave->GetSavePath(); + // Fall back on just doing a new save with that name + else + savePath = METASAVEPATH + m_NewSaveBox->GetText() + ".ini"; + } + // Coulnd't find a valid name selected by the player?? (GUI problem) + else { + g_ConsoleMan.PrintString("ERROR: Could not save Metagame, because no valid save name was specified?"); + return false; + } + + // First load all bitmap data of all Scenes in the current Metagame that have once saved em, so we can re-save them to the new files + return SaveGame(saveName, savePath, true); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1346,107 +1267,98 @@ bool MetagameGUI::SaveGameFromDialog() ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void MetagameGUI::Update() -{ - // Update the input controller - m_pController->Update(); - - // ToolTip box is hidden by default - m_pToolTipBox->SetVisible(false); - - // Handle recovering from a completed activity - if (m_ActivityRestarted || m_ActivityResumed) - CompletedActivity(); - - // Reset the specific triggers - m_ContinuePhase = false; - m_ActivityRestarted = false; - m_ActivityResumed = false; - m_StartDifficulty = 0; - m_BackToMain = false; - m_Quit = false; - - // Don't update the menu if the console is open - if (g_ConsoleMan.IsEnabled()) - return; - - // Quit now if we aren't enabled - if (m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) - return; - - //////////////////////////////////////////// - // Do all input handling! - - int mouseX, mouseY; - m_pGUIInput->GetMousePosition(&mouseX, &mouseY); - Vector mousePos(mouseX, mouseY); - - UpdateInput(); - -/* - //////////////////////////////////////////// - // Notification blinking logic - - if (m_BlinkMode == NOFUNDS) - { - m_pCostLabel->SetVisible((m_BlinkTimer.GetElapsedRealTimeMS() % 500) > 250); - } - else if (m_BlinkMode == NOCRAFT) - { - bool blink = (m_BlinkTimer.GetElapsedRealTimeMS() % 500) > 250; - m_pCraftLabel->SetVisible(blink); - m_pCraftBox->SetVisible(blink); - } - - // Time out the blinker - if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastRealMS(1500)) - { - m_pCostLabel->SetVisible(true); - m_pCraftLabel->SetVisible(true); - m_pCraftBox->SetVisible(true); - m_BlinkMode = NOBLINK; - } -*/ - ////////////////////////////////////////////////////////////// - // Update screens - - if (m_MenuScreen == NEWDIALOG) - { - if (m_ScreenChange) - { - m_ScreenChange = false; - } - } - else if (m_MenuScreen == LOADDIALOG) - { - if (m_ScreenChange) - { - // Clear out the loadable save list control so we can repopulate it - m_pSavesToLoadCombo->ClearList(); - // Get the list of all read in MetaSave:s - std::list saveList; - g_PresetMan.GetAllOfType(saveList, "MetaSave"); - // Go through the list and add their names to the combo box - int i = 0; - int autoSaveIndex = -1; - MetaSave *pAutoSave = 0; - for (std::list::iterator itr = saveList.begin(); itr != saveList.end(); ++itr) - { - m_pSavesToLoadCombo->AddItem((*itr)->GetPresetName(), "", 0, *itr); - // Take note of the autosave, if it is in here - if ((*itr)->GetPresetName() == AUTOSAVENAME) - { - autoSaveIndex = i; - pAutoSave = dynamic_cast(*itr); - } - ++i; - } - // Select the autosave index if we found it - if (autoSaveIndex >= 0 && pAutoSave) - { - m_pSavesToLoadCombo->SetSelectedIndex(autoSaveIndex); - // Update the game stats info box with the info of the autosave - char info[512]; +void MetagameGUI::Update() { + // Update the input controller + m_pController->Update(); + + // ToolTip box is hidden by default + m_pToolTipBox->SetVisible(false); + + // Handle recovering from a completed activity + if (m_ActivityRestarted || m_ActivityResumed) + CompletedActivity(); + + // Reset the specific triggers + m_ContinuePhase = false; + m_ActivityRestarted = false; + m_ActivityResumed = false; + m_StartDifficulty = 0; + m_BackToMain = false; + m_Quit = false; + + // Don't update the menu if the console is open + if (g_ConsoleMan.IsEnabled()) + return; + + // Quit now if we aren't enabled + if (m_MenuEnabled != ENABLED && m_MenuEnabled != ENABLING) + return; + + //////////////////////////////////////////// + // Do all input handling! + + int mouseX, mouseY; + m_pGUIInput->GetMousePosition(&mouseX, &mouseY); + Vector mousePos(mouseX, mouseY); + + UpdateInput(); + + /* + //////////////////////////////////////////// + // Notification blinking logic + + if (m_BlinkMode == NOFUNDS) + { + m_pCostLabel->SetVisible((m_BlinkTimer.GetElapsedRealTimeMS() % 500) > 250); + } + else if (m_BlinkMode == NOCRAFT) + { + bool blink = (m_BlinkTimer.GetElapsedRealTimeMS() % 500) > 250; + m_pCraftLabel->SetVisible(blink); + m_pCraftBox->SetVisible(blink); + } + + // Time out the blinker + if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastRealMS(1500)) + { + m_pCostLabel->SetVisible(true); + m_pCraftLabel->SetVisible(true); + m_pCraftBox->SetVisible(true); + m_BlinkMode = NOBLINK; + } + */ + ////////////////////////////////////////////////////////////// + // Update screens + + if (m_MenuScreen == NEWDIALOG) { + if (m_ScreenChange) { + m_ScreenChange = false; + } + } else if (m_MenuScreen == LOADDIALOG) { + if (m_ScreenChange) { + // Clear out the loadable save list control so we can repopulate it + m_pSavesToLoadCombo->ClearList(); + // Get the list of all read in MetaSave:s + std::list saveList; + g_PresetMan.GetAllOfType(saveList, "MetaSave"); + // Go through the list and add their names to the combo box + int i = 0; + int autoSaveIndex = -1; + MetaSave* pAutoSave = 0; + for (std::list::iterator itr = saveList.begin(); itr != saveList.end(); ++itr) { + m_pSavesToLoadCombo->AddItem((*itr)->GetPresetName(), "", 0, *itr); + // Take note of the autosave, if it is in here + if ((*itr)->GetPresetName() == AUTOSAVENAME) { + autoSaveIndex = i; + pAutoSave = dynamic_cast(*itr); + } + ++i; + } + // Select the autosave index if we found it + if (autoSaveIndex >= 0 && pAutoSave) { + m_pSavesToLoadCombo->SetSelectedIndex(autoSaveIndex); + // Update the game stats info box with the info of the autosave + char info[512]; std::string difficultyString; if (pAutoSave->GetDifficulty() < Activity::CakeDifficulty) @@ -1463,614 +1375,533 @@ void MetagameGUI::Update() difficultyString = "Difficulty: Nuts!"; std::snprintf(info, sizeof(info), "Game Size: %d sites\nTotal Players: %d\nDay: %d\n%s", pAutoSave->GetSiteCount(), pAutoSave->GetPlayerCount(), pAutoSave->GetRoundCount() + 1, difficultyString.c_str()); - m_pLoadInfoLabel->SetText(info); - // Show the Load button since we have one locked in - m_apMetaButton[LOADNOW]->SetVisible(true); - } - // Couldn't find the autosave, so leave the combobox empty and let the player select something - else - { - // Clear out the load game info box - m_pLoadInfoLabel->SetText(""); - // Hide the load button until we have a game to load selected - m_apMetaButton[LOADNOW]->SetVisible(false); - } - m_ScreenChange = false; - } - } - else if (m_MenuScreen == SAVEDIALOG) - { - if (m_ScreenChange) - { - // Clear out the new save text box - m_NewSaveBox->SetText(""); - // Clear out the overwrite save list control so we can repopulate it - m_pSavesToOverwriteCombo->ClearList(); - // Get the list of all read in MetaSave:s - std::list saveList; - g_PresetMan.GetAllOfType(saveList, "MetaSave"); - // Go through the list and add their names to the combo box - for (std::list::iterator itr = saveList.begin(); itr != saveList.end(); ++itr) - m_pSavesToOverwriteCombo->AddItem((*itr)->GetPresetName(), "", 0, *itr); - // Select the first one - don't, let the player select one if they want to overwrite -// m_pSavesToOverwriteCombo->SetSelectedIndex(0); - // Clear out the save game info box - m_pSaveInfoLabel->SetText(""); - // Hide the save button until we either have a new name or a game to overwrite selected - m_apMetaButton[SAVENOW]->SetVisible(false); - m_apMetaButton[SAVENOW]->SetText("Save"); - m_ScreenChange = false; - } - - // Something written in the new save box, so disable overwriting - if (!m_NewSaveBox->GetText().empty()) - { - m_pGUIController->GetControl("SaveOrLabel")->SetVisible(false); - m_pGUIController->GetControl("SaveAsLabel")->SetVisible(false); - m_pSavesToOverwriteCombo->SetVisible(false); - m_pSaveInfoLabel->SetVisible(false); - // Show the save button since we can now save - m_apMetaButton[SAVENOW]->SetVisible(true); - } - // Overwriting is an option - else - { - m_pGUIController->GetControl("SaveOrLabel")->SetVisible(true); - m_pGUIController->GetControl("SaveAsLabel")->SetVisible(true); - m_pSavesToOverwriteCombo->SetVisible(true); - // Hide the save button if nothing is selected in the overwrite combo box - m_apMetaButton[SAVENOW]->SetVisible(m_pSavesToOverwriteCombo->GetSelectedItem() && m_pSavesToOverwriteCombo->GetSelectedItem()->m_pEntity); - - // If the button is visible and we're overwriting something, make the player press the Save button twice to confirm overwriting a game - if (m_apMetaButton[SAVENOW]->GetVisible() && m_apMetaButton[SAVENOW]->GetText() != "Save") - { - m_apMetaButton[SAVENOW]->SetText(m_BlinkTimer.AlternateReal(333) ? "CONFIRM?" : ""); - m_pGUIController->GetControl("SaveAsLabel")->SetVisible(m_BlinkTimer.AlternateReal(333)); - } - } - } - - - ///////////////////////////////////////////////////////////// - // Update based on the MetaGame's state - - // Always show the phase box if we're in-game - if (g_MetaMan.m_GameState != MetaMan::NOGAME && !g_MetaMan.IsSuspended()) - { - m_pPhaseBox->SetVisible(true); - // Never let a game go if we have 0 players -// RTEAssert(g_MetaMan.m_Players.size() > 0, "Game in progress without any players!"); - } - - // Deselect scenes and player bars on state change - if (g_MetaMan.m_StateChanged) - { - m_pSelectedScene = 0; - m_ActivePlayerIncomeLines = -1; - // Go through all lines and make them fully visible - for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) - (*slItr).m_OnlyFirstSegments = (*slItr).m_OnlyLastSegments = -1; - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - for (std::vector::iterator slItr = m_ActionSiteLines[metaPlayer].begin(); slItr != m_ActionSiteLines[metaPlayer].end(); ++slItr) - (*slItr).m_OnlyFirstSegments = (*slItr).m_OnlyLastSegments = -1; - } - } - - // Game is suspended - if (g_MetaMan.IsSuspended()) - { - // Do nothing, game is suspended while in the game menu - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - m_AnimTimer3.Reset(); - - // Show the current menu if we're not showing some confirmation box and we're not already showing the screen we're supposed to be - if (!m_pConfirmationBox->GetVisible() && !m_apScreenBox[m_MenuScreen]->GetVisible()) - SwitchToScreen(m_MenuScreen); - } - // No game yet, show the new game menu - else if (g_MetaMan.m_GameState == MetaMan::NOGAME) - { - m_pPhaseLabel->SetText("Game Not Started"); - if (m_ScreenChange) - { - SwitchToScreen(NEWDIALOG); - UpdatePlayerSetup(); - m_ScreenChange = false; - } - } - else if (g_MetaMan.m_GameState == MetaMan::GAMEINTRO) - { - m_pPhaseLabel->SetText("Game Intro"); - m_apMetaButton[CONTINUE]->SetText("Skip Intro"); - } - else if (g_MetaMan.m_GameState == MetaMan::NEWROUND) - { - if (g_MetaMan.m_StateChanged) - { - m_pBannerYellowTop->ShowText("DAY", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 2500, 200); - m_pBannerYellowBottom->ShowText(GetRoundName(g_MetaMan.m_CurrentRound), GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 2500, 300); - } - m_pPhaseLabel->SetText("New Day"); - // Blink the start button to draw attention to it - m_apMetaButton[CONTINUE]->SetText(m_BlinkTimer.AlternateReal(333) ? "> Start <" : "Start"); - } - else if (g_MetaMan.m_GameState == MetaMan::REVEALSCENES) - { - if (g_MetaMan.m_StateChanged) - { - m_pBannerYellowTop->HideText(2500, 200); - m_pBannerYellowBottom->HideText(2500, 300); -// m_pBannerRedTop->ShowText("Sites Found", GUIBanner::FLYBYLEFTWARD, 1000, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.1, 3500, 200); - } - - m_pPhaseLabel->SetText("New Sites Found"); - m_apMetaButton[CONTINUE]->SetText("Skip"); - UpdateSiteRevealing(); - } - else if (g_MetaMan.m_GameState == MetaMan::COUNTINCOME) - { - if (g_MetaMan.m_StateChanged) - { -// m_pBannerRedBottom->ShowText("Incomes", GUIBanner::FLYBYLEFTWARD, 1000, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.2, 3500, 200); - } - m_pPhaseLabel->SetText("Counting Incomes"); - m_apMetaButton[CONTINUE]->SetText("Skip"); - UpdateIncomeCounting(); - } - else if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - { - // Who's turn is it, anyway? - int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; - - // Set up the pre-player-turn intermediate status IF this is a human player still in the game - if (g_MetaMan.m_Players[metaPlayer].IsHuman() && !g_MetaMan.m_Players[metaPlayer].IsGameOverByRound(g_MetaMan.m_CurrentRound)) - { - if (g_MetaMan.m_StateChanged) - { - // If this human player has no brains left anywhere, there's really nothing he can do, and it's game over for him - // Communicate it to the loser - if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) <= 0) - { - m_apMetaButton[CONTINUE]->SetText("Continue"); - m_pPhaseLabel->SetText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s Turn"); - m_pBannerRedTop->ShowText("Game Over", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); - m_pBannerRedBottom->ShowText("for " + g_MetaMan.m_Players[metaPlayer].GetName() + "!", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); - - // Show a lil descriptive message as to why the game ended - m_pGameMessageLabel->SetVisible(true); - m_pGameMessageLabel->SetPositionAbs(m_pGameMessageLabel->GetXPos(), (m_apScreenBox[ROOTBOX]->GetHeight() / 2) + 110 - 16); - m_pGameMessageLabel->SetText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s brains are all gone, so he/she can do nothing more. Good effort, though!"); - - // Just skip this guy's turn completely - m_PreTurn = false; - } - // Normal player turn start - else - { - m_apMetaButton[CONTINUE]->SetText("Start Turn"); - m_pPhaseLabel->SetText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s Turn"); - m_pBannerRedTop->ShowText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); - m_pBannerRedBottom->ShowText("Turn", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); - m_pGameMessageLabel->SetVisible(false); - m_PreTurn = true; - } - } - - // Do some more init and then cleanup later - UpdateHumanPlayerTurn(metaPlayer); - } - // Non-human player - else - { - m_pGameMessageLabel->SetVisible(false); - } - - // Before or after the turn prep start - if (m_PreTurn) - { - // Blink the start button to draw attention to it - m_apMetaButton[CONTINUE]->SetText(m_BlinkTimer.AlternateReal(333) ? "> Start Turn <" : "Start Turn"); - } - else - { - // Dead player's turn, just waiting for the continue button to be pressed - if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) <= 0) - { - m_apMetaButton[CONTINUE]->SetText(m_BlinkTimer.AlternateReal(333) ? "> Continue <" : "Continue"); - UpdatePlayerActionLines(metaPlayer); - } - // Normal turn - else - { - m_apMetaButton[CONTINUE]->SetText("End Turn"); - m_pBannerRedTop->HideText(3500, 0); - m_pBannerRedBottom->HideText(3500, 0); - UpdatePlayerActionLines(metaPlayer); - } - } - } - else if (g_MetaMan.m_GameState == MetaMan::BUILDBASES) - { - // Hide any banners that might be up - if (g_MetaMan.m_StateChanged) - { - m_pBannerYellowTop->HideText(2500, 200); - m_pBannerYellowBottom->HideText(2500, 300); - m_pBannerRedTop->HideText(3500, 0); - m_pBannerRedBottom->HideText(3500, 0); - } - m_apMetaButton[CONTINUE]->SetText("Skip"); - UpdateBaseBuilding(); - } - else if (g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES) - { - // Hide any banners that might be up - if (g_MetaMan.m_StateChanged) - { - m_pBannerYellowTop->HideText(2500, 200); - m_pBannerYellowBottom->HideText(2500, 300); - m_pBannerRedTop->HideText(3500, 0); - m_pBannerRedBottom->HideText(3500, 0); - } - m_apMetaButton[CONTINUE]->SetText("Start!"); - UpdateOffensives(); - } - else if (g_MetaMan.m_GameState == MetaMan::ENDROUND) - { - m_pPhaseLabel->SetText("End of Day"); - m_apMetaButton[CONTINUE]->SetText("Continue"); - } - else if (g_MetaMan.m_GameState == MetaMan::GAMEOVER) - { - if (g_MetaMan.m_StateChanged) - { - m_pPhaseLabel->SetText("Game Over"); - m_apMetaButton[CONTINUE]->SetText("Good Game!"); - // Which team has the most bases? - int winnerTeam = g_MetaMan.WhichTeamIsLeading(); - - // Noone left?? - if (winnerTeam == Activity::NoTeam) - { - m_pBannerRedTop->ShowText("EVERYONE", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); - m_pBannerYellowBottom->ShowText("-DIED-", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); - } - else - { - - // Find out who was on this winning team so we can name them by name - std::string winnerNames = ""; - bool plural = false; - for (std::vector::iterator pItr = g_MetaMan.m_Players.begin(); pItr != g_MetaMan.m_Players.end(); ++pItr) - { - // WINRAR - if ((*pItr).GetTeam() == winnerTeam) - { - // There's now more than one name in there - if (!winnerNames.empty()) - plural = true; - - winnerNames = winnerNames + (winnerNames.empty() ? "" : " and ") + (*pItr).GetName(); - } - } - m_pBannerRedTop->ShowText(winnerNames, GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); - m_pBannerYellowBottom->ShowText(plural ? "WIN!" : "WINS!", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); -// char winStr[256]; -// std::snprintf(winStr, sizeof(winStr), "Team %d", winner + 1); -// m_pBannerRedTop->ShowText(winStr, GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); -// m_pBannerYellowBottom->ShowText("WINS!", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); - } - } - - // Show that the game is over because noone has any brains left to do anyhting with - for (int metaPlayer = 0; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - m_apBrainPoolLabel[metaPlayer]->SetVisible(m_AnimTimer2.AlternateReal(333)); - - // Show a lil descriptive message as to why the game ended - m_pGameMessageLabel->SetVisible(true); - m_pGameMessageLabel->SetPositionAbs(m_pGameMessageLabel->GetXPos(), (m_apScreenBox[ROOTBOX]->GetHeight() / 2) + 110 - 16); - if (g_MetaMan.NoBrainsLeftInAnyPool()) - m_pGameMessageLabel->SetText("All players' brains have been deployed, and so the team with the most\nowned sites (and if tied, the most gold) won the mining contract for this planet!"); - else - m_pGameMessageLabel->SetText("The team that is in the lead (in owned sites - or gold, if tied)\nand has brains left to deploy has won the mining contract for this planet!"); - } - - // Update site change animations independent of the phase/mode.. they can happen here and there - UpdateSiteChangeAnim(); - - // SCENE SELECTION LOGIC - if (!g_MetaMan.IsSuspended() && !m_PreTurn) - { - if (m_ScreenChange) - { -// m_apScreenBox[SCENESCREEN]->SetVisible(true); -// m_apMetaButton[BACKTOMAIN]->SetVisible(true); - m_ScreenChange = false; - } - - Vector screenLocation; - - // Make any player box which is floated over with cursor the one to show its sitelines - if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - { - GUICollectionBox *pBox = dynamic_cast(m_pGUIController->GetControlUnderPoint(mouseX, mouseY, m_apScreenBox[ROOTBOX], 1)); - bool found = false; - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - // Find hovered box - if (pBox == m_apPlayerBox[metaPlayer]) - { - m_ActivePlayerIncomeLines = metaPlayer; - found = true; - } - } - // Not hovering over any player box, so don't show any lines - if (!found) - m_ActivePlayerIncomeLines = Players::NoPlayer; - } - - // Validate mouse position as being over the planet area for hover operations! - if (!m_pDraggedBox && (mousePos - m_PlanetCenter).MagnitudeIsLessThan(m_PlanetRadius)) - { - // If unlocked, detect any Scene close to the mouse and highlight it - bool foundAnyHover = false; - bool foundNewHover = false; - std::vector::iterator sItr; - std::vector::iterator newCandidateItr = g_MetaMan.m_Scenes.end(); - - float sqrShortestDist = std::numeric_limits::infinity(); - for (sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Only mess with Scenes we can see - if (!(*sItr)->IsRevealed()) - continue; - - screenLocation = m_PlanetCenter + (*sItr)->GetLocation() + (*sItr)->GetLocationOffset(); + m_pLoadInfoLabel->SetText(info); + // Show the Load button since we have one locked in + m_apMetaButton[LOADNOW]->SetVisible(true); + } + // Couldn't find the autosave, so leave the combobox empty and let the player select something + else { + // Clear out the load game info box + m_pLoadInfoLabel->SetText(""); + // Hide the load button until we have a game to load selected + m_apMetaButton[LOADNOW]->SetVisible(false); + } + m_ScreenChange = false; + } + } else if (m_MenuScreen == SAVEDIALOG) { + if (m_ScreenChange) { + // Clear out the new save text box + m_NewSaveBox->SetText(""); + // Clear out the overwrite save list control so we can repopulate it + m_pSavesToOverwriteCombo->ClearList(); + // Get the list of all read in MetaSave:s + std::list saveList; + g_PresetMan.GetAllOfType(saveList, "MetaSave"); + // Go through the list and add their names to the combo box + for (std::list::iterator itr = saveList.begin(); itr != saveList.end(); ++itr) + m_pSavesToOverwriteCombo->AddItem((*itr)->GetPresetName(), "", 0, *itr); + // Select the first one - don't, let the player select one if they want to overwrite + // m_pSavesToOverwriteCombo->SetSelectedIndex(0); + // Clear out the save game info box + m_pSaveInfoLabel->SetText(""); + // Hide the save button until we either have a new name or a game to overwrite selected + m_apMetaButton[SAVENOW]->SetVisible(false); + m_apMetaButton[SAVENOW]->SetText("Save"); + m_ScreenChange = false; + } + + // Something written in the new save box, so disable overwriting + if (!m_NewSaveBox->GetText().empty()) { + m_pGUIController->GetControl("SaveOrLabel")->SetVisible(false); + m_pGUIController->GetControl("SaveAsLabel")->SetVisible(false); + m_pSavesToOverwriteCombo->SetVisible(false); + m_pSaveInfoLabel->SetVisible(false); + // Show the save button since we can now save + m_apMetaButton[SAVENOW]->SetVisible(true); + } + // Overwriting is an option + else { + m_pGUIController->GetControl("SaveOrLabel")->SetVisible(true); + m_pGUIController->GetControl("SaveAsLabel")->SetVisible(true); + m_pSavesToOverwriteCombo->SetVisible(true); + // Hide the save button if nothing is selected in the overwrite combo box + m_apMetaButton[SAVENOW]->SetVisible(m_pSavesToOverwriteCombo->GetSelectedItem() && m_pSavesToOverwriteCombo->GetSelectedItem()->m_pEntity); + + // If the button is visible and we're overwriting something, make the player press the Save button twice to confirm overwriting a game + if (m_apMetaButton[SAVENOW]->GetVisible() && m_apMetaButton[SAVENOW]->GetText() != "Save") { + m_apMetaButton[SAVENOW]->SetText(m_BlinkTimer.AlternateReal(333) ? "CONFIRM?" : ""); + m_pGUIController->GetControl("SaveAsLabel")->SetVisible(m_BlinkTimer.AlternateReal(333)); + } + } + } + + ///////////////////////////////////////////////////////////// + // Update based on the MetaGame's state + + // Always show the phase box if we're in-game + if (g_MetaMan.m_GameState != MetaMan::NOGAME && !g_MetaMan.IsSuspended()) { + m_pPhaseBox->SetVisible(true); + // Never let a game go if we have 0 players + // RTEAssert(g_MetaMan.m_Players.size() > 0, "Game in progress without any players!"); + } + + // Deselect scenes and player bars on state change + if (g_MetaMan.m_StateChanged) { + m_pSelectedScene = 0; + m_ActivePlayerIncomeLines = -1; + // Go through all lines and make them fully visible + for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) + (*slItr).m_OnlyFirstSegments = (*slItr).m_OnlyLastSegments = -1; + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + for (std::vector::iterator slItr = m_ActionSiteLines[metaPlayer].begin(); slItr != m_ActionSiteLines[metaPlayer].end(); ++slItr) + (*slItr).m_OnlyFirstSegments = (*slItr).m_OnlyLastSegments = -1; + } + } + + // Game is suspended + if (g_MetaMan.IsSuspended()) { + // Do nothing, game is suspended while in the game menu + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + m_AnimTimer3.Reset(); + + // Show the current menu if we're not showing some confirmation box and we're not already showing the screen we're supposed to be + if (!m_pConfirmationBox->GetVisible() && !m_apScreenBox[m_MenuScreen]->GetVisible()) + SwitchToScreen(m_MenuScreen); + } + // No game yet, show the new game menu + else if (g_MetaMan.m_GameState == MetaMan::NOGAME) { + m_pPhaseLabel->SetText("Game Not Started"); + if (m_ScreenChange) { + SwitchToScreen(NEWDIALOG); + UpdatePlayerSetup(); + m_ScreenChange = false; + } + } else if (g_MetaMan.m_GameState == MetaMan::GAMEINTRO) { + m_pPhaseLabel->SetText("Game Intro"); + m_apMetaButton[CONTINUE]->SetText("Skip Intro"); + } else if (g_MetaMan.m_GameState == MetaMan::NEWROUND) { + if (g_MetaMan.m_StateChanged) { + m_pBannerYellowTop->ShowText("DAY", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 2500, 200); + m_pBannerYellowBottom->ShowText(GetRoundName(g_MetaMan.m_CurrentRound), GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 2500, 300); + } + m_pPhaseLabel->SetText("New Day"); + // Blink the start button to draw attention to it + m_apMetaButton[CONTINUE]->SetText(m_BlinkTimer.AlternateReal(333) ? "> Start <" : "Start"); + } else if (g_MetaMan.m_GameState == MetaMan::REVEALSCENES) { + if (g_MetaMan.m_StateChanged) { + m_pBannerYellowTop->HideText(2500, 200); + m_pBannerYellowBottom->HideText(2500, 300); + // m_pBannerRedTop->ShowText("Sites Found", GUIBanner::FLYBYLEFTWARD, 1000, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.1, 3500, 200); + } + + m_pPhaseLabel->SetText("New Sites Found"); + m_apMetaButton[CONTINUE]->SetText("Skip"); + UpdateSiteRevealing(); + } else if (g_MetaMan.m_GameState == MetaMan::COUNTINCOME) { + if (g_MetaMan.m_StateChanged) { + // m_pBannerRedBottom->ShowText("Incomes", GUIBanner::FLYBYLEFTWARD, 1000, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.2, 3500, 200); + } + m_pPhaseLabel->SetText("Counting Incomes"); + m_apMetaButton[CONTINUE]->SetText("Skip"); + UpdateIncomeCounting(); + } else if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) { + // Who's turn is it, anyway? + int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; + + // Set up the pre-player-turn intermediate status IF this is a human player still in the game + if (g_MetaMan.m_Players[metaPlayer].IsHuman() && !g_MetaMan.m_Players[metaPlayer].IsGameOverByRound(g_MetaMan.m_CurrentRound)) { + if (g_MetaMan.m_StateChanged) { + // If this human player has no brains left anywhere, there's really nothing he can do, and it's game over for him + // Communicate it to the loser + if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) <= 0) { + m_apMetaButton[CONTINUE]->SetText("Continue"); + m_pPhaseLabel->SetText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s Turn"); + m_pBannerRedTop->ShowText("Game Over", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); + m_pBannerRedBottom->ShowText("for " + g_MetaMan.m_Players[metaPlayer].GetName() + "!", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); + + // Show a lil descriptive message as to why the game ended + m_pGameMessageLabel->SetVisible(true); + m_pGameMessageLabel->SetPositionAbs(m_pGameMessageLabel->GetXPos(), (m_apScreenBox[ROOTBOX]->GetHeight() / 2) + 110 - 16); + m_pGameMessageLabel->SetText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s brains are all gone, so he/she can do nothing more. Good effort, though!"); + + // Just skip this guy's turn completely + m_PreTurn = false; + } + // Normal player turn start + else { + m_apMetaButton[CONTINUE]->SetText("Start Turn"); + m_pPhaseLabel->SetText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s Turn"); + m_pBannerRedTop->ShowText(g_MetaMan.m_Players[metaPlayer].GetName() + "'s", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); + m_pBannerRedBottom->ShowText("Turn", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); + m_pGameMessageLabel->SetVisible(false); + m_PreTurn = true; + } + } + + // Do some more init and then cleanup later + UpdateHumanPlayerTurn(metaPlayer); + } + // Non-human player + else { + m_pGameMessageLabel->SetVisible(false); + } + + // Before or after the turn prep start + if (m_PreTurn) { + // Blink the start button to draw attention to it + m_apMetaButton[CONTINUE]->SetText(m_BlinkTimer.AlternateReal(333) ? "> Start Turn <" : "Start Turn"); + } else { + // Dead player's turn, just waiting for the continue button to be pressed + if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) <= 0) { + m_apMetaButton[CONTINUE]->SetText(m_BlinkTimer.AlternateReal(333) ? "> Continue <" : "Continue"); + UpdatePlayerActionLines(metaPlayer); + } + // Normal turn + else { + m_apMetaButton[CONTINUE]->SetText("End Turn"); + m_pBannerRedTop->HideText(3500, 0); + m_pBannerRedBottom->HideText(3500, 0); + UpdatePlayerActionLines(metaPlayer); + } + } + } else if (g_MetaMan.m_GameState == MetaMan::BUILDBASES) { + // Hide any banners that might be up + if (g_MetaMan.m_StateChanged) { + m_pBannerYellowTop->HideText(2500, 200); + m_pBannerYellowBottom->HideText(2500, 300); + m_pBannerRedTop->HideText(3500, 0); + m_pBannerRedBottom->HideText(3500, 0); + } + m_apMetaButton[CONTINUE]->SetText("Skip"); + UpdateBaseBuilding(); + } else if (g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES) { + // Hide any banners that might be up + if (g_MetaMan.m_StateChanged) { + m_pBannerYellowTop->HideText(2500, 200); + m_pBannerYellowBottom->HideText(2500, 300); + m_pBannerRedTop->HideText(3500, 0); + m_pBannerRedBottom->HideText(3500, 0); + } + m_apMetaButton[CONTINUE]->SetText("Start!"); + UpdateOffensives(); + } else if (g_MetaMan.m_GameState == MetaMan::ENDROUND) { + m_pPhaseLabel->SetText("End of Day"); + m_apMetaButton[CONTINUE]->SetText("Continue"); + } else if (g_MetaMan.m_GameState == MetaMan::GAMEOVER) { + if (g_MetaMan.m_StateChanged) { + m_pPhaseLabel->SetText("Game Over"); + m_apMetaButton[CONTINUE]->SetText("Good Game!"); + // Which team has the most bases? + int winnerTeam = g_MetaMan.WhichTeamIsLeading(); + + // Noone left?? + if (winnerTeam == Activity::NoTeam) { + m_pBannerRedTop->ShowText("EVERYONE", GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); + m_pBannerYellowBottom->ShowText("-DIED-", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); + } else { + + // Find out who was on this winning team so we can name them by name + std::string winnerNames = ""; + bool plural = false; + for (std::vector::iterator pItr = g_MetaMan.m_Players.begin(); pItr != g_MetaMan.m_Players.end(); ++pItr) { + // WINRAR + if ((*pItr).GetTeam() == winnerTeam) { + // There's now more than one name in there + if (!winnerNames.empty()) + plural = true; + + winnerNames = winnerNames + (winnerNames.empty() ? "" : " and ") + (*pItr).GetName(); + } + } + m_pBannerRedTop->ShowText(winnerNames, GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); + m_pBannerYellowBottom->ShowText(plural ? "WIN!" : "WINS!", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); + // char winStr[256]; + // std::snprintf(winStr, sizeof(winStr), "Team %d", winner + 1); + // m_pBannerRedTop->ShowText(winStr, GUIBanner::FLYBYLEFTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.4, 3500, 0); + // m_pBannerYellowBottom->ShowText("WINS!", GUIBanner::FLYBYRIGHTWARD, -1, Vector(m_RootBoxMaxWidth, g_WindowMan.GetResY()), 0.6, 3500, 0); + } + } + + // Show that the game is over because noone has any brains left to do anyhting with + for (int metaPlayer = 0; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) + m_apBrainPoolLabel[metaPlayer]->SetVisible(m_AnimTimer2.AlternateReal(333)); + + // Show a lil descriptive message as to why the game ended + m_pGameMessageLabel->SetVisible(true); + m_pGameMessageLabel->SetPositionAbs(m_pGameMessageLabel->GetXPos(), (m_apScreenBox[ROOTBOX]->GetHeight() / 2) + 110 - 16); + if (g_MetaMan.NoBrainsLeftInAnyPool()) + m_pGameMessageLabel->SetText("All players' brains have been deployed, and so the team with the most\nowned sites (and if tied, the most gold) won the mining contract for this planet!"); + else + m_pGameMessageLabel->SetText("The team that is in the lead (in owned sites - or gold, if tied)\nand has brains left to deploy has won the mining contract for this planet!"); + } + + // Update site change animations independent of the phase/mode.. they can happen here and there + UpdateSiteChangeAnim(); + + // SCENE SELECTION LOGIC + if (!g_MetaMan.IsSuspended() && !m_PreTurn) { + if (m_ScreenChange) { + // m_apScreenBox[SCENESCREEN]->SetVisible(true); + // m_apMetaButton[BACKTOMAIN]->SetVisible(true); + m_ScreenChange = false; + } + + Vector screenLocation; + + // Make any player box which is floated over with cursor the one to show its sitelines + if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) { + GUICollectionBox* pBox = dynamic_cast(m_pGUIController->GetControlUnderPoint(mouseX, mouseY, m_apScreenBox[ROOTBOX], 1)); + bool found = false; + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + // Find hovered box + if (pBox == m_apPlayerBox[metaPlayer]) { + m_ActivePlayerIncomeLines = metaPlayer; + found = true; + } + } + // Not hovering over any player box, so don't show any lines + if (!found) + m_ActivePlayerIncomeLines = Players::NoPlayer; + } + + // Validate mouse position as being over the planet area for hover operations! + if (!m_pDraggedBox && (mousePos - m_PlanetCenter).MagnitudeIsLessThan(m_PlanetRadius)) { + // If unlocked, detect any Scene close to the mouse and highlight it + bool foundAnyHover = false; + bool foundNewHover = false; + std::vector::iterator sItr; + std::vector::iterator newCandidateItr = g_MetaMan.m_Scenes.end(); + + float sqrShortestDist = std::numeric_limits::infinity(); + for (sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Only mess with Scenes we can see + if (!(*sItr)->IsRevealed()) + continue; + + screenLocation = m_PlanetCenter + (*sItr)->GetLocation() + (*sItr)->GetLocationOffset(); if (m_pSceneInfoPopup->GetVisible() && m_pSceneInfoPopup->PointInside(screenLocation.GetRoundIntX(), screenLocation.GetRoundIntY())) { continue; } - float sqrDistance = (screenLocation - mousePos).GetSqrMagnitude(); - - // The first new scene the mouse's position is close to when unlocked, make selected - if (sqrDistance < (16.0F * 16.0F) && sqrDistance < sqrShortestDist) - { - // This is now the shortest - sqrShortestDist = sqrDistance; - foundAnyHover = true; - // See if the scene hovered is different from the previously hovered one, and if so, set it to the new candidate to switch hovering to -// Actually, don't because it will cause alternating each frame if two hover zones overlap! -// if (*sItr != m_pHoveredScene) - newCandidateItr = sItr; - } - } - - // Set new hovered scene to be the one now closest to the cursor, if there is any and if it is different the a currently hovered one - if (newCandidateItr != g_MetaMan.m_Scenes.end() && (*newCandidateItr) != m_pHoveredScene) - { - m_pHoveredScene = (*newCandidateItr); - foundNewHover = true; - g_GUISound.SelectionChangeSound()->Play(); - } - - // If we didn't find anything to hover over, then remove the hover status - if (!foundAnyHover) - m_pHoveredScene = 0; - - // Set up the hover label to appear over any hovered scene location - if (m_pHoveredScene) - UpdateSiteNameLabel(true, m_pHoveredScene->GetPresetName(), m_pHoveredScene->GetLocation() + m_pHoveredScene->GetLocationOffset()); - else if (g_MetaMan.m_GameState != MetaMan::COUNTINCOME && g_MetaMan.m_GameState != MetaMan::BUILDBASES && g_MetaMan.m_GameState != MetaMan::RUNACTIVITIES) - UpdateSiteNameLabel(false); - - // If clicked, whatever is hovered becomes selected - if (g_UInputMan.MenuButtonPressed(UInputMan::MENU_EITHER)) - { - if (m_pHoveredScene) - { - SelectScene(m_pHoveredScene); - g_GUISound.ItemChangeSound()->Play(); - } -/* Can't do this, doesn't take into account clicks on floating UI boxes - // Not hovering over anything on click, so deselect whatever was selected - else if (m_pSelectedScene) - { - m_pSelectedScene = 0; - g_GUISound.FocusChangeSound()->Play(); - } -*/ - } - } - } - - // Update the scene info/action box - UpdateScenesBox(); - - // Update the site lines, if neccessary - for (int metaPlayer = 0; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - { - // The tradestar is a moving target + float sqrDistance = (screenLocation - mousePos).GetSqrMagnitude(); + + // The first new scene the mouse's position is close to when unlocked, make selected + if (sqrDistance < (16.0F * 16.0F) && sqrDistance < sqrShortestDist) { + // This is now the shortest + sqrShortestDist = sqrDistance; + foundAnyHover = true; + // See if the scene hovered is different from the previously hovered one, and if so, set it to the new candidate to switch hovering to + // Actually, don't because it will cause alternating each frame if two hover zones overlap! + // if (*sItr != m_pHoveredScene) + newCandidateItr = sItr; + } + } + + // Set new hovered scene to be the one now closest to the cursor, if there is any and if it is different the a currently hovered one + if (newCandidateItr != g_MetaMan.m_Scenes.end() && (*newCandidateItr) != m_pHoveredScene) { + m_pHoveredScene = (*newCandidateItr); + foundNewHover = true; + g_GUISound.SelectionChangeSound()->Play(); + } + + // If we didn't find anything to hover over, then remove the hover status + if (!foundAnyHover) + m_pHoveredScene = 0; + + // Set up the hover label to appear over any hovered scene location + if (m_pHoveredScene) + UpdateSiteNameLabel(true, m_pHoveredScene->GetPresetName(), m_pHoveredScene->GetLocation() + m_pHoveredScene->GetLocationOffset()); + else if (g_MetaMan.m_GameState != MetaMan::COUNTINCOME && g_MetaMan.m_GameState != MetaMan::BUILDBASES && g_MetaMan.m_GameState != MetaMan::RUNACTIVITIES) + UpdateSiteNameLabel(false); + + // If clicked, whatever is hovered becomes selected + if (g_UInputMan.MenuButtonPressed(UInputMan::MENU_EITHER)) { + if (m_pHoveredScene) { + SelectScene(m_pHoveredScene); + g_GUISound.ItemChangeSound()->Play(); + } + /* Can't do this, doesn't take into account clicks on floating UI boxes + // Not hovering over anything on click, so deselect whatever was selected + else if (m_pSelectedScene) + { + m_pSelectedScene = 0; + g_GUISound.FocusChangeSound()->Play(); + } + */ + } + } + } + + // Update the scene info/action box + UpdateScenesBox(); + + // Update the site lines, if neccessary + for (int metaPlayer = 0; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) { + // The tradestar is a moving target if (m_aStationIncomeLineIndices[metaPlayer] >= 0 && !m_IncomeSiteLines.empty()) m_IncomeSiteLines[m_aStationIncomeLineIndices[metaPlayer]].m_PlanetPoint = m_StationPosOnOrbit; - // The brain pool counters might also be if player moves the player bar - if (m_aBrainSaleIncomeLineIndices[metaPlayer] >= 0 && !m_IncomeSiteLines.empty()) - { - m_IncomeSiteLines[m_aBrainSaleIncomeLineIndices[metaPlayer]].m_CircleSize = 1.0; - m_IncomeSiteLines[m_aBrainSaleIncomeLineIndices[metaPlayer]].m_PlanetPoint.SetXY(m_apBrainPoolLabel[metaPlayer]->GetXPos() + (m_apBrainPoolLabel[metaPlayer]->GetHAlignment() == GUIFont::Left ? 5 : 16), m_apBrainPoolLabel[metaPlayer]->GetYPos() + 9); - // Compensate for the fact that we're tracking a screen UI element and not a planetary site - m_IncomeSiteLines[m_aBrainSaleIncomeLineIndices[metaPlayer]].m_PlanetPoint -= m_PlanetCenter; - } - } - - // Update the GUI Banners - m_pBannerRedTop->Update(); - m_pBannerRedBottom->Update(); - m_pBannerYellowTop->Update(); - m_pBannerYellowBottom->Update(); - - // Update the floating Player bars - UpdatePlayerBars(); - - // Save mouse pos for next frame so we can do dragging - if (m_EngageDrag) - m_PrevMousePos = mousePos; -} + // The brain pool counters might also be if player moves the player bar + if (m_aBrainSaleIncomeLineIndices[metaPlayer] >= 0 && !m_IncomeSiteLines.empty()) { + m_IncomeSiteLines[m_aBrainSaleIncomeLineIndices[metaPlayer]].m_CircleSize = 1.0; + m_IncomeSiteLines[m_aBrainSaleIncomeLineIndices[metaPlayer]].m_PlanetPoint.SetXY(m_apBrainPoolLabel[metaPlayer]->GetXPos() + (m_apBrainPoolLabel[metaPlayer]->GetHAlignment() == GUIFont::Left ? 5 : 16), m_apBrainPoolLabel[metaPlayer]->GetYPos() + 9); + // Compensate for the fact that we're tracking a screen UI element and not a planetary site + m_IncomeSiteLines[m_aBrainSaleIncomeLineIndices[metaPlayer]].m_PlanetPoint -= m_PlanetCenter; + } + } + // Update the GUI Banners + m_pBannerRedTop->Update(); + m_pBannerRedBottom->Update(); + m_pBannerYellowTop->Update(); + m_pBannerYellowBottom->Update(); + + // Update the floating Player bars + UpdatePlayerBars(); + + // Save mouse pos for next frame so we can do dragging + if (m_EngageDrag) + m_PrevMousePos = mousePos; +} ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the menu -void MetagameGUI::Draw(BITMAP *drawBitmap) -{ - // Don't draw site lines and dots if we're in the menus - if (!g_MetaMan.IsSuspended()) - { - // Transparency effect on the scene dots and lines - drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); - // Screen blend the dots and lines, with some flickering in its intensity +void MetagameGUI::Draw(BITMAP* drawBitmap) { + // Don't draw site lines and dots if we're in the menus + if (!g_MetaMan.IsSuspended()) { + // Transparency effect on the scene dots and lines + drawing_mode(DRAW_MODE_TRANS, 0, 0, 0); + // Screen blend the dots and lines, with some flickering in its intensity int blendAmount = 130 + RandomNum(-45, 45); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - - // Draw the scene location dots - Vector screenLocation; - BITMAP *pIcon = 0; - for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Only draw Scenes that are revealed yet - if (!(*sItr)->IsRevealed()) - continue; - - screenLocation = m_PlanetCenter + (*sItr)->GetLocation() + (*sItr)->GetLocationOffset(); - // If currently being shown as being fought over; make more dramatic - bool battleSite = m_PostBattleReview && (*sItr) == m_pAnimScene; - - // Find out what team we should show here.. it is not always the current team ownership; but might be a previous one temporarily displayed for dramatic effect - int team = battleSite ? m_PreBattleTeamOwnership : (*sItr)->GetTeamOwnership(); - - // Make sure team is within bounds to show an icon - pIcon = g_MetaMan.IsActiveTeam(team) ? g_MetaMan.GetTeamIcon(team).GetBitmaps32()[0] : 0; - if (pIcon) - masked_blit(pIcon, drawBitmap, 0, 0, screenLocation.m_X - (pIcon->w / 2), screenLocation.m_Y - (pIcon->h / 2), pIcon->w, pIcon->h); - // Ownership not known, so place nondescript dot instead - else - { - // Make it flicker more if it's currently being fought over + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + + // Draw the scene location dots + Vector screenLocation; + BITMAP* pIcon = 0; + for (std::vector::const_iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Only draw Scenes that are revealed yet + if (!(*sItr)->IsRevealed()) + continue; + + screenLocation = m_PlanetCenter + (*sItr)->GetLocation() + (*sItr)->GetLocationOffset(); + // If currently being shown as being fought over; make more dramatic + bool battleSite = m_PostBattleReview && (*sItr) == m_pAnimScene; + + // Find out what team we should show here.. it is not always the current team ownership; but might be a previous one temporarily displayed for dramatic effect + int team = battleSite ? m_PreBattleTeamOwnership : (*sItr)->GetTeamOwnership(); + + // Make sure team is within bounds to show an icon + pIcon = g_MetaMan.IsActiveTeam(team) ? g_MetaMan.GetTeamIcon(team).GetBitmaps32()[0] : 0; + if (pIcon) + masked_blit(pIcon, drawBitmap, 0, 0, screenLocation.m_X - (pIcon->w / 2), screenLocation.m_Y - (pIcon->h / 2), pIcon->w, pIcon->h); + // Ownership not known, so place nondescript dot instead + else { + // Make it flicker more if it's currently being fought over blendAmount = 95 + (battleSite ? RandomNum(-25, 25) : RandomNum(-15, 15)); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - circlefill(drawBitmap, screenLocation.m_X, screenLocation.m_Y, 4, c_GUIColorYellow); - circlefill(drawBitmap, screenLocation.m_X, screenLocation.m_Y, 2, c_GUIColorYellow); + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + circlefill(drawBitmap, screenLocation.m_X, screenLocation.m_Y, 4, c_GUIColorYellow); + circlefill(drawBitmap, screenLocation.m_X, screenLocation.m_Y, 2, c_GUIColorYellow); blendAmount = 210 + RandomNum(-45, 45); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - circlefill(drawBitmap, screenLocation.m_X, screenLocation.m_Y, 1, c_GUIColorYellow); - } - } - - // Draw the lines etc pointing at the selected Scene from the Scene Info box - if (m_pSelectedScene && m_pSceneInfoPopup->GetVisible() && !m_PreTurn) - { - Vector sceneInfoBoxPos(m_pSceneInfoPopup->GetXPos() + (m_pSceneInfoPopup->GetWidth() / 2), m_pSceneInfoPopup->GetYPos() + (m_pSceneInfoPopup->GetHeight() / 2)); - DrawScreenLineToSitePoint(drawBitmap, sceneInfoBoxPos, m_pSelectedScene->GetLocation() + m_pSelectedScene->GetLocationOffset(), c_GUIColorWhite, -1, -1, (m_pSceneInfoPopup->GetHeight() / 2) + CHAMFERSIZE + 6, 1.0, g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())); - } - - // Draw all the player income site lines we are supposed to - // for (vector::const_iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) - for (int slI = 0; slI < m_IncomeSiteLines.size(); ++slI) - { - // Don't draw these during state change frames, to avoid blinking things inappropriately - if (m_ContinuePhase || g_MetaMan.m_StateChanged) - continue; - // Only draw the lines of the active player, when we're not in RUNACTIVITIES state - if (g_MetaMan.m_GameState != MetaMan::RUNACTIVITIES && m_IncomeSiteLines[slI].m_Player != m_ActivePlayerIncomeLines) - continue; - // If this is the line currently being animated, report back if the line connected with the current parameters - if (slI == m_AnimIncomeLine) - m_LineConnected = DrawPlayerLineToSitePoint(drawBitmap, m_IncomeSiteLines[slI]) || m_LineConnected; - // Just draw the regular unanimated line - else - DrawPlayerLineToSitePoint(drawBitmap, m_IncomeSiteLines[slI]); - } - - // Action lines - // If during a player's round phase, and not showing any income lines - if (!m_PreTurn && !g_MetaMan.m_StateChanged && g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::BUILDBASES && m_ActivePlayerIncomeLines == Players::NoPlayer) - { - int metaPlayer = 0; - // Show the lines of the relevant player during turns - if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; - // If we're showing base building or attacks, then go with the currently animated player - else if (g_MetaMan.m_GameState == MetaMan::BUILDBASES && m_AnimMetaPlayer < g_MetaMan.m_Players.size()) - metaPlayer = m_AnimMetaPlayer; - - for (int slI = 0; slI < m_ActionSiteLines[metaPlayer].size(); ++slI) - { - // Only draw the lines of the active player -// if (m_ActionSiteLines[metaPlayer][slI].m_Player != m_ActivePlayerIncomeLines) -// continue; - // If this is the line currently being animated, report back if the line connected with the current parameters - if (slI == m_AnimActionLine) - m_LineConnected = DrawPlayerLineToSitePoint(drawBitmap, m_ActionSiteLines[metaPlayer][slI], m_ActionMeterDrawOverride) || m_LineConnected; - // Just draw the regular unanimated line - else - DrawPlayerLineToSitePoint(drawBitmap, m_ActionSiteLines[metaPlayer][slI], m_ActionMeterDrawOverride); - } - } - - // Draw the new site location crosshairs when revealing them - if (g_MetaMan.m_GameState == MetaMan::REVEALSCENES && !g_MetaMan.m_StateChanged) - { - for (std::vector::iterator stItr = m_NewSiteIndicators.begin(); stItr != m_NewSiteIndicators.end(); ++stItr) - (*stItr).Draw(drawBitmap); - } - - // Draw any site ownership change animations -// if (g_MetaMan.m_GameState == MetaMan::REVEALSCENES && !g_MetaMan.m_StateChanged) - { - for (std::vector::iterator stItr = m_SiteSwitchIndicators.begin(); stItr != m_SiteSwitchIndicators.end(); ++stItr) - (*stItr).Draw(drawBitmap); - } - - // Draw the attack activity crosshairs over the site being violated - if (g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES && !g_MetaMan.m_StateChanged) - { - // Draw the target crosshairs on the attacked site - m_SiteAttackTarget.Draw(drawBitmap); - - // Draw the attack lines that are currently being revealed by possibly multiple attackers - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - for (int slI = 0; slI < m_ActionSiteLines[metaPlayer].size(); ++slI) - { - DrawPlayerLineToSitePoint(drawBitmap, m_ActionSiteLines[metaPlayer][slI], m_ActionMeterDrawOverride); - } - } - } - } - - // Back to solid drawing - drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); - - // Draw the GUI elements first - AllegroScreen drawScreen(drawBitmap); - m_pGUIController->Draw(&drawScreen); - m_pGUIController->DrawMouse(); - - // Draw the banners on top of all GUI - if (!g_MetaMan.IsSuspended()) - { - m_pBannerRedTop->Draw(drawBitmap); - m_pBannerRedBottom->Draw(drawBitmap); - m_pBannerYellowTop->Draw(drawBitmap); - m_pBannerYellowBottom->Draw(drawBitmap); - } -} + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + circlefill(drawBitmap, screenLocation.m_X, screenLocation.m_Y, 1, c_GUIColorYellow); + } + } + + // Draw the lines etc pointing at the selected Scene from the Scene Info box + if (m_pSelectedScene && m_pSceneInfoPopup->GetVisible() && !m_PreTurn) { + Vector sceneInfoBoxPos(m_pSceneInfoPopup->GetXPos() + (m_pSceneInfoPopup->GetWidth() / 2), m_pSceneInfoPopup->GetYPos() + (m_pSceneInfoPopup->GetHeight() / 2)); + DrawScreenLineToSitePoint(drawBitmap, sceneInfoBoxPos, m_pSelectedScene->GetLocation() + m_pSelectedScene->GetLocationOffset(), c_GUIColorWhite, -1, -1, (m_pSceneInfoPopup->GetHeight() / 2) + CHAMFERSIZE + 6, 1.0, g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())); + } + + // Draw all the player income site lines we are supposed to + // for (vector::const_iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) + for (int slI = 0; slI < m_IncomeSiteLines.size(); ++slI) { + // Don't draw these during state change frames, to avoid blinking things inappropriately + if (m_ContinuePhase || g_MetaMan.m_StateChanged) + continue; + // Only draw the lines of the active player, when we're not in RUNACTIVITIES state + if (g_MetaMan.m_GameState != MetaMan::RUNACTIVITIES && m_IncomeSiteLines[slI].m_Player != m_ActivePlayerIncomeLines) + continue; + // If this is the line currently being animated, report back if the line connected with the current parameters + if (slI == m_AnimIncomeLine) + m_LineConnected = DrawPlayerLineToSitePoint(drawBitmap, m_IncomeSiteLines[slI]) || m_LineConnected; + // Just draw the regular unanimated line + else + DrawPlayerLineToSitePoint(drawBitmap, m_IncomeSiteLines[slI]); + } + + // Action lines + // If during a player's round phase, and not showing any income lines + if (!m_PreTurn && !g_MetaMan.m_StateChanged && g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::BUILDBASES && m_ActivePlayerIncomeLines == Players::NoPlayer) { + int metaPlayer = 0; + // Show the lines of the relevant player during turns + if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) + metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; + // If we're showing base building or attacks, then go with the currently animated player + else if (g_MetaMan.m_GameState == MetaMan::BUILDBASES && m_AnimMetaPlayer < g_MetaMan.m_Players.size()) + metaPlayer = m_AnimMetaPlayer; + + for (int slI = 0; slI < m_ActionSiteLines[metaPlayer].size(); ++slI) { + // Only draw the lines of the active player + // if (m_ActionSiteLines[metaPlayer][slI].m_Player != m_ActivePlayerIncomeLines) + // continue; + // If this is the line currently being animated, report back if the line connected with the current parameters + if (slI == m_AnimActionLine) + m_LineConnected = DrawPlayerLineToSitePoint(drawBitmap, m_ActionSiteLines[metaPlayer][slI], m_ActionMeterDrawOverride) || m_LineConnected; + // Just draw the regular unanimated line + else + DrawPlayerLineToSitePoint(drawBitmap, m_ActionSiteLines[metaPlayer][slI], m_ActionMeterDrawOverride); + } + } + // Draw the new site location crosshairs when revealing them + if (g_MetaMan.m_GameState == MetaMan::REVEALSCENES && !g_MetaMan.m_StateChanged) { + for (std::vector::iterator stItr = m_NewSiteIndicators.begin(); stItr != m_NewSiteIndicators.end(); ++stItr) + (*stItr).Draw(drawBitmap); + } + + // Draw any site ownership change animations + // if (g_MetaMan.m_GameState == MetaMan::REVEALSCENES && !g_MetaMan.m_StateChanged) + { + for (std::vector::iterator stItr = m_SiteSwitchIndicators.begin(); stItr != m_SiteSwitchIndicators.end(); ++stItr) + (*stItr).Draw(drawBitmap); + } + + // Draw the attack activity crosshairs over the site being violated + if (g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES && !g_MetaMan.m_StateChanged) { + // Draw the target crosshairs on the attacked site + m_SiteAttackTarget.Draw(drawBitmap); + + // Draw the attack lines that are currently being revealed by possibly multiple attackers + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + for (int slI = 0; slI < m_ActionSiteLines[metaPlayer].size(); ++slI) { + DrawPlayerLineToSitePoint(drawBitmap, m_ActionSiteLines[metaPlayer][slI], m_ActionMeterDrawOverride); + } + } + } + } + + // Back to solid drawing + drawing_mode(DRAW_MODE_SOLID, 0, 0, 0); + + // Draw the GUI elements first + AllegroScreen drawScreen(drawBitmap); + m_pGUIController->Draw(&drawScreen); + m_pGUIController->DrawMouse(); + + // Draw the banners on top of all GUI + if (!g_MetaMan.IsSuspended()) { + m_pBannerRedTop->Draw(drawBitmap); + m_pBannerRedBottom->Draw(drawBitmap); + m_pBannerYellowTop->Draw(drawBitmap); + m_pBannerYellowBottom->Draw(drawBitmap); + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateInput @@ -2079,9 +1910,8 @@ void MetagameGUI::Draw(BITMAP *drawBitmap) // Arguments: None. // Return value: None. -void MetagameGUI::UpdateInput() -{ - // If esc pressed, show campaign dialog if applicable +void MetagameGUI::UpdateInput() { + // If esc pressed, show campaign dialog if applicable if (g_UInputMan.KeyPressed(SDLK_ESCAPE)) { if (m_MenuScreen == MENUDIALOG) { g_MetaMan.SetSuspend(false); @@ -2094,81 +1924,80 @@ void MetagameGUI::UpdateInput() return; } - /////////////////////////////////////////////////////////// - // Mouse handling - - // Get mouse position - int mouseX, mouseY; - m_pGUIInput->GetMousePosition(&mouseX, &mouseY); - Vector mousePos(mouseX, mouseY); - - // If not currently dragging a box, see if we should start - bool menuButtonHeld = g_UInputMan.MenuButtonHeld(UInputMan::MENU_EITHER); - if (!m_pDraggedBox && menuButtonHeld && !m_EngageDrag) - { - GUICollectionBox *pBox = dynamic_cast(m_pGUIController->GetControlUnderPoint(mouseX, mouseY, m_apScreenBox[ROOTBOX], 1)); - - // Player bars - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - if (pBox == m_apPlayerBox[metaPlayer]) - m_pDraggedBox = pBox; - } - - // Scene info box? - if (pBox == m_pSceneInfoPopup) - m_pDraggedBox = pBox; - - // Phase box? - if (pBox == m_pPhaseBox) - m_pDraggedBox = pBox; - - // Save the mouse pos at the start of the drag so we can measure if we should engage - if (m_pDraggedBox) - m_PrevMousePos = mousePos; - } - // Release if button isn't being held - else if (!menuButtonHeld) - { - m_pDraggedBox = 0; - m_EngageDrag = false; - } - - // Figure out dragging of the player bars, if one is being dragged - if (m_pDraggedBox && !m_EngageDrag) - { - // Only start drag if we're over a threshold, to prevent small unintentional nudges - if ((mousePos - m_PrevMousePos).GetLargest() > 4) - m_EngageDrag = true; - } - - // Actually drag if we now are engaged - if (m_pDraggedBox && m_EngageDrag) - { - m_pDraggedBox->MoveRelative(mousePos.m_X - m_PrevMousePos.m_X, mousePos.m_Y - m_PrevMousePos.m_Y); - // Ensure the drag didn't shove it off-screen - KeepBoxOnScreen(m_pDraggedBox); - } - - ////////////////////////////////////////// - // Update the ControlManager - - m_pGUIController->Update(); - - ////////////////////////////////////////// - // Update the ToolTip popup - - // Show the ToolTip popup, if we are hovering over anything that has one to show + /////////////////////////////////////////////////////////// + // Mouse handling + + // Get mouse position + int mouseX, mouseY; + m_pGUIInput->GetMousePosition(&mouseX, &mouseY); + Vector mousePos(mouseX, mouseY); + + // If not currently dragging a box, see if we should start + bool menuButtonHeld = g_UInputMan.MenuButtonHeld(UInputMan::MENU_EITHER); + if (!m_pDraggedBox && menuButtonHeld && !m_EngageDrag) { + GUICollectionBox* pBox = dynamic_cast(m_pGUIController->GetControlUnderPoint(mouseX, mouseY, m_apScreenBox[ROOTBOX], 1)); + + // Player bars + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) { + if (pBox == m_apPlayerBox[metaPlayer]) + m_pDraggedBox = pBox; + } + + // Scene info box? + if (pBox == m_pSceneInfoPopup) + m_pDraggedBox = pBox; + + // Phase box? + if (pBox == m_pPhaseBox) + m_pDraggedBox = pBox; + + // Save the mouse pos at the start of the drag so we can measure if we should engage + if (m_pDraggedBox) + m_PrevMousePos = mousePos; + } + // Release if button isn't being held + else if (!menuButtonHeld) { + m_pDraggedBox = 0; + m_EngageDrag = false; + } + + // Figure out dragging of the player bars, if one is being dragged + if (m_pDraggedBox && !m_EngageDrag) { + // Only start drag if we're over a threshold, to prevent small unintentional nudges + if ((mousePos - m_PrevMousePos).GetLargest() > 4) + m_EngageDrag = true; + } + + // Actually drag if we now are engaged + if (m_pDraggedBox && m_EngageDrag) { + m_pDraggedBox->MoveRelative(mousePos.m_X - m_PrevMousePos.m_X, mousePos.m_Y - m_PrevMousePos.m_Y); + // Ensure the drag didn't shove it off-screen + KeepBoxOnScreen(m_pDraggedBox); + } + + ////////////////////////////////////////// + // Update the ControlManager + + m_pGUIController->Update(); + + ////////////////////////////////////////// + // Update the ToolTip popup + + // Show the ToolTip popup, if we are hovering over anything that has one to show std::string toolTip = ""; - GUIControl *pCurrentHover = m_pGUIController->GetControlUnderPoint(mouseX, mouseY); + GUIControl* pCurrentHover = m_pGUIController->GetControlUnderPoint(mouseX, mouseY); if (pCurrentHover) { toolTip = pCurrentHover->GetToolTip(); // The control's tooltip can end up being "True" for reasons unknown to man, so just clear it. - if (toolTip == "None" || toolTip == "True") { toolTip.clear(); } + if (toolTip == "None" || toolTip == "True") { + toolTip.clear(); + } } if (g_SettingsMan.ShowToolTips() && pCurrentHover && !toolTip.empty()) { // Restart timer if there's a new thing we're hovering over - if (pCurrentHover != m_pHoveredControl) { m_ToolTipTimer.Reset(); } + if (pCurrentHover != m_pHoveredControl) { + m_ToolTipTimer.Reset(); + } // If we've been hovering over the same thing for enough time, then show the tooltip if (m_ToolTipTimer.IsPastRealMS(500)) { @@ -2193,496 +2022,442 @@ void MetagameGUI::UpdateInput() m_pHoveredControl = nullptr; } - - /////////////////////////////////////// - // Handle events + /////////////////////////////////////// + // Handle events // Phase advance button pressed while in an unpaused game; set the signal flag at the end of input handling - bool phaseButtonPressed = !g_MetaMan.IsSuspended() && g_UInputMan.AnyStartPress(); + bool phaseButtonPressed = !g_MetaMan.IsSuspended() && g_UInputMan.AnyStartPress(); GUIEvent anEvent; - while(m_pGUIController->GetEvent(&anEvent)) - { + while (m_pGUIController->GetEvent(&anEvent)) { const std::string eventControlName = anEvent.GetControl()->GetName(); - // Commands - if (anEvent.GetType() == GUIEvent::Command) - { + // Commands + if (anEvent.GetType() == GUIEvent::Command) { // Open game menu button pressed // Most big dialog cancel buttons lead back to the game menu too if (eventControlName == "OpenMenuButton" || - eventControlName == "SaveCancelButton" || - eventControlName == "LoadCancelButton" || - (eventControlName == "NewCancelButton" && g_MetaMan.GameInProgress()) || - eventControlName == "ConfirmCancelButton") - { - g_MetaMan.SetSuspend(true); - SwitchToScreen(MENUDIALOG); - g_GUISound.BackButtonPressSound()->Play(); - } + eventControlName == "SaveCancelButton" || + eventControlName == "LoadCancelButton" || + (eventControlName == "NewCancelButton" && g_MetaMan.GameInProgress()) || + eventControlName == "ConfirmCancelButton") { + g_MetaMan.SetSuspend(true); + SwitchToScreen(MENUDIALOG); + g_GUISound.BackButtonPressSound()->Play(); + } // Return to main menu button pressed - else if (eventControlName == "MainMenuButton" || eventControlName == "NewCancelButton") - { - //Return Metagame dialog to new game state - // weegee SwitchToScreen(NEWDIALOG); - // Hide all screens, the appropriate screen will reappear on next update - HideAllScreens(); - if (g_MetaMan.m_GameState == MetaMan::GAMEOVER && g_ActivityMan.GetActivity()) { g_PostProcessMan.ClearScreenPostEffects(); } - // Signal that we want to go back to main menu - m_BackToMain = true; - g_GUISound.BackButtonPressSound()->Play(); - - } + else if (eventControlName == "MainMenuButton" || eventControlName == "NewCancelButton") { + // Return Metagame dialog to new game state + // weegee SwitchToScreen(NEWDIALOG); + // Hide all screens, the appropriate screen will reappear on next update + HideAllScreens(); + if (g_MetaMan.m_GameState == MetaMan::GAMEOVER && g_ActivityMan.GetActivity()) { + g_PostProcessMan.ClearScreenPostEffects(); + } + // Signal that we want to go back to main menu + m_BackToMain = true; + g_GUISound.BackButtonPressSound()->Play(); + + } // Open save menu button pressed - else if (eventControlName == "MenuSaveButton") - { - g_MetaMan.SetSuspend(true); - SwitchToScreen(SAVEDIALOG); - g_GUISound.ButtonPressSound()->Play(); - } + else if (eventControlName == "MenuSaveButton") { + g_MetaMan.SetSuspend(true); + SwitchToScreen(SAVEDIALOG); + g_GUISound.ButtonPressSound()->Play(); + } // Open load menu button pressed else if (eventControlName == "MenuLoadButton" || - eventControlName == "NewLoadButton") - { - g_MetaMan.SetSuspend(true); - SwitchToScreen(LOADDIALOG); - g_GUISound.ButtonPressSound()->Play(); - } + eventControlName == "NewLoadButton") { + g_MetaMan.SetSuspend(true); + SwitchToScreen(LOADDIALOG); + g_GUISound.ButtonPressSound()->Play(); + } // New Game menu button pressed - else if (eventControlName == "MenuNewButton") - { - g_MetaMan.SetSuspend(true); - SwitchToScreen(NEWDIALOG); - UpdatePlayerSetup(); - g_GUISound.ButtonPressSound()->Play(); - } + else if (eventControlName == "MenuNewButton") { + g_MetaMan.SetSuspend(true); + SwitchToScreen(NEWDIALOG); + UpdatePlayerSetup(); + g_GUISound.ButtonPressSound()->Play(); + } // Quit Program button pressed - else if (eventControlName == "MenuQuitButton") - { - HideAllScreens(); - g_MetaMan.SetSuspend(true); - m_pConfirmationLabel->SetText("Sure you want to quit to OS?\nAny unsaved progress\nwill be lost!"); - m_pConfirmationButton->SetText("Quit"); - m_pConfirmationBox->SetVisible(true); - g_GUISound.ButtonPressSound()->Play(); - } + else if (eventControlName == "MenuQuitButton") { + HideAllScreens(); + g_MetaMan.SetSuspend(true); + m_pConfirmationLabel->SetText("Sure you want to quit to OS?\nAny unsaved progress\nwill be lost!"); + m_pConfirmationButton->SetText("Quit"); + m_pConfirmationBox->SetVisible(true); + g_GUISound.ButtonPressSound()->Play(); + } // Resume Game menu button pressed - else if (eventControlName == "MenuResumeButton") - { - g_MetaMan.SetSuspend(false); - // If game over, then go to new game dialog on resume - if (g_MetaMan.m_GameState == MetaMan::GAMEOVER) - { - SwitchToScreen(NEWDIALOG); - UpdatePlayerSetup(); - } - else - SwitchToScreen(ROOTBOX); - g_GUISound.ButtonPressSound()->Play(); - } + else if (eventControlName == "MenuResumeButton") { + g_MetaMan.SetSuspend(false); + // If game over, then go to new game dialog on resume + if (g_MetaMan.m_GameState == MetaMan::GAMEOVER) { + SwitchToScreen(NEWDIALOG); + UpdatePlayerSetup(); + } else + SwitchToScreen(ROOTBOX); + g_GUISound.ButtonPressSound()->Play(); + } // Confirm button pressed - if (anEvent.GetControl() == m_apMetaButton[CONFIRM]) - { - // Confirm Quit Program button + if (anEvent.GetControl() == m_apMetaButton[CONFIRM]) { + // Confirm Quit Program button if (m_pConfirmationButton->GetText() == "Quit") System::SetQuit(); - // Do the appropriate thing depending on which screen we're confirming - if (m_MenuScreen == NEWDIALOG) - { -// if (m_apMetaButton[CONFIRM]->GetText() == "Load") -// ; -// else if (m_apMetaButton[CONFIRM]->GetText() == "Start New") - StartNewGame(); - } - else if (m_MenuScreen == LOADDIALOG) - { - LoadGame(); - // Switch directly into the game after a load is done - g_MetaMan.SetSuspend(false); - SwitchToScreen(ROOTBOX); - } - else if (m_MenuScreen == SAVEDIALOG) - { - SaveGameFromDialog(); - // Go back to the metagame menu after a save is done - SwitchToScreen(MENUDIALOG); - } - - g_MetaMan.SetSuspend(false); - SwitchToScreen(ROOTBOX); - - g_GUISound.ButtonPressSound()->Play(); - } - - // NEW GAME SETUP DIALOG - // Player Control Setup toggle buttons - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (anEvent.GetControl() == m_apPlayerControlButton[player]) - { - // Cycle through the different modes - if (m_apPlayerControlButton[player]->GetText() == "None") - m_apPlayerControlButton[player]->SetText("A.I."); - else if (m_apPlayerControlButton[player]->GetText() == "A.I.") - m_apPlayerControlButton[player]->SetText("Human"); - else - m_apPlayerControlButton[player]->SetText("None"); - // Show changes in affected player' gizmos - UpdatePlayerSetup(); - - g_GUISound.ButtonPressSound()->Play(); - } - } + // Do the appropriate thing depending on which screen we're confirming + if (m_MenuScreen == NEWDIALOG) { + // if (m_apMetaButton[CONFIRM]->GetText() == "Load") + // ; + // else if (m_apMetaButton[CONFIRM]->GetText() == "Start New") + StartNewGame(); + } else if (m_MenuScreen == LOADDIALOG) { + LoadGame(); + // Switch directly into the game after a load is done + g_MetaMan.SetSuspend(false); + SwitchToScreen(ROOTBOX); + } else if (m_MenuScreen == SAVEDIALOG) { + SaveGameFromDialog(); + // Go back to the metagame menu after a save is done + SwitchToScreen(MENUDIALOG); + } - // Start New Game menu button pressed - if (eventControlName == "StartButton") - { - // Current game needs saved or there will be data loss, so show confirmation box - if (!g_MetaMan.GameIsSaved()) - { - HideAllScreens(); - m_pConfirmationLabel->SetText("There is a game going!\nAny unsaved progress\nin it will be lost!"); - m_pConfirmationButton->SetText("Start New"); - m_pConfirmationBox->SetVisible(true); - } - else - StartNewGame(); - - g_GUISound.ButtonPressSound()->Play(); - } + g_MetaMan.SetSuspend(false); + SwitchToScreen(ROOTBOX); - // Save game button pressed - if (eventControlName == "SaveButton") - { - // Overwrite confirmation click has been done already - if (!m_NewSaveBox->GetText().empty() || m_apMetaButton[SAVENOW]->GetText() != "Save") - { - // Make sure there is somehting to save - if (!g_MetaMan.GameIsSaved()) - { -// TODO: WARN the player that they will have to re-play an offensive battle from start if they save a metagame -/* if () - { - HideAllScreens(); - m_pConfirmationLabel->SetText("There is an on-planet battle\ncurrently underway!\nThe progress in it will NOT be saved here;\nyou will have to re-play it\nif you load this game later!"); - m_pConfirmationButton->SetText("Save Anyway"); - m_pConfirmationBox->SetVisible(true); - } - else - { -*/ - SaveGameFromDialog(); - // Switch back to the menu after a save is done - SwitchToScreen(MENUDIALOG); -// } - } - g_GUISound.ButtonPressSound()->Play(); - } - else - { - m_apMetaButton[SAVENOW]->SetText("CONFIRM?"); - g_GUISound.ItemChangeSound()->Play(); - } - } + g_GUISound.ButtonPressSound()->Play(); + } + + // NEW GAME SETUP DIALOG + // Player Control Setup toggle buttons + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (anEvent.GetControl() == m_apPlayerControlButton[player]) { + // Cycle through the different modes + if (m_apPlayerControlButton[player]->GetText() == "None") + m_apPlayerControlButton[player]->SetText("A.I."); + else if (m_apPlayerControlButton[player]->GetText() == "A.I.") + m_apPlayerControlButton[player]->SetText("Human"); + else + m_apPlayerControlButton[player]->SetText("None"); + // Show changes in affected player' gizmos + UpdatePlayerSetup(); + + g_GUISound.ButtonPressSound()->Play(); + } + } + + // Start New Game menu button pressed + if (eventControlName == "StartButton") { + // Current game needs saved or there will be data loss, so show confirmation box + if (!g_MetaMan.GameIsSaved()) { + HideAllScreens(); + m_pConfirmationLabel->SetText("There is a game going!\nAny unsaved progress\nin it will be lost!"); + m_pConfirmationButton->SetText("Start New"); + m_pConfirmationBox->SetVisible(true); + } else + StartNewGame(); + + g_GUISound.ButtonPressSound()->Play(); + } + + // Save game button pressed + if (eventControlName == "SaveButton") { + // Overwrite confirmation click has been done already + if (!m_NewSaveBox->GetText().empty() || m_apMetaButton[SAVENOW]->GetText() != "Save") { + // Make sure there is somehting to save + if (!g_MetaMan.GameIsSaved()) { + // TODO: WARN the player that they will have to re-play an offensive battle from start if they save a metagame + /* if () + { + HideAllScreens(); + m_pConfirmationLabel->SetText("There is an on-planet battle\ncurrently underway!\nThe progress in it will NOT be saved here;\nyou will have to re-play it\nif you load this game later!"); + m_pConfirmationButton->SetText("Save Anyway"); + m_pConfirmationBox->SetVisible(true); + } + else + { + */ + SaveGameFromDialog(); + // Switch back to the menu after a save is done + SwitchToScreen(MENUDIALOG); + // } + } + g_GUISound.ButtonPressSound()->Play(); + } else { + m_apMetaButton[SAVENOW]->SetText("CONFIRM?"); + g_GUISound.ItemChangeSound()->Play(); + } + } // Load game button pressed - if (eventControlName == "LoadButton" && m_pSavesToLoadCombo->GetSelectedItem()) - { - // Save this Entity selection because the ComboBox gets cleared out when the conf dlg appears, so we can't get to the selection later when we acutally decide to load the damn thing - m_pSelectedGameToLoad = m_pSavesToLoadCombo->GetSelectedItem()->m_pEntity; - - // Current game needs saved or there will be data loss, so show conf box - if (!g_MetaMan.GameIsSaved()) - { - HideAllScreens(); - m_pConfirmationLabel->SetText("There is a game going!\nAny unsaved progress\nin it will be lost!"); - m_pConfirmationButton->SetText("Load"); - m_pConfirmationBox->SetVisible(true); - } - else - { - LoadGame(); - // Switch directly into the game after a load is done - g_MetaMan.SetSuspend(false); - SwitchToScreen(ROOTBOX); - } - - g_GUISound.ButtonPressSound()->Play(); - } + if (eventControlName == "LoadButton" && m_pSavesToLoadCombo->GetSelectedItem()) { + // Save this Entity selection because the ComboBox gets cleared out when the conf dlg appears, so we can't get to the selection later when we acutally decide to load the damn thing + m_pSelectedGameToLoad = m_pSavesToLoadCombo->GetSelectedItem()->m_pEntity; + + // Current game needs saved or there will be data loss, so show conf box + if (!g_MetaMan.GameIsSaved()) { + HideAllScreens(); + m_pConfirmationLabel->SetText("There is a game going!\nAny unsaved progress\nin it will be lost!"); + m_pConfirmationButton->SetText("Load"); + m_pConfirmationBox->SetVisible(true); + } else { + LoadGame(); + // Switch directly into the game after a load is done + g_MetaMan.SetSuspend(false); + SwitchToScreen(ROOTBOX); + } + + g_GUISound.ButtonPressSound()->Play(); + } // Graphical 'Continue Phase' button pressed; set the signal flag and handle at the end of UpdateInput if (anEvent.GetControl() == m_apMetaButton[CONTINUE]) - phaseButtonPressed = true; + phaseButtonPressed = true; // Scene Action button pressed; this only means to scan at this point - if (anEvent.GetControl() == m_apMetaButton[SCENEACTION] && m_pSelectedScene) - { - // Set up site scan of it (for a price) - int metaPlayer = g_MetaMan.GetPlayerTurn(); - int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); - // Check if we have enough money for this! - if (g_MetaMan.GetRemainingFundsOfPlayer(metaPlayer, 0, false, false) < SCANCOST) - { - m_apMetaButton[SCENEACTION]->SetText("NOT ENOUGH FUNDS!"); - g_GUISound.UserErrorSound()->Play(); - } - // Ask whether the player wants to scan now or later, with two new buttons - else - { - m_apMetaButton[SCENEACTION]->SetVisible(false); - m_apMetaButton[DESIGNBASE]->SetVisible(false); - m_apMetaButton[SCANNOW]->SetVisible(true); - m_apMetaButton[SCANLATER]->SetVisible(true); - m_pScanInfoLabel->SetVisible(true); - m_pScanInfoLabel->SetText("or"); - - g_GUISound.ButtonPressSound()->Play(); - } - } + if (anEvent.GetControl() == m_apMetaButton[SCENEACTION] && m_pSelectedScene) { + // Set up site scan of it (for a price) + int metaPlayer = g_MetaMan.GetPlayerTurn(); + int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); + // Check if we have enough money for this! + if (g_MetaMan.GetRemainingFundsOfPlayer(metaPlayer, 0, false, false) < SCANCOST) { + m_apMetaButton[SCENEACTION]->SetText("NOT ENOUGH FUNDS!"); + g_GUISound.UserErrorSound()->Play(); + } + // Ask whether the player wants to scan now or later, with two new buttons + else { + m_apMetaButton[SCENEACTION]->SetVisible(false); + m_apMetaButton[DESIGNBASE]->SetVisible(false); + m_apMetaButton[SCANNOW]->SetVisible(true); + m_apMetaButton[SCANLATER]->SetVisible(true); + m_pScanInfoLabel->SetVisible(true); + m_pScanInfoLabel->SetText("or"); + + g_GUISound.ButtonPressSound()->Play(); + } + } // manual Base Design button pressed; start an activity to let player design the blueprints to be built there - if (anEvent.GetControl() == m_apMetaButton[DESIGNBASE] && m_pSelectedScene) - { - // If owned by this player, then set up base building controls - if (m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(g_MetaMan.GetPlayerTurn())) - { - // Set up and start the editor activity for making changes to the base blueprint for this round - BaseEditor *pNewEditor = new BaseEditor; - pNewEditor->Create(); - char str[64]; - std::snprintf(str, sizeof(str), "R%dEdit", g_MetaMan.m_CurrentRound + 1); - pNewEditor->SetPresetName(g_MetaMan.GetGameName() + str); - - // Gotto deact all players since by default there is one in slot 1 - pNewEditor->ClearPlayers(); - // Editing player - int metaPlayer = g_MetaMan.GetPlayerTurn(); - int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); -// TODO: add all other players of same team, for coop editing?? Whata bout resident brains of lazy teammates who hacen't placed yet -// NO, this is silly. Just make the objects placed by this player marked as placed by him - pNewEditor->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), true, team, 0, &(g_MetaMan.GetTeamIcon(team))); - - // Send in the Scene to load in later when the screen has faded out etc - m_pPlayingScene = m_pSelectedScene; - g_SceneMan.SetSceneToLoad(m_pPlayingScene); - g_ActivityMan.SetStartActivity(pNewEditor); - m_ActivityRestarted = true; - - g_GUISound.ButtonPressSound()->Play(); - } - } + if (anEvent.GetControl() == m_apMetaButton[DESIGNBASE] && m_pSelectedScene) { + // If owned by this player, then set up base building controls + if (m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(g_MetaMan.GetPlayerTurn())) { + // Set up and start the editor activity for making changes to the base blueprint for this round + BaseEditor* pNewEditor = new BaseEditor; + pNewEditor->Create(); + char str[64]; + std::snprintf(str, sizeof(str), "R%dEdit", g_MetaMan.m_CurrentRound + 1); + pNewEditor->SetPresetName(g_MetaMan.GetGameName() + str); + + // Gotto deact all players since by default there is one in slot 1 + pNewEditor->ClearPlayers(); + // Editing player + int metaPlayer = g_MetaMan.GetPlayerTurn(); + int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); + // TODO: add all other players of same team, for coop editing?? Whata bout resident brains of lazy teammates who hacen't placed yet + // NO, this is silly. Just make the objects placed by this player marked as placed by him + pNewEditor->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), true, team, 0, &(g_MetaMan.GetTeamIcon(team))); + + // Send in the Scene to load in later when the screen has faded out etc + m_pPlayingScene = m_pSelectedScene; + g_SceneMan.SetSceneToLoad(m_pPlayingScene); + g_ActivityMan.SetStartActivity(pNewEditor); + m_ActivityRestarted = true; + + g_GUISound.ButtonPressSound()->Play(); + } + } // Scan Now button pressed; time to start the scanning process immediately - if (anEvent.GetControl() == m_apMetaButton[SCANNOW] && m_pSelectedScene) - { - int metaPlayer = g_MetaMan.GetPlayerTurn(); - int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); - // Actually change the player's funds - g_MetaMan.m_Players[metaPlayer].m_Funds -= SCANCOST; - // Set up and start the scripted activity for scanning the site for this' team - GAScripted *pScanActivity = new GAScripted; - pScanActivity->Create("Base.rte/Activities/SiteScan.lua", "SiteScan"); - char str[64]; - std::snprintf(str, sizeof(str), "R%dScan", g_MetaMan.m_CurrentRound + 1); - pScanActivity->SetPresetName(g_MetaMan.GetGameName() + str); - - // Gotto deact all players since by default there is one in slot 1 - pScanActivity->ClearPlayers(); - // Add the player who ordered this snooping around - pScanActivity->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), true, team, SCANCOST, &(g_MetaMan.GetTeamIcon(team))); - // Add the players who own this place, if any - their actors and brains are in the scene and should be shown - if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) - { - // Go through all players and add the ones of the defending team, based on who has resident brains here - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Got to remember to translate from metagame player index into the in-game player index and to flag them as not a human so they dont' get their own screens -// if (g_MetaMan.m_Players[mp].GetTeam() == m_pSelectedScene->GetTeamOwnership()) - if (m_pSelectedScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - pScanActivity->AddPlayer(g_MetaMan.m_Players[mp].GetInGamePlayer(), false, g_MetaMan.m_Players[mp].GetTeam(), 0, &(g_MetaMan.GetTeamIcon(g_MetaMan.m_Players[mp].GetTeam()))); - } - } - // Send in the Scene to load in later when the screen has faded out etc - m_pPlayingScene = m_pSelectedScene; - g_SceneMan.SetSceneToLoad(m_pPlayingScene); - g_ActivityMan.SetStartActivity(pScanActivity); - m_ActivityRestarted = true; - - g_GUISound.ButtonPressSound()->Play(); - } + if (anEvent.GetControl() == m_apMetaButton[SCANNOW] && m_pSelectedScene) { + int metaPlayer = g_MetaMan.GetPlayerTurn(); + int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); + // Actually change the player's funds + g_MetaMan.m_Players[metaPlayer].m_Funds -= SCANCOST; + // Set up and start the scripted activity for scanning the site for this' team + GAScripted* pScanActivity = new GAScripted; + pScanActivity->Create("Base.rte/Activities/SiteScan.lua", "SiteScan"); + char str[64]; + std::snprintf(str, sizeof(str), "R%dScan", g_MetaMan.m_CurrentRound + 1); + pScanActivity->SetPresetName(g_MetaMan.GetGameName() + str); + + // Gotto deact all players since by default there is one in slot 1 + pScanActivity->ClearPlayers(); + // Add the player who ordered this snooping around + pScanActivity->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), true, team, SCANCOST, &(g_MetaMan.GetTeamIcon(team))); + // Add the players who own this place, if any - their actors and brains are in the scene and should be shown + if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) { + // Go through all players and add the ones of the defending team, based on who has resident brains here + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Got to remember to translate from metagame player index into the in-game player index and to flag them as not a human so they dont' get their own screens + // if (g_MetaMan.m_Players[mp].GetTeam() == m_pSelectedScene->GetTeamOwnership()) + if (m_pSelectedScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) + pScanActivity->AddPlayer(g_MetaMan.m_Players[mp].GetInGamePlayer(), false, g_MetaMan.m_Players[mp].GetTeam(), 0, &(g_MetaMan.GetTeamIcon(g_MetaMan.m_Players[mp].GetTeam()))); + } + } + // Send in the Scene to load in later when the screen has faded out etc + m_pPlayingScene = m_pSelectedScene; + g_SceneMan.SetSceneToLoad(m_pPlayingScene); + g_ActivityMan.SetStartActivity(pScanActivity); + m_ActivityRestarted = true; + + g_GUISound.ButtonPressSound()->Play(); + } // Scan Later button pressed; mark the Scene for scanning by this metaplayer's team - if (anEvent.GetControl() == m_apMetaButton[SCANLATER] && m_pSelectedScene) - { - int metaPlayer = g_MetaMan.GetPlayerTurn(); - int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); - // Double-check to make sure we do have the funds to do this AND that the scan hasn't already been paid for - if (g_MetaMan.m_Players[metaPlayer].m_Funds < SCANCOST && !m_pSelectedScene->IsScanScheduled(team)) - g_GUISound.UserErrorSound()->Play(); - else - { - // Show the cost change the funds meter - FundsChangeIndication(metaPlayer, -SCANCOST, Vector(m_apPlayerBarLabel[metaPlayer]->GetXPos() + m_apPlayerBarLabel[metaPlayer]->GetWidth(), m_apPlayerBarLabel[metaPlayer]->GetYPos()), 2000); - // Actually change the player's funds - g_MetaMan.m_Players[metaPlayer].m_Funds -= SCANCOST; - - // Mark the selected Scene to be scanned next time it is loaded by a player of this' team - m_pSelectedScene->SetScheduledScan(team, true); - - // Update the scenes box to show that we have scheduled this scan - UpdateScenesBox(true); - - // Update the budget slider to reflect the scan cost being deducted from the funds - if (g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName() == m_pSelectedScene->GetPresetName()) - m_pSceneBudgetSlider->SetValue(std::floor((g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget() / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); - - // Play an appropriate sound to indicate that the scan is bought and scheduled - g_GUISound.ItemChangeSound()->Play(); - } - } + if (anEvent.GetControl() == m_apMetaButton[SCANLATER] && m_pSelectedScene) { + int metaPlayer = g_MetaMan.GetPlayerTurn(); + int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); + // Double-check to make sure we do have the funds to do this AND that the scan hasn't already been paid for + if (g_MetaMan.m_Players[metaPlayer].m_Funds < SCANCOST && !m_pSelectedScene->IsScanScheduled(team)) + g_GUISound.UserErrorSound()->Play(); + else { + // Show the cost change the funds meter + FundsChangeIndication(metaPlayer, -SCANCOST, Vector(m_apPlayerBarLabel[metaPlayer]->GetXPos() + m_apPlayerBarLabel[metaPlayer]->GetWidth(), m_apPlayerBarLabel[metaPlayer]->GetYPos()), 2000); + // Actually change the player's funds + g_MetaMan.m_Players[metaPlayer].m_Funds -= SCANCOST; + + // Mark the selected Scene to be scanned next time it is loaded by a player of this' team + m_pSelectedScene->SetScheduledScan(team, true); + + // Update the scenes box to show that we have scheduled this scan + UpdateScenesBox(true); + + // Update the budget slider to reflect the scan cost being deducted from the funds + if (g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName() == m_pSelectedScene->GetPresetName()) + m_pSceneBudgetSlider->SetValue(std::floor((g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget() / g_MetaMan.m_Players[metaPlayer].GetFunds()) * 100)); + + // Play an appropriate sound to indicate that the scan is bought and scheduled + g_GUISound.ItemChangeSound()->Play(); + } + } // Scene info box close button pressed - if (anEvent.GetControl() == m_pSceneCloseButton) - { - m_pSelectedScene = 0; - g_GUISound.ButtonPressSound()->Play(); - } - } + if (anEvent.GetControl() == m_pSceneCloseButton) { + m_pSelectedScene = 0; + g_GUISound.ButtonPressSound()->Play(); + } + } // Notifications - else if (anEvent.GetType() == GUIEvent::Notification) - { - // Button focus notification that we can play a sound to - if (dynamic_cast(anEvent.GetControl())) - { - if (anEvent.GetMsg() == GUIButton::Focused) - g_GUISound.SelectionChangeSound()->Play(); - // Also stop dragging any panels if we're over any button - m_pDraggedBox = 0; - m_EngageDrag = true; - } + else if (anEvent.GetType() == GUIEvent::Notification) { + // Button focus notification that we can play a sound to + if (dynamic_cast(anEvent.GetControl())) { + if (anEvent.GetMsg() == GUIButton::Focused) + g_GUISound.SelectionChangeSound()->Play(); + // Also stop dragging any panels if we're over any button + m_pDraggedBox = 0; + m_EngageDrag = true; + } // Site budget slider changed - if(anEvent.GetControl() == m_pSceneBudgetSlider) - { - // Update the appropriate budget var - if (m_pSelectedScene && !g_MetaMan.IsSuspended()) - { - // If during a player's round phase, figure out which player - if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - { - int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; - - // Update the scenes box - UpdateScenesBox(true); - - // If owned by this player, then set update base building budget for this Scene - float budget = ((float)m_pSceneBudgetSlider->GetValue() / 100.0f) * g_MetaMan.m_Players[metaPlayer].GetFunds(); - if (m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer)) - { - m_pSelectedScene->SetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), budget); - } - // Site owned by enemy player, update the attack budget - else if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) - { - g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(budget); - g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(m_pSelectedScene->GetPresetName()); - } - // Unowned site, update the expedition budget - else - { - g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(budget); - g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(m_pSelectedScene->GetPresetName()); - } - } - } - - // Also stop dragging any panels if we're over any button - m_pDraggedBox = 0; - m_EngageDrag = true; - } - - // Checkbox for changing the auto design setting of a scene changed; update the actual scene to reflect this - if (anEvent.GetControl() == m_pAutoDesignCheckbox && m_pSelectedScene) - { - if (anEvent.GetMsg() == GUICheckbox::Changed) - m_pSelectedScene->SetAutoDesigned(m_pAutoDesignCheckbox->GetCheck()); - } + if (anEvent.GetControl() == m_pSceneBudgetSlider) { + // Update the appropriate budget var + if (m_pSelectedScene && !g_MetaMan.IsSuspended()) { + // If during a player's round phase, figure out which player + if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) { + int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; + + // Update the scenes box + UpdateScenesBox(true); + + // If owned by this player, then set update base building budget for this Scene + float budget = ((float)m_pSceneBudgetSlider->GetValue() / 100.0f) * g_MetaMan.m_Players[metaPlayer].GetFunds(); + if (m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer)) { + m_pSelectedScene->SetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), budget); + } + // Site owned by enemy player, update the attack budget + else if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) { + g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(budget); + g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(m_pSelectedScene->GetPresetName()); + } + // Unowned site, update the expedition budget + else { + g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(budget); + g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(m_pSelectedScene->GetPresetName()); + } + } + } + + // Also stop dragging any panels if we're over any button + m_pDraggedBox = 0; + m_EngageDrag = true; + } + + // Checkbox for changing the auto design setting of a scene changed; update the actual scene to reflect this + if (anEvent.GetControl() == m_pAutoDesignCheckbox && m_pSelectedScene) { + if (anEvent.GetMsg() == GUICheckbox::Changed) + m_pSelectedScene->SetAutoDesigned(m_pAutoDesignCheckbox->GetCheck()); + } // Game Size slider changed - if(anEvent.GetControl() == m_pSizeSlider || anEvent.GetControl() == m_pGoldSlider || anEvent.GetControl() == m_pLengthSlider || anEvent.GetControl() == m_pDifficultySlider) - UpdateGameSizeLabels(); - - if(anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerOne]) - UpdateAISkillSliders(Players::PlayerOne); - if(anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerTwo]) - UpdateAISkillSliders(Players::PlayerTwo); - if(anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerThree]) - UpdateAISkillSliders(Players::PlayerThree); - if(anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerFour]) - UpdateAISkillSliders(Players::PlayerFour); - -/* Dun work so well, only if hovering naked box - // If hovering over any player bar, show the site lines going out from it - for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) - { - if (anEvent.GetControl() == m_apPlayerBox[metaPlayer]) - m_ActivePlayerIncomeLines = metaPlayer; - } -*/ - // Player flag selection changed - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (anEvent.GetControl() == m_apPlayerTeamSelect[player] && anEvent.GetMsg() == GUIComboBox::Closed) - { -/* Not relevant anymore, more than one Player can be of the same Team - // If some flag has been selected, make sure all other lists don't show the currently selected icon - if (m_apPlayerTeamSelect[player]->GetSelectedItem() && m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity) - { - for (int otherPlayer = Players::PlayerOne; otherPlayer < Players::MaxPlayerCount; ++otherPlayer) - { - if (player != otherPlayer && m_apPlayerTeamSelect[otherPlayer]->GetSelectedItem() && m_apPlayerTeamSelect[otherPlayer]->GetSelectedItem()->m_pEntity) - { - // They're the same, so swap them so they'll all stay unique - if (m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity->GetPresetName() == m_apPlayerTeamSelect[otherPlayer]->GetSelectedItem()->m_pEntity->GetPresetName()) - { - // Gotto use the old selection previous to the list opening - int swapIndex = m_apPlayerTeamSelect[player]->GetOldSelectionIndex(); - m_apPlayerTeamSelect[player]->SetSelectedIndex(m_apPlayerTeamSelect[otherPlayer]->GetSelectedIndex()); - m_apPlayerTeamSelect[otherPlayer]->SetSelectedIndex(swapIndex); - } - } - } - } -*/ + if (anEvent.GetControl() == m_pSizeSlider || anEvent.GetControl() == m_pGoldSlider || anEvent.GetControl() == m_pLengthSlider || anEvent.GetControl() == m_pDifficultySlider) + UpdateGameSizeLabels(); + + if (anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerOne]) + UpdateAISkillSliders(Players::PlayerOne); + if (anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerTwo]) + UpdateAISkillSliders(Players::PlayerTwo); + if (anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerThree]) + UpdateAISkillSliders(Players::PlayerThree); + if (anEvent.GetControl() == m_apPlayerAISkillSlider[Players::PlayerFour]) + UpdateAISkillSliders(Players::PlayerFour); + + /* Dun work so well, only if hovering naked box + // If hovering over any player bar, show the site lines going out from it + for (int metaPlayer = Players::PlayerOne; metaPlayer < Players::MaxPlayerCount; ++metaPlayer) + { + if (anEvent.GetControl() == m_apPlayerBox[metaPlayer]) + m_ActivePlayerIncomeLines = metaPlayer; + } + */ + // Player flag selection changed + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (anEvent.GetControl() == m_apPlayerTeamSelect[player] && anEvent.GetMsg() == GUIComboBox::Closed) { + /* Not relevant anymore, more than one Player can be of the same Team + // If some flag has been selected, make sure all other lists don't show the currently selected icon + if (m_apPlayerTeamSelect[player]->GetSelectedItem() && m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity) + { + for (int otherPlayer = Players::PlayerOne; otherPlayer < Players::MaxPlayerCount; ++otherPlayer) + { + if (player != otherPlayer && m_apPlayerTeamSelect[otherPlayer]->GetSelectedItem() && m_apPlayerTeamSelect[otherPlayer]->GetSelectedItem()->m_pEntity) + { + // They're the same, so swap them so they'll all stay unique + if (m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity->GetPresetName() == m_apPlayerTeamSelect[otherPlayer]->GetSelectedItem()->m_pEntity->GetPresetName()) + { + // Gotto use the old selection previous to the list opening + int swapIndex = m_apPlayerTeamSelect[player]->GetOldSelectionIndex(); + m_apPlayerTeamSelect[player]->SetSelectedIndex(m_apPlayerTeamSelect[otherPlayer]->GetSelectedIndex()); + m_apPlayerTeamSelect[otherPlayer]->SetSelectedIndex(swapIndex); + } + } + } + } + */ // Update sliders UpdateAISkillSliders(player); - UpdatePlayerSetup(); -// g_GUISound.ButtonPressSound()->Play(); - } - } - - // Load game combo box selection changed - if (anEvent.GetControl() == m_pSavesToLoadCombo && anEvent.GetMsg() == GUIComboBox::Closed) - { - // Get a handle to the actual game save Entity so we can extract its info - const MetaSave *pGame = 0; - GUIListPanel::Item *pItem = m_pSavesToLoadCombo->GetSelectedItem(); - if (pItem) - pGame = dynamic_cast(pItem->m_pEntity); - if (pGame) - { - // Update the game stats info box with the info of the selected game - char info[512]; + UpdatePlayerSetup(); + // g_GUISound.ButtonPressSound()->Play(); + } + } + + // Load game combo box selection changed + if (anEvent.GetControl() == m_pSavesToLoadCombo && anEvent.GetMsg() == GUIComboBox::Closed) { + // Get a handle to the actual game save Entity so we can extract its info + const MetaSave* pGame = 0; + GUIListPanel::Item* pItem = m_pSavesToLoadCombo->GetSelectedItem(); + if (pItem) + pGame = dynamic_cast(pItem->m_pEntity); + if (pGame) { + // Update the game stats info box with the info of the selected game + char info[512]; std::string difficultyString; if (pGame->GetDifficulty() < Activity::CakeDifficulty) @@ -2698,30 +2473,28 @@ void MetagameGUI::UpdateInput() else difficultyString = "Difficulty: Nuts!"; - std::snprintf(info, sizeof(info), "Game Size: %d sites\nTotal Players: %d\nDay: %d\n%s", pGame->GetSiteCount(), pGame->GetPlayerCount(), pGame->GetRoundCount() + 1, difficultyString.c_str()); - m_pLoadInfoLabel->SetText(info); - // Show the Load button since we have one locked in - m_apMetaButton[LOADNOW]->SetVisible(true); - } - // Hide the Load button if we don't have a valid game selected - else - m_apMetaButton[LOADNOW]->SetVisible(false); - // Play a ding - g_GUISound.ItemChangeSound()->Play(); - } - - // Save overwrite combo box selection changed - if (anEvent.GetControl() == m_pSavesToOverwriteCombo && anEvent.GetMsg() == GUIComboBox::Closed) - { - // Get a handle to the actual game save Entity so we can extract its info - const MetaSave *pGame = 0; - GUIListPanel::Item *pItem = m_pSavesToOverwriteCombo->GetSelectedItem(); - if (pItem) - pGame = dynamic_cast(pItem->m_pEntity); - if (pGame) - { - // Update the game stats info box with the info of the selected game - char info[512]; + std::snprintf(info, sizeof(info), "Game Size: %d sites\nTotal Players: %d\nDay: %d\n%s", pGame->GetSiteCount(), pGame->GetPlayerCount(), pGame->GetRoundCount() + 1, difficultyString.c_str()); + m_pLoadInfoLabel->SetText(info); + // Show the Load button since we have one locked in + m_apMetaButton[LOADNOW]->SetVisible(true); + } + // Hide the Load button if we don't have a valid game selected + else + m_apMetaButton[LOADNOW]->SetVisible(false); + // Play a ding + g_GUISound.ItemChangeSound()->Play(); + } + + // Save overwrite combo box selection changed + if (anEvent.GetControl() == m_pSavesToOverwriteCombo && anEvent.GetMsg() == GUIComboBox::Closed) { + // Get a handle to the actual game save Entity so we can extract its info + const MetaSave* pGame = 0; + GUIListPanel::Item* pItem = m_pSavesToOverwriteCombo->GetSelectedItem(); + if (pItem) + pGame = dynamic_cast(pItem->m_pEntity); + if (pGame) { + // Update the game stats info box with the info of the selected game + char info[512]; std::string difficultyString; if (pGame->GetDifficulty() < Activity::CakeDifficulty) @@ -2737,118 +2510,107 @@ void MetagameGUI::UpdateInput() else difficultyString = "Difficulty: Nuts!"; - std::snprintf(info, sizeof(info), "Game Size: %d sites\nTotal Players: %d\nDay: %d\n%s", pGame->GetSiteCount(), pGame->GetPlayerCount(), pGame->GetRoundCount() + 1, difficultyString.c_str()); - m_pSaveInfoLabel->SetText(info); - m_pSaveInfoLabel->SetVisible(true); - // Show the Save button since we have one to overwrite locked in - m_apMetaButton[SAVENOW]->SetVisible(true); - m_apMetaButton[SAVENOW]->SetText("Save"); - } - // Hide the Save button if we don't have a valid game selected, AND no new save name to use - else if (m_NewSaveBox->GetText().empty()) - { - m_pSaveInfoLabel->SetVisible(false); - m_apMetaButton[SAVENOW]->SetVisible(false); - } - - // Play a ding - g_GUISound.ItemChangeSound()->Play(); - } - } - } + std::snprintf(info, sizeof(info), "Game Size: %d sites\nTotal Players: %d\nDay: %d\n%s", pGame->GetSiteCount(), pGame->GetPlayerCount(), pGame->GetRoundCount() + 1, difficultyString.c_str()); + m_pSaveInfoLabel->SetText(info); + m_pSaveInfoLabel->SetVisible(true); + // Show the Save button since we have one to overwrite locked in + m_apMetaButton[SAVENOW]->SetVisible(true); + m_apMetaButton[SAVENOW]->SetText("Save"); + } + // Hide the Save button if we don't have a valid game selected, AND no new save name to use + else if (m_NewSaveBox->GetText().empty()) { + m_pSaveInfoLabel->SetVisible(false); + m_apMetaButton[SAVENOW]->SetVisible(false); + } + + // Play a ding + g_GUISound.ItemChangeSound()->Play(); + } + } + } // Phase advance button pressed; set the signal flag at the end of input handling - if (phaseButtonPressed) - { - // If we're in a pre-player-turn state, then continue out of it first - if (m_PreTurn && g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - m_PreTurn = false; - // If we/re going through offensive ativities, then that's what the continue button starts - else if (m_PreTurn && g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES) - m_PreTurn = false; - else if (g_MetaMan.m_GameState == MetaMan::GAMEOVER) - SwitchToScreen(MENUDIALOG); - else - m_ContinuePhase = true; - g_GUISound.ButtonPressSound()->Play(); - } + if (phaseButtonPressed) { + // If we're in a pre-player-turn state, then continue out of it first + if (m_PreTurn && g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) + m_PreTurn = false; + // If we/re going through offensive ativities, then that's what the continue button starts + else if (m_PreTurn && g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES) + m_PreTurn = false; + else if (g_MetaMan.m_GameState == MetaMan::GAMEOVER) + SwitchToScreen(MENUDIALOG); + else + m_ContinuePhase = true; + g_GUISound.ButtonPressSound()->Play(); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: HideAllScreens ////////////////////////////////////////////////////////////////////////////////////////// // Description: Hides all menu screens, so one can easily be unhidden and shown only. -void MetagameGUI::HideAllScreens() -{ - for (int iscreen = 0; iscreen < SCREENCOUNT; ++iscreen) - { - if (m_apScreenBox[iscreen] && iscreen != ROOTBOX) - m_apScreenBox[iscreen]->SetVisible(false); - } - - // Also hide the player bars - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - m_apPlayerBox[player]->SetVisible(false); - m_apBrainPoolLabel[player]->SetVisible(false); - m_apFundsChangeLabel[player]->SetVisible(false); - m_apBrainChangeLabel[player]->SetVisible(false); - m_apPlayerTeamActionBox[player]->SetVisible(false); - m_apPlayerBrainTravelLabel[player]->SetVisible(false); - } - - // Message label too - m_pGameMessageLabel->SetVisible(false); - - // And the phase, scene info, and confirmation boxes - m_pPhaseBox->SetVisible(false); - m_pSceneInfoPopup->SetVisible(false); - m_pConfirmationBox->SetVisible(false); - UpdateSiteNameLabel(false); - - // And the big text banners - m_pBannerRedTop->HideText(); - m_pBannerRedBottom->HideText(); - m_pBannerYellowTop->HideText(); - m_pBannerYellowBottom->HideText(); - - m_ScreenChange = true; -} +void MetagameGUI::HideAllScreens() { + for (int iscreen = 0; iscreen < SCREENCOUNT; ++iscreen) { + if (m_apScreenBox[iscreen] && iscreen != ROOTBOX) + m_apScreenBox[iscreen]->SetVisible(false); + } + + // Also hide the player bars + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + m_apPlayerBox[player]->SetVisible(false); + m_apBrainPoolLabel[player]->SetVisible(false); + m_apFundsChangeLabel[player]->SetVisible(false); + m_apBrainChangeLabel[player]->SetVisible(false); + m_apPlayerTeamActionBox[player]->SetVisible(false); + m_apPlayerBrainTravelLabel[player]->SetVisible(false); + } + + // Message label too + m_pGameMessageLabel->SetVisible(false); + + // And the phase, scene info, and confirmation boxes + m_pPhaseBox->SetVisible(false); + m_pSceneInfoPopup->SetVisible(false); + m_pConfirmationBox->SetVisible(false); + UpdateSiteNameLabel(false); + // And the big text banners + m_pBannerRedTop->HideText(); + m_pBannerRedBottom->HideText(); + m_pBannerYellowTop->HideText(); + m_pBannerYellowBottom->HideText(); + + m_ScreenChange = true; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: KeepBoxOnScreen ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes sure a specific box doesn't end up moved completely off-screen. -void MetagameGUI::KeepBoxOnScreen(GUICollectionBox *pBox, int margin) -{ - if (margin < 0) - { - // Use the dimensions of the box itself to prevent it from at all going outside the screen - if (pBox->GetXPos() < 0) - pBox->SetPositionAbs(0, pBox->GetYPos()); - if (pBox->GetXPos() > m_apScreenBox[ROOTBOX]->GetWidth() - pBox->GetWidth()) - pBox->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth() - pBox->GetWidth(), pBox->GetYPos()); - if (pBox->GetYPos() < 0) - pBox->SetPositionAbs(pBox->GetXPos(), 0); - if (pBox->GetYPos() > m_apScreenBox[ROOTBOX]->GetHeight() - pBox->GetHeight()) - pBox->SetPositionAbs(pBox->GetXPos(), m_apScreenBox[ROOTBOX]->GetHeight() - pBox->GetHeight()); - } - else - { - // Make sure the box doesn't go entirely outside of the screen - if (pBox->GetXPos() < (-pBox->GetWidth() + margin)) - pBox->SetPositionAbs(-pBox->GetWidth() + margin, pBox->GetYPos()); - if (pBox->GetXPos() > m_apScreenBox[ROOTBOX]->GetWidth() - margin) - pBox->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth() - margin, pBox->GetYPos()); - if (pBox->GetYPos() < (-pBox->GetHeight() + margin)) - pBox->SetPositionAbs(pBox->GetXPos(), -pBox->GetHeight() + margin); - if (pBox->GetYPos() > m_apScreenBox[ROOTBOX]->GetHeight() - margin) - pBox->SetPositionAbs(pBox->GetXPos(), m_apScreenBox[ROOTBOX]->GetHeight() - margin); - } +void MetagameGUI::KeepBoxOnScreen(GUICollectionBox* pBox, int margin) { + if (margin < 0) { + // Use the dimensions of the box itself to prevent it from at all going outside the screen + if (pBox->GetXPos() < 0) + pBox->SetPositionAbs(0, pBox->GetYPos()); + if (pBox->GetXPos() > m_apScreenBox[ROOTBOX]->GetWidth() - pBox->GetWidth()) + pBox->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth() - pBox->GetWidth(), pBox->GetYPos()); + if (pBox->GetYPos() < 0) + pBox->SetPositionAbs(pBox->GetXPos(), 0); + if (pBox->GetYPos() > m_apScreenBox[ROOTBOX]->GetHeight() - pBox->GetHeight()) + pBox->SetPositionAbs(pBox->GetXPos(), m_apScreenBox[ROOTBOX]->GetHeight() - pBox->GetHeight()); + } else { + // Make sure the box doesn't go entirely outside of the screen + if (pBox->GetXPos() < (-pBox->GetWidth() + margin)) + pBox->SetPositionAbs(-pBox->GetWidth() + margin, pBox->GetYPos()); + if (pBox->GetXPos() > m_apScreenBox[ROOTBOX]->GetWidth() - margin) + pBox->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth() - margin, pBox->GetYPos()); + if (pBox->GetYPos() < (-pBox->GetHeight() + margin)) + pBox->SetPositionAbs(pBox->GetXPos(), -pBox->GetHeight() + margin); + if (pBox->GetYPos() > m_apScreenBox[ROOTBOX]->GetHeight() - margin) + pBox->SetPositionAbs(pBox->GetXPos(), m_apScreenBox[ROOTBOX]->GetHeight() - margin); + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2857,148 +2619,137 @@ void MetagameGUI::KeepBoxOnScreen(GUICollectionBox *pBox, int margin) // Description: Handles what happens after an Activity within the Metagame was // run and completed fully. -void MetagameGUI::CompletedActivity() -{ - Activity *pDoneActivity = dynamic_cast(g_ActivityMan.GetActivity()); - GAScripted *pDoneScriptedActivity = dynamic_cast(g_ActivityMan.GetActivity()); - Scene *pAlteredScene = g_SceneMan.GetScene(); - bool autoResolved = false; - int winningTeam = Activity::NoTeam; - - // Retain any changes done to the Scene just played to the one that is kept by the MetaMan session - if (pDoneActivity && pAlteredScene && m_pPlayingScene) - { - // There was an error with the activity and it bailed.. try to recover - if (pDoneActivity->GetActivityState() == Activity::HasError) - { - m_AnimTimer2.Reset(); - m_apMetaButton[CONTINUE]->SetText("Start!"); - m_PreTurn = true; - } - // If a MetaFight activity isn't over yet, that means we're just pausing and will resume - else if (pDoneScriptedActivity && pDoneScriptedActivity->GetLuaClassName() == "MetaFight" && !pDoneActivity->IsOver()) - { - m_AnimTimer2.Reset(); - m_apMetaButton[CONTINUE]->SetText("Resume"); - m_BattleToResume = true; - m_PreTurn = true; - } - // All types of activites should be saving their scenes to disk - objects may have placed/stamped onto their layers - else - { - // Coming out of a base design session - if (pDoneActivity->GetClassName() == "BaseEditor") - { - // ? - } - // Site scan session - else if (pDoneScriptedActivity && pDoneScriptedActivity->GetLuaClassName() == "SiteScan") - { - // ? - } - // Offensive action session needs some things done after a battle is concluded - else if (pDoneScriptedActivity && pDoneScriptedActivity->GetLuaClassName() == "MetaFight") - { - if (pDoneActivity->IsOver()) - { - // If this ended for whatever reason without a winning team, then resolve the rest of the fight automatically - if (pDoneScriptedActivity->GetWinnerTeam() == Activity::NoTeam)//pDoneActivity->HumanBrainCount() == 0) - { - // Resolve the rest of the fight between the AI guys and display the outcome - m_BattleCausedOwnershipChange = AutoResolveOffensive(pDoneScriptedActivity, pAlteredScene, true); - - autoResolved = true; - winningTeam = pDoneScriptedActivity->GetWinnerTeam(); - } - // If it ended and is truly over, see if it resulted in a team ownership change - else - m_BattleCausedOwnershipChange = m_pPlayingScene->GetTeamOwnership() != pAlteredScene->GetTeamOwnership(); - - // Copy the completed activity back on the one in the queue that it started as, so we can grab parameters for the post battle review - g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->Destroy(); - g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->Create(*pDoneScriptedActivity); - // Scrub the module ID so the migration goes well.. this is a bit hacky, but ok in this special case - g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->SetModuleID(-1); - // Remind the Offensive that it is a unique snowflake and should save itself as such - g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->MigrateToModule(g_PresetMan.GetModuleID(METASAVEMODULENAME)); - - // We are now reviewing the battle after it has concluded; UpdateOffensives will show all that stuff - m_PreTurn = true; - m_PostBattleReview = true; - // Pause for a little to allow players to reorient themselves visually on the new screen before animaitons start happening - ChangeAnimMode(SHOWPOSTBATTLEPAUSE); - } - } - - // Transfer back the brain to the Scene as a resident AND collect the remaining funds left over - // UNLESS we're editing the base, which handles the brains specially by not actually placing them into the scene, but always keeping them as residents in the scene - // Also BaseEditor doesn't use funds at all, so there's nothing to collect - if (pDoneActivity->GetClassName() != "BaseEditor") - { - // Don't mess with this if activity was automatically resolved - then the resident brains and funds adjustments are already taken care of - if (!autoResolved) - pAlteredScene->RetrieveResidentBrains(*pDoneActivity); -/* Later in FinalizeOffensive - // Deduct the original funds contribution of each player - less any unused funds of the team, taking original player contribution ratios into account - for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - { -// ANIMATE THIS NICELY INSTEAD - // Deduct the player's original contribution to team funds - g_MetaMan.m_Players[metaPlayer].m_Funds -= pDoneActivity->GetPlayerFundsContribution(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); - // Add back whatever his share of whatever his team has left in the fight at its end - g_MetaMan.m_Players[metaPlayer].m_Funds += pDoneActivity->GetPlayerFundsShare(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); - // IF This guy was ATTACKING this turn, adjust his attack budget to match what just happened in the battle - // so in case he is defending in a upcoming battle this turn, his avaialbe funds will be accurately calculated - if (g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName() == m_pAnimScene->GetPresetName()) - { - g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer())); -// g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(""); - } - // Update the ratios of the meter now that the funds have changed - UpdatePlayerLineRatios(m_ActionSiteLines[metaPlayer], metaPlayer, false, g_MetaMan.m_Players[metaPlayer].m_Funds); - } -*/ - } - // Suck up all the remaining Actors and Items left in the world and put them into the list to place next load - // However, don't suck up actors of any non-winning team, and don't save the brains if we autoresolved, because that took care of placing the resident brains already - pAlteredScene->RetrieveSceneObjects(true, winningTeam, autoResolved); - // Save out the altered scene before clearing out its data from memory - pAlteredScene->SaveData(METASAVEPATH + std::string(AUTOSAVENAME) + " - " + pAlteredScene->GetPresetName(), false); - // Clear the bitmap data etc of the altered scene, we don't need to copy that over - pAlteredScene->ClearData(); +void MetagameGUI::CompletedActivity() { + Activity* pDoneActivity = dynamic_cast(g_ActivityMan.GetActivity()); + GAScripted* pDoneScriptedActivity = dynamic_cast(g_ActivityMan.GetActivity()); + Scene* pAlteredScene = g_SceneMan.GetScene(); + bool autoResolved = false; + int winningTeam = Activity::NoTeam; + + // Retain any changes done to the Scene just played to the one that is kept by the MetaMan session + if (pDoneActivity && pAlteredScene && m_pPlayingScene) { + // There was an error with the activity and it bailed.. try to recover + if (pDoneActivity->GetActivityState() == Activity::HasError) { + m_AnimTimer2.Reset(); + m_apMetaButton[CONTINUE]->SetText("Start!"); + m_PreTurn = true; + } + // If a MetaFight activity isn't over yet, that means we're just pausing and will resume + else if (pDoneScriptedActivity && pDoneScriptedActivity->GetLuaClassName() == "MetaFight" && !pDoneActivity->IsOver()) { + m_AnimTimer2.Reset(); + m_apMetaButton[CONTINUE]->SetText("Resume"); + m_BattleToResume = true; + m_PreTurn = true; + } + // All types of activites should be saving their scenes to disk - objects may have placed/stamped onto their layers + else { + // Coming out of a base design session + if (pDoneActivity->GetClassName() == "BaseEditor") { + // ? + } + // Site scan session + else if (pDoneScriptedActivity && pDoneScriptedActivity->GetLuaClassName() == "SiteScan") { + // ? + } + // Offensive action session needs some things done after a battle is concluded + else if (pDoneScriptedActivity && pDoneScriptedActivity->GetLuaClassName() == "MetaFight") { + if (pDoneActivity->IsOver()) { + // If this ended for whatever reason without a winning team, then resolve the rest of the fight automatically + if (pDoneScriptedActivity->GetWinnerTeam() == Activity::NoTeam) // pDoneActivity->HumanBrainCount() == 0) + { + // Resolve the rest of the fight between the AI guys and display the outcome + m_BattleCausedOwnershipChange = AutoResolveOffensive(pDoneScriptedActivity, pAlteredScene, true); + + autoResolved = true; + winningTeam = pDoneScriptedActivity->GetWinnerTeam(); + } + // If it ended and is truly over, see if it resulted in a team ownership change + else + m_BattleCausedOwnershipChange = m_pPlayingScene->GetTeamOwnership() != pAlteredScene->GetTeamOwnership(); + + // Copy the completed activity back on the one in the queue that it started as, so we can grab parameters for the post battle review + g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->Destroy(); + g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->Create(*pDoneScriptedActivity); + // Scrub the module ID so the migration goes well.. this is a bit hacky, but ok in this special case + g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->SetModuleID(-1); + // Remind the Offensive that it is a unique snowflake and should save itself as such + g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->MigrateToModule(g_PresetMan.GetModuleID(METASAVEMODULENAME)); + + // We are now reviewing the battle after it has concluded; UpdateOffensives will show all that stuff + m_PreTurn = true; + m_PostBattleReview = true; + // Pause for a little to allow players to reorient themselves visually on the new screen before animaitons start happening + ChangeAnimMode(SHOWPOSTBATTLEPAUSE); + } + } + + // Transfer back the brain to the Scene as a resident AND collect the remaining funds left over + // UNLESS we're editing the base, which handles the brains specially by not actually placing them into the scene, but always keeping them as residents in the scene + // Also BaseEditor doesn't use funds at all, so there's nothing to collect + if (pDoneActivity->GetClassName() != "BaseEditor") { + // Don't mess with this if activity was automatically resolved - then the resident brains and funds adjustments are already taken care of + if (!autoResolved) + pAlteredScene->RetrieveResidentBrains(*pDoneActivity); + /* Later in FinalizeOffensive + // Deduct the original funds contribution of each player - less any unused funds of the team, taking original player contribution ratios into account + for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) + { + // ANIMATE THIS NICELY INSTEAD + // Deduct the player's original contribution to team funds + g_MetaMan.m_Players[metaPlayer].m_Funds -= pDoneActivity->GetPlayerFundsContribution(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); + // Add back whatever his share of whatever his team has left in the fight at its end + g_MetaMan.m_Players[metaPlayer].m_Funds += pDoneActivity->GetPlayerFundsShare(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); + // IF This guy was ATTACKING this turn, adjust his attack budget to match what just happened in the battle + // so in case he is defending in a upcoming battle this turn, his avaialbe funds will be accurately calculated + if (g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName() == m_pAnimScene->GetPresetName()) + { + g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer())); + // g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(""); + } + // Update the ratios of the meter now that the funds have changed + UpdatePlayerLineRatios(m_ActionSiteLines[metaPlayer], metaPlayer, false, g_MetaMan.m_Players[metaPlayer].m_Funds); + } + */ + } + // Suck up all the remaining Actors and Items left in the world and put them into the list to place next load + // However, don't suck up actors of any non-winning team, and don't save the brains if we autoresolved, because that took care of placing the resident brains already + pAlteredScene->RetrieveSceneObjects(true, winningTeam, autoResolved); + // Save out the altered scene before clearing out its data from memory + pAlteredScene->SaveData(METASAVEPATH + std::string(AUTOSAVENAME) + " - " + pAlteredScene->GetPresetName(), false); + // Clear the bitmap data etc of the altered scene, we don't need to copy that over + pAlteredScene->ClearData(); // Clear waypoints on resident brains, otherwise when they're cloned they try to update their move paths, which requires a material bitmap (which we destroyed when we cleared data above). for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { - if (Actor *residentBrain = dynamic_cast(pAlteredScene->GetResidentBrain(player))) { + if (Actor* residentBrain = dynamic_cast(pAlteredScene->GetResidentBrain(player))) { residentBrain->ClearAIWaypoints(); } } - // Deep copy over all the edits made to the newly played Scene - m_pPlayingScene->Destroy(); - m_pPlayingScene->Create(*pAlteredScene); - // Null the current scene, which is pointed to by pAlteredScene. - g_SceneMan.ClearCurrentScene(); - // Scrub the module ID so the migration goes well.. this is a bit hacky, but ok in this special case - m_pPlayingScene->SetModuleID(-1); - m_pPlayingScene->GetTerrain()->SetModuleID(-1); - // Remind the Scene that it is a unique snowflake and should save itself as such - m_pPlayingScene->MigrateToModule(g_PresetMan.GetModuleID(METASAVEMODULENAME)); - // We're not playing this anymore - m_pPlayingScene = 0; - // Auto save the entire MetaMan state too -// Do this later in FinalizeOffensive, since the funds change until then -// SaveGame(AUTOSAVENAME, METASAVEPATH + string(AUTOSAVENAME) + ".ini", false); - - // Update the Scene info box since the scene might have changed - UpdateScenesBox(true); - - // Play some nice ambient music - g_AudioMan.PlayMusic("Base.rte/Music/Hubnester/ccmenu.ogg", -1, 0.4); - } - } + // Deep copy over all the edits made to the newly played Scene + m_pPlayingScene->Destroy(); + m_pPlayingScene->Create(*pAlteredScene); + // Null the current scene, which is pointed to by pAlteredScene. + g_SceneMan.ClearCurrentScene(); + // Scrub the module ID so the migration goes well.. this is a bit hacky, but ok in this special case + m_pPlayingScene->SetModuleID(-1); + m_pPlayingScene->GetTerrain()->SetModuleID(-1); + // Remind the Scene that it is a unique snowflake and should save itself as such + m_pPlayingScene->MigrateToModule(g_PresetMan.GetModuleID(METASAVEMODULENAME)); + // We're not playing this anymore + m_pPlayingScene = 0; + // Auto save the entire MetaMan state too + // Do this later in FinalizeOffensive, since the funds change until then + // SaveGame(AUTOSAVENAME, METASAVEPATH + string(AUTOSAVENAME) + ".ini", false); + + // Update the Scene info box since the scene might have changed + UpdateScenesBox(true); + + // Play some nice ambient music + g_AudioMan.PlayMusic("Base.rte/Music/Hubnester/ccmenu.ogg", -1, 0.4); + } + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: AutoResolveOffensive ////////////////////////////////////////////////////////////////////////////////////////// @@ -3006,439 +2757,391 @@ void MetagameGUI::CompletedActivity() // and going through an Activity. Will randomly determine who won and // what the consequences are. -bool MetagameGUI::AutoResolveOffensive(GAScripted *pOffensive, Scene *pScene, bool brainCheck) -{ - bool changedOwnership = false; - const Loadout *pLoadout = 0; - Actor *pBrain = 0; - float cost = 0; -/* - // Find the scene being attacked in this offensive Activity - Scene *pScene = 0; - for (vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == pOffensive->GetSceneName()) - pScene = (*sItr); - } -*/ - RTEAssert(pScene, "Couldn't find the Site that has been selected as auto resolution of an attack!"); - - // Check all players for active brains, and deactivate them if they don't have them - if (brainCheck) - { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - // Deactivate any players which had brains but don't anymore - ie they died and are not in the game anymore - if (pOffensive->PlayerActive(player) && pOffensive->PlayerHadBrain(player) && !pOffensive->GetPlayerBrain(player)) - pOffensive->DeactivatePlayer(player); - } - } - // If we're not making this check, we should assume all active players had a brain at some point - // This is effectively a simluation for pure offensive activities where no human player was ever involved - else - { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - // Simulate that all active players had a brain at some point - if (pOffensive->PlayerActive(player)) - pOffensive->SetPlayerHadBrain(player, true); - } - } - - // SINGLE player going to an unowned site.. it will be always be taken over, at some base cost of a brain landing - if (pOffensive->GetPlayerCount() == 1) - { - // Find out which single player is visiting this place, and grant him victory - int activePlayer = Players::NoPlayer; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (pOffensive->PlayerActive(player)) - { - activePlayer = player; - break; - } - } - // Add a resident brain to this scene for the AI player, based on the metaplayer's Loadout corresponding to its tech - MetaPlayer *pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(activePlayer); - if (pMetaPlayer) - { - // NOTE: Brain pool resource counter gets adjusted down in FinalizeOffense - - // Find the player's tech's brain, and instantiate it - if (pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Brain", pMetaPlayer->GetNativeTechModule()))) - pBrain = pLoadout->CreateFirstActor(pMetaPlayer->GetNativeTechModule(), pMetaPlayer->GetForeignCostMultiplier(), pMetaPlayer->GetNativeCostMultiplier(), cost); - // Pass the instance and ownership thereof to the scene as a resident - if (pBrain) - { - // Set a pos outside the Scene so it'll be gracefully placed later when Scene's Terrain is actually loaded - pBrain->SetPos(Vector(-1, -1)); +bool MetagameGUI::AutoResolveOffensive(GAScripted* pOffensive, Scene* pScene, bool brainCheck) { + bool changedOwnership = false; + const Loadout* pLoadout = 0; + Actor* pBrain = 0; + float cost = 0; + /* + // Find the scene being attacked in this offensive Activity + Scene *pScene = 0; + for (vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) + { + if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == pOffensive->GetSceneName()) + pScene = (*sItr); + } + */ + RTEAssert(pScene, "Couldn't find the Site that has been selected as auto resolution of an attack!"); + + // Check all players for active brains, and deactivate them if they don't have them + if (brainCheck) { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + // Deactivate any players which had brains but don't anymore - ie they died and are not in the game anymore + if (pOffensive->PlayerActive(player) && pOffensive->PlayerHadBrain(player) && !pOffensive->GetPlayerBrain(player)) + pOffensive->DeactivatePlayer(player); + } + } + // If we're not making this check, we should assume all active players had a brain at some point + // This is effectively a simluation for pure offensive activities where no human player was ever involved + else { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + // Simulate that all active players had a brain at some point + if (pOffensive->PlayerActive(player)) + pOffensive->SetPlayerHadBrain(player, true); + } + } + + // SINGLE player going to an unowned site.. it will be always be taken over, at some base cost of a brain landing + if (pOffensive->GetPlayerCount() == 1) { + // Find out which single player is visiting this place, and grant him victory + int activePlayer = Players::NoPlayer; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (pOffensive->PlayerActive(player)) { + activePlayer = player; + break; + } + } + // Add a resident brain to this scene for the AI player, based on the metaplayer's Loadout corresponding to its tech + MetaPlayer* pMetaPlayer = g_MetaMan.GetMetaPlayerOfInGamePlayer(activePlayer); + if (pMetaPlayer) { + // NOTE: Brain pool resource counter gets adjusted down in FinalizeOffense + + // Find the player's tech's brain, and instantiate it + if (pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Brain", pMetaPlayer->GetNativeTechModule()))) + pBrain = pLoadout->CreateFirstActor(pMetaPlayer->GetNativeTechModule(), pMetaPlayer->GetForeignCostMultiplier(), pMetaPlayer->GetNativeCostMultiplier(), cost); + // Pass the instance and ownership thereof to the scene as a resident + if (pBrain) { + // Set a pos outside the Scene so it'll be gracefully placed later when Scene's Terrain is actually loaded + pBrain->SetPos(Vector(-1, -1)); pBrain->SetTeam(pMetaPlayer->GetTeam()); - pScene->SetResidentBrain(activePlayer, pBrain); - // Set his team to own this place now - pScene->SetTeamOwnership(pOffensive->GetTeamOfPlayer(activePlayer)); - // Also declare winner of the activity - pOffensive->SetWinnerTeam(pOffensive->GetTeamOfPlayer(activePlayer)); - // Just mess with the funds; the metaplayers' funds will be affected afterward, according to their shares etc -// pOffensive->SetTeamFunds(pOffensive->GetTeamFunds(pOffensive->GetTeamOfPlayer(activePlayer)) * RandomNum(), pOffensive->GetTeamOfPlayer(activePlayer)); - // For now, just deduct the price of the brain - pOffensive->ChangeTeamFunds(-cost, pOffensive->GetTeamOfPlayer(activePlayer)); - // Signal that ownership of the site has changed - changedOwnership = true; - } - } - } - // MULTIPLE players are battling it out.. randomize the outcome - else - { - // First see if NO TEAM will get this - could be all brains die - if (RandomNum() < 0.05F) - { - // See if we should signal change of ownership - if (pScene->GetTeamOwnership() != Activity::NoTeam) - changedOwnership = true; - - // Eliminate all ownership of this place + pScene->SetResidentBrain(activePlayer, pBrain); + // Set his team to own this place now + pScene->SetTeamOwnership(pOffensive->GetTeamOfPlayer(activePlayer)); + // Also declare winner of the activity + pOffensive->SetWinnerTeam(pOffensive->GetTeamOfPlayer(activePlayer)); + // Just mess with the funds; the metaplayers' funds will be affected afterward, according to their shares etc + // pOffensive->SetTeamFunds(pOffensive->GetTeamFunds(pOffensive->GetTeamOfPlayer(activePlayer)) * RandomNum(), pOffensive->GetTeamOfPlayer(activePlayer)); + // For now, just deduct the price of the brain + pOffensive->ChangeTeamFunds(-cost, pOffensive->GetTeamOfPlayer(activePlayer)); + // Signal that ownership of the site has changed + changedOwnership = true; + } + } + } + // MULTIPLE players are battling it out.. randomize the outcome + else { + // First see if NO TEAM will get this - could be all brains die + if (RandomNum() < 0.05F) { + // See if we should signal change of ownership + if (pScene->GetTeamOwnership() != Activity::NoTeam) + changedOwnership = true; + + // Eliminate all ownership of this place pScene->RemoveAllPlacedActors(Activity::NoTeam); - pScene->SetTeamOwnership(Activity::NoTeam); - - // Each player's brain gets wiped out - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (pOffensive->PlayerActive(player)) - pScene->SetResidentBrain(player, 0); - } - } - // Okay, someone got this place - now figure out who - else - { - MetaPlayer * aMetaPlayers[Players::MaxPlayerCount]; - // The normalized scalar chances of each team to win - float aTeamChance[Activity::MaxTeamCount]; + pScene->SetTeamOwnership(Activity::NoTeam); + + // Each player's brain gets wiped out + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (pOffensive->PlayerActive(player)) + pScene->SetResidentBrain(player, 0); + } + } + // Okay, someone got this place - now figure out who + else { + MetaPlayer* aMetaPlayers[Players::MaxPlayerCount]; + // The normalized scalar chances of each team to win + float aTeamChance[Activity::MaxTeamCount]; for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) aTeamChance[team] = 0; - // The total number of 'chance' points that all teams have in aggregate - float totalPoints = 0; - - // Add the points representing the defense investment for the defenders - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - // Invested defenses counts for half the points.. some may have been destroyed, defense is harder etc - if (pOffensive->TeamActive(team) && pScene->GetTeamOwnership() == team) - aTeamChance[team] += pScene->GetTotalInvestment() / 2; - } - - // Now add the funds contributed by each player to each team's chance pool - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (pOffensive->PlayerActive(player)) - { - aMetaPlayers[player] = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); - // Add the funds contributed to this activity's attack or defense - if (aMetaPlayers[player]) - aTeamChance[aMetaPlayers[player]->GetTeam()] += pOffensive->GetPlayerFundsContribution(player); - } - } - - // Now tally up the total chance points - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - if (pOffensive->TeamActive(team)) - totalPoints += aTeamChance[team]; - } - // Normalize all the teams' chances - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - if (pOffensive->TeamActive(team)) - aTeamChance[team] = aTeamChance[team] / totalPoints; - } - // The deciding normalized scalar number - float decision = RandomNum(); - // Keeps track of the thresholds - float teamChanceTally = 0; - int winnerTeam = Activity::NoTeam; - // See who actually won, based on the respective chances - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - if (pOffensive->TeamActive(team)) - { - // Move the threshold forward - teamChanceTally += aTeamChance[team]; - // See if this team was chosen as winner - if (decision < teamChanceTally) - { - // Declare winner - winnerTeam = team; - // See if we should signal change of ownership - if (pScene->GetTeamOwnership() != winnerTeam) - changedOwnership = true; - // We have picked our winner and are done + // The total number of 'chance' points that all teams have in aggregate + float totalPoints = 0; + + // Add the points representing the defense investment for the defenders + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + // Invested defenses counts for half the points.. some may have been destroyed, defense is harder etc + if (pOffensive->TeamActive(team) && pScene->GetTeamOwnership() == team) + aTeamChance[team] += pScene->GetTotalInvestment() / 2; + } + + // Now add the funds contributed by each player to each team's chance pool + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (pOffensive->PlayerActive(player)) { + aMetaPlayers[player] = g_MetaMan.GetMetaPlayerOfInGamePlayer(player); + // Add the funds contributed to this activity's attack or defense + if (aMetaPlayers[player]) + aTeamChance[aMetaPlayers[player]->GetTeam()] += pOffensive->GetPlayerFundsContribution(player); + } + } + + // Now tally up the total chance points + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + if (pOffensive->TeamActive(team)) + totalPoints += aTeamChance[team]; + } + // Normalize all the teams' chances + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + if (pOffensive->TeamActive(team)) + aTeamChance[team] = aTeamChance[team] / totalPoints; + } + // The deciding normalized scalar number + float decision = RandomNum(); + // Keeps track of the thresholds + float teamChanceTally = 0; + int winnerTeam = Activity::NoTeam; + // See who actually won, based on the respective chances + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + if (pOffensive->TeamActive(team)) { + // Move the threshold forward + teamChanceTally += aTeamChance[team]; + // See if this team was chosen as winner + if (decision < teamChanceTally) { + // Declare winner + winnerTeam = team; + // See if we should signal change of ownership + if (pScene->GetTeamOwnership() != winnerTeam) + changedOwnership = true; + // We have picked our winner and are done // NOTE: Actual scene owners will be set below, along with removal of actors // and door replacements. - break; - } - } - } - - // Now change brain residencies if the ownership actually changed - if (changedOwnership) - { - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - pLoadout = 0; - pBrain = 0; - if (pOffensive->PlayerActive(player) && aMetaPlayers[player]) - { - // Winning player, so place a brain of his as a resident - if (aMetaPlayers[player]->GetTeam() == winnerTeam) - { - // NOTE: Brain pool resource counter gets adjusted down in FinalizeOffense - - // Find the player's tech's brain, and instantiate it - if (pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Brain", aMetaPlayers[player]->GetNativeTechModule()))) - pBrain = pLoadout->CreateFirstActor(aMetaPlayers[player]->GetNativeTechModule(), aMetaPlayers[player]->GetForeignCostMultiplier(), aMetaPlayers[player]->GetNativeCostMultiplier(), cost); - // Pass the instance and ownership thereof to the scene as a resident - if (pBrain) - { - // Set a pos outside the Scene so it'll be gracefully placed later when Scene's Terrain is actually loaded - pBrain->SetPos(Vector(-1, -1)); - pScene->SetResidentBrain(player, pBrain); - // Deduct the cost of the brain from the player's funds -// This is covered by the global cost adjustments below -// aMetaPlayers[player]->ChangeFunds(-cost); - } - // Change the ownership of all placed doors to the winning team - pScene->SetOwnerOfAllDoors(winnerTeam, player); - } - // Losing player, clear out his resident brain, if any - else - pScene->SetResidentBrain(player, 0); - } - // Nonexistent player, so clear out the resident brain just to be safe - else - pScene->SetResidentBrain(player, 0); - } - // Remove all remaining actors placed in blueprints etc by teams other than the winning one - pScene->RemoveAllPlacedActors(winnerTeam); - - // Actually change ownership and declare winner team - pScene->SetTeamOwnership(winnerTeam); - pOffensive->SetWinnerTeam(winnerTeam); - } - - // Figure out who of the losers actually evacuated instead of dying - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - // LOSER.. but evacuated successfully? - if (pOffensive->PlayerActive(player) && pOffensive->PlayerHadBrain(player) && aMetaPlayers[player] && aMetaPlayers[player]->GetTeam() != winnerTeam) - pOffensive->SetBrainEvacuated(player, RandomNum() < 0.25F); - } - } - - // Now make the party cost for all the teams - for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) - { - // Only mess with active teams - if (pOffensive->TeamActive(team)) - { - // Just mess with the funds; the metaplayers' funds will be affected afterward, according to their shares - // Never let team funds dip below 0 - pOffensive->SetTeamFunds(MAX(0, pOffensive->GetTeamFunds(team) * RandomNum()), team); - } - } - } - - return changedOwnership; -} + break; + } + } + } + + // Now change brain residencies if the ownership actually changed + if (changedOwnership) { + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + pLoadout = 0; + pBrain = 0; + if (pOffensive->PlayerActive(player) && aMetaPlayers[player]) { + // Winning player, so place a brain of his as a resident + if (aMetaPlayers[player]->GetTeam() == winnerTeam) { + // NOTE: Brain pool resource counter gets adjusted down in FinalizeOffense + + // Find the player's tech's brain, and instantiate it + if (pLoadout = dynamic_cast(g_PresetMan.GetEntityPreset("Loadout", "Infantry Brain", aMetaPlayers[player]->GetNativeTechModule()))) + pBrain = pLoadout->CreateFirstActor(aMetaPlayers[player]->GetNativeTechModule(), aMetaPlayers[player]->GetForeignCostMultiplier(), aMetaPlayers[player]->GetNativeCostMultiplier(), cost); + // Pass the instance and ownership thereof to the scene as a resident + if (pBrain) { + // Set a pos outside the Scene so it'll be gracefully placed later when Scene's Terrain is actually loaded + pBrain->SetPos(Vector(-1, -1)); + pScene->SetResidentBrain(player, pBrain); + // Deduct the cost of the brain from the player's funds + // This is covered by the global cost adjustments below + // aMetaPlayers[player]->ChangeFunds(-cost); + } + // Change the ownership of all placed doors to the winning team + pScene->SetOwnerOfAllDoors(winnerTeam, player); + } + // Losing player, clear out his resident brain, if any + else + pScene->SetResidentBrain(player, 0); + } + // Nonexistent player, so clear out the resident brain just to be safe + else + pScene->SetResidentBrain(player, 0); + } + // Remove all remaining actors placed in blueprints etc by teams other than the winning one + pScene->RemoveAllPlacedActors(winnerTeam); + + // Actually change ownership and declare winner team + pScene->SetTeamOwnership(winnerTeam); + pOffensive->SetWinnerTeam(winnerTeam); + } + + // Figure out who of the losers actually evacuated instead of dying + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + // LOSER.. but evacuated successfully? + if (pOffensive->PlayerActive(player) && pOffensive->PlayerHadBrain(player) && aMetaPlayers[player] && aMetaPlayers[player]->GetTeam() != winnerTeam) + pOffensive->SetBrainEvacuated(player, RandomNum() < 0.25F); + } + } + + // Now make the party cost for all the teams + for (int team = Activity::TeamOne; team < Activity::MaxTeamCount; ++team) { + // Only mess with active teams + if (pOffensive->TeamActive(team)) { + // Just mess with the funds; the metaplayers' funds will be affected afterward, according to their shares + // Never let team funds dip below 0 + pOffensive->SetTeamFunds(MAX(0, pOffensive->GetTeamFunds(team) * RandomNum()), team); + } + } + } + return changedOwnership; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateSiteRevealing ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the New Site Revealing animation -void MetagameGUI::UpdateSiteRevealing() -{ - // First set up all the targets we'll be animating into view - if (g_MetaMan.m_StateChanged) - { - // Save the number of sites we have reveelaed up til now so we can compare - m_AnimCountStart = m_AnimCountCurrent = (int)std::floor(g_MetaMan.m_RevealedScenes); - // Progress the number of site we have revealed with the set rate + the extra - g_MetaMan.m_RevealedScenes += g_MetaMan.m_RevealRate + g_MetaMan.m_RevealExtra; - // Reset the extra to 0 now after we've applied it - g_MetaMan.m_RevealExtra = 0; - // Don't reveal more than there are scenes! - if ((int)std::floor(g_MetaMan.m_RevealedScenes) >= g_MetaMan.m_Scenes.size()) - g_MetaMan.m_RevealedScenes = g_MetaMan.m_Scenes.size(); - // Figure out how many new sites we gots this round - int delta = (int)std::floor(g_MetaMan.m_RevealedScenes) - m_AnimCountStart; - // No new sites this round, so just continue onto next phase! - if (delta < 1) - { - m_ContinuePhase = true; - return; - } - // Where we need to go with the animation - m_AnimCountEnd = m_AnimCountStart + delta; - RTEAssert(m_AnimCountEnd <= g_MetaMan.m_Scenes.size(), "Trying to reveal more scenes than there are!"); - - // Clear and add target crosshairs pointing out all the new scenes - m_NewSiteIndicators.clear(); - m_AnimTimer1.Reset(); - // We want to start right away - m_AnimTimer1.SetElapsedRealTimeMS(1000); - m_AnimTimer2.Reset(); - } - - // Show a new set of crosshairs - if (m_AnimTimer1.GetElapsedRealTimeMS() > 600 && m_AnimCountCurrent < m_AnimCountEnd) - { - // Make the scene draw and selectable in the metagame view - g_MetaMan.m_Scenes[m_AnimCountCurrent]->SetRevealed(true); - // Create and set up its crosshairs -// TODO: TEMP change this back - m_NewSiteIndicators.push_back(SiteTarget(m_PlanetCenter + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocation() + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocationOffset(), 0, SiteTarget::CROSSHAIRSSHRINK, c_GUIColorYellow, m_AnimTimer2.GetElapsedRealTimeMS())); - m_SiteSwitchIndicators.push_back(SiteTarget(m_PlanetCenter + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocation() + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocationOffset(), 0, SiteTarget::CIRCLEGROW, c_GUIColorYellow, m_AnimTimer2.GetElapsedRealTimeMS())); - // Increment the current scene index - m_AnimCountCurrent++; - // Reset the timer so we will get the next reveal in the set time - m_AnimTimer1.Reset(); - } - - // Animate the existing crosshairs - double shrinkTime = 0; - double shrinkInterval = 600; - for (int i = 0 ; i < (m_AnimCountCurrent - m_AnimCountStart); ++i) - { - // How long have we been animating this one? - shrinkTime = m_AnimTimer2.GetElapsedRealTimeMS() - m_NewSiteIndicators[i].m_StartTime; - // If it's still in the shrink interval, keep doing it - if (shrinkTime < shrinkInterval) - m_NewSiteIndicators[i].m_AnimProgress = EaseOut(0.0, 1.0, shrinkTime / shrinkInterval); - // If it's after, then just keep pulsating the target - else - m_NewSiteIndicators[i].m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)shrinkTime % (int)shrinkInterval) / shrinkInterval); - } - - // Set the phase label grammatically correct - m_pPhaseLabel->SetText((m_AnimCountEnd - m_AnimCountStart) > 1 ? "Gold Sites Found!" : "Gold Site Found!"); - - // If we are done showing things, then make the continue button blink - if (m_NewSiteIndicators.size() == m_AnimCountEnd - m_AnimCountStart) - { - m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Continue <" : "Continue"); - } - - // Clean up if we're going onto next phase - if (m_ContinuePhase) - { - m_NewSiteIndicators.clear(); - - // Reveal all sites that are supposed to ahve been revelaed if player skipped the animation early - for (m_AnimCountCurrent = m_AnimCountStart; m_AnimCountCurrent < m_AnimCountEnd; ++m_AnimCountCurrent) - if (m_AnimCountCurrent < g_MetaMan.m_Scenes.size()) - g_MetaMan.m_Scenes[m_AnimCountCurrent]->SetRevealed(true); - } -} +void MetagameGUI::UpdateSiteRevealing() { + // First set up all the targets we'll be animating into view + if (g_MetaMan.m_StateChanged) { + // Save the number of sites we have reveelaed up til now so we can compare + m_AnimCountStart = m_AnimCountCurrent = (int)std::floor(g_MetaMan.m_RevealedScenes); + // Progress the number of site we have revealed with the set rate + the extra + g_MetaMan.m_RevealedScenes += g_MetaMan.m_RevealRate + g_MetaMan.m_RevealExtra; + // Reset the extra to 0 now after we've applied it + g_MetaMan.m_RevealExtra = 0; + // Don't reveal more than there are scenes! + if ((int)std::floor(g_MetaMan.m_RevealedScenes) >= g_MetaMan.m_Scenes.size()) + g_MetaMan.m_RevealedScenes = g_MetaMan.m_Scenes.size(); + // Figure out how many new sites we gots this round + int delta = (int)std::floor(g_MetaMan.m_RevealedScenes) - m_AnimCountStart; + // No new sites this round, so just continue onto next phase! + if (delta < 1) { + m_ContinuePhase = true; + return; + } + // Where we need to go with the animation + m_AnimCountEnd = m_AnimCountStart + delta; + RTEAssert(m_AnimCountEnd <= g_MetaMan.m_Scenes.size(), "Trying to reveal more scenes than there are!"); + + // Clear and add target crosshairs pointing out all the new scenes + m_NewSiteIndicators.clear(); + m_AnimTimer1.Reset(); + // We want to start right away + m_AnimTimer1.SetElapsedRealTimeMS(1000); + m_AnimTimer2.Reset(); + } + + // Show a new set of crosshairs + if (m_AnimTimer1.GetElapsedRealTimeMS() > 600 && m_AnimCountCurrent < m_AnimCountEnd) { + // Make the scene draw and selectable in the metagame view + g_MetaMan.m_Scenes[m_AnimCountCurrent]->SetRevealed(true); + // Create and set up its crosshairs + // TODO: TEMP change this back + m_NewSiteIndicators.push_back(SiteTarget(m_PlanetCenter + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocation() + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocationOffset(), 0, SiteTarget::CROSSHAIRSSHRINK, c_GUIColorYellow, m_AnimTimer2.GetElapsedRealTimeMS())); + m_SiteSwitchIndicators.push_back(SiteTarget(m_PlanetCenter + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocation() + g_MetaMan.m_Scenes[m_AnimCountCurrent]->GetLocationOffset(), 0, SiteTarget::CIRCLEGROW, c_GUIColorYellow, m_AnimTimer2.GetElapsedRealTimeMS())); + // Increment the current scene index + m_AnimCountCurrent++; + // Reset the timer so we will get the next reveal in the set time + m_AnimTimer1.Reset(); + } + + // Animate the existing crosshairs + double shrinkTime = 0; + double shrinkInterval = 600; + for (int i = 0; i < (m_AnimCountCurrent - m_AnimCountStart); ++i) { + // How long have we been animating this one? + shrinkTime = m_AnimTimer2.GetElapsedRealTimeMS() - m_NewSiteIndicators[i].m_StartTime; + // If it's still in the shrink interval, keep doing it + if (shrinkTime < shrinkInterval) + m_NewSiteIndicators[i].m_AnimProgress = EaseOut(0.0, 1.0, shrinkTime / shrinkInterval); + // If it's after, then just keep pulsating the target + else + m_NewSiteIndicators[i].m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)shrinkTime % (int)shrinkInterval) / shrinkInterval); + } + + // Set the phase label grammatically correct + m_pPhaseLabel->SetText((m_AnimCountEnd - m_AnimCountStart) > 1 ? "Gold Sites Found!" : "Gold Site Found!"); + + // If we are done showing things, then make the continue button blink + if (m_NewSiteIndicators.size() == m_AnimCountEnd - m_AnimCountStart) { + m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Continue <" : "Continue"); + } + + // Clean up if we're going onto next phase + if (m_ContinuePhase) { + m_NewSiteIndicators.clear(); + // Reveal all sites that are supposed to ahve been revelaed if player skipped the animation early + for (m_AnimCountCurrent = m_AnimCountStart; m_AnimCountCurrent < m_AnimCountEnd; ++m_AnimCountCurrent) + if (m_AnimCountCurrent < g_MetaMan.m_Scenes.size()) + g_MetaMan.m_Scenes[m_AnimCountCurrent]->SetRevealed(true); + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateSiteChangeAnim ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates team ownership change animations, if any. -void MetagameGUI::UpdateSiteChangeAnim() -{ - // Continue animating the existing markers - double animInterval = 600; - double animTime = 0; - for (std::vector::iterator itr = m_SiteSwitchIndicators.begin(); itr != m_SiteSwitchIndicators.end(); ++itr) - { - // How long have we been animating this one? - animTime = (*itr).m_AnimTimer.GetElapsedRealTimeMS(); - // If it's still in the shrink interval, keep doing it - if (animTime < animInterval) - (*itr).m_AnimProgress = EaseOut(0.0, 1.0, animTime / animInterval); -// // If it's after, then just keep pulsating the target -// else -// (*itr).m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)animTime % (int)animInterval) / animInterval); - } - - // Remove the markers that are done animating - for (std::vector::iterator itr = m_SiteSwitchIndicators.begin(); itr != m_SiteSwitchIndicators.end();) - { - if ((*itr).m_AnimTimer.GetElapsedRealTimeMS() > animInterval)//(*itr).m_AnimProgress >= 1.0) - { - m_SiteSwitchIndicators.erase(itr); - // Start over so we don't have trouble with invalidated iterators - itr = m_SiteSwitchIndicators.begin(); - } - else - itr++; - } -} +void MetagameGUI::UpdateSiteChangeAnim() { + // Continue animating the existing markers + double animInterval = 600; + double animTime = 0; + for (std::vector::iterator itr = m_SiteSwitchIndicators.begin(); itr != m_SiteSwitchIndicators.end(); ++itr) { + // How long have we been animating this one? + animTime = (*itr).m_AnimTimer.GetElapsedRealTimeMS(); + // If it's still in the shrink interval, keep doing it + if (animTime < animInterval) + (*itr).m_AnimProgress = EaseOut(0.0, 1.0, animTime / animInterval); + // // If it's after, then just keep pulsating the target + // else + // (*itr).m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)animTime % (int)animInterval) / animInterval); + } + // Remove the markers that are done animating + for (std::vector::iterator itr = m_SiteSwitchIndicators.begin(); itr != m_SiteSwitchIndicators.end();) { + if ((*itr).m_AnimTimer.GetElapsedRealTimeMS() > animInterval) //(*itr).m_AnimProgress >= 1.0) + { + m_SiteSwitchIndicators.erase(itr); + // Start over so we don't have trouble with invalidated iterators + itr = m_SiteSwitchIndicators.begin(); + } else + itr++; + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateIncomeCounting ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the Count Income animation -void MetagameGUI::UpdateIncomeCounting(bool initOverride) -{ - // First set up all the site lines we should be animating into view - if (g_MetaMan.m_StateChanged || initOverride) - { - // Make note of all funds from previous round - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - (*mpItr).m_PhaseStartFunds = (*mpItr).m_Funds; - - // If this is the very first round and no Scenes are owned yet, then we should just skip this - // Don't return out of this yet thuogh because there's some finalization going on in the end of this func - if (g_MetaMan.m_CurrentRound == 0) - m_ContinuePhase = true; - - // Init all the SiteLine:s and make them hidden; we will reveal each one sequentially with an animation - m_IncomeSiteLines.clear(); - for (int metaPlayer = 0; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - m_aStationIncomeLineIndices[metaPlayer] = -1; - m_AnimMetaPlayer = m_ActivePlayerIncomeLines = Players::PlayerOne; - m_pAnimScene = 0; - float totalRent, totalIncome, totalEndFunds; - int channelHeight; - // Loop through the players - do - { - // If this player is DONE FOR, skip income counting completely - if (g_MetaMan.GetTotalBrainCountOfPlayer(m_AnimMetaPlayer) <= 0 || - g_MetaMan.m_Players[m_AnimMetaPlayer].IsGameOverByRound(g_MetaMan.m_CurrentRound)) - { - m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] = -1; - UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer, false); - continue; - } - - // Only charge rent if there's any brains left in pool -// Make this rent variable somehow?? - totalRent = initOverride ? 0 : g_MetaMan.m_Players[m_AnimMetaPlayer].GetBrainPoolCount() > 0 ? TRADESTARRENT : 0; - totalIncome = initOverride ? 0 : g_MetaMan.GetSceneIncomeOfPlayer(m_AnimMetaPlayer); - totalEndFunds = g_MetaMan.m_Players[m_AnimMetaPlayer].m_PhaseStartFunds + totalIncome - totalRent; - channelHeight = 60; - - // TRADESTAR BANK ACCOUNT AND RENT - // Add line to show existing funds stored in space station, and deduct rent from - m_IncomeSiteLines.push_back(SiteLine(m_AnimMetaPlayer, 0, 1.0, m_StationPosOnOrbit, "TradeStar Midas", 0, c_GUIColorYellow, -1, 0, channelHeight, 2.0f)); - m_IncomeSiteLines.back().m_FundsAmount = g_MetaMan.m_Players[m_AnimMetaPlayer].m_PhaseStartFunds; - m_IncomeSiteLines.back().m_FundsTarget = m_IncomeSiteLines.back().m_FundsAmount - totalRent; - // Save the index so we can update the line later - m_aStationIncomeLineIndices[m_AnimMetaPlayer] = m_IncomeSiteLines.size() - 1; - - // SCENE INCOME - // Loop through the scenes owned by that player, setting up the site line for each +void MetagameGUI::UpdateIncomeCounting(bool initOverride) { + // First set up all the site lines we should be animating into view + if (g_MetaMan.m_StateChanged || initOverride) { + // Make note of all funds from previous round + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) + (*mpItr).m_PhaseStartFunds = (*mpItr).m_Funds; + + // If this is the very first round and no Scenes are owned yet, then we should just skip this + // Don't return out of this yet thuogh because there's some finalization going on in the end of this func + if (g_MetaMan.m_CurrentRound == 0) + m_ContinuePhase = true; + + // Init all the SiteLine:s and make them hidden; we will reveal each one sequentially with an animation + m_IncomeSiteLines.clear(); + for (int metaPlayer = 0; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) + m_aStationIncomeLineIndices[metaPlayer] = -1; + m_AnimMetaPlayer = m_ActivePlayerIncomeLines = Players::PlayerOne; + m_pAnimScene = 0; + float totalRent, totalIncome, totalEndFunds; + int channelHeight; + // Loop through the players + do { + // If this player is DONE FOR, skip income counting completely + if (g_MetaMan.GetTotalBrainCountOfPlayer(m_AnimMetaPlayer) <= 0 || + g_MetaMan.m_Players[m_AnimMetaPlayer].IsGameOverByRound(g_MetaMan.m_CurrentRound)) { + m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] = -1; + UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer, false); + continue; + } + + // Only charge rent if there's any brains left in pool + // Make this rent variable somehow?? + totalRent = initOverride ? 0 : g_MetaMan.m_Players[m_AnimMetaPlayer].GetBrainPoolCount() > 0 ? TRADESTARRENT + : 0; + totalIncome = initOverride ? 0 : g_MetaMan.GetSceneIncomeOfPlayer(m_AnimMetaPlayer); + totalEndFunds = g_MetaMan.m_Players[m_AnimMetaPlayer].m_PhaseStartFunds + totalIncome - totalRent; + channelHeight = 60; + + // TRADESTAR BANK ACCOUNT AND RENT + // Add line to show existing funds stored in space station, and deduct rent from + m_IncomeSiteLines.push_back(SiteLine(m_AnimMetaPlayer, 0, 1.0, m_StationPosOnOrbit, "TradeStar Midas", 0, c_GUIColorYellow, -1, 0, channelHeight, 2.0f)); + m_IncomeSiteLines.back().m_FundsAmount = g_MetaMan.m_Players[m_AnimMetaPlayer].m_PhaseStartFunds; + m_IncomeSiteLines.back().m_FundsTarget = m_IncomeSiteLines.back().m_FundsAmount - totalRent; + // Save the index so we can update the line later + m_aStationIncomeLineIndices[m_AnimMetaPlayer] = m_IncomeSiteLines.size() - 1; + + // SCENE INCOME + // Loop through the scenes owned by that player, setting up the site line for each if (!initOverride) { - while (m_pAnimScene = g_MetaMan.GetNextSceneOfPlayer(m_AnimMetaPlayer, m_pAnimScene)) - { + while (m_pAnimScene = g_MetaMan.GetNextSceneOfPlayer(m_AnimMetaPlayer, m_pAnimScene)) { m_IncomeSiteLines.push_back(SiteLine(m_AnimMetaPlayer, 1.0, 0, m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), m_pAnimScene->GetPresetName(), m_pAnimScene, c_GUIColorYellow, -1, 0, channelHeight, 1.0f, g_MetaMan.IsActiveTeam(m_pAnimScene->GetTeamOwnership()))); // Star them at 0, make them go to the round income for this base m_IncomeSiteLines.back().m_FundsAmount = 0; @@ -3447,764 +3150,659 @@ void MetagameGUI::UpdateIncomeCounting(bool initOverride) } } - // BRAIN LIQUIDATION if funds will end up under 0 - if (totalEndFunds <= 0 || g_MetaMan.GetTotalBrainCountOfPlayer(m_AnimMetaPlayer) <= 0) - { - m_IncomeSiteLines.push_back(SiteLine(m_AnimMetaPlayer, 1.0, 0, Vector(m_apBrainPoolLabel[m_AnimMetaPlayer]->GetXPos() + (m_apBrainPoolLabel[m_AnimMetaPlayer]->GetHAlignment() == GUIFont::Left ? 5 : 16), m_apBrainPoolLabel[m_AnimMetaPlayer]->GetYPos() + 9) - m_PlanetCenter, "Brain Liquidation", 0, c_GUIColorYellow, -1, 0, channelHeight, 2.0f, false)); - // Start at 0 and grow to how much the brain is worth - m_IncomeSiteLines.back().m_FundsAmount = 0; - m_IncomeSiteLines.back().m_FundsTarget = BRAINGOLDVALUE; - m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] = m_IncomeSiteLines.size() - 1; - } - else - m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] = -1; - - // This will set up all meter ratios properly, based on the actual funds numbers -// TODO, really?: "actually not a good idea here, the values above are good init" - UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer, false); - } - while (++m_AnimMetaPlayer < g_MetaMan.m_Players.size()); - - // Start animating these lines appearing, one after another - m_AnimIncomeLine = 0; - m_AnimIncomeLineChange = true; - m_AnimTimer1.Reset(); - ChangeAnimMode(PAUSEANIM); - } - - // Animate sitelines into view, one by one - if (!initOverride && !m_IncomeSiteLines.empty() && m_AnimIncomeLine < m_IncomeSiteLines.size()) - { - // Did the players change? If so, pause -// if (m_AnimMetaPlayer != m_IncomeSiteLines[m_AnimIncomeLine].m_Player && !m_AnimTimer1.IsPastRealMS(1000)) -// ChangeAnimMode(PAUSEANIM); - // If a new line, choose which animation is appropriate - if (m_AnimIncomeLineChange) - { - // Which player is this line of? - m_AnimMetaPlayer = m_ActivePlayerIncomeLines = m_IncomeSiteLines[m_AnimIncomeLine].m_Player; - // Station line, blink its meter and grow outward to the station - if (m_AnimIncomeLine == m_aStationIncomeLineIndices[m_AnimMetaPlayer]) - ChangeAnimMode(BLINKMETER); - // Regular site line, start with shrinking circle around the site and draw the line backward toward the bar - else - ChangeAnimMode(SHRINKCIRCLE); - - m_AnimIncomeLineChange = false; - } - - if (m_AnimMode == BLINKCIRCLE) - { -/* - // Show the meter - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = 1; - // Start blinking - if (!m_AnimTimer1.IsPastRealMS(600)) - { - m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(m_AnimTimer1.AlternateReal(150)); - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = m_AnimTimer1.AlternateReal(150) ? 0 : 1; - } - else - { - // Leave the label showing - m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(true); - // Start connecting the meter to the circle! - ChangeAnimMode(LINECONNECTFW); - } -*/ - } - else if (m_AnimMode == SHRINKCIRCLE) - { - if (NewAnimMode()) - { - m_AnimTimer1.Reset(); - // Start with the circle showing - m_AnimSegment = 1; - m_AnimFundsMax = 0; - m_LineConnected = false; - } - // Show the circle - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = m_AnimSegment; - // Show the site name over the site loc - UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint); - // Shrink by certain rate - if (!m_AnimTimer1.IsPastRealMS(350)) - { - // If line to space station, special case animation - if (m_AnimIncomeLine == m_aStationIncomeLineIndices[m_AnimMetaPlayer]) - m_IncomeSiteLines[m_AnimIncomeLine].m_CircleSize = EaseOut(20.0, 2.0, EaseOut(0, 1.0, m_AnimTimer1.GetElapsedRealTimeMS() / 350)); - else - m_IncomeSiteLines[m_AnimIncomeLine].m_CircleSize = EaseOut(7.0, 1.0, EaseOut(0, 1.0, m_AnimTimer1.GetElapsedRealTimeMS() / 350)); - - m_AnimTimer2.Reset(); - } - // Finished shrinking circle to the target size, now pause and blink it for a lil bit - else if (!m_AnimTimer2.IsPastRealMS(600)) - { - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = m_AnimTimer2.AlternateReal(150) ? 0 : 1; - // Also finish the circle in the destination size - m_IncomeSiteLines[m_AnimIncomeLine].m_CircleSize = m_AnimIncomeLine == m_aStationIncomeLineIndices[m_AnimMetaPlayer] ? 2.0 : 1.0; - } - else - { - // Start connecting the circle to the player bar! - ChangeAnimMode(LINECONNECTBW); - m_LineConnected = false; - } - } - else if (m_AnimMode == LINECONNECTFW) - { - if (NewAnimMode()) - { - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = 0; - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; - m_LineConnected = false; - // Hide the site name over the site loc at first - UpdateSiteNameLabel(false); - } - - // If line not yet connected, keep revealing segments - if (!m_LineConnected) - { - if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) - { - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = ++m_AnimSegment; - m_AnimTimer1.Reset(); - } - } -/* - // Oh! Line now completed, pause for a while before continuing to next line - else if (!m_AnimTimer1.IsPastRealMS(1500)) - { - // Show the site name over the site loc while we're waiting - UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint, 1.3); - } -*/ - // Done waiting, continue to next line - else - { - // If this is also the last line of a player, then do the retract animation -// if ((m_AnimIncomeLine + 1) >= m_IncomeSiteLines.size() || m_IncomeSiteLines[m_AnimIncomeLine + 1].m_Player != m_AnimMetaPlayer) -// ChangeAnimMode(RETRACTLINES); - // Just another line on the same player, so start animating it immediately -// else - { - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = -1; -/* - // Hide the site label again - UpdateSiteNameLabel(false); - m_AnimIncomeLine++; - m_AnimIncomeLineChange = true; -*/ - // Going to show rent being deducted from the tradestar - ChangeAnimMode(SHRINKMETER); - } - } - } - else if (m_AnimMode == LINECONNECTBW) - { - if (NewAnimMode()) - { - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = -1; - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = 0; - m_LineConnected = false; - } - // Show the site name over the site loc - UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint); - // Need to set up the ratio animation before we draw the line so it appears as the meter is 0 - if (m_AnimFundsMax == 0) - { - m_AnimFundsMax = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount; - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = 0; - } - - // If line not yet connected, keep revealing segments - if (!m_LineConnected) - { - if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) - { - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = ++m_AnimSegment; - m_AnimTimer1.Reset(); - } - } - // Oh! Line now completed, start growing the meter - else - ChangeAnimMode(GROWMETER); - } - else if (m_AnimMode == BLINKMETER) - { - if (NewAnimMode()) - { - m_AnimTimer1.Reset(); - // Show the meter - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = 1; - } - // Start blinking - if (!m_AnimTimer1.IsPastRealMS(1500)) - { - m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(m_AnimTimer1.AlternateReal(150)); - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = m_AnimTimer1.AlternateReal(150) ? 1 : 0; - } - else - { - // Leave the label showing - m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(true); - // Start connecting the meter to the circle! - ChangeAnimMode(LINECONNECTFW); - m_AnimSegment = 1; - } - } - // Grow each meter from 0 to its target ratio - else if (m_AnimMode == GROWMETER) - { - if (NewAnimMode()) - { - // Longer if we're liquidating brain.. it's important - m_AnimModeDuration = m_AnimIncomeLine == m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] ? 4000 : 2000; - m_AnimTimer1.Reset(); - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; - // Show the change - FundsChangeIndication(m_AnimMetaPlayer, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), m_AnimModeDuration); - - // Show the brain being sucked away if this is a brain liquidation income event - if (m_AnimIncomeLine == m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer]) - { - // This is the text label showing the brain going away - BrainsChangeIndication(m_AnimMetaPlayer, -1, Vector(m_apBrainPoolLabel[m_AnimMetaPlayer]->GetXPos(), m_apBrainPoolLabel[m_AnimMetaPlayer]->GetYPos()), m_apBrainPoolLabel[m_AnimMetaPlayer]->GetHAlignment(), m_AnimModeDuration); - // This is the display adjustment to the actual counter; the final actual change at the end of the animation - g_MetaMan.m_Players[m_AnimMetaPlayer].ChangeBrainsInTransit(1); - } - } - // Show the site name over the site loc - UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint); - // Grow for a certain amount of time - if (!m_AnimTimer1.IsPastRealMS(m_AnimModeDuration)) - { - // Make this animation correlate in duration with the funds change label that rises - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = EaseOut(0, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); - g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); - UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); - m_AnimTimer2.Reset(); - } - // Finished growing the meter to the target size - else - { - UpdateSiteNameLabel(false); - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget; - g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); - UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); - - // Check if there's more lines to draw, and if so, if the next one is of a different player - // OR if there's no lines left at all, just retract the last player's lines we just finished - // Then pause to retract all the lines of the just finished player - if ((m_AnimIncomeLine + 1) >= m_IncomeSiteLines.size() || m_IncomeSiteLines[m_AnimIncomeLine + 1].m_Player != m_AnimMetaPlayer) - { - // Wait for a little bit when we've displayed all sites of a player - if (m_AnimTimer2.IsPastRealMS(500)) - ChangeAnimMode(RETRACTLINES); - } - // Just another line on the same player, so start animating it immediately - else - { - m_AnimIncomeLine++; - m_AnimIncomeLineChange = true; - ChangeAnimMode(SHRINKCIRCLE); - } - } - } - // Shrink the station line to show it costing rent - else if (m_AnimMode == SHRINKMETER) - { - if (NewAnimMode()) - { - m_AnimModeDuration = 2000; - m_AnimTimer1.Reset(); - m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; - // Show the change, if any - if (fabs(m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount) > 0) - { - // Show why we are paying money - PlayerTextIndication(m_AnimMetaPlayer, "TradeStar brain storage rent", Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth() / 2), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetHeight() / 2)), m_AnimModeDuration); - FundsChangeIndication(m_AnimMetaPlayer, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), m_AnimModeDuration); - } - // Indicate why we're not paying anything - else - PlayerTextIndication(m_AnimMetaPlayer, "No brains; no rent!", Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth() / 2), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetHeight() / 2)), m_AnimModeDuration); - -/* This is done above on init now - // Only charge rent if we've still got brains at the tradestar - if (g_MetaMan.m_Players[m_AnimMetaPlayer].GetBrainPoolCount() > 0) - { - // Establish the after-rent target - m_AnimFundsMin = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount - TRADESTARRENT; - // Show the change in rent - FundsChangeIndication(m_AnimMetaPlayer, -TRADESTARRENT, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), 2000); - } - // No change in funds - else - m_AnimFundsMin = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount; -*/ - } - // Show the site name over the site loc -// UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint, 1.2); - // This'll always be the tradestar, so hardcode some descriptive text - UpdateSiteNameLabel(true, "TradeStar Midas", m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint, 1.25); - // Shrink for a certain amount of time - if (!m_AnimTimer1.IsPastRealMS(m_AnimModeDuration)) - { - // Make this animation correlate in duration with the funds change label that rises - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = EaseOut(g_MetaMan.m_Players[m_AnimMetaPlayer].m_PhaseStartFunds, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); - UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); - g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); - m_AnimTimer2.Reset(); - } - // Finished shrinking the meter to the target size - else - { - UpdateSiteNameLabel(false); - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget; - g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); - UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); - - // Check if there's more lines to draw, and if so, if the next one is of a different player - // OR if there's no lines left at all, just retract the last player's lines we just finished - // Then pause to retract all the lines of the just finished player - if ((m_AnimIncomeLine + 1) >= m_IncomeSiteLines.size() || m_IncomeSiteLines[m_AnimIncomeLine + 1].m_Player != m_AnimMetaPlayer) - { - // Wait for a little bit when we've displayed all sites of a player - if (m_AnimTimer2.IsPastRealMS(500)) - ChangeAnimMode(RETRACTLINES); - } - // Just another line on the same player, so start animating it immediately - else - { - m_AnimIncomeLine++; - m_AnimIncomeLineChange = true; - ChangeAnimMode(SHRINKCIRCLE); - } - } - } - // Retract all the lines for a specific player from the sites to the bar - else if (m_AnimMode == RETRACTLINES) - { - if (NewAnimMode()) - { - m_AnimTimer1.Reset(); - // A few extra will give some pause - m_AnimSegment = 7; - // Stop showing the site label - UpdateSiteNameLabel(false); - } - - if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) - { - m_AnimSegment--; - m_AnimTimer1.Reset(); - // Go through all lines and animate away the ones belonging to this player - for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) - { - if ((*slItr).m_Player == m_AnimMetaPlayer) - { - (*slItr).m_OnlyFirstSegments = m_AnimSegment; - (*slItr).m_OnlyLastSegments = -1; - } - } - } - if (m_AnimSegment == 0) - { - // Have another player's lines to animate, so start doing that - m_AnimIncomeLine++; - m_AnimIncomeLineChange = true; - ChangeAnimMode(SHRINKCIRCLE); - } - } - } - - // If no more lines, DONE, continue phase to next - if (m_AnimIncomeLine >= m_IncomeSiteLines.size() && !initOverride) - m_ContinuePhase = true; - - // Phase ending, make sure everything is set up to continue - if (m_ContinuePhase || initOverride) - { - // Set all lines' fund amounts to their targets and reset their segment animations so we can see them - int lineIndex = 0; - for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) - { - (*slItr).m_FundsAmount = (*slItr).m_FundsTarget; - (*slItr).m_OnlyFirstSegments = -1; - (*slItr).m_OnlyLastSegments = -1; - - // Also, if there are any brain liquidation lines, then adjust the brain counter for that poor player - if ((*slItr).m_Player >= Players::PlayerOne && (*slItr).m_Player < Players::MaxPlayerCount && - m_aBrainSaleIncomeLineIndices[(*slItr).m_Player] == lineIndex) - { - // Remove the display adjustment and APPLY the actual change to brains when one is liquidated - g_MetaMan.m_Players[(*slItr).m_Player].SetBrainsInTransit(0); - g_MetaMan.m_Players[(*slItr).m_Player].ChangeBrainPoolCount(-1); - } - // Keep this synched with the iterator - lineIndex++; - } - // Hide all lines for rendering.. appropriate lines will show up when user mouseovers bars in turn phases - m_ActivePlayerIncomeLines = -1; - - // Make sure all fund labels and line ratios are good - for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - { - UpdatePlayerLineRatios(m_IncomeSiteLines, metaPlayer, false); - m_apPlayerBarLabel[metaPlayer]->SetVisible(true); - // Set all funds to the final values, if not a gameover guy - if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) > 0) - g_MetaMan.m_Players[metaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, metaPlayer, false); - - if (g_SettingsMan.EndlessMetaGameMode()) - { + // BRAIN LIQUIDATION if funds will end up under 0 + if (totalEndFunds <= 0 || g_MetaMan.GetTotalBrainCountOfPlayer(m_AnimMetaPlayer) <= 0) { + m_IncomeSiteLines.push_back(SiteLine(m_AnimMetaPlayer, 1.0, 0, Vector(m_apBrainPoolLabel[m_AnimMetaPlayer]->GetXPos() + (m_apBrainPoolLabel[m_AnimMetaPlayer]->GetHAlignment() == GUIFont::Left ? 5 : 16), m_apBrainPoolLabel[m_AnimMetaPlayer]->GetYPos() + 9) - m_PlanetCenter, "Brain Liquidation", 0, c_GUIColorYellow, -1, 0, channelHeight, 2.0f, false)); + // Start at 0 and grow to how much the brain is worth + m_IncomeSiteLines.back().m_FundsAmount = 0; + m_IncomeSiteLines.back().m_FundsTarget = BRAINGOLDVALUE; + m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] = m_IncomeSiteLines.size() - 1; + } else + m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] = -1; + + // This will set up all meter ratios properly, based on the actual funds numbers + // TODO, really?: "actually not a good idea here, the values above are good init" + UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer, false); + } while (++m_AnimMetaPlayer < g_MetaMan.m_Players.size()); + + // Start animating these lines appearing, one after another + m_AnimIncomeLine = 0; + m_AnimIncomeLineChange = true; + m_AnimTimer1.Reset(); + ChangeAnimMode(PAUSEANIM); + } + + // Animate sitelines into view, one by one + if (!initOverride && !m_IncomeSiteLines.empty() && m_AnimIncomeLine < m_IncomeSiteLines.size()) { + // Did the players change? If so, pause + // if (m_AnimMetaPlayer != m_IncomeSiteLines[m_AnimIncomeLine].m_Player && !m_AnimTimer1.IsPastRealMS(1000)) + // ChangeAnimMode(PAUSEANIM); + // If a new line, choose which animation is appropriate + if (m_AnimIncomeLineChange) { + // Which player is this line of? + m_AnimMetaPlayer = m_ActivePlayerIncomeLines = m_IncomeSiteLines[m_AnimIncomeLine].m_Player; + // Station line, blink its meter and grow outward to the station + if (m_AnimIncomeLine == m_aStationIncomeLineIndices[m_AnimMetaPlayer]) + ChangeAnimMode(BLINKMETER); + // Regular site line, start with shrinking circle around the site and draw the line backward toward the bar + else + ChangeAnimMode(SHRINKCIRCLE); + + m_AnimIncomeLineChange = false; + } + + if (m_AnimMode == BLINKCIRCLE) { + /* + // Show the meter + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = 1; + // Start blinking + if (!m_AnimTimer1.IsPastRealMS(600)) + { + m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(m_AnimTimer1.AlternateReal(150)); + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = m_AnimTimer1.AlternateReal(150) ? 0 : 1; + } + else + { + // Leave the label showing + m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(true); + // Start connecting the meter to the circle! + ChangeAnimMode(LINECONNECTFW); + } + */ + } else if (m_AnimMode == SHRINKCIRCLE) { + if (NewAnimMode()) { + m_AnimTimer1.Reset(); + // Start with the circle showing + m_AnimSegment = 1; + m_AnimFundsMax = 0; + m_LineConnected = false; + } + // Show the circle + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = m_AnimSegment; + // Show the site name over the site loc + UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint); + // Shrink by certain rate + if (!m_AnimTimer1.IsPastRealMS(350)) { + // If line to space station, special case animation + if (m_AnimIncomeLine == m_aStationIncomeLineIndices[m_AnimMetaPlayer]) + m_IncomeSiteLines[m_AnimIncomeLine].m_CircleSize = EaseOut(20.0, 2.0, EaseOut(0, 1.0, m_AnimTimer1.GetElapsedRealTimeMS() / 350)); + else + m_IncomeSiteLines[m_AnimIncomeLine].m_CircleSize = EaseOut(7.0, 1.0, EaseOut(0, 1.0, m_AnimTimer1.GetElapsedRealTimeMS() / 350)); + + m_AnimTimer2.Reset(); + } + // Finished shrinking circle to the target size, now pause and blink it for a lil bit + else if (!m_AnimTimer2.IsPastRealMS(600)) { + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = m_AnimTimer2.AlternateReal(150) ? 0 : 1; + // Also finish the circle in the destination size + m_IncomeSiteLines[m_AnimIncomeLine].m_CircleSize = m_AnimIncomeLine == m_aStationIncomeLineIndices[m_AnimMetaPlayer] ? 2.0 : 1.0; + } else { + // Start connecting the circle to the player bar! + ChangeAnimMode(LINECONNECTBW); + m_LineConnected = false; + } + } else if (m_AnimMode == LINECONNECTFW) { + if (NewAnimMode()) { + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = 0; + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; + m_LineConnected = false; + // Hide the site name over the site loc at first + UpdateSiteNameLabel(false); + } + + // If line not yet connected, keep revealing segments + if (!m_LineConnected) { + if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) { + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = ++m_AnimSegment; + m_AnimTimer1.Reset(); + } + } + /* + // Oh! Line now completed, pause for a while before continuing to next line + else if (!m_AnimTimer1.IsPastRealMS(1500)) + { + // Show the site name over the site loc while we're waiting + UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint, 1.3); + } + */ + // Done waiting, continue to next line + else { + // If this is also the last line of a player, then do the retract animation + // if ((m_AnimIncomeLine + 1) >= m_IncomeSiteLines.size() || m_IncomeSiteLines[m_AnimIncomeLine + 1].m_Player != m_AnimMetaPlayer) + // ChangeAnimMode(RETRACTLINES); + // Just another line on the same player, so start animating it immediately + // else + { + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = -1; + /* + // Hide the site label again + UpdateSiteNameLabel(false); + m_AnimIncomeLine++; + m_AnimIncomeLineChange = true; + */ + // Going to show rent being deducted from the tradestar + ChangeAnimMode(SHRINKMETER); + } + } + } else if (m_AnimMode == LINECONNECTBW) { + if (NewAnimMode()) { + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = -1; + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = 0; + m_LineConnected = false; + } + // Show the site name over the site loc + UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint); + // Need to set up the ratio animation before we draw the line so it appears as the meter is 0 + if (m_AnimFundsMax == 0) { + m_AnimFundsMax = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount; + m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = 0; + } + + // If line not yet connected, keep revealing segments + if (!m_LineConnected) { + if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) { + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = ++m_AnimSegment; + m_AnimTimer1.Reset(); + } + } + // Oh! Line now completed, start growing the meter + else + ChangeAnimMode(GROWMETER); + } else if (m_AnimMode == BLINKMETER) { + if (NewAnimMode()) { + m_AnimTimer1.Reset(); + // Show the meter + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = 1; + } + // Start blinking + if (!m_AnimTimer1.IsPastRealMS(1500)) { + m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(m_AnimTimer1.AlternateReal(150)); + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyFirstSegments = m_AnimTimer1.AlternateReal(150) ? 1 : 0; + } else { + // Leave the label showing + m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(true); + // Start connecting the meter to the circle! + ChangeAnimMode(LINECONNECTFW); + m_AnimSegment = 1; + } + } + // Grow each meter from 0 to its target ratio + else if (m_AnimMode == GROWMETER) { + if (NewAnimMode()) { + // Longer if we're liquidating brain.. it's important + m_AnimModeDuration = m_AnimIncomeLine == m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer] ? 4000 : 2000; + m_AnimTimer1.Reset(); + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; + // Show the change + FundsChangeIndication(m_AnimMetaPlayer, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), m_AnimModeDuration); + + // Show the brain being sucked away if this is a brain liquidation income event + if (m_AnimIncomeLine == m_aBrainSaleIncomeLineIndices[m_AnimMetaPlayer]) { + // This is the text label showing the brain going away + BrainsChangeIndication(m_AnimMetaPlayer, -1, Vector(m_apBrainPoolLabel[m_AnimMetaPlayer]->GetXPos(), m_apBrainPoolLabel[m_AnimMetaPlayer]->GetYPos()), m_apBrainPoolLabel[m_AnimMetaPlayer]->GetHAlignment(), m_AnimModeDuration); + // This is the display adjustment to the actual counter; the final actual change at the end of the animation + g_MetaMan.m_Players[m_AnimMetaPlayer].ChangeBrainsInTransit(1); + } + } + // Show the site name over the site loc + UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint); + // Grow for a certain amount of time + if (!m_AnimTimer1.IsPastRealMS(m_AnimModeDuration)) { + // Make this animation correlate in duration with the funds change label that rises + m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = EaseOut(0, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); + g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); + UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); + m_AnimTimer2.Reset(); + } + // Finished growing the meter to the target size + else { + UpdateSiteNameLabel(false); + m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget; + g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); + UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); + + // Check if there's more lines to draw, and if so, if the next one is of a different player + // OR if there's no lines left at all, just retract the last player's lines we just finished + // Then pause to retract all the lines of the just finished player + if ((m_AnimIncomeLine + 1) >= m_IncomeSiteLines.size() || m_IncomeSiteLines[m_AnimIncomeLine + 1].m_Player != m_AnimMetaPlayer) { + // Wait for a little bit when we've displayed all sites of a player + if (m_AnimTimer2.IsPastRealMS(500)) + ChangeAnimMode(RETRACTLINES); + } + // Just another line on the same player, so start animating it immediately + else { + m_AnimIncomeLine++; + m_AnimIncomeLineChange = true; + ChangeAnimMode(SHRINKCIRCLE); + } + } + } + // Shrink the station line to show it costing rent + else if (m_AnimMode == SHRINKMETER) { + if (NewAnimMode()) { + m_AnimModeDuration = 2000; + m_AnimTimer1.Reset(); + m_IncomeSiteLines[m_AnimIncomeLine].m_OnlyLastSegments = -1; + // Show the change, if any + if (fabs(m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount) > 0) { + // Show why we are paying money + PlayerTextIndication(m_AnimMetaPlayer, "TradeStar brain storage rent", Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth() / 2), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetHeight() / 2)), m_AnimModeDuration); + FundsChangeIndication(m_AnimMetaPlayer, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget - m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), m_AnimModeDuration); + } + // Indicate why we're not paying anything + else + PlayerTextIndication(m_AnimMetaPlayer, "No brains; no rent!", Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth() / 2), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos() + (m_apPlayerBarLabel[m_AnimMetaPlayer]->GetHeight() / 2)), m_AnimModeDuration); + + /* This is done above on init now + // Only charge rent if we've still got brains at the tradestar + if (g_MetaMan.m_Players[m_AnimMetaPlayer].GetBrainPoolCount() > 0) + { + // Establish the after-rent target + m_AnimFundsMin = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount - TRADESTARRENT; + // Show the change in rent + FundsChangeIndication(m_AnimMetaPlayer, -TRADESTARRENT, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), 2000); + } + // No change in funds + else + m_AnimFundsMin = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount; + */ + } + // Show the site name over the site loc + // UpdateSiteNameLabel(true, m_IncomeSiteLines[m_AnimIncomeLine].m_SiteName, m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint, 1.2); + // This'll always be the tradestar, so hardcode some descriptive text + UpdateSiteNameLabel(true, "TradeStar Midas", m_IncomeSiteLines[m_AnimIncomeLine].m_PlanetPoint, 1.25); + // Shrink for a certain amount of time + if (!m_AnimTimer1.IsPastRealMS(m_AnimModeDuration)) { + // Make this animation correlate in duration with the funds change label that rises + m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = EaseOut(g_MetaMan.m_Players[m_AnimMetaPlayer].m_PhaseStartFunds, m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); + UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); + g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); + m_AnimTimer2.Reset(); + } + // Finished shrinking the meter to the target size + else { + UpdateSiteNameLabel(false); + m_IncomeSiteLines[m_AnimIncomeLine].m_FundsAmount = m_IncomeSiteLines[m_AnimIncomeLine].m_FundsTarget; + g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, m_AnimMetaPlayer); + UpdatePlayerLineRatios(m_IncomeSiteLines, m_AnimMetaPlayer); + + // Check if there's more lines to draw, and if so, if the next one is of a different player + // OR if there's no lines left at all, just retract the last player's lines we just finished + // Then pause to retract all the lines of the just finished player + if ((m_AnimIncomeLine + 1) >= m_IncomeSiteLines.size() || m_IncomeSiteLines[m_AnimIncomeLine + 1].m_Player != m_AnimMetaPlayer) { + // Wait for a little bit when we've displayed all sites of a player + if (m_AnimTimer2.IsPastRealMS(500)) + ChangeAnimMode(RETRACTLINES); + } + // Just another line on the same player, so start animating it immediately + else { + m_AnimIncomeLine++; + m_AnimIncomeLineChange = true; + ChangeAnimMode(SHRINKCIRCLE); + } + } + } + // Retract all the lines for a specific player from the sites to the bar + else if (m_AnimMode == RETRACTLINES) { + if (NewAnimMode()) { + m_AnimTimer1.Reset(); + // A few extra will give some pause + m_AnimSegment = 7; + // Stop showing the site label + UpdateSiteNameLabel(false); + } + + if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) { + m_AnimSegment--; + m_AnimTimer1.Reset(); + // Go through all lines and animate away the ones belonging to this player + for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) { + if ((*slItr).m_Player == m_AnimMetaPlayer) { + (*slItr).m_OnlyFirstSegments = m_AnimSegment; + (*slItr).m_OnlyLastSegments = -1; + } + } + } + if (m_AnimSegment == 0) { + // Have another player's lines to animate, so start doing that + m_AnimIncomeLine++; + m_AnimIncomeLineChange = true; + ChangeAnimMode(SHRINKCIRCLE); + } + } + } + + // If no more lines, DONE, continue phase to next + if (m_AnimIncomeLine >= m_IncomeSiteLines.size() && !initOverride) + m_ContinuePhase = true; + + // Phase ending, make sure everything is set up to continue + if (m_ContinuePhase || initOverride) { + // Set all lines' fund amounts to their targets and reset their segment animations so we can see them + int lineIndex = 0; + for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) { + (*slItr).m_FundsAmount = (*slItr).m_FundsTarget; + (*slItr).m_OnlyFirstSegments = -1; + (*slItr).m_OnlyLastSegments = -1; + + // Also, if there are any brain liquidation lines, then adjust the brain counter for that poor player + if ((*slItr).m_Player >= Players::PlayerOne && (*slItr).m_Player < Players::MaxPlayerCount && + m_aBrainSaleIncomeLineIndices[(*slItr).m_Player] == lineIndex) { + // Remove the display adjustment and APPLY the actual change to brains when one is liquidated + g_MetaMan.m_Players[(*slItr).m_Player].SetBrainsInTransit(0); + g_MetaMan.m_Players[(*slItr).m_Player].ChangeBrainPoolCount(-1); + } + // Keep this synched with the iterator + lineIndex++; + } + // Hide all lines for rendering.. appropriate lines will show up when user mouseovers bars in turn phases + m_ActivePlayerIncomeLines = -1; + + // Make sure all fund labels and line ratios are good + for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) { + UpdatePlayerLineRatios(m_IncomeSiteLines, metaPlayer, false); + m_apPlayerBarLabel[metaPlayer]->SetVisible(true); + // Set all funds to the final values, if not a gameover guy + if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) > 0) + g_MetaMan.m_Players[metaPlayer].m_Funds = GetPlayerLineFunds(m_IncomeSiteLines, metaPlayer, false); + + if (g_SettingsMan.EndlessMetaGameMode()) { g_MetaMan.m_Players[metaPlayer].ChangeBrainPoolCount(20 - g_MetaMan.m_Players[metaPlayer].GetBrainPoolCount()); g_MetaMan.m_Players[metaPlayer].ChangeFunds(10000 - g_MetaMan.m_Players[metaPlayer].GetFunds()); } - } - } + } + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateHumanPlayerTurn ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates a human player's turn -void MetagameGUI::UpdateHumanPlayerTurn(int metaPlayer) -{ - // In-game player - IMPORTANT to pass this to the Scenes, and not the metaplayer - int player = g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(); - - // First do setup - if (g_MetaMan.m_StateChanged) - { - // Reset the target so we don't put the player into autopilot (and also he might not have brains to deploy!) - g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(0); - g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(""); - // Re-set up all build budgets in oz to match what the player spent on this site last round, proportionally - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Only mess with Scenes we can see and that are owned by this player, and he spent something on last turn - if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam() && (*sItr)->GetBuildBudgetRatio(player) > 0) - (*sItr)->SetBuildBudget(player, g_MetaMan.m_Players[metaPlayer].GetFunds() * (*sItr)->GetBuildBudgetRatio(player)); - } - } - - // Phase ENDING, make sure everything is set up to continue - if (m_ContinuePhase) - { - // Save all the base building budget ratios sowe can re-set the gold values next turn, for player convenience - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Only mess with Scenes we can see and that are owned by this player, and he spent something on last turn - if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam() && g_MetaMan.m_Players[metaPlayer].GetFunds() > 0) - (*sItr)->SetBuildBudgetRatio(player, (*sItr)->GetBuildBudget(player) / g_MetaMan.m_Players[metaPlayer].GetFunds()); - else - (*sItr)->SetBuildBudgetRatio(player, 0); - } - - // Hide the game message label - m_pGameMessageLabel->SetVisible(false); - } -} +void MetagameGUI::UpdateHumanPlayerTurn(int metaPlayer) { + // In-game player - IMPORTANT to pass this to the Scenes, and not the metaplayer + int player = g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(); + + // First do setup + if (g_MetaMan.m_StateChanged) { + // Reset the target so we don't put the player into autopilot (and also he might not have brains to deploy!) + g_MetaMan.m_Players[metaPlayer].SetOffensiveBudget(0); + g_MetaMan.m_Players[metaPlayer].SetOffensiveTargetName(""); + // Re-set up all build budgets in oz to match what the player spent on this site last round, proportionally + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Only mess with Scenes we can see and that are owned by this player, and he spent something on last turn + if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam() && (*sItr)->GetBuildBudgetRatio(player) > 0) + (*sItr)->SetBuildBudget(player, g_MetaMan.m_Players[metaPlayer].GetFunds() * (*sItr)->GetBuildBudgetRatio(player)); + } + } + // Phase ENDING, make sure everything is set up to continue + if (m_ContinuePhase) { + // Save all the base building budget ratios sowe can re-set the gold values next turn, for player convenience + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Only mess with Scenes we can see and that are owned by this player, and he spent something on last turn + if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam() && g_MetaMan.m_Players[metaPlayer].GetFunds() > 0) + (*sItr)->SetBuildBudgetRatio(player, (*sItr)->GetBuildBudget(player) / g_MetaMan.m_Players[metaPlayer].GetFunds()); + else + (*sItr)->SetBuildBudgetRatio(player, 0); + } + + // Hide the game message label + m_pGameMessageLabel->SetVisible(false); + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateBaseBuilding ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the Base Building animation -void MetagameGUI::UpdateBaseBuilding() -{ - m_pPhaseLabel->SetText("Building Bases"); - - // First do setup - if (g_MetaMan.m_StateChanged) - { - // Make sure all fund labels and line ratios are good - for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - { - // Save the fund levels FROM THE START so we can calculate the after state if players skip the animation - g_MetaMan.m_Players[metaPlayer].m_PhaseStartFunds = g_MetaMan.m_Players[metaPlayer].m_Funds; - - // Update the player action lines for all players one last time; this will catch the AI ones as well and reflect their actions - UpdatePlayerActionLines(metaPlayer); - - // Hide all lines so we only see their meters - for (std::vector::iterator slItr = m_ActionSiteLines[metaPlayer].begin(); slItr != m_ActionSiteLines[metaPlayer].end(); ++slItr) - { - (*slItr).m_OnlyFirstSegments = 1; - (*slItr).m_OnlyLastSegments = -1; - } - UpdatePlayerLineRatios(m_ActionSiteLines[metaPlayer], metaPlayer, false, g_MetaMan.m_Players[metaPlayer].m_Funds); - - // Also, for human players, auto design their blueprints if they have chosen to do so - if (g_MetaMan.m_Players[metaPlayer].IsHuman()) - { - // Go through all scenes and check if they're owned by this, and if so, whether their defenses should be automatically designed by canned AI plan - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Move building pieces from the Scene's AI plan queue to the actual blueprints, but only approximately as much as can afford, so the entire AI pre-built base plan isn't revealed - if ((*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam() && (*sItr)->GetAutoDesigned()) - (*sItr)->ApplyAIPlan(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); - } - } - } - - // Start animating these defensive lines appearing, one after another - m_AnimMetaPlayer = Players::PlayerOne; - m_AnimActionLine = 0; - m_AnimActionLineChange = true; - m_ActionMeterDrawOverride = false; - m_AnimTimer1.Reset(); - ChangeAnimMode(PAUSEANIM); - } - - // If a new line, set it up - if (m_AnimActionLineChange) - { - // New Player also? If so, set up his lines - if (m_AnimActionLine == 0) - { - // Hide all but the meters of all lines - for (std::vector::iterator slItr = m_ActionSiteLines[m_AnimMetaPlayer].begin(); slItr != m_ActionSiteLines[m_AnimMetaPlayer].end(); ++slItr) - { - (*slItr).m_OnlyFirstSegments = 1; - (*slItr).m_OnlyLastSegments = -1; - } - } - - // Did the players change? If so, pause -// if (m_AnimMetaPlayer != m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_Player && !m_AnimTimer1.IsPastRealMS(1000)) -// ChangeAnimMode(PAUSEANIM); - - // Find the next green defense line of this player - while (m_AnimActionLine < m_ActionSiteLines[m_AnimMetaPlayer].size() && m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_Color != c_GUIColorGreen) - m_AnimActionLine++; - - // Regular site line, start with bar bracket and line appearing toward the site -// Blinking is too tedious to watch -// ChangeAnimMode(BLINKMETER); - ChangeAnimMode(LINECONNECTFW); - - m_AnimActionLineChange = false; - } - - // Animate defense spending sitelines into view, and then count them away one by one -// for (vector::iterator slItr = m_ActionSiteLines[m_AnimMetaPlayer].begin(); slItr != m_ActionSiteLines[m_AnimMetaPlayer].end(); ++slItr) - if (!m_ActionSiteLines[m_AnimMetaPlayer].empty() && m_AnimActionLine < m_ActionSiteLines[m_AnimMetaPlayer].size()) - { - if (m_AnimMode == BLINKMETER) - { - if (NewAnimMode()) - { - m_AnimTimer1.Reset(); - // Show the meter - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = -1; - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = 1; - } - // Start blinking - if (!m_AnimTimer1.IsPastRealMS(1500)) - { -// m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(m_AnimTimer1.AlternateReal(150)); - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = m_AnimTimer1.AlternateReal(150) ? 1 : 0; - } - else - { - // Leave the label showing - m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(true); - // Start connecting the meter to the circle! - ChangeAnimMode(LINECONNECTFW); - m_AnimSegment = 1; - } - } - else if (m_AnimMode == LINECONNECTFW) - { - if (NewAnimMode()) - { - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = 1; - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = -1; - m_LineConnected = false; - // Hide the site name over the site loc at first - UpdateSiteNameLabel(false); - m_AnimSegment = 1; - m_AnimTimer1.Reset(); - } - - // If line not yet connected, keep revealing segments - if (!m_LineConnected) - { - if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) - { - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments++; - m_AnimTimer1.Reset(); - } - } - // Oh! Line now completed, pause for a while before continuing to shrinking the meter away - else if (!m_AnimTimer1.IsPastRealMS(500)) - { - // Show the site name over the site loc while we're waiting - UpdateSiteNameLabel(true, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_SiteName, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint); - } - // Done waiting, proceed to shrink the meter - else - { - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = -1; - // Start shrinking the meter, showing that the money is being spent on the base - ChangeAnimMode(SHRINKMETER); - } - } - // Shrink each meter from its current value to 0 - else if (m_AnimMode == SHRINKMETER) - { - if (NewAnimMode()) - { - m_AnimTimer1.Reset(); - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = -1; - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = -1; - // Save the total funds so we can make the proportional animation right - m_AnimTotalFunds = g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds; - // Get a handy pointer to the scene we're talking about - m_pAnimScene = m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_pScene; - RTEAssert(m_pAnimScene, "Couldn't find the scene that we're building the base on!"); - // Using the line target as the going-from point - m_AnimFundsMax = m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount; - // The calculated budget use is the target value we're shrinking to - m_AnimFundsMin = m_AnimFundsMax - m_pAnimScene->CalcBuildBudgetUse(g_MetaMan.m_Players[m_AnimMetaPlayer].GetInGamePlayer(), &m_AnimBuildCount); - // Show the negative change of funds, if any - if ((m_AnimFundsMin - m_AnimFundsMax) < 0) - FundsChangeIndication(m_AnimMetaPlayer, m_AnimFundsMin - m_AnimFundsMax, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), 2000); - } - // Show the site name over the site loc - UpdateSiteNameLabel(true, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_SiteName, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint); - // Shrink by certain rate to the target value - if (m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount > m_AnimFundsMin) - { - // Make this animation match in duration with the funds change label that is falling - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount = EaseOut(m_AnimFundsMax, m_AnimFundsMin, m_AnimTimer1.GetElapsedRealTimeMS() / 2000);//(m_AnimFundsMax * 2)); - // Adjust the funds to show how much we subtracted this frame - g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = m_AnimTotalFunds - (m_AnimFundsMax - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount); - UpdatePlayerLineRatios(m_ActionSiteLines[m_AnimMetaPlayer], m_AnimMetaPlayer, false, g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds); - m_AnimTimer2.Reset(); - } - // Finished shrinking the meter to the target size, now start disconnecting it - else - { - UpdateSiteNameLabel(false); - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount = m_AnimFundsMin; - UpdatePlayerLineRatios(m_ActionSiteLines[m_AnimMetaPlayer], m_AnimMetaPlayer, false, g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds); - - ChangeAnimMode(LINEDISCONNECTFW); - } - } - else if (m_AnimMode == LINEDISCONNECTFW) - { - if (NewAnimMode()) - { - // Describe what happened over the site while the lines are disconnecting - if (m_AnimBuildCount == 0) - PlayerTextIndication(m_AnimMetaPlayer, m_AnimFundsMax < 100 ? "Can't afford any!" : "Nothing to build!", m_PlanetCenter + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint, 1500); - else - { - char str[64]; - std::snprintf(str, sizeof(str), m_AnimBuildCount == 1 ? "Built %d item" : "Built %d items", m_AnimBuildCount); - PlayerTextIndication(m_AnimMetaPlayer, str, m_PlanetCenter + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint, 2500); - } - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = -1; - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = 6; - m_LineConnected = false; - } - - // If line not yet gone, keep removing segments - if (m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments > 0) - { - if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) - { - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments--; - m_AnimTimer1.Reset(); - } - } - // Oh! site line completely gone, remove it and continue to next line - else - { -// No need to do this; the budgets get set to 0 so they will diasappear next update of the bars -// DON'T DO THIS, we need it later to make sure everyhting got built! -// RemoveSiteLine(m_ActionSiteLines[m_AnimMetaPlayer], m_AnimActionLine); - // Dont' need to increment since the vector just shrunk due to removal - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = 0; - m_AnimActionLine++; - m_AnimActionLineChange = true; - ChangeAnimMode(BLINKMETER); - } - } - } - - // If no more lines, DONE, continue to next player, and if no more players, continue to next phase of the round - if (m_AnimActionLine >= m_ActionSiteLines[m_AnimMetaPlayer].size()) - { - m_AnimActionLineChange = true; - m_AnimActionLine = 0; - - if (++m_AnimMetaPlayer >= g_MetaMan.m_Players.size()) - m_ContinuePhase = true; - } - - // Phase ENDING, make sure everything is set up to continue - if (m_ContinuePhase) - { - m_AnimMetaPlayer = g_MetaMan.m_Players.size() - 1; - - // Make sure all fund labels and line ratios are good - Scene *pScene = 0; - for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - { - // Reset the funds to the full value before we started messing with animating them - g_MetaMan.m_Players[metaPlayer].m_Funds = g_MetaMan.m_Players[metaPlayer].m_PhaseStartFunds; - - // Go through the sitelines and make sure all the things that need to be done are done before moving onto next phase - for (std::vector::iterator slItr = m_ActionSiteLines[metaPlayer].begin(); slItr != m_ActionSiteLines[metaPlayer].end(); ++slItr) - { - // APPLY all the defense budget allocations to actually building, but not before subtracting their values from the pre funds - if ((*slItr).m_Color == c_GUIColorGreen) - { - if ((*slItr).m_pScene) - { - // Get a non-const pointer to the scene - pScene = const_cast((*slItr).m_pScene); - // Acutally do the spending on these places that have this player's brain and has funds budgeted for them - // THIS IS WHAT GETS STUFF BUILT - // NOTE THE CAREFUL MAPPING BETWEEN METAPLAYERS AND IN-GAME PLAYERS - int player = g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(); - if (pScene->GetResidentBrain(player) && pScene->GetBuildBudget(player) > 0) - g_MetaMan.m_Players[metaPlayer].m_Funds -= pScene->ApplyBuildBudget(player); - } - } - // Reset all non-defensive lines' segment animations so we can see them - else - { - (*slItr).m_OnlyFirstSegments = -1; - (*slItr).m_OnlyLastSegments = -1; - } - } - - // Make all scene build budgets set to 0; they will be re-set to their previous turns' budget ratios on the next player turns - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - // Only mess with Scenes we can see and that are owned by this player's team - if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam()) - (*sItr)->SetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), 0); - } - // Refresh the aciton lines one last time before moving on, which will CLEAN OUT all defensive action lines! - UpdatePlayerActionLines(metaPlayer); - } - } -} +void MetagameGUI::UpdateBaseBuilding() { + m_pPhaseLabel->SetText("Building Bases"); + + // First do setup + if (g_MetaMan.m_StateChanged) { + // Make sure all fund labels and line ratios are good + for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) { + // Save the fund levels FROM THE START so we can calculate the after state if players skip the animation + g_MetaMan.m_Players[metaPlayer].m_PhaseStartFunds = g_MetaMan.m_Players[metaPlayer].m_Funds; + + // Update the player action lines for all players one last time; this will catch the AI ones as well and reflect their actions + UpdatePlayerActionLines(metaPlayer); + + // Hide all lines so we only see their meters + for (std::vector::iterator slItr = m_ActionSiteLines[metaPlayer].begin(); slItr != m_ActionSiteLines[metaPlayer].end(); ++slItr) { + (*slItr).m_OnlyFirstSegments = 1; + (*slItr).m_OnlyLastSegments = -1; + } + UpdatePlayerLineRatios(m_ActionSiteLines[metaPlayer], metaPlayer, false, g_MetaMan.m_Players[metaPlayer].m_Funds); + + // Also, for human players, auto design their blueprints if they have chosen to do so + if (g_MetaMan.m_Players[metaPlayer].IsHuman()) { + // Go through all scenes and check if they're owned by this, and if so, whether their defenses should be automatically designed by canned AI plan + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Move building pieces from the Scene's AI plan queue to the actual blueprints, but only approximately as much as can afford, so the entire AI pre-built base plan isn't revealed + if ((*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam() && (*sItr)->GetAutoDesigned()) + (*sItr)->ApplyAIPlan(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); + } + } + } + + // Start animating these defensive lines appearing, one after another + m_AnimMetaPlayer = Players::PlayerOne; + m_AnimActionLine = 0; + m_AnimActionLineChange = true; + m_ActionMeterDrawOverride = false; + m_AnimTimer1.Reset(); + ChangeAnimMode(PAUSEANIM); + } + + // If a new line, set it up + if (m_AnimActionLineChange) { + // New Player also? If so, set up his lines + if (m_AnimActionLine == 0) { + // Hide all but the meters of all lines + for (std::vector::iterator slItr = m_ActionSiteLines[m_AnimMetaPlayer].begin(); slItr != m_ActionSiteLines[m_AnimMetaPlayer].end(); ++slItr) { + (*slItr).m_OnlyFirstSegments = 1; + (*slItr).m_OnlyLastSegments = -1; + } + } + // Did the players change? If so, pause + // if (m_AnimMetaPlayer != m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_Player && !m_AnimTimer1.IsPastRealMS(1000)) + // ChangeAnimMode(PAUSEANIM); + + // Find the next green defense line of this player + while (m_AnimActionLine < m_ActionSiteLines[m_AnimMetaPlayer].size() && m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_Color != c_GUIColorGreen) + m_AnimActionLine++; + + // Regular site line, start with bar bracket and line appearing toward the site + // Blinking is too tedious to watch + // ChangeAnimMode(BLINKMETER); + ChangeAnimMode(LINECONNECTFW); + + m_AnimActionLineChange = false; + } + + // Animate defense spending sitelines into view, and then count them away one by one + // for (vector::iterator slItr = m_ActionSiteLines[m_AnimMetaPlayer].begin(); slItr != m_ActionSiteLines[m_AnimMetaPlayer].end(); ++slItr) + if (!m_ActionSiteLines[m_AnimMetaPlayer].empty() && m_AnimActionLine < m_ActionSiteLines[m_AnimMetaPlayer].size()) { + if (m_AnimMode == BLINKMETER) { + if (NewAnimMode()) { + m_AnimTimer1.Reset(); + // Show the meter + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = -1; + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = 1; + } + // Start blinking + if (!m_AnimTimer1.IsPastRealMS(1500)) { + // m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(m_AnimTimer1.AlternateReal(150)); + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = m_AnimTimer1.AlternateReal(150) ? 1 : 0; + } else { + // Leave the label showing + m_apPlayerBarLabel[m_AnimMetaPlayer]->SetVisible(true); + // Start connecting the meter to the circle! + ChangeAnimMode(LINECONNECTFW); + m_AnimSegment = 1; + } + } else if (m_AnimMode == LINECONNECTFW) { + if (NewAnimMode()) { + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = 1; + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = -1; + m_LineConnected = false; + // Hide the site name over the site loc at first + UpdateSiteNameLabel(false); + m_AnimSegment = 1; + m_AnimTimer1.Reset(); + } + + // If line not yet connected, keep revealing segments + if (!m_LineConnected) { + if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) { + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments++; + m_AnimTimer1.Reset(); + } + } + // Oh! Line now completed, pause for a while before continuing to shrinking the meter away + else if (!m_AnimTimer1.IsPastRealMS(500)) { + // Show the site name over the site loc while we're waiting + UpdateSiteNameLabel(true, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_SiteName, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint); + } + // Done waiting, proceed to shrink the meter + else { + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = -1; + // Start shrinking the meter, showing that the money is being spent on the base + ChangeAnimMode(SHRINKMETER); + } + } + // Shrink each meter from its current value to 0 + else if (m_AnimMode == SHRINKMETER) { + if (NewAnimMode()) { + m_AnimTimer1.Reset(); + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = -1; + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = -1; + // Save the total funds so we can make the proportional animation right + m_AnimTotalFunds = g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds; + // Get a handy pointer to the scene we're talking about + m_pAnimScene = m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_pScene; + RTEAssert(m_pAnimScene, "Couldn't find the scene that we're building the base on!"); + // Using the line target as the going-from point + m_AnimFundsMax = m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount; + // The calculated budget use is the target value we're shrinking to + m_AnimFundsMin = m_AnimFundsMax - m_pAnimScene->CalcBuildBudgetUse(g_MetaMan.m_Players[m_AnimMetaPlayer].GetInGamePlayer(), &m_AnimBuildCount); + // Show the negative change of funds, if any + if ((m_AnimFundsMin - m_AnimFundsMax) < 0) + FundsChangeIndication(m_AnimMetaPlayer, m_AnimFundsMin - m_AnimFundsMax, Vector(m_apPlayerBarLabel[m_AnimMetaPlayer]->GetXPos() + m_apPlayerBarLabel[m_AnimMetaPlayer]->GetWidth(), m_apPlayerBarLabel[m_AnimMetaPlayer]->GetYPos()), 2000); + } + // Show the site name over the site loc + UpdateSiteNameLabel(true, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_SiteName, m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint); + // Shrink by certain rate to the target value + if (m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount > m_AnimFundsMin) { + // Make this animation match in duration with the funds change label that is falling + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount = EaseOut(m_AnimFundsMax, m_AnimFundsMin, m_AnimTimer1.GetElapsedRealTimeMS() / 2000); //(m_AnimFundsMax * 2)); + // Adjust the funds to show how much we subtracted this frame + g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds = m_AnimTotalFunds - (m_AnimFundsMax - m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount); + UpdatePlayerLineRatios(m_ActionSiteLines[m_AnimMetaPlayer], m_AnimMetaPlayer, false, g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds); + m_AnimTimer2.Reset(); + } + // Finished shrinking the meter to the target size, now start disconnecting it + else { + UpdateSiteNameLabel(false); + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_FundsAmount = m_AnimFundsMin; + UpdatePlayerLineRatios(m_ActionSiteLines[m_AnimMetaPlayer], m_AnimMetaPlayer, false, g_MetaMan.m_Players[m_AnimMetaPlayer].m_Funds); + + ChangeAnimMode(LINEDISCONNECTFW); + } + } else if (m_AnimMode == LINEDISCONNECTFW) { + if (NewAnimMode()) { + // Describe what happened over the site while the lines are disconnecting + if (m_AnimBuildCount == 0) + PlayerTextIndication(m_AnimMetaPlayer, m_AnimFundsMax < 100 ? "Can't afford any!" : "Nothing to build!", m_PlanetCenter + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint, 1500); + else { + char str[64]; + std::snprintf(str, sizeof(str), m_AnimBuildCount == 1 ? "Built %d item" : "Built %d items", m_AnimBuildCount); + PlayerTextIndication(m_AnimMetaPlayer, str, m_PlanetCenter + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_PlanetPoint, 2500); + } + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyFirstSegments = -1; + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = 6; + m_LineConnected = false; + } + + // If line not yet gone, keep removing segments + if (m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments > 0) { + if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) { + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments--; + m_AnimTimer1.Reset(); + } + } + // Oh! site line completely gone, remove it and continue to next line + else { + // No need to do this; the budgets get set to 0 so they will diasappear next update of the bars + // DON'T DO THIS, we need it later to make sure everyhting got built! + // RemoveSiteLine(m_ActionSiteLines[m_AnimMetaPlayer], m_AnimActionLine); + // Dont' need to increment since the vector just shrunk due to removal + m_ActionSiteLines[m_AnimMetaPlayer][m_AnimActionLine].m_OnlyLastSegments = 0; + m_AnimActionLine++; + m_AnimActionLineChange = true; + ChangeAnimMode(BLINKMETER); + } + } + } + + // If no more lines, DONE, continue to next player, and if no more players, continue to next phase of the round + if (m_AnimActionLine >= m_ActionSiteLines[m_AnimMetaPlayer].size()) { + m_AnimActionLineChange = true; + m_AnimActionLine = 0; + + if (++m_AnimMetaPlayer >= g_MetaMan.m_Players.size()) + m_ContinuePhase = true; + } + + // Phase ENDING, make sure everything is set up to continue + if (m_ContinuePhase) { + m_AnimMetaPlayer = g_MetaMan.m_Players.size() - 1; + + // Make sure all fund labels and line ratios are good + Scene* pScene = 0; + for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) { + // Reset the funds to the full value before we started messing with animating them + g_MetaMan.m_Players[metaPlayer].m_Funds = g_MetaMan.m_Players[metaPlayer].m_PhaseStartFunds; + + // Go through the sitelines and make sure all the things that need to be done are done before moving onto next phase + for (std::vector::iterator slItr = m_ActionSiteLines[metaPlayer].begin(); slItr != m_ActionSiteLines[metaPlayer].end(); ++slItr) { + // APPLY all the defense budget allocations to actually building, but not before subtracting their values from the pre funds + if ((*slItr).m_Color == c_GUIColorGreen) { + if ((*slItr).m_pScene) { + // Get a non-const pointer to the scene + pScene = const_cast((*slItr).m_pScene); + // Acutally do the spending on these places that have this player's brain and has funds budgeted for them + // THIS IS WHAT GETS STUFF BUILT + // NOTE THE CAREFUL MAPPING BETWEEN METAPLAYERS AND IN-GAME PLAYERS + int player = g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(); + if (pScene->GetResidentBrain(player) && pScene->GetBuildBudget(player) > 0) + g_MetaMan.m_Players[metaPlayer].m_Funds -= pScene->ApplyBuildBudget(player); + } + } + // Reset all non-defensive lines' segment animations so we can see them + else { + (*slItr).m_OnlyFirstSegments = -1; + (*slItr).m_OnlyLastSegments = -1; + } + } + + // Make all scene build budgets set to 0; they will be re-set to their previous turns' budget ratios on the next player turns + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + // Only mess with Scenes we can see and that are owned by this player's team + if ((*sItr)->IsRevealed() && (*sItr)->GetTeamOwnership() == g_MetaMan.m_Players[metaPlayer].GetTeam()) + (*sItr)->SetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), 0); + } + // Refresh the aciton lines one last time before moving on, which will CLEAN OUT all defensive action lines! + UpdatePlayerActionLines(metaPlayer); + } + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetupOffensives @@ -4212,974 +3810,858 @@ void MetagameGUI::UpdateBaseBuilding() // Description: Sets up the Activities that represent all the offensive actions of // the teams this round. -void MetagameGUI::SetupOffensives() -{ - // Clear out the old ones, if any - g_MetaMan.ClearActivities(); - - // Go through all players' offensive actions and create the unique activities - std::string targetName; - float offensiveBudget; - bool playerDone = false; - int team = Activity::NoTeam; - int offensiveCount = 0; - for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) - { - playerDone = false; - team = g_MetaMan.m_Players[metaPlayer].GetTeam(); - // If we have a selected offensive target, find its scene in the metagame - targetName = g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName(); - offensiveBudget = g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget(); - if (!targetName.empty() && offensiveBudget > 0) - { - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); !playerDone && sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == targetName) - { - // Now check that we haven't already created an offensive action at this site - for (std::vector::iterator aItr = g_MetaMan.m_RoundOffensives.begin(); aItr != g_MetaMan.m_RoundOffensives.end(); ++aItr) - { - if ((*aItr)->GetSceneName() == targetName) - { - // Ok, activity at this site already exists, so add this player to the attacking forces - (*aItr)->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), g_MetaMan.m_Players[metaPlayer].IsHuman(), team, offensiveBudget, &(g_MetaMan.GetTeamIcon(team))); - // Move onto next player - playerDone = true; - } - } - - // Create new offensive Activity - if (!playerDone) - { - // Set up the MetaFight activity - GAScripted *pOffensive = new GAScripted; - pOffensive->Create("Base.rte/Activities/MetaFight.lua", "MetaFight"); - char str[64]; - std::snprintf(str, sizeof(str), "R%dA%d", g_MetaMan.m_CurrentRound + 1, offensiveCount); - pOffensive->SetPresetName(g_MetaMan.GetGameName() + str); - // Associate the name of the scene with where this thing is supposed to take place - pOffensive->SetSceneName(targetName); - // Gotto deact all players since by default there is one in slot 1 - pOffensive->ClearPlayers(); +void MetagameGUI::SetupOffensives() { + // Clear out the old ones, if any + g_MetaMan.ClearActivities(); + + // Go through all players' offensive actions and create the unique activities + std::string targetName; + float offensiveBudget; + bool playerDone = false; + int team = Activity::NoTeam; + int offensiveCount = 0; + for (int metaPlayer = Players::PlayerOne; metaPlayer < g_MetaMan.m_Players.size(); ++metaPlayer) { + playerDone = false; + team = g_MetaMan.m_Players[metaPlayer].GetTeam(); + // If we have a selected offensive target, find its scene in the metagame + targetName = g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName(); + offensiveBudget = g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget(); + if (!targetName.empty() && offensiveBudget > 0) { + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); !playerDone && sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == targetName) { + // Now check that we haven't already created an offensive action at this site + for (std::vector::iterator aItr = g_MetaMan.m_RoundOffensives.begin(); aItr != g_MetaMan.m_RoundOffensives.end(); ++aItr) { + if ((*aItr)->GetSceneName() == targetName) { + // Ok, activity at this site already exists, so add this player to the attacking forces + (*aItr)->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), g_MetaMan.m_Players[metaPlayer].IsHuman(), team, offensiveBudget, &(g_MetaMan.GetTeamIcon(team))); + // Move onto next player + playerDone = true; + } + } + + // Create new offensive Activity + if (!playerDone) { + // Set up the MetaFight activity + GAScripted* pOffensive = new GAScripted; + pOffensive->Create("Base.rte/Activities/MetaFight.lua", "MetaFight"); + char str[64]; + std::snprintf(str, sizeof(str), "R%dA%d", g_MetaMan.m_CurrentRound + 1, offensiveCount); + pOffensive->SetPresetName(g_MetaMan.GetGameName() + str); + // Associate the name of the scene with where this thing is supposed to take place + pOffensive->SetSceneName(targetName); + // Gotto deact all players since by default there is one in slot 1 + pOffensive->ClearPlayers(); // Set difficulty pOffensive->SetDifficulty(g_MetaMan.m_Difficulty); // Set AI skill levels for (int t = Activity::TeamOne; t < Activity::MaxTeamCount; t++) pOffensive->SetTeamAISkill(t, g_MetaMan.m_TeamAISkill[t]); - // Attacker - pOffensive->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), g_MetaMan.m_Players[metaPlayer].IsHuman(), team, offensiveBudget, &(g_MetaMan.GetTeamIcon(team))); - - // Unless exploring an unclaimed spot, there's going to be defenders - if ((*sItr)->GetTeamOwnership() != Activity::NoTeam) - { - // Go through all players and add the ones of the defending team, based on who has resident brains here - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Got to remember to translate from metagame player index into the in-game player index -// TODO: Remove this requirement to have a brain resident to play? error-prone and not so fun for co-op player on sme team if they can't all play -// if (g_MetaMan.m_Players[mp].GetTeam() == (*sItr)->GetTeamOwnership()) - if ((*sItr)->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - pOffensive->AddPlayer(g_MetaMan.m_Players[mp].GetInGamePlayer(), g_MetaMan.m_Players[mp].IsHuman(), g_MetaMan.m_Players[mp].GetTeam(), g_MetaMan.GetRemainingFundsOfPlayer(mp, *sItr, false, false), &(g_MetaMan.GetTeamIcon(g_MetaMan.m_Players[mp].GetTeam()))); - } - } - } - - // Add the new Activity to the queue of offensive events that should happen this round! - g_MetaMan.m_RoundOffensives.push_back(pOffensive); - // Done with this guy's offensive action - playerDone = true; - // Count this new offensive Activity - ++offensiveCount; - } - } - } - } - } -/* - // Check all created Offensive Activites that none only contain AI MetaPlayer:s, because they have to be handled differently and not actually played - for (vector::iterator aItr = g_MetaMan.m_RoundOffensives.begin(); aItr != g_MetaMan.m_RoundOffensives.end(); ++aItr) - { - // No hooomins?? - if ((*aItr)->GetHumanCount() < 1) - { - - } - } -*/ -} + // Attacker + pOffensive->AddPlayer(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer(), g_MetaMan.m_Players[metaPlayer].IsHuman(), team, offensiveBudget, &(g_MetaMan.GetTeamIcon(team))); + + // Unless exploring an unclaimed spot, there's going to be defenders + if ((*sItr)->GetTeamOwnership() != Activity::NoTeam) { + // Go through all players and add the ones of the defending team, based on who has resident brains here + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Got to remember to translate from metagame player index into the in-game player index + // TODO: Remove this requirement to have a brain resident to play? error-prone and not so fun for co-op player on sme team if they can't all play + // if (g_MetaMan.m_Players[mp].GetTeam() == (*sItr)->GetTeamOwnership()) + if ((*sItr)->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + pOffensive->AddPlayer(g_MetaMan.m_Players[mp].GetInGamePlayer(), g_MetaMan.m_Players[mp].IsHuman(), g_MetaMan.m_Players[mp].GetTeam(), g_MetaMan.GetRemainingFundsOfPlayer(mp, *sItr, false, false), &(g_MetaMan.GetTeamIcon(g_MetaMan.m_Players[mp].GetTeam()))); + } + } + } + + // Add the new Activity to the queue of offensive events that should happen this round! + g_MetaMan.m_RoundOffensives.push_back(pOffensive); + // Done with this guy's offensive action + playerDone = true; + // Count this new offensive Activity + ++offensiveCount; + } + } + } + } + } + /* + // Check all created Offensive Activites that none only contain AI MetaPlayer:s, because they have to be handled differently and not actually played + for (vector::iterator aItr = g_MetaMan.m_RoundOffensives.begin(); aItr != g_MetaMan.m_RoundOffensives.end(); ++aItr) + { + // No hooomins?? + if ((*aItr)->GetHumanCount() < 1) + { + + } + } + */ +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Method: UpdateOffensives +////////////////////////////////////////////////////////////////////////////////////////// +// Description: Updates the offensive actions animation + +void MetagameGUI::UpdateOffensives() { + char str[256]; + + /////////////////////////////////// + // First do setup of all the activities we're going to play in order + if (g_MetaMan.m_StateChanged) { + // Generate all offensive activites, based on the players' offensive moves + // But ONLY do this if it doesn't appear we are continuing a loaded game that has already completed battles!! + if (g_MetaMan.m_CurrentOffensive == 0) + SetupOffensives(); + + // Hide all income lines so they don't flash once on phase start + for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) + (*slItr).m_OnlyFirstSegments = (*slItr).m_OnlyLastSegments = 0; + + // Set the battle info display to the start of its animation. + UpdatePreBattleAttackers(0); + UpdatePreBattleDefenders(0); + + // Start processing the first activity + m_AnimActivityChange = true; + // Turn off the post battle review flag + m_PostBattleReview = false; + // Don't clear this! We may have loaded a game with a battle completed so we don't want to start on 0 again + // g_MetaMan.m_CurrentOffensive = 0; + } + + // No Offensives this round? then skip all this business + if (g_MetaMan.m_RoundOffensives.empty() || g_MetaMan.m_CurrentOffensive < 0 || g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size()) { + m_ContinuePhase = true; + // TODO: Make sure that quitting out here is ok + return; + } + + // If we're still reviewing a previous battle and the player decided to skip to the next battle right away then do so and move directly to the next offensive + if (m_PostBattleReview && !m_PreTurn) { + // We're done with this activity + m_AnimActivityChange = true; + // Turn off the post battle review flag too + m_PostBattleReview = false; + // This finishes off the current battle we're reviewing, and moves onto the next + if (!FinalizeOffensive()) + return; + } + + //////////////////////////////////////////////////// + // New Offensive, so set it up + if (m_AnimActivityChange) { + // Show which mission we're on of all the offensive activities in queue + std::snprintf(str, sizeof(str), "Battle %d of %d", (g_MetaMan.m_CurrentOffensive + 1), (int)(g_MetaMan.m_RoundOffensives.size())); + m_pPhaseLabel->SetText(str); + + // Find the scene being attacked in this offensive Activity + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetSceneName()) + m_pAnimScene = (*sItr); + } + RTEAssert(m_pAnimScene, "Couldn't find the Site that has been selected as attacked!"); + + // It's owned by a team, so set up and show its defenders + if (m_pAnimScene->GetTeamOwnership() != Activity::NoTeam) + m_AnimDefenseTeam = m_pAnimScene->GetTeamOwnership(); + + // Set up all the offensive and defensive lines for each player involved in this site's battle + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // If this player is involved in this fight, show his lines etc + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // Save the fund levels FROM THE START of each battle so we can calculate the after state if players skip the animation + g_MetaMan.m_Players[mp].m_PhaseStartFunds = g_MetaMan.m_Players[mp].m_Funds; + + // Rebuild all the action site lines for the player + float meterStart = UpdatePlayerActionLines(mp); + // Reset battle funds and other animation indicators + m_aBattleFunds[mp] = 0; + m_aBattleAttacker[mp] = false; + m_aAnimDestroyed[mp] = false; + m_aBrainIconPos[mp].Reset(); + + // What is this player attacking? + std::string targetName = g_MetaMan.m_Players[mp].GetOffensiveTargetName(); + float offensiveBudget = g_MetaMan.m_Players[mp].GetOffensiveBudget(); + // If attacking anything, see if it's the current site that's getting hit + if (!targetName.empty() && offensiveBudget > 0) { + // Set the displayed battle funds for this player if it's attacking this site + if (m_pAnimScene->GetPresetName() == targetName) { + m_aBattleFunds[mp] = offensiveBudget; + m_aBattleAttacker[mp] = true; + } + } + + // If this player owns and has a resident brain at this site, add his defending action line of unallocated funds, + // and also update the offensive activity itself to match teh defensive funds to what he has left after multiple completed offensives this turn + if (m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // Find out how much gold this player has left after all allocations and previous battles this turn + float remainingFunds = g_MetaMan.GetRemainingFundsOfPlayer(mp); + // UPDATE the contributed funds of the defending player to whatever gold he has left after all (if any) previous battles this turn! + bool updated = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->UpdatePlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer(), remainingFunds); + // Add the unused build budget FOR THIS SCENE to the battle funds display - doesn't do anyhting now because build budgets are set to 0 in UpdateBaseBuilding + m_aBattleFunds[mp] += m_pAnimScene->GetBuildBudget(g_MetaMan.m_Players[mp].GetInGamePlayer()); + // Add the unallocated funds meter, even if there's 0 left.. it shows why there's 0, and also the meter can grow after battle if the defending player digs up gold + if (remainingFunds >= 0) { + // Tell the player why he has no defensive money... uh too early + // if (remainingFunds <= 0) + // PlayerTextIndication(mp, "No unallocated funds!", Vector(m_apPlayerBox[mp]->GetXPos(), m_apPlayerBox[mp]->GetYPos()), 1500); + + m_ActionSiteLines[mp].push_back(SiteLine(mp, meterStart, remainingFunds / g_MetaMan.m_Players[mp].m_Funds, m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), m_pAnimScene->GetPresetName(), m_pAnimScene, c_GUIColorYellow, -1, -1, 60, 1.0f, g_MetaMan.IsActiveTeam(m_pAnimScene->GetTeamOwnership()))); + // This will actually affect the line meter + m_ActionSiteLines[mp].back().m_FundsAmount = remainingFunds; + // Add to the battle funds display too + m_aBattleFunds[mp] += remainingFunds; + // Move the meter start position forward as necessary + meterStart += m_ActionSiteLines[mp].back().m_MeterAmount; + } + } + + // Hide all action lines except for their bars + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + (*slItr).m_OnlyFirstSegments = 1; + (*slItr).m_OnlyLastSegments = -1; + } + + // Update the ratios now that we've messed with them + UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); + } + // If player not involved in the fight then hide all lines of this player + { + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + (*slItr).m_OnlyFirstSegments = 0; + (*slItr).m_OnlyLastSegments = -1; + } + } + } + + // Start out the brain travel animaitons hidden and at 0 + ResetBattleInfo(); + UpdatePreBattleAttackers(0); + UpdatePreBattleDefenders(0); + // Make the meters draw all the time + // This might not be such a great thing after all to show all the bars.. not needed anymore since we're not connecting to defensive budgets in offensive phases anymore + // m_ActionMeterDrawOverride = true; + + // Show that we are waiting for the players to press the Continue button so we can start the Activity we're setting up here + m_PreTurn = true; + m_BattleToResume = false; + // New battle, reset the post battle flags + m_PostBattleReview = false; + m_BattleCausedOwnershipChange = false; + m_PreBattleTeamOwnership = Activity::NoTeam; + + ChangeAnimMode(TARGETZEROING); + m_AnimActivityChange = false; + } + + ///////////////////////////////////////////// + // Make a menacing target crosshairs zero in on the site we're playing this activity on + if (m_AnimMode == TARGETZEROING) { + if (NewAnimMode()) { + m_SiteAttackTarget.m_CenterPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); + m_SiteAttackTarget.m_AnimProgress = 0; + m_SiteAttackTarget.m_Color = c_GUIColorRed; + m_AnimModeDuration = 600; + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + m_SiteAttackTarget.m_AnimProgress = EaseOut(0.0, 1.0, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); + + // BAM - show the name of the site and start showing who's attacking it + if (m_SiteAttackTarget.m_AnimProgress == 1.0) { + // // After a while, go on to show the attacker action site lines + // if (m_AnimTimer1.IsPastRealMS(1200)) + // { + ChangeAnimMode(LINECONNECTFW); + } + } + + ///////////////////////////////////////////// + // Show who's attacking this target; connect the attack budget lines (while still zeroed) and animate the brains going there from their respective pools + if (m_AnimMode == LINECONNECTFW) { + if (NewAnimMode()) { + // Make sure all offensive action lines are set up for this phase + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Find all players that are active during this battle + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // If this player is attacking, indicate that we've got a brain in transit.. this just changes the display, not the actual brain pool count yet + if (m_pAnimScene->GetPresetName() == g_MetaMan.m_Players[mp].GetOffensiveTargetName()) + g_MetaMan.m_Players[mp].ChangeBrainsInTransit(1); + + // Find their offensive funds site lines + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + // Offensive lines are red; set them up to have their meters visible + if ((*slItr).m_Color == c_GUIColorRed) { + (*slItr).m_OnlyFirstSegments = 1; + (*slItr).m_OnlyLastSegments = -1; + } + } + } + } + + m_AnimSegment = 0; + m_AnimModeDuration = 2000; + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + + // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site + UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); + + // Keep revealing segments simultaneously from all attackers until they are all revealed + if (m_AnimSegment < 15) { + if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) { + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only care if this player is attacking this site + if (m_pAnimScene->GetPresetName() == g_MetaMan.m_Players[mp].GetOffensiveTargetName() && g_MetaMan.m_Players[mp].GetOffensiveBudget() > 0) + // if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) + { + // Find their offensive funds site lines + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + // Offensive lines are red; grow all of em + if ((*slItr).m_Color == c_GUIColorRed) + (*slItr).m_OnlyFirstSegments++; + } + } + } + + m_AnimSegment++; + m_AnimTimer1.Reset(); + } + } + + // Animate the crosshairs subtly + m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); + + // Animate the brain label travel animations + UpdatePreBattleAttackers(EaseInOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); + UpdatePreBattleDefenders(0); + + // Just wait until the players hit the continue button.. + if (m_BattleToResume) + m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Resume <" : "Resume"); + else + m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Start! <" : "Start!"); + + // Move onto growing the attack budget meters + if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) + ChangeAnimMode(SHOWDEFENDERS); + } + + ///////////////////////////////////////////// + // Show the defending brains for this battle + if (m_AnimMode == SHOWDEFENDERS) { + if (NewAnimMode()) { + // Make sure all defensive and unallocated budget action lines are set up for this phase + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + } + + m_AnimModeDuration = 500; + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + + // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site + UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); + + // Animate the crosshairs subtly + m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); + + // Keep the brain label travel animations in one spot and their labels updated + UpdatePreBattleAttackers(1.0); + UpdatePreBattleDefenders(EaseOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); + + // Just wait until the players hit the continue button.. + if (m_BattleToResume) + m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Resume <" : "Resume"); + else + m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Start! <" : "Start!"); + + // Move onto growing the attack budget meters + if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) + ChangeAnimMode(LINECONNECTBW); + } + + ///////////////////////////////////////////// + // Show the defending budget lines of the players who are defending this site + if (m_AnimMode == LINECONNECTBW) { + if (NewAnimMode()) { + // Make sure all defensive and unallocated budget action lines are set up for this phase + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only care of this player is involved in this particular battle + // Only care about defending players of this site + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer()) && + m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && + m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // Find their defensive funds site lines + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + // Offensive lines are green; unallocated funds are white - attach all of them + if ((*slItr).m_Color != c_GUIColorRed) { + (*slItr).m_OnlyFirstSegments = -1; + (*slItr).m_OnlyLastSegments = 0; + } + } + } + } + + m_AnimSegment = 0; + m_AnimModeDuration = 1000; + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + + // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site + UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); + + // Keep revealing segments simultaneously from all attackers until they are all revealed + if (m_AnimSegment < 15) { + if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) { + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only care of this player is involved in this particular battle + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // Find their defensive-related funds site lines + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + // Offensive lines are red; grow the defensive ones relevant to this scene + if ((*slItr).m_Color != c_GUIColorRed && m_pAnimScene->GetPresetName() == (*slItr).m_SiteName && + (m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer()))) + (*slItr).m_OnlyLastSegments++; + } + } + } + m_AnimSegment++; + m_AnimTimer1.Reset(); + } + } + + // Animate the crosshairs subtly + m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); + + // Keep the brain label travel animations in one spot and their labels updated + UpdatePreBattleAttackers(1.0); + UpdatePreBattleDefenders(1.0); + + // Just wait until the players hit the continue button.. + if (m_BattleToResume) + m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Resume <" : "Resume"); + else + m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Start! <" : "Start!"); + } + + ////////////////////////////////// + // POST BATTLE REVIEW + + ///////////////////////////////////////////// + // A Short pause for after players come out of a run simulation battle, + // so they can orient themselves visually before battle review starts happening + if (m_AnimMode == SHOWPOSTBATTLEPAUSE) { + if (NewAnimMode()) { + // The length of the pause + m_AnimModeDuration = 2000; + + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + + // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site + UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); + // Animate the crosshairs subtly + m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); + + UpdatePostBattleRetreaters(0); + UpdatePostBattleResidents(0); + + // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles + m_apMetaButton[CONTINUE]->SetText("Next"); + + // Move onto having the victorious brains go back inside the site and take it over + if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) + ChangeAnimMode(SHOWPOSTBATTLEBALANCE); + } + + ///////////////////////////////////////////// + // Show how much is being allocated to attacking this place + if (m_AnimMode == SHOWPOSTBATTLEBALANCE) { + if (NewAnimMode()) { + m_AnimModeDuration = 2000; + + // Make sure all offensive action-related lines are set up for this battle review animation + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only the players of this battle + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // Find their site lines that are connected to the site + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + // Only lines that are connected are relevant + if ((*slItr).m_OnlyFirstSegments > 1 || (*slItr).m_OnlyLastSegments > 1) { + // Re-set the funds amount we're going from - actually, not necessary + (*slItr).m_FundsAmount = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer()); + // Set the target we're going toward + (*slItr).m_FundsTarget = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[mp].GetInGamePlayer()); + // Start the battle money display off at the right point too + m_aBattleFunds[mp] = (*slItr).m_FundsAmount; + // Display the change amount over/under the player bar + FundsChangeIndication(mp, (*slItr).m_FundsTarget - (*slItr).m_FundsAmount, Vector(m_apPlayerBarLabel[mp]->GetXPos() + m_apPlayerBarLabel[mp]->GetWidth(), m_apPlayerBarLabel[mp]->GetYPos()), m_AnimModeDuration); + + // Update the ratios.. shouldn't do anyhitng, really + UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); + } + } + } + } + + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + + // Find the players who are involved in this battle + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only the players of this battle + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // The brains who DID NOT MAKE IT - Show them blowing up at some random interval into the animation + if (!m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer()) && + !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // If not yet blown up, then see if we should yet + if (!m_aAnimDestroyed[mp] && m_AnimTimer2.GetElapsedRealTimeMS() > (m_AnimModeDuration * 0.5F) && RandomNum() < 0.05F) { + // Add circle explosion effect to where the brain icon used to be + m_SiteSwitchIndicators.push_back(SiteTarget(m_aBrainIconPos[mp], 0, SiteTarget::CIRCLEGROW, c_GUIColorRed)); + // Switch the brain icon drawing off + m_aAnimDestroyed[mp] = true; + } + } + + // Find their site lines that are connected to the site + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + // Only lines that are connected are relevant + if ((*slItr).m_OnlyFirstSegments > 1 || (*slItr).m_OnlyLastSegments > 1) { + float startFunds = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer()); + + // Grow/shrink all the meters, showing how the funds changed during battle + if (m_AnimTimer1.GetElapsedRealTimeMS() < m_AnimModeDuration) { + // Make this animation correlate in duration with the funds change label that rises + (*slItr).m_FundsAmount = EaseOut(startFunds, (*slItr).m_FundsTarget, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); + // Update the battle funds display; it will be shown in the brian action label + m_aBattleFunds[mp] = (*slItr).m_FundsAmount; + // Adjust the funds to show how much we subtracted this frame - this will be reset in the end anyway, it's just for show during this battle review animation + g_MetaMan.m_Players[mp].m_Funds = g_MetaMan.m_Players[mp].m_PhaseStartFunds - (startFunds - (*slItr).m_FundsAmount); + UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); + } + // Finished growing the meter to the target size + else { + m_aBattleFunds[mp] = (*slItr).m_FundsAmount = (*slItr).m_FundsTarget; + g_MetaMan.m_Players[mp].m_Funds = g_MetaMan.m_Players[mp].m_PhaseStartFunds - (startFunds - (*slItr).m_FundsAmount); + UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); + } + } + } + } + } + + // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site + UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); + // Animate the crosshairs subtly + m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); + + // Animate the brain label travel animations + UpdatePostBattleRetreaters(0); + UpdatePostBattleResidents(0); + + UpdatePlayerBars(); + // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles + m_apMetaButton[CONTINUE]->SetText("Next"); + + // Move onto showing what happened to each brain + if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) { + // Blow up any remaining brains who are doomed + // Find the players who are involved in this battle + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only the players of this battle who didn't evacuate + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer()) && + !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // The brains who DID NOT MAKE IT - Show them blowing up + if (!m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // If not yet blown up, then we should be + if (!m_aAnimDestroyed[mp]) { + // Add circle explosion effect to where the brain icon used to be + m_SiteSwitchIndicators.push_back(SiteTarget(m_aBrainIconPos[mp], 0, SiteTarget::CIRCLEGROW, c_GUIColorRed)); + // Switch the brain icon drawing off + m_aAnimDestroyed[mp] = true; + } + } + } + } + ChangeAnimMode(SHOWPOSTBATTLEBRAINS); + } + } + + ///////////////////////////////////////////// + // Show what happened to the brains after a battle + if (m_AnimMode == SHOWPOSTBATTLEBRAINS) { + if (NewAnimMode()) { + // Make sure all defensive and unallocated budget action lines are set up for this phase + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + } + + // The duration of this depends on whethere there are any evacuees to travel back + m_AnimModeDuration = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->AnyBrainWasEvacuated() ? 2000 : 500; + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + + // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site + UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); + // Animate the crosshairs subtly + m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); + + // The retreating brain label travel animations get updated to go back to their pools + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->AnyBrainWasEvacuated()) + UpdatePostBattleRetreaters(EaseInOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); + else + UpdatePostBattleRetreaters(1.0); + UpdatePostBattleResidents(0); + + // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles + m_apMetaButton[CONTINUE]->SetText("Next"); + + // Move onto having the victorious brains go back inside the site and take it over + if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) { + // Change the display to show the evacuees transferring back to their brain pools + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->AnyBrainWasEvacuated()) { + // Find the players who are evacuated anything this battle + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only the players of this battle who evac'd their brain + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // Both an Attacker aborting an attack, and a Defender abandoning his site has the same effect here on the brian pool display + g_MetaMan.m_Players[mp].ChangeBrainsInTransit(-1); + } + } + } + + ChangeAnimMode(SHOWNEWRESIDENTS); + } + } + + ///////////////////////////////////////////// + // Show the victorious brains going back into the site and taking it over + if (m_AnimMode == SHOWNEWRESIDENTS) { + if (NewAnimMode()) { + // Make sure all defensive and unallocated budget action lines are set up for this phase + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + } + + m_AnimModeDuration = m_BattleCausedOwnershipChange ? 500 : 750; + m_AnimTimer1.Reset(); + m_AnimTimer2.Reset(); + } + + // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site + UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); + // Animate the crosshairs subtly + m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); + + // The brains going back into their lair are animated + UpdatePostBattleRetreaters(1.0); + // Tweak the animaiton slightly based on whether the site switched hands or not + if (m_BattleCausedOwnershipChange) + UpdatePostBattleResidents(EaseIn(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); + else + UpdatePostBattleResidents(EaseOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); + + // Find the players who are involved in this battle + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only the players of this battle + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // The guys who died - remove their icons completely + if (!m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) + m_apPlayerBrainTravelLabel[mp]->SetVisible(false); + } + } + + // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles + m_apMetaButton[CONTINUE]->SetText("Next"); + // Move onto the next offensive in line, if any! + if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) { + // Quit if there's no more offensives after the one we just finalized + if (!FinalizeOffensive()) + return; + } + } -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateOffensives -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the offensive actions animation + ///////////////////////////////////////////// + // If the player have chosen to start the attack activity by hitting the continue button, then do eeeet + if (!m_PreTurn) { + // Make sure this is set back + m_apMetaButton[CONTINUE]->SetText("Start!"); + UpdateSiteNameLabel(false); + + // Max out the offensive lines in case the player started the battle before the lines were fully animated as connected + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only care of this player is involved in this particular battle + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) { + // Only show lines that are going to the site we're battling on + if ((*slItr).m_SiteName == m_pAnimScene->GetPresetName()) { + // Find their offensive funds site lines and set the offensive budget back to where it is supposed to end up + if ((*slItr).m_Color == c_GUIColorRed) + (*slItr).m_OnlyFirstSegments = 15; + // Defensive site + else if (m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) + (*slItr).m_OnlyLastSegments = 15; + } + // Hide all other lines + else { + (*slItr).m_OnlyFirstSegments = 0; + (*slItr).m_OnlyLastSegments = 0; + } + } + } + } -void MetagameGUI::UpdateOffensives() -{ - char str[256]; - - /////////////////////////////////// - // First do setup of all the activities we're going to play in order - if (g_MetaMan.m_StateChanged) - { - // Generate all offensive activites, based on the players' offensive moves - // But ONLY do this if it doesn't appear we are continuing a loaded game that has already completed battles!! - if (g_MetaMan.m_CurrentOffensive == 0) - SetupOffensives(); - - // Hide all income lines so they don't flash once on phase start - for (std::vector::iterator slItr = m_IncomeSiteLines.begin(); slItr != m_IncomeSiteLines.end(); ++slItr) - (*slItr).m_OnlyFirstSegments = (*slItr).m_OnlyLastSegments = 0; - - // Set the battle info display to the start of its animation. - UpdatePreBattleAttackers(0); - UpdatePreBattleDefenders(0); - - // Start processing the first activity - m_AnimActivityChange = true; - // Turn off the post battle review flag - m_PostBattleReview = false; -// Don't clear this! We may have loaded a game with a battle completed so we don't want to start on 0 again -// g_MetaMan.m_CurrentOffensive = 0; - } - - // No Offensives this round? then skip all this business - if (g_MetaMan.m_RoundOffensives.empty() || g_MetaMan.m_CurrentOffensive < 0 || g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size()) - { - m_ContinuePhase = true; -// TODO: Make sure that quitting out here is ok - return; - } - - // If we're still reviewing a previous battle and the player decided to skip to the next battle right away then do so and move directly to the next offensive - if (m_PostBattleReview && !m_PreTurn) - { - // We're done with this activity - m_AnimActivityChange = true; - // Turn off the post battle review flag too - m_PostBattleReview = false; - // This finishes off the current battle we're reviewing, and moves onto the next - if (!FinalizeOffensive()) - return; - } - - //////////////////////////////////////////////////// - // New Offensive, so set it up - if (m_AnimActivityChange) - { - // Show which mission we're on of all the offensive activities in queue - std::snprintf(str, sizeof(str), "Battle %d of %d", (g_MetaMan.m_CurrentOffensive + 1), (int)(g_MetaMan.m_RoundOffensives.size())); - m_pPhaseLabel->SetText(str); - - // Find the scene being attacked in this offensive Activity - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetSceneName()) - m_pAnimScene = (*sItr); - } - RTEAssert(m_pAnimScene, "Couldn't find the Site that has been selected as attacked!"); - - // It's owned by a team, so set up and show its defenders - if (m_pAnimScene->GetTeamOwnership() != Activity::NoTeam) - m_AnimDefenseTeam = m_pAnimScene->GetTeamOwnership(); - - // Set up all the offensive and defensive lines for each player involved in this site's battle - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // If this player is involved in this fight, show his lines etc - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Save the fund levels FROM THE START of each battle so we can calculate the after state if players skip the animation - g_MetaMan.m_Players[mp].m_PhaseStartFunds = g_MetaMan.m_Players[mp].m_Funds; - - // Rebuild all the action site lines for the player - float meterStart = UpdatePlayerActionLines(mp); - // Reset battle funds and other animation indicators - m_aBattleFunds[mp] = 0; - m_aBattleAttacker[mp] = false; - m_aAnimDestroyed[mp] = false; - m_aBrainIconPos[mp].Reset(); - - // What is this player attacking? - std::string targetName = g_MetaMan.m_Players[mp].GetOffensiveTargetName(); - float offensiveBudget = g_MetaMan.m_Players[mp].GetOffensiveBudget(); - // If attacking anything, see if it's the current site that's getting hit - if (!targetName.empty() && offensiveBudget > 0) - { - // Set the displayed battle funds for this player if it's attacking this site - if (m_pAnimScene->GetPresetName() == targetName) - { - m_aBattleFunds[mp] = offensiveBudget; - m_aBattleAttacker[mp] = true; - } - } - - // If this player owns and has a resident brain at this site, add his defending action line of unallocated funds, - // and also update the offensive activity itself to match teh defensive funds to what he has left after multiple completed offensives this turn - if (m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Find out how much gold this player has left after all allocations and previous battles this turn - float remainingFunds = g_MetaMan.GetRemainingFundsOfPlayer(mp); - // UPDATE the contributed funds of the defending player to whatever gold he has left after all (if any) previous battles this turn! - bool updated = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->UpdatePlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer(), remainingFunds); - // Add the unused build budget FOR THIS SCENE to the battle funds display - doesn't do anyhting now because build budgets are set to 0 in UpdateBaseBuilding - m_aBattleFunds[mp] += m_pAnimScene->GetBuildBudget(g_MetaMan.m_Players[mp].GetInGamePlayer()); - // Add the unallocated funds meter, even if there's 0 left.. it shows why there's 0, and also the meter can grow after battle if the defending player digs up gold - if (remainingFunds >= 0) - { - // Tell the player why he has no defensive money... uh too early -// if (remainingFunds <= 0) -// PlayerTextIndication(mp, "No unallocated funds!", Vector(m_apPlayerBox[mp]->GetXPos(), m_apPlayerBox[mp]->GetYPos()), 1500); - - m_ActionSiteLines[mp].push_back(SiteLine(mp, meterStart, remainingFunds / g_MetaMan.m_Players[mp].m_Funds, m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), m_pAnimScene->GetPresetName(), m_pAnimScene, c_GUIColorYellow, -1, -1, 60, 1.0f, g_MetaMan.IsActiveTeam(m_pAnimScene->GetTeamOwnership()))); - // This will actually affect the line meter - m_ActionSiteLines[mp].back().m_FundsAmount = remainingFunds; - // Add to the battle funds display too - m_aBattleFunds[mp] += remainingFunds; - // Move the meter start position forward as necessary - meterStart += m_ActionSiteLines[mp].back().m_MeterAmount; - } - } - - // Hide all action lines except for their bars - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - (*slItr).m_OnlyFirstSegments = 1; - (*slItr).m_OnlyLastSegments = -1; - } - - // Update the ratios now that we've messed with them - UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); - } - // If player not involved in the fight then hide all lines of this player - { - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - (*slItr).m_OnlyFirstSegments = 0; - (*slItr).m_OnlyLastSegments = -1; - } - } - } - - // Start out the brain travel animaitons hidden and at 0 - ResetBattleInfo(); - UpdatePreBattleAttackers(0); - UpdatePreBattleDefenders(0); - // Make the meters draw all the time -// This might not be such a great thing after all to show all the bars.. not needed anymore since we're not connecting to defensive budgets in offensive phases anymore -// m_ActionMeterDrawOverride = true; - - // Show that we are waiting for the players to press the Continue button so we can start the Activity we're setting up here - m_PreTurn = true; - m_BattleToResume = false; - // New battle, reset the post battle flags - m_PostBattleReview = false; - m_BattleCausedOwnershipChange = false; - m_PreBattleTeamOwnership = Activity::NoTeam; - - ChangeAnimMode(TARGETZEROING); - m_AnimActivityChange = false; - } - - ///////////////////////////////////////////// - // Make a menacing target crosshairs zero in on the site we're playing this activity on - if (m_AnimMode == TARGETZEROING) - { - if (NewAnimMode()) - { - m_SiteAttackTarget.m_CenterPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); - m_SiteAttackTarget.m_AnimProgress = 0; - m_SiteAttackTarget.m_Color = c_GUIColorRed; - m_AnimModeDuration = 600; - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - m_SiteAttackTarget.m_AnimProgress = EaseOut(0.0, 1.0, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); - - // BAM - show the name of the site and start showing who's attacking it - if (m_SiteAttackTarget.m_AnimProgress == 1.0) - { -// // After a while, go on to show the attacker action site lines -// if (m_AnimTimer1.IsPastRealMS(1200)) -// { - ChangeAnimMode(LINECONNECTFW); - } - } - - ///////////////////////////////////////////// - // Show who's attacking this target; connect the attack budget lines (while still zeroed) and animate the brains going there from their respective pools - if (m_AnimMode == LINECONNECTFW) - { - if (NewAnimMode()) - { - // Make sure all offensive action lines are set up for this phase - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Find all players that are active during this battle - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // If this player is attacking, indicate that we've got a brain in transit.. this just changes the display, not the actual brain pool count yet - if (m_pAnimScene->GetPresetName() == g_MetaMan.m_Players[mp].GetOffensiveTargetName()) - g_MetaMan.m_Players[mp].ChangeBrainsInTransit(1); - - // Find their offensive funds site lines - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - // Offensive lines are red; set them up to have their meters visible - if ((*slItr).m_Color == c_GUIColorRed) - { - (*slItr).m_OnlyFirstSegments = 1; - (*slItr).m_OnlyLastSegments = -1; - } - } - } - } - - m_AnimSegment = 0; - m_AnimModeDuration = 2000; - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - - // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site - UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); - - // Keep revealing segments simultaneously from all attackers until they are all revealed - if (m_AnimSegment < 15) - { - if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) - { - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only care if this player is attacking this site - if (m_pAnimScene->GetPresetName() == g_MetaMan.m_Players[mp].GetOffensiveTargetName() && g_MetaMan.m_Players[mp].GetOffensiveBudget() > 0) -// if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Find their offensive funds site lines - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - // Offensive lines are red; grow all of em - if ((*slItr).m_Color == c_GUIColorRed) - (*slItr).m_OnlyFirstSegments++; - } - } - } - - m_AnimSegment++; - m_AnimTimer1.Reset(); - } - } - - // Animate the crosshairs subtly - m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); - - // Animate the brain label travel animations - UpdatePreBattleAttackers(EaseInOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); - UpdatePreBattleDefenders(0); - - // Just wait until the players hit the continue button.. - if (m_BattleToResume) - m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Resume <" : "Resume"); - else - m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Start! <" : "Start!"); - - // Move onto growing the attack budget meters - if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) - ChangeAnimMode(SHOWDEFENDERS); - } - - ///////////////////////////////////////////// - // Show the defending brains for this battle - if (m_AnimMode == SHOWDEFENDERS) - { - if (NewAnimMode()) - { - // Make sure all defensive and unallocated budget action lines are set up for this phase - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - - } - - m_AnimModeDuration = 500; - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - - // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site - UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); - - // Animate the crosshairs subtly - m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); - - // Keep the brain label travel animations in one spot and their labels updated - UpdatePreBattleAttackers(1.0); - UpdatePreBattleDefenders(EaseOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); - - // Just wait until the players hit the continue button.. - if (m_BattleToResume) - m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Resume <" : "Resume"); - else - m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Start! <" : "Start!"); - - // Move onto growing the attack budget meters - if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) - ChangeAnimMode(LINECONNECTBW); - } - - ///////////////////////////////////////////// - // Show the defending budget lines of the players who are defending this site - if (m_AnimMode == LINECONNECTBW) - { - if (NewAnimMode()) - { - // Make sure all defensive and unallocated budget action lines are set up for this phase - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only care of this player is involved in this particular battle - // Only care about defending players of this site - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())&& - m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && - m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Find their defensive funds site lines - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - // Offensive lines are green; unallocated funds are white - attach all of them - if ((*slItr).m_Color != c_GUIColorRed) - { - (*slItr).m_OnlyFirstSegments = -1; - (*slItr).m_OnlyLastSegments = 0; - } - } - } - } - - m_AnimSegment = 0; - m_AnimModeDuration = 1000; - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - - // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site - UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); - - // Keep revealing segments simultaneously from all attackers until they are all revealed - if (m_AnimSegment < 15) - { - if (m_AnimTimer1.GetElapsedRealTimeMS() > 150) - { - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only care of this player is involved in this particular battle - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Find their defensive-related funds site lines - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - // Offensive lines are red; grow the defensive ones relevant to this scene - if ((*slItr).m_Color != c_GUIColorRed && m_pAnimScene->GetPresetName() == (*slItr).m_SiteName && - (m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer()))) - (*slItr).m_OnlyLastSegments++; - } - } - } - m_AnimSegment++; - m_AnimTimer1.Reset(); - } - } - - // Animate the crosshairs subtly - m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); - - // Keep the brain label travel animations in one spot and their labels updated - UpdatePreBattleAttackers(1.0); - UpdatePreBattleDefenders(1.0); - - // Just wait until the players hit the continue button.. - if (m_BattleToResume) - m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Resume <" : "Resume"); - else - m_apMetaButton[CONTINUE]->SetText(m_AnimTimer2.AlternateReal(333) ? "> Start! <" : "Start!"); - } - - ////////////////////////////////// - // POST BATTLE REVIEW - - ///////////////////////////////////////////// - // A Short pause for after players come out of a run simulation battle, - // so they can orient themselves visually before battle review starts happening - if (m_AnimMode == SHOWPOSTBATTLEPAUSE) - { - if (NewAnimMode()) - { - // The length of the pause - m_AnimModeDuration = 2000; - - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - - // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site - UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); - // Animate the crosshairs subtly - m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); - - UpdatePostBattleRetreaters(0); - UpdatePostBattleResidents(0); - - // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles - m_apMetaButton[CONTINUE]->SetText("Next"); - - // Move onto having the victorious brains go back inside the site and take it over - if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) - ChangeAnimMode(SHOWPOSTBATTLEBALANCE); - } - - ///////////////////////////////////////////// - // Show how much is being allocated to attacking this place - if (m_AnimMode == SHOWPOSTBATTLEBALANCE) - { - if (NewAnimMode()) - { - m_AnimModeDuration = 2000; - - // Make sure all offensive action-related lines are set up for this battle review animation - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only the players of this battle - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Find their site lines that are connected to the site - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - // Only lines that are connected are relevant - if ((*slItr).m_OnlyFirstSegments > 1 || (*slItr).m_OnlyLastSegments > 1) - { - // Re-set the funds amount we're going from - actually, not necessary - (*slItr).m_FundsAmount = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer()); - // Set the target we're going toward - (*slItr).m_FundsTarget = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[mp].GetInGamePlayer()); - // Start the battle money display off at the right point too - m_aBattleFunds[mp] = (*slItr).m_FundsAmount; - // Display the change amount over/under the player bar - FundsChangeIndication(mp, (*slItr).m_FundsTarget - (*slItr).m_FundsAmount, Vector(m_apPlayerBarLabel[mp]->GetXPos() + m_apPlayerBarLabel[mp]->GetWidth(), m_apPlayerBarLabel[mp]->GetYPos()), m_AnimModeDuration); - - // Update the ratios.. shouldn't do anyhitng, really - UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); - } - } - } - } - - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - - // Find the players who are involved in this battle - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only the players of this battle - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // The brains who DID NOT MAKE IT - Show them blowing up at some random interval into the animation - if (!m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer()) && - !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // If not yet blown up, then see if we should yet - if (!m_aAnimDestroyed[mp] && m_AnimTimer2.GetElapsedRealTimeMS() > (m_AnimModeDuration * 0.5F) && RandomNum() < 0.05F) - { - // Add circle explosion effect to where the brain icon used to be - m_SiteSwitchIndicators.push_back(SiteTarget(m_aBrainIconPos[mp], 0, SiteTarget::CIRCLEGROW, c_GUIColorRed)); - // Switch the brain icon drawing off - m_aAnimDestroyed[mp] = true; - } - } - - // Find their site lines that are connected to the site - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - // Only lines that are connected are relevant - if ((*slItr).m_OnlyFirstSegments > 1 || (*slItr).m_OnlyLastSegments > 1) - { - float startFunds = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer()); - - // Grow/shrink all the meters, showing how the funds changed during battle - if (m_AnimTimer1.GetElapsedRealTimeMS() < m_AnimModeDuration) - { - // Make this animation correlate in duration with the funds change label that rises - (*slItr).m_FundsAmount = EaseOut(startFunds, (*slItr).m_FundsTarget, m_AnimTimer1.GetElapsedRealTimeMS() / m_AnimModeDuration); - // Update the battle funds display; it will be shown in the brian action label - m_aBattleFunds[mp] = (*slItr).m_FundsAmount; - // Adjust the funds to show how much we subtracted this frame - this will be reset in the end anyway, it's just for show during this battle review animation - g_MetaMan.m_Players[mp].m_Funds = g_MetaMan.m_Players[mp].m_PhaseStartFunds - (startFunds - (*slItr).m_FundsAmount); - UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); - } - // Finished growing the meter to the target size - else - { - m_aBattleFunds[mp] = (*slItr).m_FundsAmount = (*slItr).m_FundsTarget; - g_MetaMan.m_Players[mp].m_Funds = g_MetaMan.m_Players[mp].m_PhaseStartFunds - (startFunds - (*slItr).m_FundsAmount); - UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); - } - } - } - } - } - - // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site - UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); - // Animate the crosshairs subtly - m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); - - // Animate the brain label travel animations - UpdatePostBattleRetreaters(0); - UpdatePostBattleResidents(0); - - UpdatePlayerBars(); - // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles - m_apMetaButton[CONTINUE]->SetText("Next"); - - // Move onto showing what happened to each brain - if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) - { - // Blow up any remaining brains who are doomed - // Find the players who are involved in this battle - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only the players of this battle who didn't evacuate - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer()) && - !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // The brains who DID NOT MAKE IT - Show them blowing up - if (!m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // If not yet blown up, then we should be - if (!m_aAnimDestroyed[mp]) - { - // Add circle explosion effect to where the brain icon used to be - m_SiteSwitchIndicators.push_back(SiteTarget(m_aBrainIconPos[mp], 0, SiteTarget::CIRCLEGROW, c_GUIColorRed)); - // Switch the brain icon drawing off - m_aAnimDestroyed[mp] = true; - } - } - } - } - ChangeAnimMode(SHOWPOSTBATTLEBRAINS); - } - } - - ///////////////////////////////////////////// - // Show what happened to the brains after a battle - if (m_AnimMode == SHOWPOSTBATTLEBRAINS) - { - if (NewAnimMode()) - { - // Make sure all defensive and unallocated budget action lines are set up for this phase - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - - } - - // The duration of this depends on whethere there are any evacuees to travel back - m_AnimModeDuration = g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->AnyBrainWasEvacuated() ? 2000 : 500; - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - - // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site - UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); - // Animate the crosshairs subtly - m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); - - // The retreating brain label travel animations get updated to go back to their pools - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->AnyBrainWasEvacuated()) - UpdatePostBattleRetreaters(EaseInOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); - else - UpdatePostBattleRetreaters(1.0); - UpdatePostBattleResidents(0); - - // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles - m_apMetaButton[CONTINUE]->SetText("Next"); - - // Move onto having the victorious brains go back inside the site and take it over - if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) - { - // Change the display to show the evacuees transferring back to their brain pools - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->AnyBrainWasEvacuated()) - { - // Find the players who are evacuated anything this battle - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only the players of this battle who evac'd their brain - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Both an Attacker aborting an attack, and a Defender abandoning his site has the same effect here on the brian pool display - g_MetaMan.m_Players[mp].ChangeBrainsInTransit(-1); - } - } - } - - ChangeAnimMode(SHOWNEWRESIDENTS); - } - } - - ///////////////////////////////////////////// - // Show the victorious brains going back into the site and taking it over - if (m_AnimMode == SHOWNEWRESIDENTS) - { - if (NewAnimMode()) - { - // Make sure all defensive and unallocated budget action lines are set up for this phase - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - - } - - m_AnimModeDuration = m_BattleCausedOwnershipChange ? 500 : 750; - m_AnimTimer1.Reset(); - m_AnimTimer2.Reset(); - } - - // Keep the name on the attack site, keeping the name high so the contestants' info can fit in the quadrants around the site - UpdateSiteNameLabel(true, m_pAnimScene->GetPresetName(), m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 1.8); - // Animate the crosshairs subtly - m_SiteAttackTarget.m_AnimProgress = 0.975 + 0.025 * cos(c_TwoPI * (float)((int)m_AnimTimer2.GetElapsedRealTimeMS() % 666) / 666.0f); - - // The brains going back into their lair are animated - UpdatePostBattleRetreaters(1.0); - // Tweak the animaiton slightly based on whether the site switched hands or not - if (m_BattleCausedOwnershipChange) - UpdatePostBattleResidents(EaseIn(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); - else - UpdatePostBattleResidents(EaseOut(0, 1.0, MIN(1.0, m_AnimTimer2.GetElapsedRealTimeMS() / m_AnimModeDuration))); - - // Find the players who are involved in this battle - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only the players of this battle - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // The guys who died - remove their icons completely - if (!m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - m_apPlayerBrainTravelLabel[mp]->SetVisible(false); - } - } - - // Give the players the option to skip the post battle review and go to next battle, or phase if there aren't any more battles - m_apMetaButton[CONTINUE]->SetText("Next"); - - // Move onto the next offensive in line, if any! - if (m_AnimTimer2.GetElapsedRealTimeMS() > m_AnimModeDuration) - { - // Quit if there's no more offensives after the one we just finalized - if (!FinalizeOffensive()) - return; - } - } - - - ///////////////////////////////////////////// - // If the player have chosen to start the attack activity by hitting the continue button, then do eeeet - if (!m_PreTurn) - { - // Make sure this is set back - m_apMetaButton[CONTINUE]->SetText("Start!"); - UpdateSiteNameLabel(false); - - // Max out the offensive lines in case the player started the battle before the lines were fully animated as connected - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only care of this player is involved in this particular battle - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - for (std::vector::iterator slItr = m_ActionSiteLines[mp].begin(); slItr != m_ActionSiteLines[mp].end(); ++slItr) - { - // Only show lines that are going to the site we're battling on - if ((*slItr).m_SiteName == m_pAnimScene->GetPresetName()) - { - // Find their offensive funds site lines and set the offensive budget back to where it is supposed to end up - if ((*slItr).m_Color == c_GUIColorRed) - (*slItr).m_OnlyFirstSegments = 15; - // Defensive site - else if (m_pAnimScene->GetTeamOwnership() == g_MetaMan.m_Players[mp].GetTeam() && m_pAnimScene->GetResidentBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - (*slItr).m_OnlyLastSegments = 15; - } - // Hide all other lines - else - { - (*slItr).m_OnlyFirstSegments = 0; - (*slItr).m_OnlyLastSegments = 0; - } - } - } - } - - // Resuming ongoing battle - if (m_BattleToResume) - { - m_BattleToResume = false; - m_ActivityResumed = true; - g_GUISound.ExitMenuSound()->Play(); - } - // Starting the next battle - else - { - // Clear the battle info of the last one -// No need here; it is done in FinalizeOffensive, and it actually screw up the positions of the losing brain labels, which should stay put until after rewview is over -// ResetBattleInfo(); - - if (g_MetaMan.m_CurrentOffensive < g_MetaMan.m_RoundOffensives.size()) - { - // Temporarly save the previous ownership state of the scene, so it can be held and displayed until the dramatic change is shown in battle review - m_PreBattleTeamOwnership = m_pAnimScene->GetTeamOwnership(); - - // No human players in this one, or only one team going here? Then skip the whole sim and just show the result of the site - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetHumanCount() < 1 || g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetTeamCount() == 1) - { - // AUTOMATIC BATTLE RESOLUTION - // If the automatic resolution caused a site change, show it clearly with animated crosshairs - m_BattleCausedOwnershipChange = AutoResolveOffensive(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive], const_cast(m_pAnimScene)); - - // Move onto showing what happened in the battle before we move on to next battle - m_PreTurn = true; - m_PostBattleReview = true; - ChangeAnimMode(SHOWPOSTBATTLEBALANCE); - } - // START SIM with activity that has at least one human player involved and more than one team total - else - { - m_pPlayingScene = const_cast(m_pAnimScene); - g_SceneMan.SetSceneToLoad(m_pPlayingScene); - g_ActivityMan.SetStartActivity(dynamic_cast(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->Clone())); - m_ActivityRestarted = true; - } - } - // Whoops, we have no further activities left to start, so just continue to next round phase (shouldn't happen; this is handled in CompletedActivity) - else - { - // Turn off drawing the aciton meters draw all the time - m_ActionMeterDrawOverride = false; - m_ContinuePhase = true; - } - } - } + // Resuming ongoing battle + if (m_BattleToResume) { + m_BattleToResume = false; + m_ActivityResumed = true; + g_GUISound.ExitMenuSound()->Play(); + } + // Starting the next battle + else { + // Clear the battle info of the last one + // No need here; it is done in FinalizeOffensive, and it actually screw up the positions of the losing brain labels, which should stay put until after rewview is over + // ResetBattleInfo(); + + if (g_MetaMan.m_CurrentOffensive < g_MetaMan.m_RoundOffensives.size()) { + // Temporarly save the previous ownership state of the scene, so it can be held and displayed until the dramatic change is shown in battle review + m_PreBattleTeamOwnership = m_pAnimScene->GetTeamOwnership(); + + // No human players in this one, or only one team going here? Then skip the whole sim and just show the result of the site + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetHumanCount() < 1 || g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetTeamCount() == 1) { + // AUTOMATIC BATTLE RESOLUTION + // If the automatic resolution caused a site change, show it clearly with animated crosshairs + m_BattleCausedOwnershipChange = AutoResolveOffensive(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive], const_cast(m_pAnimScene)); + + // Move onto showing what happened in the battle before we move on to next battle + m_PreTurn = true; + m_PostBattleReview = true; + ChangeAnimMode(SHOWPOSTBATTLEBALANCE); + } + // START SIM with activity that has at least one human player involved and more than one team total + else { + m_pPlayingScene = const_cast(m_pAnimScene); + g_SceneMan.SetSceneToLoad(m_pPlayingScene); + g_ActivityMan.SetStartActivity(dynamic_cast(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->Clone())); + m_ActivityRestarted = true; + } + } + // Whoops, we have no further activities left to start, so just continue to next round phase (shouldn't happen; this is handled in CompletedActivity) + else { + // Turn off drawing the aciton meters draw all the time + m_ActionMeterDrawOverride = false; + m_ContinuePhase = true; + } + } + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: FinalizeOffensive ////////////////////////////////////////////////////////////////////////////////////////// // Description: Finishes one battle in the UpdateOffensives and moves onto the next. -bool MetagameGUI::FinalizeOffensive() -{ - // No Offensives this round? then skip all this business - if (g_MetaMan.m_RoundOffensives.empty() || g_MetaMan.m_CurrentOffensive < 0 || g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || !m_pAnimScene) - { - m_ContinuePhase = true; - return false; - } - - // Deduct the original funds contribution of each player - less any unused funds of the team, taking original player contribution ratios into account - for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) - { - // Only the players who were battling this offensive - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) - { - // Re-set the funds level to where it was at the start of this offensive (NOT at the start of the phase, actually) - g_MetaMan.m_Players[mp].m_Funds = g_MetaMan.m_Players[mp].m_PhaseStartFunds; - // Deduct the original contribution to team funds - g_MetaMan.m_Players[mp].m_Funds -= g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer()); - // Add back whatever his share of whatever his team has left in the fight at its end - g_MetaMan.m_Players[mp].m_Funds += g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[mp].GetInGamePlayer()); - // IF This guy was ATTACKING this turn, adjust his attack budget to match what just happened in the battle - // so in case he is defending in a upcoming battle this turn, his avaialbe funds will be accurately calculated - if (g_MetaMan.m_Players[mp].GetOffensiveTargetName() == m_pAnimScene->GetPresetName()) - { - g_MetaMan.m_Players[mp].SetOffensiveBudget(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[mp].GetInGamePlayer())); -// g_MetaMan.m_Players[mp].SetOffensiveTargetName(""); - - // The only condition where this attacking player does NOT get a brain deducted from pool, is when he aborts the attack with an evacuation and the brain goes back to pool! - if (!g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) - g_MetaMan.m_Players[mp].ChangeBrainPoolCount(-1); - } - // Defending player - else - { - // If this player evacuated his brain, WHILE DEFENDING, then add it back to his pool - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) - g_MetaMan.m_Players[mp].ChangeBrainPoolCount(1); - } - // Update the ratios of the meter now that the funds have changed - UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); - // Clear out the brain transit display either way; nothing should be out flying now anyway - g_MetaMan.m_Players[mp].SetBrainsInTransit(0); - } - } - - // If the battle caused ownership change, then show it with a cool indication - if (m_BattleCausedOwnershipChange) - m_SiteSwitchIndicators.push_back(SiteTarget(m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 0, m_pAnimScene->GetTeamOwnership() != Activity::NoTeam ? SiteTarget::SQUAREGROW : SiteTarget::CIRCLEGROW, c_GUIColorRed, m_AnimTimer2.GetElapsedRealTimeMS())); - - // Clear the battle info of the last one - ResetBattleInfo(); - // Clear the site name label - UpdateSiteNameLabel(false); - // Done reviewing the battle - m_PostBattleReview = false; - // We're done with this activity - m_AnimActivityChange = true; - - // Update the count to point to the next (now current) offensive - g_MetaMan.m_CurrentOffensive++; - - // AUTO-SAVE THE GAME AFTER EACH PLAYED BATTLE - SaveGame(AUTOSAVENAME, METASAVEPATH + std::string(AUTOSAVENAME) + ".ini", false); - - // If we're out of offensives, then move onto the next phase - if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size()) - { - m_ContinuePhase = true; - // Quit out of here, there's no more battles to fight! - return false; - } - // Indicate that there's at least one more battle lined up now - return true; -} +bool MetagameGUI::FinalizeOffensive() { + // No Offensives this round? then skip all this business + if (g_MetaMan.m_RoundOffensives.empty() || g_MetaMan.m_CurrentOffensive < 0 || g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || !m_pAnimScene) { + m_ContinuePhase = true; + return false; + } + + // Deduct the original funds contribution of each player - less any unused funds of the team, taking original player contribution ratios into account + for (int mp = Players::PlayerOne; mp < g_MetaMan.m_Players.size(); ++mp) { + // Only the players who were battling this offensive + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain(g_MetaMan.m_Players[mp].GetInGamePlayer())) { + // Re-set the funds level to where it was at the start of this offensive (NOT at the start of the phase, actually) + g_MetaMan.m_Players[mp].m_Funds = g_MetaMan.m_Players[mp].m_PhaseStartFunds; + // Deduct the original contribution to team funds + g_MetaMan.m_Players[mp].m_Funds -= g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsContribution(g_MetaMan.m_Players[mp].GetInGamePlayer()); + // Add back whatever his share of whatever his team has left in the fight at its end + g_MetaMan.m_Players[mp].m_Funds += g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[mp].GetInGamePlayer()); + // IF This guy was ATTACKING this turn, adjust his attack budget to match what just happened in the battle + // so in case he is defending in a upcoming battle this turn, his avaialbe funds will be accurately calculated + if (g_MetaMan.m_Players[mp].GetOffensiveTargetName() == m_pAnimScene->GetPresetName()) { + g_MetaMan.m_Players[mp].SetOffensiveBudget(g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->GetPlayerFundsShare(g_MetaMan.m_Players[mp].GetInGamePlayer())); + // g_MetaMan.m_Players[mp].SetOffensiveTargetName(""); + + // The only condition where this attacking player does NOT get a brain deducted from pool, is when he aborts the attack with an evacuation and the brain goes back to pool! + if (!g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) + g_MetaMan.m_Players[mp].ChangeBrainPoolCount(-1); + } + // Defending player + else { + // If this player evacuated his brain, WHILE DEFENDING, then add it back to his pool + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated(g_MetaMan.m_Players[mp].GetInGamePlayer())) + g_MetaMan.m_Players[mp].ChangeBrainPoolCount(1); + } + // Update the ratios of the meter now that the funds have changed + UpdatePlayerLineRatios(m_ActionSiteLines[mp], mp, false, g_MetaMan.m_Players[mp].m_Funds); + // Clear out the brain transit display either way; nothing should be out flying now anyway + g_MetaMan.m_Players[mp].SetBrainsInTransit(0); + } + } + // If the battle caused ownership change, then show it with a cool indication + if (m_BattleCausedOwnershipChange) + m_SiteSwitchIndicators.push_back(SiteTarget(m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(), 0, m_pAnimScene->GetTeamOwnership() != Activity::NoTeam ? SiteTarget::SQUAREGROW : SiteTarget::CIRCLEGROW, c_GUIColorRed, m_AnimTimer2.GetElapsedRealTimeMS())); + + // Clear the battle info of the last one + ResetBattleInfo(); + // Clear the site name label + UpdateSiteNameLabel(false); + // Done reviewing the battle + m_PostBattleReview = false; + // We're done with this activity + m_AnimActivityChange = true; + + // Update the count to point to the next (now current) offensive + g_MetaMan.m_CurrentOffensive++; + + // AUTO-SAVE THE GAME AFTER EACH PLAYED BATTLE + SaveGame(AUTOSAVENAME, METASAVEPATH + std::string(AUTOSAVENAME) + ".ini", false); + + // If we're out of offensives, then move onto the next phase + if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size()) { + m_ContinuePhase = true; + // Quit out of here, there's no more battles to fight! + return false; + } + // Indicate that there's at least one more battle lined up now + return true; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: ResetBattleInfo ////////////////////////////////////////////////////////////////////////////////////////// // Description: Hides and resets all battle info labels and panels -void MetagameGUI::ResetBattleInfo() -{ - int mp = 0; - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - { - // Init and hide everything initially - if (!m_apPlayerTeamActionBox[mp]->GetDrawImage()) - { - // Set the flag icons on the floating player bars - m_apPlayerTeamActionBox[mp]->SetDrawType(GUICollectionBox::Image); - m_apPlayerTeamActionBox[mp]->SetDrawImage(new AllegroBitmap(g_MetaMan.m_TeamIcons[(*mpItr).GetTeam()].GetBitmaps32()[0])); - } - // Hide everything initially - m_apPlayerTeamActionBox[mp]->SetVisible(false); - m_apPlayerTeamActionBox[mp]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - m_apPlayerBrainTravelLabel[mp]->SetVisible(false); - m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - - ++mp; - } - - // Done reviewing the battle too - m_PostBattleReview = false; -} +void MetagameGUI::ResetBattleInfo() { + int mp = 0; + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) { + // Init and hide everything initially + if (!m_apPlayerTeamActionBox[mp]->GetDrawImage()) { + // Set the flag icons on the floating player bars + m_apPlayerTeamActionBox[mp]->SetDrawType(GUICollectionBox::Image); + m_apPlayerTeamActionBox[mp]->SetDrawImage(new AllegroBitmap(g_MetaMan.m_TeamIcons[(*mpItr).GetTeam()].GetBitmaps32()[0])); + } + // Hide everything initially + m_apPlayerTeamActionBox[mp]->SetVisible(false); + m_apPlayerTeamActionBox[mp]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + m_apPlayerBrainTravelLabel[mp]->SetVisible(false); + m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + ++mp; + } + + // Done reviewing the battle too + m_PostBattleReview = false; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateBattleQuads @@ -5187,196 +4669,179 @@ void MetagameGUI::ResetBattleInfo() // Description: Updates which player get placed in which quad around a fought-over // site. -void MetagameGUI::UpdateBattleQuads(Vector targetPos) -{ - // Start with a clean slate - for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) - m_aQuadTakenBy[q] = Players::NoPlayer; - - // Go through all players, assigning the quads depending on how the player bars are positioned in relation to each other - int mp = 0; - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - { - // Select which quadrant makes most sense for this player, based on his floating bar's position relative to the site - int initialQuad = 0; - if (m_apPlayerBox[mp]->GetXPos() < targetPos.m_X) - initialQuad = m_apPlayerBox[mp]->GetYPos() < targetPos.m_Y ? 0 : 1; - else - initialQuad = m_apPlayerBox[mp]->GetYPos() < targetPos.m_Y ? 3 : 2; - - // If the initial selection is taken, just find the next available one - int quadIndex = initialQuad; - while (m_aQuadTakenBy[quadIndex] != Players::NoPlayer) - { - quadIndex++; - // Loop around - if (quadIndex >= 4) - quadIndex = 0; - // If we've looped completely around, somehting's wrong! There should always be at least one quad available - if (quadIndex == initialQuad) - break; - } - // Mark this spot as taken by this player - m_aQuadTakenBy[quadIndex] = mp; - // Advance the metaplayer index to sync with the iterator - mp++; - } +void MetagameGUI::UpdateBattleQuads(Vector targetPos) { + // Start with a clean slate + for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) + m_aQuadTakenBy[q] = Players::NoPlayer; + + // Go through all players, assigning the quads depending on how the player bars are positioned in relation to each other + int mp = 0; + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) { + // Select which quadrant makes most sense for this player, based on his floating bar's position relative to the site + int initialQuad = 0; + if (m_apPlayerBox[mp]->GetXPos() < targetPos.m_X) + initialQuad = m_apPlayerBox[mp]->GetYPos() < targetPos.m_Y ? 0 : 1; + else + initialQuad = m_apPlayerBox[mp]->GetYPos() < targetPos.m_Y ? 3 : 2; + + // If the initial selection is taken, just find the next available one + int quadIndex = initialQuad; + while (m_aQuadTakenBy[quadIndex] != Players::NoPlayer) { + quadIndex++; + // Loop around + if (quadIndex >= 4) + quadIndex = 0; + // If we've looped completely around, somehting's wrong! There should always be at least one quad available + if (quadIndex == initialQuad) + break; + } + // Mark this spot as taken by this player + m_aQuadTakenBy[quadIndex] = mp; + // Advance the metaplayer index to sync with the iterator + mp++; + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePreBattleAttackers ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the animation and display of the info for the current // offensive battle being next in line for this round. -void MetagameGUI::UpdatePreBattleAttackers(float progress) -{ - // Sanity check that we have any offensive battle activity and scene to display around - if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || - !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || - !m_pAnimScene) - return; - - int mp = 0; - char str[256]; - int quadIndex = Players::NoPlayer; - // The screen coordinate position of the current battle site - Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); - // Where the brain label starts from - Vector brainLabelStartPos; - // Where it ends up, aligned properly next to the site, in the proper quadrant - Vector brainLabelSitePos; - // The distance the brain label should travel between the two - Vector brainLabelTravel; - // The actual total distance it will travel, when going along each cardinal axis at a time - float brainTravelLength; - // The animation progress point at which travel switches from one axis to the other - float travelSwitchRatio; - // The actual current position of the brain label at the current specified animaiton progress point - Vector brainTravelPos; - - // Update the quad assignments for all players - UpdateBattleQuads(siteScreenPos); - - // Go through all attacking players for this activity - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - { - // Player active and ATTACKING in current battle, so display his team flag and place it according to the animation progress - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive((*mpItr).GetInGamePlayer()) && - !m_pAnimScene->GetResidentBrain((*mpItr).GetInGamePlayer())) - { - // Show the active players' team flag icons around the site if the brains have arrived - m_apPlayerTeamActionBox[mp]->SetVisible(progress >= 1.0); - // Show the traveling brain if we're not at 0 - m_apPlayerBrainTravelLabel[mp]->SetVisible(progress > 0); - - // Figure out which quad this player is assigned to - for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) - { - if (m_aQuadTakenBy[q] == mp) - { - quadIndex = q; - break; - } - } - - // Write the brain label, with info if applicable for the current progress of animation - if (progress < 1.0) - std::snprintf(str, sizeof(str), "%c", -48); - // When at site destination, take into account the side the brain icon needs to be on - else - { - if (quadIndex <= 1) - std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); - else - std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); - } - m_apPlayerBrainTravelLabel[mp]->SetText(str); - m_apPlayerBrainTravelLabel[mp]->SetToolTip("The specific brain that is being sent in to attack this place, and the funds he has been budgeted to do so with."); - - // Figure out start and ending positions for the brain label's travels and the team flag badge - // Upper left quadrant - if (quadIndex == 0) - { - // Team flag position - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - } - // Lower left quadrant - else if (quadIndex == 1) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); - } - // Lower right quadrant - else if (quadIndex == 2) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); - } - // Upper right quadrant - else if (quadIndex == 3) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - } - - // Now place the travelling brain label at the appropriate spot based on the animation progress - brainLabelTravel = brainLabelSitePos - brainLabelStartPos; - // The raw distance the label needs to travel when going down one axis and then the other - brainTravelLength = fabs(brainLabelTravel.m_X) + fabs(brainLabelTravel.m_Y); - // Figure out where along the progression that brain travel switches from one axis to the other - travelSwitchRatio = fabs(brainLabelTravel.m_Y) / brainTravelLength; - - // If animation progress is less than where the switch happens, handle that - if (progress <= travelSwitchRatio) - { - // No progress in X - brainTravelPos.m_X = brainLabelStartPos.m_X; - // Some progress in Y - brainTravelPos.m_Y = brainLabelStartPos.m_Y + (brainLabelTravel.m_Y * (progress / travelSwitchRatio)); - } - // Progress is past the switch - else if (progress < 1.0) - { - // Some progress in X - brainTravelPos.m_X = brainLabelStartPos.m_X + (brainLabelTravel.m_X * ((progress - travelSwitchRatio) / (1.0 - travelSwitchRatio))); - // FULL progress in Y - brainTravelPos.m_Y = brainLabelSitePos.m_Y; - } - // Reached destination - else - brainTravelPos = brainLabelSitePos; - - // Now actually move the label - m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); - } - // Advance the metaplayer index to sync with the iterator - mp++; - } -} +void MetagameGUI::UpdatePreBattleAttackers(float progress) { + // Sanity check that we have any offensive battle activity and scene to display around + if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || + !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || + !m_pAnimScene) + return; + + int mp = 0; + char str[256]; + int quadIndex = Players::NoPlayer; + // The screen coordinate position of the current battle site + Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); + // Where the brain label starts from + Vector brainLabelStartPos; + // Where it ends up, aligned properly next to the site, in the proper quadrant + Vector brainLabelSitePos; + // The distance the brain label should travel between the two + Vector brainLabelTravel; + // The actual total distance it will travel, when going along each cardinal axis at a time + float brainTravelLength; + // The animation progress point at which travel switches from one axis to the other + float travelSwitchRatio; + // The actual current position of the brain label at the current specified animaiton progress point + Vector brainTravelPos; + + // Update the quad assignments for all players + UpdateBattleQuads(siteScreenPos); + + // Go through all attacking players for this activity + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) { + // Player active and ATTACKING in current battle, so display his team flag and place it according to the animation progress + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive((*mpItr).GetInGamePlayer()) && + !m_pAnimScene->GetResidentBrain((*mpItr).GetInGamePlayer())) { + // Show the active players' team flag icons around the site if the brains have arrived + m_apPlayerTeamActionBox[mp]->SetVisible(progress >= 1.0); + // Show the traveling brain if we're not at 0 + m_apPlayerBrainTravelLabel[mp]->SetVisible(progress > 0); + + // Figure out which quad this player is assigned to + for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) { + if (m_aQuadTakenBy[q] == mp) { + quadIndex = q; + break; + } + } + + // Write the brain label, with info if applicable for the current progress of animation + if (progress < 1.0) + std::snprintf(str, sizeof(str), "%c", -48); + // When at site destination, take into account the side the brain icon needs to be on + else { + if (quadIndex <= 1) + std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); + else + std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); + } + m_apPlayerBrainTravelLabel[mp]->SetText(str); + m_apPlayerBrainTravelLabel[mp]->SetToolTip("The specific brain that is being sent in to attack this place, and the funds he has been budgeted to do so with."); + + // Figure out start and ending positions for the brain label's travels and the team flag badge + // Upper left quadrant + if (quadIndex == 0) { + // Team flag position + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + } + // Lower left quadrant + else if (quadIndex == 1) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); + } + // Lower right quadrant + else if (quadIndex == 2) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); + } + // Upper right quadrant + else if (quadIndex == 3) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + } + // Now place the travelling brain label at the appropriate spot based on the animation progress + brainLabelTravel = brainLabelSitePos - brainLabelStartPos; + // The raw distance the label needs to travel when going down one axis and then the other + brainTravelLength = fabs(brainLabelTravel.m_X) + fabs(brainLabelTravel.m_Y); + // Figure out where along the progression that brain travel switches from one axis to the other + travelSwitchRatio = fabs(brainLabelTravel.m_Y) / brainTravelLength; + + // If animation progress is less than where the switch happens, handle that + if (progress <= travelSwitchRatio) { + // No progress in X + brainTravelPos.m_X = brainLabelStartPos.m_X; + // Some progress in Y + brainTravelPos.m_Y = brainLabelStartPos.m_Y + (brainLabelTravel.m_Y * (progress / travelSwitchRatio)); + } + // Progress is past the switch + else if (progress < 1.0) { + // Some progress in X + brainTravelPos.m_X = brainLabelStartPos.m_X + (brainLabelTravel.m_X * ((progress - travelSwitchRatio) / (1.0 - travelSwitchRatio))); + // FULL progress in Y + brainTravelPos.m_Y = brainLabelSitePos.m_Y; + } + // Reached destination + else + brainTravelPos = brainLabelSitePos; + + // Now actually move the label + m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); + } + // Advance the metaplayer index to sync with the iterator + mp++; + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePreBattleDefenders @@ -5384,139 +4849,128 @@ void MetagameGUI::UpdatePreBattleAttackers(float progress) // Description: Updates the animation and display of the info for the current // offensive battle's defenders being next in line for this round. -void MetagameGUI::UpdatePreBattleDefenders(float progress) -{ - // Sanity check that we have any offensive battle activity and scene to display around - if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || - !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || - !m_pAnimScene) - return; - - int mp = 0; - char str[256]; - int quadIndex = Players::NoPlayer; - // The screen coordinate position of the current battle site - Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); - // Where the brain label starts from - Vector brainLabelStartPos; - // Where it ends up, aligned properly next to the site, in the proper quadrant - Vector brainLabelSitePos; - // The distance the brain label should travel between the two - Vector brainLabelTravel; - // The actual total distance it will travel, when going along each cardinal axis at a time - //float brainTravelLength; - // The animation progress point at which travel switches from one axis to the other - //float travelSwitchRatio; - // The actual current position of the brain label at the current specified animaiton progress point - Vector brainTravelPos; - - // Update the quad assignments for all players - UpdateBattleQuads(siteScreenPos); - - // Go through all players for this activity - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - { - // Player active and DEFENDING in current battle, so display his team flag and place it according to the animation progress - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive((*mpItr).GetInGamePlayer()) && - m_pAnimScene->GetResidentBrain((*mpItr).GetInGamePlayer())) - { - // Show the active players' team flag icons around the site if the brains have arrived - m_apPlayerTeamActionBox[mp]->SetVisible(progress >= 1.0); - // Show the traveling brain if we're not at 0 - m_apPlayerBrainTravelLabel[mp]->SetVisible(progress > 0); - - // Figure out which quad this player is assigned to - for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) - { - if (m_aQuadTakenBy[q] == mp) - { - quadIndex = q; - break; - } - } - - // Write the brain label, with info if applicable for the current progress of animation - if (progress < 1.0) - std::snprintf(str, sizeof(str), "%c", -48); - // When at site destination, take into account the side the brain icon needs to be on - else - { - if (quadIndex <= 1) - std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); - else - std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); - } - m_apPlayerBrainTravelLabel[mp]->SetText(str); - m_apPlayerBrainTravelLabel[mp]->SetToolTip("The resident brain that is defending this site from attack, and the unallocated funds of its player that he gets to use (beyond the defense investments already made here)."); - - // Figure out start and ending positions for the brain label's travels and the team flag badge - // Upper left quadrant - if (quadIndex == 0) - { - // Team flag position - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - } - // Lower left quadrant - else if (quadIndex == 1) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); - } - // Lower right quadrant - else if (quadIndex == 2) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); - } - // Upper right quadrant - else if (quadIndex == 3) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label start position, taking into account its text alignment - brainLabelStartPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - } - - // Now place the travelling brain label at the appropriate spot based on the animation progress - brainLabelTravel = brainLabelSitePos - brainLabelStartPos; - - // How far have we come - if (progress <= 0) - brainTravelPos = brainLabelStartPos; - // Somewhere in between - else if (progress < 1.0) - brainTravelPos = brainLabelStartPos + brainLabelTravel * progress; - // Reached destination - else - brainTravelPos = brainLabelSitePos; - - // Now actually move the label - m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); - } - // Advance the metaplayer index to sync with the iterator - mp++; - } -} +void MetagameGUI::UpdatePreBattleDefenders(float progress) { + // Sanity check that we have any offensive battle activity and scene to display around + if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || + !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || + !m_pAnimScene) + return; + + int mp = 0; + char str[256]; + int quadIndex = Players::NoPlayer; + // The screen coordinate position of the current battle site + Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); + // Where the brain label starts from + Vector brainLabelStartPos; + // Where it ends up, aligned properly next to the site, in the proper quadrant + Vector brainLabelSitePos; + // The distance the brain label should travel between the two + Vector brainLabelTravel; + // The actual total distance it will travel, when going along each cardinal axis at a time + // float brainTravelLength; + // The animation progress point at which travel switches from one axis to the other + // float travelSwitchRatio; + // The actual current position of the brain label at the current specified animaiton progress point + Vector brainTravelPos; + + // Update the quad assignments for all players + UpdateBattleQuads(siteScreenPos); + + // Go through all players for this activity + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) { + // Player active and DEFENDING in current battle, so display his team flag and place it according to the animation progress + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerActive((*mpItr).GetInGamePlayer()) && + m_pAnimScene->GetResidentBrain((*mpItr).GetInGamePlayer())) { + // Show the active players' team flag icons around the site if the brains have arrived + m_apPlayerTeamActionBox[mp]->SetVisible(progress >= 1.0); + // Show the traveling brain if we're not at 0 + m_apPlayerBrainTravelLabel[mp]->SetVisible(progress > 0); + + // Figure out which quad this player is assigned to + for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) { + if (m_aQuadTakenBy[q] == mp) { + quadIndex = q; + break; + } + } + + // Write the brain label, with info if applicable for the current progress of animation + if (progress < 1.0) + std::snprintf(str, sizeof(str), "%c", -48); + // When at site destination, take into account the side the brain icon needs to be on + else { + if (quadIndex <= 1) + std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); + else + std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); + } + m_apPlayerBrainTravelLabel[mp]->SetText(str); + m_apPlayerBrainTravelLabel[mp]->SetToolTip("The resident brain that is defending this site from attack, and the unallocated funds of its player that he gets to use (beyond the defense investments already made here)."); + + // Figure out start and ending positions for the brain label's travels and the team flag badge + // Upper left quadrant + if (quadIndex == 0) { + // Team flag position + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + } + // Lower left quadrant + else if (quadIndex == 1) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); + } + // Lower right quadrant + else if (quadIndex == 2) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); + } + // Upper right quadrant + else if (quadIndex == 3) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label start position, taking into account its text alignment + brainLabelStartPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + } + // Now place the travelling brain label at the appropriate spot based on the animation progress + brainLabelTravel = brainLabelSitePos - brainLabelStartPos; + + // How far have we come + if (progress <= 0) + brainTravelPos = brainLabelStartPos; + // Somewhere in between + else if (progress < 1.0) + brainTravelPos = brainLabelStartPos + brainLabelTravel * progress; + // Reached destination + else + brainTravelPos = brainLabelSitePos; + + // Now actually move the label + m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); + } + // Advance the metaplayer index to sync with the iterator + mp++; + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePostBattleRetreaters @@ -5524,154 +4978,141 @@ void MetagameGUI::UpdatePreBattleDefenders(float progress) // Description: Updates the animation and display of the info for the current // offensive battle's retreating brains going back to their pools -void MetagameGUI::UpdatePostBattleRetreaters(float progress) -{ - // Sanity check that we have any offensive battle activity and scene to display around - if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || - !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || - !m_pAnimScene) - return; - - int mp = 0; - char str[256]; - int quadIndex = Players::NoPlayer; - // The screen coordinate position of the current battle site - Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); - // Where it ends up, aligned properly next to the site, in the proper quadrant - Vector brainLabelSitePos; - // Where the brain label ends at, back at the pool - Vector brainLabelEndPos; - // The distance the brain label should travel between the two - Vector brainLabelTravel; - // The actual total distance it will travel, when going along each cardinal axis at a time - float brainTravelLength; - // The animation progress point at which travel switches from one axis to the other - float travelSwitchRatio; - // The actual current position of the brain label at the current specified animaiton progress point - Vector brainTravelPos; - - // Update the quad assignments for all players - UpdateBattleQuads(siteScreenPos); - - // Go through all players for this activity - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - { - // Player active and EVACUATION/RETREATING in current battle, so display his team flag and place it according to the animation progress - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain((*mpItr).GetInGamePlayer()) && - g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated((*mpItr).GetInGamePlayer())) - { - // Show the active players' team flag icons around the site if the brains have arrived - m_apPlayerTeamActionBox[mp]->SetVisible(progress <= 0); - // Show the traveling brain if we're not at destination yet - m_apPlayerBrainTravelLabel[mp]->SetVisible(progress < 1.0); - - // Figure out which quad this player is assigned to - for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) - { - if (m_aQuadTakenBy[q] == mp) - { - quadIndex = q; - break; - } - } - - // Write the brain label, with info if applicable for the current progress of animation - if (progress > 0) - std::snprintf(str, sizeof(str), "%c", -48); - // When at site destination, take into account the side the brain icon needs to be on - else - { - if (quadIndex <= 1) - std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); - else - std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); - } - m_apPlayerBrainTravelLabel[mp]->SetText(str); - m_apPlayerBrainTravelLabel[mp]->SetToolTip("The specific brain that is being sent in to attack this place, and the funds he has been budgeted to do so with."); - - // Figure out start and ending positions for the brain label's travels and the team flag badge - // Upper left quadrant - if (quadIndex == 0) - { - // Team flag position - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); - } - // Lower left quadrant - else if (quadIndex == 1) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); - } - // Lower right quadrant - else if (quadIndex == 2) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); - } - // Upper right quadrant - else if (quadIndex == 3) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); - } - - // Now place the travelling brain label at the appropriate spot based on the animation progress - brainLabelTravel = brainLabelEndPos - brainLabelSitePos; - // The raw distance the label needs to travel when going down one axis and then the other - brainTravelLength = fabs(brainLabelTravel.m_X) + fabs(brainLabelTravel.m_Y); - // Figure out where along the progression that brain travel switches from one axis to the other - travelSwitchRatio = fabs(brainLabelTravel.m_X) / brainTravelLength; - - // If animation progress is less than where the switch happens, handle that - if (progress <= travelSwitchRatio) - { - - // Some progress in X - brainTravelPos.m_X = brainLabelSitePos.m_X + (brainLabelTravel.m_X * (progress / travelSwitchRatio)); - // No progress in Y - brainTravelPos.m_Y = brainLabelSitePos.m_Y; - } - // Progress is past the switch - else if (progress < 1.0) - { - // FULL progress in X - brainTravelPos.m_X = brainLabelEndPos.m_X; - // Some progress in Y - brainTravelPos.m_Y = brainLabelSitePos.m_Y + (brainLabelTravel.m_Y * ((progress - travelSwitchRatio) / (1.0 - travelSwitchRatio))); - } - // Reached destination - else - brainTravelPos = brainLabelEndPos; - - // Now actually move the label - m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); - } - // Advance the metaplayer index to sync with the iterator - mp++; - } -} +void MetagameGUI::UpdatePostBattleRetreaters(float progress) { + // Sanity check that we have any offensive battle activity and scene to display around + if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || + !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || + !m_pAnimScene) + return; + + int mp = 0; + char str[256]; + int quadIndex = Players::NoPlayer; + // The screen coordinate position of the current battle site + Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); + // Where it ends up, aligned properly next to the site, in the proper quadrant + Vector brainLabelSitePos; + // Where the brain label ends at, back at the pool + Vector brainLabelEndPos; + // The distance the brain label should travel between the two + Vector brainLabelTravel; + // The actual total distance it will travel, when going along each cardinal axis at a time + float brainTravelLength; + // The animation progress point at which travel switches from one axis to the other + float travelSwitchRatio; + // The actual current position of the brain label at the current specified animaiton progress point + Vector brainTravelPos; + + // Update the quad assignments for all players + UpdateBattleQuads(siteScreenPos); + + // Go through all players for this activity + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) { + // Player active and EVACUATION/RETREATING in current battle, so display his team flag and place it according to the animation progress + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain((*mpItr).GetInGamePlayer()) && + g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated((*mpItr).GetInGamePlayer())) { + // Show the active players' team flag icons around the site if the brains have arrived + m_apPlayerTeamActionBox[mp]->SetVisible(progress <= 0); + // Show the traveling brain if we're not at destination yet + m_apPlayerBrainTravelLabel[mp]->SetVisible(progress < 1.0); + + // Figure out which quad this player is assigned to + for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) { + if (m_aQuadTakenBy[q] == mp) { + quadIndex = q; + break; + } + } + + // Write the brain label, with info if applicable for the current progress of animation + if (progress > 0) + std::snprintf(str, sizeof(str), "%c", -48); + // When at site destination, take into account the side the brain icon needs to be on + else { + if (quadIndex <= 1) + std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); + else + std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); + } + m_apPlayerBrainTravelLabel[mp]->SetText(str); + m_apPlayerBrainTravelLabel[mp]->SetToolTip("The specific brain that is being sent in to attack this place, and the funds he has been budgeted to do so with."); + + // Figure out start and ending positions for the brain label's travels and the team flag badge + // Upper left quadrant + if (quadIndex == 0) { + // Team flag position + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); + } + // Lower left quadrant + else if (quadIndex == 1) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() - (m_apPlayerBrainTravelLabel[mp]->GetWidth() / 2) - 30, m_apBrainPoolLabel[mp]->GetYPos() - 5); + } + // Lower right quadrant + else if (quadIndex == 2) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); + } + // Upper right quadrant + else if (quadIndex == 3) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(m_apBrainPoolLabel[mp]->GetXPos() + 8, m_apBrainPoolLabel[mp]->GetYPos() - 5); + } + + // Now place the travelling brain label at the appropriate spot based on the animation progress + brainLabelTravel = brainLabelEndPos - brainLabelSitePos; + // The raw distance the label needs to travel when going down one axis and then the other + brainTravelLength = fabs(brainLabelTravel.m_X) + fabs(brainLabelTravel.m_Y); + // Figure out where along the progression that brain travel switches from one axis to the other + travelSwitchRatio = fabs(brainLabelTravel.m_X) / brainTravelLength; + // If animation progress is less than where the switch happens, handle that + if (progress <= travelSwitchRatio) { + + // Some progress in X + brainTravelPos.m_X = brainLabelSitePos.m_X + (brainLabelTravel.m_X * (progress / travelSwitchRatio)); + // No progress in Y + brainTravelPos.m_Y = brainLabelSitePos.m_Y; + } + // Progress is past the switch + else if (progress < 1.0) { + // FULL progress in X + brainTravelPos.m_X = brainLabelEndPos.m_X; + // Some progress in Y + brainTravelPos.m_Y = brainLabelSitePos.m_Y + (brainLabelTravel.m_Y * ((progress - travelSwitchRatio) / (1.0 - travelSwitchRatio))); + } + // Reached destination + else + brainTravelPos = brainLabelEndPos; + + // Now actually move the label + m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); + } + // Advance the metaplayer index to sync with the iterator + mp++; + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePostBattleResidents @@ -5679,232 +5120,210 @@ void MetagameGUI::UpdatePostBattleRetreaters(float progress) // Description: Updates the animation and display of the info for the current done // offensive battle's winning brains going back into the site. -void MetagameGUI::UpdatePostBattleResidents(float progress) -{ - // Sanity check that we have any offensive battle activity and scene to display around - if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || - !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || - !m_pAnimScene) - return; - - int mp = 0; - char str[256]; - int quadIndex = Players::NoPlayer; - // The screen coordinate position of the current battle site - Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); - // Where the brain label ends at - Vector brainLabelEndPos; - // Where it ends up, aligned properly next to the site, in the proper quadrant - Vector brainLabelSitePos; - // The distance the brain label should travel between the two - Vector brainLabelTravel; - // The actual total distance it will travel, when going along each cardinal axis at a time - //float brainTravelLength; - // The animation progress point at which travel switches from one axis to the other - //float travelSwitchRatio; - // The actual current position of the brain label at the current specified animaiton progress point - Vector brainTravelPos; - - // Update the quad assignments for all players - UpdateBattleQuads(siteScreenPos); - - // Go through all players for this activity - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - { - // Player active in the past battle, so display his team flag and place it according to the animation progress - // Also player who didn't evacuate - they are handled by UpdatePostBattleRetreaters - if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain((*mpItr).GetInGamePlayer()) && - !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated((*mpItr).GetInGamePlayer())) - { - // Figure out which quad this player is assigned to - for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) - { - if (m_aQuadTakenBy[q] == mp) - { - quadIndex = q; - break; - } - } - - // The brains who DID NOT MAKE IT - DEAD and did not evac - if (!m_pAnimScene->GetResidentBrain((*mpItr).GetInGamePlayer())) - { - // Hide the losers after the residents start moving in - m_apPlayerTeamActionBox[mp]->SetVisible(progress <= 0); - m_apPlayerBrainTravelLabel[mp]->SetVisible(progress <= 0); - - if (progress <= 0) - { - // Death mask - if (progress > 0) - std::snprintf(str, sizeof(str), "%c", -26); - // Brain with line blinking over it and the funds still showing - else - { - if (quadIndex <= 1) - { - if (m_aAnimDestroyed[mp]) - std::snprintf(str, sizeof(str), "%c %.0f oz ", -58, m_aBattleFunds[mp]); - else - std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -26); -// std::snprintf(str, sizeof(str), "%c %.0f oz %c", -58, m_aBattleFunds[mp], m_AnimTimer2.AlternateReal(200) ? -39 : -26); - } - else - { - if (m_aAnimDestroyed[mp]) - std::snprintf(str, sizeof(str), " %c %.0f oz", -58, m_aBattleFunds[mp]); - else - std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", m_aAnimDestroyed[mp] ? ' ' : -26, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); -// std::snprintf(str, sizeof(str), "%c %c %.0f oz", m_AnimTimer2.AlternateReal(200) ? -39 : -26, -58, m_aBattleFunds[mp]); - } - } - m_apPlayerBrainTravelLabel[mp]->SetText(str); - m_apPlayerBrainTravelLabel[mp]->SetToolTip("The specific brain that is being sent in to attack this place, and the funds he has been budgeted to do so with."); - } - - // Figure out the position of the dead brain label - // Upper left quadrant - if (quadIndex == 0) - { - // Team flag position - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label start position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it - m_aBrainIconPos[mp] = brainLabelSitePos + Vector(m_apPlayerBrainTravelLabel[mp]->GetWidth() - 6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); - } - // Lower left quadrant - else if (quadIndex == 1) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label start position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); - // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it - m_aBrainIconPos[mp] = brainLabelSitePos + Vector(m_apPlayerBrainTravelLabel[mp]->GetWidth() - 6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); - } - // Lower right quadrant - else if (quadIndex == 2) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label start position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); - // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it - m_aBrainIconPos[mp] = brainLabelSitePos + Vector(6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); - } - // Upper right quadrant - else if (quadIndex == 3) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label start position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it - m_aBrainIconPos[mp] = brainLabelSitePos + Vector(6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); - } - - // Now actually place the label - m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainLabelSitePos.m_X, brainLabelSitePos.m_Y); - } - // The SURVIVORS who aren't evacuating either - ie they won and are staying - else - { - // Show the active players' team flag icons around the site if the brains have arrived - m_apPlayerTeamActionBox[mp]->SetVisible(progress <= 0); - // Show the traveling brain if we're not at 1.0 - m_apPlayerBrainTravelLabel[mp]->SetVisible(progress < 1.0); - - // Write the brain label, with info if applicable for the current progress of animation - if (progress > 0) - std::snprintf(str, sizeof(str), "%c", -48); - // When at site start position, take into account the side the brain icon needs to be on - else - { - if (quadIndex <= 1) - std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); -// std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], -47, -48); - else - std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); -// std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, -47, -58, m_aBattleFunds[mp]); - } - m_apPlayerBrainTravelLabel[mp]->SetText(str); - m_apPlayerBrainTravelLabel[mp]->SetToolTip("The new resident brain that has won this site and is settling in here now."); - - // Figure out start and ending positions for the brain label's travels and the team flag badge - // Upper left quadrant - if (quadIndex == 0) - { - // Team flag position - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - } - // Lower left quadrant - else if (quadIndex == 1) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - } - // Lower right quadrant - else if (quadIndex == 2) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - } - // Upper right quadrant - else if (quadIndex == 3) - { - m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); - // Brain label text alignment, depending on the quadrant - m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); - // Brain label end/site position, taking into account its text alignment - brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); - // Brain label start position, taking into account its text alignment - brainLabelEndPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); - } - - // Now place the travelling brain label at the appropriate spot based on the animation progress - brainLabelTravel = brainLabelEndPos - brainLabelSitePos; - - // How far have we come - if (progress <= 0) - brainTravelPos = brainLabelSitePos; - // Somewhere in between - else if (progress < 1.0) - brainTravelPos = brainLabelSitePos + brainLabelTravel * progress; - // Reached destination - else - brainTravelPos = brainLabelEndPos; - - // Now actually move the label - m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); - } - } - // Advance the metaplayer index to sync with the iterator - mp++; - } -} +void MetagameGUI::UpdatePostBattleResidents(float progress) { + // Sanity check that we have any offensive battle activity and scene to display around + if (g_MetaMan.m_CurrentOffensive >= g_MetaMan.m_RoundOffensives.size() || + !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive] || + !m_pAnimScene) + return; + + int mp = 0; + char str[256]; + int quadIndex = Players::NoPlayer; + // The screen coordinate position of the current battle site + Vector siteScreenPos = m_PlanetCenter + m_pAnimScene->GetLocation() + m_pAnimScene->GetLocationOffset(); + // Where the brain label ends at + Vector brainLabelEndPos; + // Where it ends up, aligned properly next to the site, in the proper quadrant + Vector brainLabelSitePos; + // The distance the brain label should travel between the two + Vector brainLabelTravel; + // The actual total distance it will travel, when going along each cardinal axis at a time + // float brainTravelLength; + // The animation progress point at which travel switches from one axis to the other + // float travelSwitchRatio; + // The actual current position of the brain label at the current specified animaiton progress point + Vector brainTravelPos; + + // Update the quad assignments for all players + UpdateBattleQuads(siteScreenPos); + + // Go through all players for this activity + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) { + // Player active in the past battle, so display his team flag and place it according to the animation progress + // Also player who didn't evacuate - they are handled by UpdatePostBattleRetreaters + if (g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->PlayerHadBrain((*mpItr).GetInGamePlayer()) && + !g_MetaMan.m_RoundOffensives[g_MetaMan.m_CurrentOffensive]->BrainWasEvacuated((*mpItr).GetInGamePlayer())) { + // Figure out which quad this player is assigned to + for (int q = Players::PlayerOne; q < Players::MaxPlayerCount; ++q) { + if (m_aQuadTakenBy[q] == mp) { + quadIndex = q; + break; + } + } + + // The brains who DID NOT MAKE IT - DEAD and did not evac + if (!m_pAnimScene->GetResidentBrain((*mpItr).GetInGamePlayer())) { + // Hide the losers after the residents start moving in + m_apPlayerTeamActionBox[mp]->SetVisible(progress <= 0); + m_apPlayerBrainTravelLabel[mp]->SetVisible(progress <= 0); + + if (progress <= 0) { + // Death mask + if (progress > 0) + std::snprintf(str, sizeof(str), "%c", -26); + // Brain with line blinking over it and the funds still showing + else { + if (quadIndex <= 1) { + if (m_aAnimDestroyed[mp]) + std::snprintf(str, sizeof(str), "%c %.0f oz ", -58, m_aBattleFunds[mp]); + else + std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -26); + // std::snprintf(str, sizeof(str), "%c %.0f oz %c", -58, m_aBattleFunds[mp], m_AnimTimer2.AlternateReal(200) ? -39 : -26); + } else { + if (m_aAnimDestroyed[mp]) + std::snprintf(str, sizeof(str), " %c %.0f oz", -58, m_aBattleFunds[mp]); + else + std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", m_aAnimDestroyed[mp] ? ' ' : -26, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); + // std::snprintf(str, sizeof(str), "%c %c %.0f oz", m_AnimTimer2.AlternateReal(200) ? -39 : -26, -58, m_aBattleFunds[mp]); + } + } + m_apPlayerBrainTravelLabel[mp]->SetText(str); + m_apPlayerBrainTravelLabel[mp]->SetToolTip("The specific brain that is being sent in to attack this place, and the funds he has been budgeted to do so with."); + } + + // Figure out the position of the dead brain label + // Upper left quadrant + if (quadIndex == 0) { + // Team flag position + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label start position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it + m_aBrainIconPos[mp] = brainLabelSitePos + Vector(m_apPlayerBrainTravelLabel[mp]->GetWidth() - 6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); + } + // Lower left quadrant + else if (quadIndex == 1) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label start position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); + // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it + m_aBrainIconPos[mp] = brainLabelSitePos + Vector(m_apPlayerBrainTravelLabel[mp]->GetWidth() - 6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); + } + // Lower right quadrant + else if (quadIndex == 2) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label start position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); + // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it + m_aBrainIconPos[mp] = brainLabelSitePos + Vector(6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); + } + // Upper right quadrant + else if (quadIndex == 3) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label start position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + // Where the brain icon is now exactly, so we can accurately pin the blow up animation on it + m_aBrainIconPos[mp] = brainLabelSitePos + Vector(6, m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2); + } + + // Now actually place the label + m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainLabelSitePos.m_X, brainLabelSitePos.m_Y); + } + // The SURVIVORS who aren't evacuating either - ie they won and are staying + else { + // Show the active players' team flag icons around the site if the brains have arrived + m_apPlayerTeamActionBox[mp]->SetVisible(progress <= 0); + // Show the traveling brain if we're not at 1.0 + m_apPlayerBrainTravelLabel[mp]->SetVisible(progress < 1.0); + + // Write the brain label, with info if applicable for the current progress of animation + if (progress > 0) + std::snprintf(str, sizeof(str), "%c", -48); + // When at site start position, take into account the side the brain icon needs to be on + else { + if (quadIndex <= 1) + std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], m_aBattleAttacker[mp] ? -46 : -47, -48); + // std::snprintf(str, sizeof(str), "%c %.0f oz %c%c", -58, m_aBattleFunds[mp], -47, -48); + else + std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, m_aBattleAttacker[mp] ? -46 : -47, -58, m_aBattleFunds[mp]); + // std::snprintf(str, sizeof(str), "%c%c %c %.0f oz", -48, -47, -58, m_aBattleFunds[mp]); + } + m_apPlayerBrainTravelLabel[mp]->SetText(str); + m_apPlayerBrainTravelLabel[mp]->SetToolTip("The new resident brain that has won this site and is settling in here now."); + + // Figure out start and ending positions for the brain label's travels and the team flag badge + // Upper left quadrant + if (quadIndex == 0) { + // Team flag position + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + } + // Lower left quadrant + else if (quadIndex == 1) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X - m_apPlayerTeamActionBox[mp]->GetWidth() - BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Right); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(-BATTLEPAD - (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) - BRAINOVERLAP - m_apPlayerBrainTravelLabel[mp]->GetWidth(), 0); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(siteScreenPos.m_X - m_apPlayerBrainTravelLabel[mp]->GetWidth() + 7, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + } + // Lower right quadrant + else if (quadIndex == 2) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y + BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, 0); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + } + // Upper right quadrant + else if (quadIndex == 3) { + m_apPlayerTeamActionBox[mp]->SetPositionAbs(siteScreenPos.m_X + BATTLEPAD, siteScreenPos.m_Y - m_apPlayerTeamActionBox[mp]->GetHeight() - BATTLEPAD); + // Brain label text alignment, depending on the quadrant + m_apPlayerBrainTravelLabel[mp]->SetHAlignment(GUIFont::Left); + // Brain label end/site position, taking into account its text alignment + brainLabelSitePos = siteScreenPos + Vector(BATTLEPAD + (m_apPlayerTeamActionBox[mp]->GetWidth() / 2) + BRAINOVERLAP, -m_apPlayerBrainTravelLabel[mp]->GetHeight()); + // Brain label start position, taking into account its text alignment + brainLabelEndPos.SetXY(siteScreenPos.m_X - 5, siteScreenPos.m_Y - (m_apPlayerBrainTravelLabel[mp]->GetHeight() / 2) + 2); + } + + // Now place the travelling brain label at the appropriate spot based on the animation progress + brainLabelTravel = brainLabelEndPos - brainLabelSitePos; + // How far have we come + if (progress <= 0) + brainTravelPos = brainLabelSitePos; + // Somewhere in between + else if (progress < 1.0) + brainTravelPos = brainLabelSitePos + brainLabelTravel * progress; + // Reached destination + else + brainTravelPos = brainLabelEndPos; + + // Now actually move the label + m_apPlayerBrainTravelLabel[mp]->SetPositionAbs(brainTravelPos.m_X, brainTravelPos.m_Y); + } + } + // Advance the metaplayer index to sync with the iterator + mp++; + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePlayerActionLines @@ -5912,259 +5331,232 @@ void MetagameGUI::UpdatePostBattleResidents(float progress) // Description: Updates the action lines as per what the player has chosen to do // during the current turn so far. -float MetagameGUI::UpdatePlayerActionLines(int metaPlayer)//, bool addUnallocated) +float MetagameGUI::UpdatePlayerActionLines(int metaPlayer) //, bool addUnallocated) { - // Make sure we're in a player turn phase - if (metaPlayer < Players::PlayerOne || metaPlayer >= g_MetaMan.m_Players.size()) - return 0; - - // First clean out all Action sitelines for this player - m_ActionSiteLines[metaPlayer].clear(); - - // Get the total funds we have to work with - float totalFunds = g_MetaMan.m_Players[metaPlayer].GetFunds(); - - // Loop through the scenes owned by that player, setting up the building budget site line for each - const Scene *pScene = 0; - int channelHeight = 60; - float meterStart = 0; - while (pScene = g_MetaMan.GetNextSceneOfPlayer(metaPlayer, pScene)) - { - // Add line for scenes which are owned and whose build budgets have been set to something - if (pScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer) && std::floor(pScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer())) > 0) - { - m_ActionSiteLines[metaPlayer].push_back(SiteLine(metaPlayer, meterStart, pScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()) / totalFunds, pScene->GetLocation() + pScene->GetLocationOffset(), pScene->GetPresetName(), pScene, c_GUIColorGreen, -1, -1, channelHeight, 1.0f, g_MetaMan.IsActiveTeam(pScene->GetTeamOwnership()))); - m_ActionSiteLines[metaPlayer].back().m_FundsAmount = pScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); - meterStart += m_ActionSiteLines[metaPlayer].back().m_MeterAmount; - channelHeight += 10; - } - } - - // If we have a selected offensive target, find it and create its line as well - std::string targetName = g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName(); - float offensiveBudget = g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget(); - if (!targetName.empty() && offensiveBudget > 0) - { - for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) - { - if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == targetName) - { - m_ActionSiteLines[metaPlayer].push_back(SiteLine(metaPlayer, meterStart, offensiveBudget / totalFunds, (*sItr)->GetLocation() + (*sItr)->GetLocationOffset(), (*sItr)->GetPresetName(), (*sItr), c_GUIColorRed, -1, -1, channelHeight, 1.0f, g_MetaMan.IsActiveTeam((*sItr)->GetTeamOwnership()))); - m_ActionSiteLines[metaPlayer].back().m_FundsAmount = offensiveBudget; - meterStart += m_ActionSiteLines[metaPlayer].back().m_MeterAmount; - } - } - } - - return meterStart; -} + // Make sure we're in a player turn phase + if (metaPlayer < Players::PlayerOne || metaPlayer >= g_MetaMan.m_Players.size()) + return 0; + + // First clean out all Action sitelines for this player + m_ActionSiteLines[metaPlayer].clear(); + + // Get the total funds we have to work with + float totalFunds = g_MetaMan.m_Players[metaPlayer].GetFunds(); + + // Loop through the scenes owned by that player, setting up the building budget site line for each + const Scene* pScene = 0; + int channelHeight = 60; + float meterStart = 0; + while (pScene = g_MetaMan.GetNextSceneOfPlayer(metaPlayer, pScene)) { + // Add line for scenes which are owned and whose build budgets have been set to something + if (pScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer) && std::floor(pScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer())) > 0) { + m_ActionSiteLines[metaPlayer].push_back(SiteLine(metaPlayer, meterStart, pScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()) / totalFunds, pScene->GetLocation() + pScene->GetLocationOffset(), pScene->GetPresetName(), pScene, c_GUIColorGreen, -1, -1, channelHeight, 1.0f, g_MetaMan.IsActiveTeam(pScene->GetTeamOwnership()))); + m_ActionSiteLines[metaPlayer].back().m_FundsAmount = pScene->GetBuildBudget(g_MetaMan.m_Players[metaPlayer].GetInGamePlayer()); + meterStart += m_ActionSiteLines[metaPlayer].back().m_MeterAmount; + channelHeight += 10; + } + } + + // If we have a selected offensive target, find it and create its line as well + std::string targetName = g_MetaMan.m_Players[metaPlayer].GetOffensiveTargetName(); + float offensiveBudget = g_MetaMan.m_Players[metaPlayer].GetOffensiveBudget(); + if (!targetName.empty() && offensiveBudget > 0) { + for (std::vector::iterator sItr = g_MetaMan.m_Scenes.begin(); sItr != g_MetaMan.m_Scenes.end(); ++sItr) { + if ((*sItr)->IsRevealed() && (*sItr)->GetPresetName() == targetName) { + m_ActionSiteLines[metaPlayer].push_back(SiteLine(metaPlayer, meterStart, offensiveBudget / totalFunds, (*sItr)->GetLocation() + (*sItr)->GetLocationOffset(), (*sItr)->GetPresetName(), (*sItr), c_GUIColorRed, -1, -1, channelHeight, 1.0f, g_MetaMan.IsActiveTeam((*sItr)->GetTeamOwnership()))); + m_ActionSiteLines[metaPlayer].back().m_FundsAmount = offensiveBudget; + meterStart += m_ActionSiteLines[metaPlayer].back().m_MeterAmount; + } + } + } + return meterStart; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateScenesBox ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the contents of the scene selection box. -void MetagameGUI::UpdateScenesBox(bool sceneChanged) -{ - // Always show the info box if something is selected - if (m_pSelectedScene && !g_MetaMan.IsSuspended()) - { - char str[256]; - // Set the close button to have that fancy X - std::snprintf(str, sizeof(str), "%c", -36); - m_pSceneCloseButton->SetText(std::string(str)); - - // Set the currently selected scene's texts - m_pSceneInfoPopup->SetVisible(true); - m_pSceneNameLabel->SetText(m_pSelectedScene->GetPresetName()); - - // Show which team owns this place, and how many resident brains there are here of that team - if (m_pSelectedScene->GetTeamOwnership() > Activity::NoTeam && m_pSelectedScene->GetTeamOwnership() < Activity::MaxTeamCount) - { - // Set the team flag icon - m_pSceneOwnerTeam->SetVisible(true); - m_pSceneOwnerTeam->SetDrawType(GUICollectionBox::Image); - m_pSceneOwnerTeam->SetDrawImage(new AllegroBitmap(g_MetaMan.m_TeamIcons[m_pSelectedScene->GetTeamOwnership()].GetBitmaps32()[0])); - // Show how many resident brains there are hanging out here - std::snprintf(str, sizeof(str), "%c", -26); - std::string brainString = ""; - int brainCount = m_pSelectedScene->GetResidentBrainCount(); - for (int i = 0; i < brainCount; ++i) - brainString += str; - m_pSceneResidentsLabel->SetText(brainString); - m_pSceneResidentsLabel->SetVisible(true); - } - // Noone owns this place, so hide this ownership stuff - else - { - m_pSceneOwnerTeam->SetVisible(false); - m_pSceneResidentsLabel->SetVisible(false); - m_pSceneResidentsLabel->SetText(""); - } - - // Write the description, and add the total defense investment in this place so far as a lil stat +void MetagameGUI::UpdateScenesBox(bool sceneChanged) { + // Always show the info box if something is selected + if (m_pSelectedScene && !g_MetaMan.IsSuspended()) { + char str[256]; + // Set the close button to have that fancy X + std::snprintf(str, sizeof(str), "%c", -36); + m_pSceneCloseButton->SetText(std::string(str)); + + // Set the currently selected scene's texts + m_pSceneInfoPopup->SetVisible(true); + m_pSceneNameLabel->SetText(m_pSelectedScene->GetPresetName()); + + // Show which team owns this place, and how many resident brains there are here of that team + if (m_pSelectedScene->GetTeamOwnership() > Activity::NoTeam && m_pSelectedScene->GetTeamOwnership() < Activity::MaxTeamCount) { + // Set the team flag icon + m_pSceneOwnerTeam->SetVisible(true); + m_pSceneOwnerTeam->SetDrawType(GUICollectionBox::Image); + m_pSceneOwnerTeam->SetDrawImage(new AllegroBitmap(g_MetaMan.m_TeamIcons[m_pSelectedScene->GetTeamOwnership()].GetBitmaps32()[0])); + // Show how many resident brains there are hanging out here + std::snprintf(str, sizeof(str), "%c", -26); + std::string brainString = ""; + int brainCount = m_pSelectedScene->GetResidentBrainCount(); + for (int i = 0; i < brainCount; ++i) + brainString += str; + m_pSceneResidentsLabel->SetText(brainString); + m_pSceneResidentsLabel->SetVisible(true); + } + // Noone owns this place, so hide this ownership stuff + else { + m_pSceneOwnerTeam->SetVisible(false); + m_pSceneResidentsLabel->SetVisible(false); + m_pSceneResidentsLabel->SetText(""); + } + + // Write the description, and add the total defense investment in this place so far as a lil stat Vector sceneSizeMeters = m_pSelectedScene->GetDimensions() / c_PPM; std::string sceneDimensions = "Site Dimensions: " + std::to_string(sceneSizeMeters.GetFloorIntX()) + " x " + std::to_string(sceneSizeMeters.GetFloorIntY()) + " meters"; std::string sceneInvestments = "Total base investments here: " + std::to_string(static_cast(m_pSelectedScene->GetTotalInvestment())) + "oz"; - m_pSceneInfoLabel->SetText(m_pSelectedScene->GetDescription() + "\n\n" + sceneDimensions + "\n\n" + sceneInvestments); - // Adjust the height of the text box and container so it fits the text to display - int newHeight = m_pSceneInfoLabel->ResizeHeightToFit(); - m_pSceneInfoPopup->Resize(m_pSceneInfoPopup->GetWidth(), newHeight + 96); - - // If during a player's round phase, show the budget slider and edit button - if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - { - int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; - int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); - - // Resize the collection box to fit the extra controls - m_pSceneInfoPopup->Resize(m_pSceneInfoPopup->GetWidth(), newHeight + 96); - m_pSceneBudgetLabel->SetVisible(true); - m_pSceneBudgetSlider->SetVisible(true); - m_pSceneBudgetBar->SetVisible(true); - - // Set up the slider limit bar - bool sceneOwnedByPlayer = m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer); - int blockedWidth = std::floor((m_pSceneBudgetSlider->GetWidth() - 4) * g_MetaMan.GetBudgetedRatioOfPlayer(metaPlayer, m_pSelectedScene, sceneOwnedByPlayer)); - - if (blockedWidth > 0) - { - m_pSceneBudgetBar->SetVisible(true); - m_pSceneBudgetBar->SetPositionAbs(m_pSceneBudgetSlider->GetXPos() - 2 + m_pSceneBudgetSlider->GetWidth() - blockedWidth, m_pSceneBudgetSlider->GetYPos()); - m_pSceneBudgetBar->SetSize(blockedWidth, m_pSceneBudgetSlider->GetHeight()); - } - else - m_pSceneBudgetBar->SetVisible(false); - - // Make sure the slider can't go over the max allowed, as blocked by already budgeted funds - int maxVal = 100 - g_MetaMan.GetBudgetedRatioOfPlayer(metaPlayer, m_pSelectedScene, sceneOwnedByPlayer) * 100; - if (m_pSceneBudgetSlider->GetValue() > maxVal) - { -// TODO: Play some sound, blink the bar etc too - m_pSceneBudgetSlider->SetValue(maxVal); - } - - // If owned by this player, then set up base building controls - if (sceneOwnedByPlayer) - { - // Set the budget label as per the slider - int budget = floorf(((float)m_pSceneBudgetSlider->GetValue() / 100.0f) * g_MetaMan.m_Players[metaPlayer].GetFunds()); - std::snprintf(str, sizeof(str), "Build Budget: %d oz", budget); - m_pSceneBudgetLabel->SetText(str); - m_apMetaButton[SCANNOW]->SetVisible(false); - m_apMetaButton[SCANLATER]->SetVisible(false); - m_pScanInfoLabel->SetVisible(false); - m_apMetaButton[SCENEACTION]->SetVisible(false); - m_apMetaButton[DESIGNBASE]->SetVisible(true); - m_apMetaButton[DESIGNBASE]->SetText("Design Base"); - m_pSceneBudgetLabel->SetToolTip("Sets how much of your total funds will be budgeted toward building base defense blueprints on this site."); - m_pSceneBudgetSlider->SetToolTip("Sets how much of your total funds will be budgeted toward building base defense blueprints on this site."); - m_pAutoDesignCheckbox->SetVisible(true); - m_pAutoDesignCheckbox->SetCheck(m_pSelectedScene->GetAutoDesigned()); - } - // Not owned by this player's team, so set up the scanning controls - else - { - // Only update this if the scene has changed in any way - otherwise UI changes done elsewhere might be overridden - if (sceneChanged) - { - // Set the budget label as per the slider - int budget = std::floor(((float)m_pSceneBudgetSlider->GetValue() / 100.0f) * g_MetaMan.m_Players[metaPlayer].GetFunds()); - // Set the appropriate action message, depending on whether this is enemy owned, or merely unexplored - if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) - { - std::snprintf(str, sizeof(str), "Attack Budget: %d oz", budget); - m_pSceneBudgetLabel->SetToolTip("Sets how much of your total funds will be budgeted toward exploring this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only attack one site per turn!"); - m_pSceneBudgetSlider->SetToolTip("Sets how much of your total funds will be budgeted toward exploring this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only attack one site per turn!"); - } - else - { - std::snprintf(str, sizeof(str), "Expedition Budget: %d oz", budget); - m_pSceneBudgetLabel->SetToolTip("Sets how much of your total funds will be budgeted toward attacking this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only explore one site per turn!"); - m_pSceneBudgetSlider->SetToolTip("Sets how much of your total funds will be budgeted toward attacking this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only explore one site per turn!"); - } - m_pSceneBudgetLabel->SetText(str); - - // A Scan is already scheduled for this scene - if (m_pSelectedScene->IsScanScheduled(team)) - { - // Hide buttons and show feedback message that scan has already been scheduled - m_apMetaButton[SCENEACTION]->SetVisible(false); - m_apMetaButton[DESIGNBASE]->SetVisible(false); - m_apMetaButton[SCANNOW]->SetVisible(false); - m_apMetaButton[SCANLATER]->SetVisible(false); - m_pScanInfoLabel->SetVisible(true); - m_pScanInfoLabel->SetText("- Orbital scan scheduled -"); - } - // Check to make sure we're even able to afford a new scan at all - else if (g_MetaMan.GetRemainingFundsOfPlayer(metaPlayer, 0, false, false) < SCANCOST) - { - // Hide buttons and show feedback message that scan has already been scheduled - m_apMetaButton[SCENEACTION]->SetVisible(false); - m_apMetaButton[DESIGNBASE]->SetVisible(false); - m_apMetaButton[SCANNOW]->SetVisible(false); - m_apMetaButton[SCANLATER]->SetVisible(false); - m_pScanInfoLabel->SetVisible(true); - std::snprintf(str, sizeof(str), "%d", SCANCOST); - m_pScanInfoLabel->SetText("Need " + std::string(str) + " oz left to Scan!"); - } - // Site can be scheduled to be scanned - else - { - // Show the scan button and hide the label - m_apMetaButton[SCANNOW]->SetVisible(false); - m_apMetaButton[SCANLATER]->SetVisible(false); - m_pScanInfoLabel->SetVisible(false); - m_apMetaButton[DESIGNBASE]->SetVisible(false); - m_apMetaButton[SCENEACTION]->SetVisible(true); - std::snprintf(str, sizeof(str), "%d", SCANCOST); - m_apMetaButton[SCENEACTION]->SetText("Scan Site (" + std::string(str) + " oz)"); - m_apMetaButton[SCENEACTION]->SetToolTip("Performs an orbital scan of this site, which will show everything that is on the surface, but will not be able to penetrate far into the ground."); - } - // Hide the auto check box - m_pAutoDesignCheckbox->SetVisible(false); - } - - // If the player doesn't have any brains left to deploy, then disable these attack controls instead - if (g_MetaMan.m_Players[metaPlayer].GetBrainPoolCount() <= 0) - { - m_pSceneBudgetLabel->SetText("- NO BRAINS TO DEPLOY -"); - m_pSceneBudgetLabel->SetToolTip("Since you do not have any more brains in your brain pool available for deployment, you can't attack this or any other site. Defend the sites you do own and hope you'll keep enough of them to win the game!"); - m_pSceneBudgetBar->SetToolTip("Since you do not have any more brains in your brain pool available for deployment, you can't attack this or any other site. Defend the sites you do own and hope you'll keep enough of them to win the game!"); - // Make the blockage bar be all over the place - m_pSceneBudgetBar->SetVisible(true); - m_pSceneBudgetBar->SetPositionAbs(m_pSceneBudgetSlider->GetXPos() - 2, m_pSceneBudgetSlider->GetYPos()); - m_pSceneBudgetBar->SetSize(std::floor((m_pSceneBudgetSlider->GetWidth() + 4)), m_pSceneBudgetSlider->GetHeight()); - m_pSceneBudgetSlider->SetVisible(false); - } - } - } - // Just showing scene info - else - { - // Resize the collection box to not show the player-relevant controls - m_pSceneInfoPopup->Resize(m_pSceneInfoPopup->GetWidth(), newHeight + 34); - m_pSceneBudgetLabel->SetVisible(false); - m_pSceneBudgetSlider->SetVisible(false); - m_pSceneBudgetBar->SetVisible(false); - m_apMetaButton[SCENEACTION]->SetVisible(false); - m_apMetaButton[DESIGNBASE]->SetVisible(false); - m_apMetaButton[SCANNOW]->SetVisible(false); - m_apMetaButton[SCANLATER]->SetVisible(false); - m_pAutoDesignCheckbox->SetVisible(false); - m_pScanInfoLabel->SetVisible(false); - } - - // Make sure the box doesn't go entirely outside of the screen - KeepBoxOnScreen(m_pSceneInfoPopup); - } - else - { - m_pSceneInfoPopup->SetVisible(false); - m_pSceneNameLabel->SetText(""); - m_pSceneInfoLabel->SetText(""); - } + m_pSceneInfoLabel->SetText(m_pSelectedScene->GetDescription() + "\n\n" + sceneDimensions + "\n\n" + sceneInvestments); + // Adjust the height of the text box and container so it fits the text to display + int newHeight = m_pSceneInfoLabel->ResizeHeightToFit(); + m_pSceneInfoPopup->Resize(m_pSceneInfoPopup->GetWidth(), newHeight + 96); + + // If during a player's round phase, show the budget slider and edit button + if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) { + int metaPlayer = g_MetaMan.m_GameState - MetaMan::PLAYER1TURN; + int team = g_MetaMan.m_Players[metaPlayer].GetTeam(); + + // Resize the collection box to fit the extra controls + m_pSceneInfoPopup->Resize(m_pSceneInfoPopup->GetWidth(), newHeight + 96); + m_pSceneBudgetLabel->SetVisible(true); + m_pSceneBudgetSlider->SetVisible(true); + m_pSceneBudgetBar->SetVisible(true); + + // Set up the slider limit bar + bool sceneOwnedByPlayer = m_pSelectedScene->GetTeamOwnership() == g_MetaMan.GetTeamOfPlayer(metaPlayer); + int blockedWidth = std::floor((m_pSceneBudgetSlider->GetWidth() - 4) * g_MetaMan.GetBudgetedRatioOfPlayer(metaPlayer, m_pSelectedScene, sceneOwnedByPlayer)); + + if (blockedWidth > 0) { + m_pSceneBudgetBar->SetVisible(true); + m_pSceneBudgetBar->SetPositionAbs(m_pSceneBudgetSlider->GetXPos() - 2 + m_pSceneBudgetSlider->GetWidth() - blockedWidth, m_pSceneBudgetSlider->GetYPos()); + m_pSceneBudgetBar->SetSize(blockedWidth, m_pSceneBudgetSlider->GetHeight()); + } else + m_pSceneBudgetBar->SetVisible(false); + + // Make sure the slider can't go over the max allowed, as blocked by already budgeted funds + int maxVal = 100 - g_MetaMan.GetBudgetedRatioOfPlayer(metaPlayer, m_pSelectedScene, sceneOwnedByPlayer) * 100; + if (m_pSceneBudgetSlider->GetValue() > maxVal) { + // TODO: Play some sound, blink the bar etc too + m_pSceneBudgetSlider->SetValue(maxVal); + } + + // If owned by this player, then set up base building controls + if (sceneOwnedByPlayer) { + // Set the budget label as per the slider + int budget = floorf(((float)m_pSceneBudgetSlider->GetValue() / 100.0f) * g_MetaMan.m_Players[metaPlayer].GetFunds()); + std::snprintf(str, sizeof(str), "Build Budget: %d oz", budget); + m_pSceneBudgetLabel->SetText(str); + m_apMetaButton[SCANNOW]->SetVisible(false); + m_apMetaButton[SCANLATER]->SetVisible(false); + m_pScanInfoLabel->SetVisible(false); + m_apMetaButton[SCENEACTION]->SetVisible(false); + m_apMetaButton[DESIGNBASE]->SetVisible(true); + m_apMetaButton[DESIGNBASE]->SetText("Design Base"); + m_pSceneBudgetLabel->SetToolTip("Sets how much of your total funds will be budgeted toward building base defense blueprints on this site."); + m_pSceneBudgetSlider->SetToolTip("Sets how much of your total funds will be budgeted toward building base defense blueprints on this site."); + m_pAutoDesignCheckbox->SetVisible(true); + m_pAutoDesignCheckbox->SetCheck(m_pSelectedScene->GetAutoDesigned()); + } + // Not owned by this player's team, so set up the scanning controls + else { + // Only update this if the scene has changed in any way - otherwise UI changes done elsewhere might be overridden + if (sceneChanged) { + // Set the budget label as per the slider + int budget = std::floor(((float)m_pSceneBudgetSlider->GetValue() / 100.0f) * g_MetaMan.m_Players[metaPlayer].GetFunds()); + // Set the appropriate action message, depending on whether this is enemy owned, or merely unexplored + if (g_MetaMan.IsActiveTeam(m_pSelectedScene->GetTeamOwnership())) { + std::snprintf(str, sizeof(str), "Attack Budget: %d oz", budget); + m_pSceneBudgetLabel->SetToolTip("Sets how much of your total funds will be budgeted toward exploring this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only attack one site per turn!"); + m_pSceneBudgetSlider->SetToolTip("Sets how much of your total funds will be budgeted toward exploring this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only attack one site per turn!"); + } else { + std::snprintf(str, sizeof(str), "Expedition Budget: %d oz", budget); + m_pSceneBudgetLabel->SetToolTip("Sets how much of your total funds will be budgeted toward attacking this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only explore one site per turn!"); + m_pSceneBudgetSlider->SetToolTip("Sets how much of your total funds will be budgeted toward attacking this site. Any gold that isn't used in the attack will return to your account afterward, but will also be tied up and can't be used for defense if someone else attacks any of your bases during the same turn. You can only explore one site per turn!"); + } + m_pSceneBudgetLabel->SetText(str); + + // A Scan is already scheduled for this scene + if (m_pSelectedScene->IsScanScheduled(team)) { + // Hide buttons and show feedback message that scan has already been scheduled + m_apMetaButton[SCENEACTION]->SetVisible(false); + m_apMetaButton[DESIGNBASE]->SetVisible(false); + m_apMetaButton[SCANNOW]->SetVisible(false); + m_apMetaButton[SCANLATER]->SetVisible(false); + m_pScanInfoLabel->SetVisible(true); + m_pScanInfoLabel->SetText("- Orbital scan scheduled -"); + } + // Check to make sure we're even able to afford a new scan at all + else if (g_MetaMan.GetRemainingFundsOfPlayer(metaPlayer, 0, false, false) < SCANCOST) { + // Hide buttons and show feedback message that scan has already been scheduled + m_apMetaButton[SCENEACTION]->SetVisible(false); + m_apMetaButton[DESIGNBASE]->SetVisible(false); + m_apMetaButton[SCANNOW]->SetVisible(false); + m_apMetaButton[SCANLATER]->SetVisible(false); + m_pScanInfoLabel->SetVisible(true); + std::snprintf(str, sizeof(str), "%d", SCANCOST); + m_pScanInfoLabel->SetText("Need " + std::string(str) + " oz left to Scan!"); + } + // Site can be scheduled to be scanned + else { + // Show the scan button and hide the label + m_apMetaButton[SCANNOW]->SetVisible(false); + m_apMetaButton[SCANLATER]->SetVisible(false); + m_pScanInfoLabel->SetVisible(false); + m_apMetaButton[DESIGNBASE]->SetVisible(false); + m_apMetaButton[SCENEACTION]->SetVisible(true); + std::snprintf(str, sizeof(str), "%d", SCANCOST); + m_apMetaButton[SCENEACTION]->SetText("Scan Site (" + std::string(str) + " oz)"); + m_apMetaButton[SCENEACTION]->SetToolTip("Performs an orbital scan of this site, which will show everything that is on the surface, but will not be able to penetrate far into the ground."); + } + // Hide the auto check box + m_pAutoDesignCheckbox->SetVisible(false); + } + + // If the player doesn't have any brains left to deploy, then disable these attack controls instead + if (g_MetaMan.m_Players[metaPlayer].GetBrainPoolCount() <= 0) { + m_pSceneBudgetLabel->SetText("- NO BRAINS TO DEPLOY -"); + m_pSceneBudgetLabel->SetToolTip("Since you do not have any more brains in your brain pool available for deployment, you can't attack this or any other site. Defend the sites you do own and hope you'll keep enough of them to win the game!"); + m_pSceneBudgetBar->SetToolTip("Since you do not have any more brains in your brain pool available for deployment, you can't attack this or any other site. Defend the sites you do own and hope you'll keep enough of them to win the game!"); + // Make the blockage bar be all over the place + m_pSceneBudgetBar->SetVisible(true); + m_pSceneBudgetBar->SetPositionAbs(m_pSceneBudgetSlider->GetXPos() - 2, m_pSceneBudgetSlider->GetYPos()); + m_pSceneBudgetBar->SetSize(std::floor((m_pSceneBudgetSlider->GetWidth() + 4)), m_pSceneBudgetSlider->GetHeight()); + m_pSceneBudgetSlider->SetVisible(false); + } + } + } + // Just showing scene info + else { + // Resize the collection box to not show the player-relevant controls + m_pSceneInfoPopup->Resize(m_pSceneInfoPopup->GetWidth(), newHeight + 34); + m_pSceneBudgetLabel->SetVisible(false); + m_pSceneBudgetSlider->SetVisible(false); + m_pSceneBudgetBar->SetVisible(false); + m_apMetaButton[SCENEACTION]->SetVisible(false); + m_apMetaButton[DESIGNBASE]->SetVisible(false); + m_apMetaButton[SCANNOW]->SetVisible(false); + m_apMetaButton[SCANLATER]->SetVisible(false); + m_pAutoDesignCheckbox->SetVisible(false); + m_pScanInfoLabel->SetVisible(false); + } + + // Make sure the box doesn't go entirely outside of the screen + KeepBoxOnScreen(m_pSceneInfoPopup); + } else { + m_pSceneInfoPopup->SetVisible(false); + m_pSceneNameLabel->SetText(""); + m_pSceneInfoLabel->SetText(""); + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -6172,16 +5564,12 @@ void MetagameGUI::UpdateScenesBox(bool sceneChanged) ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates AI skill sliders and labels for all players. -void MetagameGUI::UpdateAISkillSliders(int player) -{ - if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) - { +void MetagameGUI::UpdateAISkillSliders(int player) { + if (player >= Players::PlayerOne && player < Players::MaxPlayerCount) { m_apPlayerAISkillLabel[player]->SetText(Activity::GetAISkillString(m_apPlayerAISkillSlider[player]->GetValue())); - for (int otherPlayer = Players::PlayerOne; otherPlayer < Players::MaxPlayerCount; otherPlayer++) - { - if (otherPlayer != player && m_apPlayerTeamSelect[player]->GetSelectedIndex() == m_apPlayerTeamSelect[otherPlayer]->GetSelectedIndex()) - { + for (int otherPlayer = Players::PlayerOne; otherPlayer < Players::MaxPlayerCount; otherPlayer++) { + if (otherPlayer != player && m_apPlayerTeamSelect[player]->GetSelectedIndex() == m_apPlayerTeamSelect[otherPlayer]->GetSelectedIndex()) { m_apPlayerAISkillSlider[otherPlayer]->SetValue(m_apPlayerAISkillSlider[player]->GetValue()); m_apPlayerAISkillLabel[otherPlayer]->SetText(Activity::GetAISkillString(m_apPlayerAISkillSlider[otherPlayer]->GetValue())); } @@ -6189,23 +5577,21 @@ void MetagameGUI::UpdateAISkillSliders(int player) } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateGameSizeLabels ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the game size label of the new game dialog -void MetagameGUI::UpdateGameSizeLabels() -{ - // How many players do we have set to go - int playerCount = 0; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - if (m_apPlayerControlButton[player]->GetText() != "None") - ++playerCount; +void MetagameGUI::UpdateGameSizeLabels() { + // How many players do we have set to go + int playerCount = 0; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) + if (m_apPlayerControlButton[player]->GetText() != "None") + ++playerCount; // How many scenes the game should end up with, according to the specified game size. // Note that it will never be all or none of all the available scenes! -// TODO: Hook these constants up to settings!! + // TODO: Hook these constants up to settings!! // How many scenes are there total const int totalCount = g_MetaMan.TotalScenePresets(); int minCount = std::max((playerCount * 3 / 2), 3); @@ -6215,433 +5601,388 @@ void MetagameGUI::UpdateGameSizeLabels() m_pSizeSlider->SetMaximum(std::max(totalCount * 7 / 10, minCount)); m_pSizeSlider->SetValueResolution(1); - char str[256]; - std::snprintf(str, sizeof(str), "Game Size: %d/%d sites", m_pSizeSlider->GetValue(), totalCount); - m_pSizeLabel->SetText(str); - - // How much starting gold does the slider yield - int startGold = STARTGOLDMIN + ((STARTGOLDMAX - STARTGOLDMIN) * (float)m_pGoldSlider->GetValue() / 100.0); - std::snprintf(str, sizeof(str), "Starting Gold: %c %d oz", -58, startGold); - m_pGoldLabel->SetText(str); - - // Set the length label also according to the game length slider - int brainCount = m_pLengthSlider->GetValue(); - brainCount = MAX(brainCount, 1); - std::snprintf(str, sizeof(str), "Game Length: %c%c%d starting brains", -48, -36, brainCount); - m_pLengthLabel->SetText(str); - - if (m_pDifficultySlider->GetValue() < Activity::CakeDifficulty) - m_pDifficultyLabel->SetText("Difficulty: Cake"); - else if (m_pDifficultySlider->GetValue() < Activity::EasyDifficulty) - m_pDifficultyLabel->SetText("Difficulty: Easy"); - else if (m_pDifficultySlider->GetValue() < Activity::MediumDifficulty) - m_pDifficultyLabel->SetText("Difficulty: Medium"); - else if (m_pDifficultySlider->GetValue() < Activity::HardDifficulty) - m_pDifficultyLabel->SetText("Difficulty: Hard"); - else if (m_pDifficultySlider->GetValue() < Activity::NutsDifficulty) - m_pDifficultyLabel->SetText("Difficulty: Nuts"); - else - m_pDifficultyLabel->SetText("Difficulty: Nuts!"); + char str[256]; + std::snprintf(str, sizeof(str), "Game Size: %d/%d sites", m_pSizeSlider->GetValue(), totalCount); + m_pSizeLabel->SetText(str); + + // How much starting gold does the slider yield + int startGold = STARTGOLDMIN + ((STARTGOLDMAX - STARTGOLDMIN) * (float)m_pGoldSlider->GetValue() / 100.0); + std::snprintf(str, sizeof(str), "Starting Gold: %c %d oz", -58, startGold); + m_pGoldLabel->SetText(str); + + // Set the length label also according to the game length slider + int brainCount = m_pLengthSlider->GetValue(); + brainCount = MAX(brainCount, 1); + std::snprintf(str, sizeof(str), "Game Length: %c%c%d starting brains", -48, -36, brainCount); + m_pLengthLabel->SetText(str); + + if (m_pDifficultySlider->GetValue() < Activity::CakeDifficulty) + m_pDifficultyLabel->SetText("Difficulty: Cake"); + else if (m_pDifficultySlider->GetValue() < Activity::EasyDifficulty) + m_pDifficultyLabel->SetText("Difficulty: Easy"); + else if (m_pDifficultySlider->GetValue() < Activity::MediumDifficulty) + m_pDifficultyLabel->SetText("Difficulty: Medium"); + else if (m_pDifficultySlider->GetValue() < Activity::HardDifficulty) + m_pDifficultyLabel->SetText("Difficulty: Hard"); + else if (m_pDifficultySlider->GetValue() < Activity::NutsDifficulty) + m_pDifficultyLabel->SetText("Difficulty: Nuts"); + else + m_pDifficultyLabel->SetText("Difficulty: Nuts!"); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePlayerSetup ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the player setup controls of the new game dialog -void MetagameGUI::UpdatePlayerSetup() -{ - int humanPlayers = 0; - int totalPlayers = 0; - const Icon *pTeamIcon = 0; - std::list teamList; - for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) - { - if (m_apPlayerControlButton[player]->GetText() == "None") - { - m_apPlayerTeamSelect[player]->SetVisible(false); - m_apPlayerTechSelect[player]->SetVisible(false); - m_apPlayerHandicap[player]->SetVisible(false); - m_apPlayerNameBox[player]->SetVisible(false); +void MetagameGUI::UpdatePlayerSetup() { + int humanPlayers = 0; + int totalPlayers = 0; + const Icon* pTeamIcon = 0; + std::list teamList; + for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { + if (m_apPlayerControlButton[player]->GetText() == "None") { + m_apPlayerTeamSelect[player]->SetVisible(false); + m_apPlayerTechSelect[player]->SetVisible(false); + m_apPlayerHandicap[player]->SetVisible(false); + m_apPlayerNameBox[player]->SetVisible(false); m_apPlayerAISkillSlider[player]->SetVisible(false); m_apPlayerAISkillLabel[player]->SetVisible(false); - continue; - } - else - { - totalPlayers++; - if (m_apPlayerControlButton[player]->GetText() == "Human") - humanPlayers++; - m_apPlayerTeamSelect[player]->SetVisible(true); - m_apPlayerTechSelect[player]->SetVisible(true); - m_apPlayerHandicap[player]->SetVisible(true); - m_apPlayerNameBox[player]->SetVisible(true); + continue; + } else { + totalPlayers++; + if (m_apPlayerControlButton[player]->GetText() == "Human") + humanPlayers++; + m_apPlayerTeamSelect[player]->SetVisible(true); + m_apPlayerTechSelect[player]->SetVisible(true); + m_apPlayerHandicap[player]->SetVisible(true); + m_apPlayerNameBox[player]->SetVisible(true); m_apPlayerAISkillSlider[player]->SetVisible(true); m_apPlayerAISkillLabel[player]->SetVisible(true); - } - - // Count teams - if (m_apPlayerTeamSelect[player]->GetVisible()) - { - // Get the chosen team icon - if (m_apPlayerTeamSelect[player]->GetSelectedItem()) - pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity); - // Just get the first one if nothing is selected - else if (m_apPlayerTeamSelect[player]->GetCount() > 0) - pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetItem(0)->m_pEntity); - - if (pTeamIcon) - { - // See if the player is designated to a new team or one that has already been found - bool newTeam = true; - for (std::list::iterator itr = teamList.begin(); itr != teamList.end(); ++itr) - { - // Found existing team! - if (pTeamIcon->GetPresetName() == (*itr)->GetPresetName()) - { - newTeam = false; - break; - } - } - - // If we didn't find that the team we were designated already exists, then count it - if (newTeam) - teamList.push_back(pTeamIcon); - } - } - } - - // Hide/show the start game button depending on whether there's a valid player config right now - m_apMetaButton[STARTNEW]->SetVisible(humanPlayers >= 1 && totalPlayers >= 2 && teamList.size() >= 2); - - // Show a helpful error message if the requirements for starting a game aren't met - if (humanPlayers < 1) - m_pErrorLabel->SetText("Need 1 Human"); - else if (totalPlayers < 2) - m_pErrorLabel->SetText("Need 2 Players"); - else if (teamList.size() < 2) - m_pErrorLabel->SetText("Need 2 Teams"); - else - m_pErrorLabel->SetText(""); - - // Update the game size label since the number of players may have changed - UpdateGameSizeLabels(); -} + } + + // Count teams + if (m_apPlayerTeamSelect[player]->GetVisible()) { + // Get the chosen team icon + if (m_apPlayerTeamSelect[player]->GetSelectedItem()) + pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetSelectedItem()->m_pEntity); + // Just get the first one if nothing is selected + else if (m_apPlayerTeamSelect[player]->GetCount() > 0) + pTeamIcon = dynamic_cast(m_apPlayerTeamSelect[player]->GetItem(0)->m_pEntity); + + if (pTeamIcon) { + // See if the player is designated to a new team or one that has already been found + bool newTeam = true; + for (std::list::iterator itr = teamList.begin(); itr != teamList.end(); ++itr) { + // Found existing team! + if (pTeamIcon->GetPresetName() == (*itr)->GetPresetName()) { + newTeam = false; + break; + } + } + + // If we didn't find that the team we were designated already exists, then count it + if (newTeam) + teamList.push_back(pTeamIcon); + } + } + } + // Hide/show the start game button depending on whether there's a valid player config right now + m_apMetaButton[STARTNEW]->SetVisible(humanPlayers >= 1 && totalPlayers >= 2 && teamList.size() >= 2); + + // Show a helpful error message if the requirements for starting a game aren't met + if (humanPlayers < 1) + m_pErrorLabel->SetText("Need 1 Human"); + else if (totalPlayers < 2) + m_pErrorLabel->SetText("Need 2 Players"); + else if (teamList.size() < 2) + m_pErrorLabel->SetText("Need 2 Teams"); + else + m_pErrorLabel->SetText(""); + + // Update the game size label since the number of players may have changed + UpdateGameSizeLabels(); +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePlayerBars ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the floating player bars with current funds, flag, etc. -void MetagameGUI::UpdatePlayerBars() -{ - if (g_MetaMan.m_GameState >= MetaMan::NOGAME && g_MetaMan.m_GameState <= MetaMan::ENDROUND && !g_MetaMan.IsSuspended()) - { - int metaPlayer = 0; - char str[256]; - for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) - { -// m_apPlayerBox[metaPlayer]; -// m_apPlayerTeamBox[metaPlayer]; - - // Show only the active players this game - m_apPlayerBox[metaPlayer]->SetVisible(true); - - // Make sure their team flag icons are set up correctly - if (!m_apPlayerTeamBox[metaPlayer]->GetDrawImage()) - { - // Set the flag icons on the floating player bars - m_apPlayerTeamBox[metaPlayer]->SetDrawType(GUICollectionBox::Image); - m_apPlayerTeamBox[metaPlayer]->SetDrawImage(new AllegroBitmap(g_MetaMan.m_TeamIcons[(*mpItr).GetTeam()].GetBitmaps32()[0])); - } - - // Show funds of player if income lines are showing, or we are counting income/expenses somehow - if ((!m_PreTurn && metaPlayer == (g_MetaMan.m_GameState - MetaMan::PLAYER1TURN) && m_pSelectedScene) || - metaPlayer == m_ActivePlayerIncomeLines || g_MetaMan.m_GameState == MetaMan::COUNTINCOME || g_MetaMan.m_GameState == MetaMan::BUILDBASES || g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES || g_MetaMan.m_GameState == MetaMan::ENDROUND) - { - std::snprintf(str, sizeof(str), "%c %.0f oz", -58, (*mpItr).m_Funds); -// std::snprintf(str, sizeof(str), "%cx%d %c %.0f oz", -48, (*mpItr).GetBrainPoolCount(), -58, (*mpItr).m_Funds); - m_apPlayerBarLabel[metaPlayer]->SetText(str); - m_apPlayerBarLabel[metaPlayer]->SetHAlignment(GUIFont::Right); - m_apPlayerBarLabel[metaPlayer]->SetToolTip("This player's total funds"); - } - // Show player name instead - else - { - // If the player is out of the game, show a skull before the name - if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) <= 0) - std::snprintf(str, sizeof(str), "%c ", -39); - else - str[0] = 0; - - m_apPlayerBarLabel[metaPlayer]->SetText(std::string(str) + (*mpItr).GetName()); - m_apPlayerBarLabel[metaPlayer]->SetHAlignment(GUIFont::Left); - m_apPlayerBarLabel[metaPlayer]->SetToolTip(""); - } - - // Update the brain pool count display - m_apBrainPoolLabel[metaPlayer]->SetVisible(true); - // Put the brain label on the right or left of the player box based on which half of the screen it's on - if (m_apPlayerBox[metaPlayer]->GetXPos() > ((m_apScreenBox[ROOTBOX]->GetWidth() / 2) - (m_apPlayerBox[metaPlayer]->GetWidth() / 2))) - { - m_apBrainPoolLabel[metaPlayer]->SetPositionAbs(m_apPlayerBox[metaPlayer]->GetXPos() - m_apBrainPoolLabel[metaPlayer]->GetWidth() - 5, m_apPlayerBox[metaPlayer]->GetYPos()); - m_apBrainPoolLabel[metaPlayer]->SetHAlignment(GUIFont::Right); - } - else - { - m_apBrainPoolLabel[metaPlayer]->SetPositionAbs(m_apPlayerBox[metaPlayer]->GetXPos() + m_apPlayerBox[metaPlayer]->GetWidth() + 5, m_apPlayerBox[metaPlayer]->GetYPos()); - m_apBrainPoolLabel[metaPlayer]->SetHAlignment(GUIFont::Left); - } - // [Brain Icon] [X] Number - // The number to display is adjusted with whether any brains are out and about in the gui animations - int brainDisplayCount = (*mpItr).GetBrainPoolCount() - (*mpItr).GetBrainsInTransit(); - std::snprintf(str, sizeof(str), "%c%c%d", brainDisplayCount > 0 ? -48 : -25, -36, brainDisplayCount); - m_apBrainPoolLabel[metaPlayer]->SetText(str); - - // Animate any funds change indicator labels, make them float upward - if (!m_apFundsChangeTimer[metaPlayer].IsPastRealTimeLimit()) - { - // Animate downward if value is negative, upward if positive - int animDir = m_apFundsChangeLabel[metaPlayer]->GetText()[2] == '-' ? 1 : -1; - int heightChange = EaseOut(0, 25, m_apFundsChangeTimer[metaPlayer].RealTimeLimitProgress()); - // Use the height of the label to keep track of the animation progress over several frames - m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apFundsChangeLabel[metaPlayer]->GetXPos(), m_apFundsChangeLabel[metaPlayer]->GetYPos() + animDir * (heightChange - m_apFundsChangeLabel[metaPlayer]->GetHeight() + 16)); - m_apFundsChangeLabel[metaPlayer]->Resize(m_apFundsChangeLabel[metaPlayer]->GetWidth(), 16 + heightChange); - m_apFundsChangeLabel[metaPlayer]->SetVisible(true); - } - // Done animating and showing the change label, make it invisible and disappear - else - { - m_apFundsChangeLabel[metaPlayer]->SetVisible(false); - m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - } - - // Animate any brain change indicator labels, make them float upward - if (!m_apBrainsChangeTimer[metaPlayer].IsPastRealTimeLimit()) - { - // Animate downward if value is negative, upward if positive - int animDir = m_apBrainChangeLabel[metaPlayer]->GetText()[1] == '-' ? 1 : -1; - int heightChange = EaseOut(0, 25, m_apBrainsChangeTimer[metaPlayer].RealTimeLimitProgress()); - // Use the height of the label to keep track of the animation progress over several frames - m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(m_apBrainChangeLabel[metaPlayer]->GetXPos(), m_apBrainChangeLabel[metaPlayer]->GetYPos() + animDir * (heightChange - m_apBrainChangeLabel[metaPlayer]->GetHeight() + 16)); - m_apBrainChangeLabel[metaPlayer]->Resize(m_apBrainChangeLabel[metaPlayer]->GetWidth(), 16 + heightChange); - m_apBrainChangeLabel[metaPlayer]->SetVisible(true); - } - // Done animating and showing the change label, make it invisible and disappear - else - { - m_apBrainChangeLabel[metaPlayer]->SetVisible(false); - m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); - } - -/* This is now obsolete; we show the name inside the bar - // Update the player name labels above each floating bar, IF we're not drawing lines - if (metaPlayer != m_ActivePlayerIncomeLines) - { - m_apFundsChangeLabel[metaPlayer]->SetText((*mpItr).GetName()); - m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apPlayerBox[metaPlayer]->GetXPos() + 5, m_apPlayerBox[metaPlayer]->GetYPos() - 15); - m_apFundsChangeLabel[metaPlayer]->SetVisible(true); - } - // Don't show the name label if we're drawing lines out of this player bar - else - { - - if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) - { - if () - m_apFundsChangeLabel[metaPlayer]->SetVisible(false); - } - else - } -*/ - metaPlayer++; - } - - // Always hide any remaining player labels - while (metaPlayer < Players::MaxPlayerCount) - { - m_apFundsChangeLabel[metaPlayer]->SetVisible(false); - m_apBrainChangeLabel[metaPlayer]->SetVisible(false); - metaPlayer++; - } - } -} +void MetagameGUI::UpdatePlayerBars() { + if (g_MetaMan.m_GameState >= MetaMan::NOGAME && g_MetaMan.m_GameState <= MetaMan::ENDROUND && !g_MetaMan.IsSuspended()) { + int metaPlayer = 0; + char str[256]; + for (std::vector::iterator mpItr = g_MetaMan.m_Players.begin(); mpItr != g_MetaMan.m_Players.end(); ++mpItr) { + // m_apPlayerBox[metaPlayer]; + // m_apPlayerTeamBox[metaPlayer]; + + // Show only the active players this game + m_apPlayerBox[metaPlayer]->SetVisible(true); + + // Make sure their team flag icons are set up correctly + if (!m_apPlayerTeamBox[metaPlayer]->GetDrawImage()) { + // Set the flag icons on the floating player bars + m_apPlayerTeamBox[metaPlayer]->SetDrawType(GUICollectionBox::Image); + m_apPlayerTeamBox[metaPlayer]->SetDrawImage(new AllegroBitmap(g_MetaMan.m_TeamIcons[(*mpItr).GetTeam()].GetBitmaps32()[0])); + } + + // Show funds of player if income lines are showing, or we are counting income/expenses somehow + if ((!m_PreTurn && metaPlayer == (g_MetaMan.m_GameState - MetaMan::PLAYER1TURN) && m_pSelectedScene) || + metaPlayer == m_ActivePlayerIncomeLines || g_MetaMan.m_GameState == MetaMan::COUNTINCOME || g_MetaMan.m_GameState == MetaMan::BUILDBASES || g_MetaMan.m_GameState == MetaMan::RUNACTIVITIES || g_MetaMan.m_GameState == MetaMan::ENDROUND) { + std::snprintf(str, sizeof(str), "%c %.0f oz", -58, (*mpItr).m_Funds); + // std::snprintf(str, sizeof(str), "%cx%d %c %.0f oz", -48, (*mpItr).GetBrainPoolCount(), -58, (*mpItr).m_Funds); + m_apPlayerBarLabel[metaPlayer]->SetText(str); + m_apPlayerBarLabel[metaPlayer]->SetHAlignment(GUIFont::Right); + m_apPlayerBarLabel[metaPlayer]->SetToolTip("This player's total funds"); + } + // Show player name instead + else { + // If the player is out of the game, show a skull before the name + if (g_MetaMan.GetTotalBrainCountOfPlayer(metaPlayer) <= 0) + std::snprintf(str, sizeof(str), "%c ", -39); + else + str[0] = 0; + + m_apPlayerBarLabel[metaPlayer]->SetText(std::string(str) + (*mpItr).GetName()); + m_apPlayerBarLabel[metaPlayer]->SetHAlignment(GUIFont::Left); + m_apPlayerBarLabel[metaPlayer]->SetToolTip(""); + } + + // Update the brain pool count display + m_apBrainPoolLabel[metaPlayer]->SetVisible(true); + // Put the brain label on the right or left of the player box based on which half of the screen it's on + if (m_apPlayerBox[metaPlayer]->GetXPos() > ((m_apScreenBox[ROOTBOX]->GetWidth() / 2) - (m_apPlayerBox[metaPlayer]->GetWidth() / 2))) { + m_apBrainPoolLabel[metaPlayer]->SetPositionAbs(m_apPlayerBox[metaPlayer]->GetXPos() - m_apBrainPoolLabel[metaPlayer]->GetWidth() - 5, m_apPlayerBox[metaPlayer]->GetYPos()); + m_apBrainPoolLabel[metaPlayer]->SetHAlignment(GUIFont::Right); + } else { + m_apBrainPoolLabel[metaPlayer]->SetPositionAbs(m_apPlayerBox[metaPlayer]->GetXPos() + m_apPlayerBox[metaPlayer]->GetWidth() + 5, m_apPlayerBox[metaPlayer]->GetYPos()); + m_apBrainPoolLabel[metaPlayer]->SetHAlignment(GUIFont::Left); + } + // [Brain Icon] [X] Number + // The number to display is adjusted with whether any brains are out and about in the gui animations + int brainDisplayCount = (*mpItr).GetBrainPoolCount() - (*mpItr).GetBrainsInTransit(); + std::snprintf(str, sizeof(str), "%c%c%d", brainDisplayCount > 0 ? -48 : -25, -36, brainDisplayCount); + m_apBrainPoolLabel[metaPlayer]->SetText(str); + + // Animate any funds change indicator labels, make them float upward + if (!m_apFundsChangeTimer[metaPlayer].IsPastRealTimeLimit()) { + // Animate downward if value is negative, upward if positive + int animDir = m_apFundsChangeLabel[metaPlayer]->GetText()[2] == '-' ? 1 : -1; + int heightChange = EaseOut(0, 25, m_apFundsChangeTimer[metaPlayer].RealTimeLimitProgress()); + // Use the height of the label to keep track of the animation progress over several frames + m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apFundsChangeLabel[metaPlayer]->GetXPos(), m_apFundsChangeLabel[metaPlayer]->GetYPos() + animDir * (heightChange - m_apFundsChangeLabel[metaPlayer]->GetHeight() + 16)); + m_apFundsChangeLabel[metaPlayer]->Resize(m_apFundsChangeLabel[metaPlayer]->GetWidth(), 16 + heightChange); + m_apFundsChangeLabel[metaPlayer]->SetVisible(true); + } + // Done animating and showing the change label, make it invisible and disappear + else { + m_apFundsChangeLabel[metaPlayer]->SetVisible(false); + m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + } + + // Animate any brain change indicator labels, make them float upward + if (!m_apBrainsChangeTimer[metaPlayer].IsPastRealTimeLimit()) { + // Animate downward if value is negative, upward if positive + int animDir = m_apBrainChangeLabel[metaPlayer]->GetText()[1] == '-' ? 1 : -1; + int heightChange = EaseOut(0, 25, m_apBrainsChangeTimer[metaPlayer].RealTimeLimitProgress()); + // Use the height of the label to keep track of the animation progress over several frames + m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(m_apBrainChangeLabel[metaPlayer]->GetXPos(), m_apBrainChangeLabel[metaPlayer]->GetYPos() + animDir * (heightChange - m_apBrainChangeLabel[metaPlayer]->GetHeight() + 16)); + m_apBrainChangeLabel[metaPlayer]->Resize(m_apBrainChangeLabel[metaPlayer]->GetWidth(), 16 + heightChange); + m_apBrainChangeLabel[metaPlayer]->SetVisible(true); + } + // Done animating and showing the change label, make it invisible and disappear + else { + m_apBrainChangeLabel[metaPlayer]->SetVisible(false); + m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(m_apScreenBox[ROOTBOX]->GetWidth(), 0); + } + + /* This is now obsolete; we show the name inside the bar + // Update the player name labels above each floating bar, IF we're not drawing lines + if (metaPlayer != m_ActivePlayerIncomeLines) + { + m_apFundsChangeLabel[metaPlayer]->SetText((*mpItr).GetName()); + m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(m_apPlayerBox[metaPlayer]->GetXPos() + 5, m_apPlayerBox[metaPlayer]->GetYPos() - 15); + m_apFundsChangeLabel[metaPlayer]->SetVisible(true); + } + // Don't show the name label if we're drawing lines out of this player bar + else + { + + if (g_MetaMan.m_GameState >= MetaMan::PLAYER1TURN && g_MetaMan.m_GameState <= MetaMan::PLAYER4TURN) + { + if () + m_apFundsChangeLabel[metaPlayer]->SetVisible(false); + } + else + } + */ + metaPlayer++; + } + // Always hide any remaining player labels + while (metaPlayer < Players::MaxPlayerCount) { + m_apFundsChangeLabel[metaPlayer]->SetVisible(false); + m_apBrainChangeLabel[metaPlayer]->SetVisible(false); + metaPlayer++; + } + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdateSiteHoverLabel ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the floating label over a planet site. -void MetagameGUI::UpdateSiteNameLabel(bool visible, std::string text, const Vector &location, float height) -{ - // Set up the hover label to appear over any hovered scene location - m_pScenePlanetLabel->SetVisible(visible); - if (visible) - { - m_pScenePlanetLabel->SetText(text); - m_pScenePlanetLabel->SetPositionAbs(m_PlanetCenter.m_X + location.m_X - (m_pScenePlanetLabel->GetWidth() / 2), - m_PlanetCenter.m_Y + location.m_Y - (m_pScenePlanetLabel->GetHeight() * 1.5 * height)); - - // Clamp it to within the screen.. only Y applies to the label though - int pad = 6; -/* - if (m_pScenePlanetLabel->GetXPos() < pad) - m_pScenePlanetLabel->SetPositionAbs(pad, m_pScenePlanetLabel->GetYPos()); - else if (m_pScenePlanetLabel->GetXPos() + m_pScenePlanetLabel->GetWidth() + pad >= m_RootBoxMaxWidth) - m_pScenePlanetLabel->SetPositionAbs(m_RootBoxMaxWidth - m_pScenePlanetLabel->GetWidth() - pad, m_pScenePlanetLabel->GetYPos()); -*/ - if (m_pScenePlanetLabel->GetYPos() < pad) - m_pScenePlanetLabel->SetPositionAbs(m_pScenePlanetLabel->GetXPos(), pad); - else if (m_pScenePlanetLabel->GetYPos() + m_pScenePlanetLabel->GetHeight() + pad >= g_WindowMan.GetResY()) - m_pScenePlanetLabel->SetPositionAbs(m_pScenePlanetLabel->GetXPos(), g_WindowMan.GetResY() - m_pScenePlanetLabel->GetHeight() - pad); - } +void MetagameGUI::UpdateSiteNameLabel(bool visible, std::string text, const Vector& location, float height) { + // Set up the hover label to appear over any hovered scene location + m_pScenePlanetLabel->SetVisible(visible); + if (visible) { + m_pScenePlanetLabel->SetText(text); + m_pScenePlanetLabel->SetPositionAbs(m_PlanetCenter.m_X + location.m_X - (m_pScenePlanetLabel->GetWidth() / 2), + m_PlanetCenter.m_Y + location.m_Y - (m_pScenePlanetLabel->GetHeight() * 1.5 * height)); + + // Clamp it to within the screen.. only Y applies to the label though + int pad = 6; + /* + if (m_pScenePlanetLabel->GetXPos() < pad) + m_pScenePlanetLabel->SetPositionAbs(pad, m_pScenePlanetLabel->GetYPos()); + else if (m_pScenePlanetLabel->GetXPos() + m_pScenePlanetLabel->GetWidth() + pad >= m_RootBoxMaxWidth) + m_pScenePlanetLabel->SetPositionAbs(m_RootBoxMaxWidth - m_pScenePlanetLabel->GetWidth() - pad, m_pScenePlanetLabel->GetYPos()); + */ + if (m_pScenePlanetLabel->GetYPos() < pad) + m_pScenePlanetLabel->SetPositionAbs(m_pScenePlanetLabel->GetXPos(), pad); + else if (m_pScenePlanetLabel->GetYPos() + m_pScenePlanetLabel->GetHeight() + pad >= g_WindowMan.GetResY()) + m_pScenePlanetLabel->SetPositionAbs(m_pScenePlanetLabel->GetXPos(), g_WindowMan.GetResY() - m_pScenePlanetLabel->GetHeight() - pad); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: PlayerTextIndication ////////////////////////////////////////////////////////////////////////////////////////// // Description: Starts an animation of a label showing a text string over a player bar -void MetagameGUI::PlayerTextIndication(int metaPlayer, std::string text, const Vector &screenPos, double animLengthMS) -{ - m_apFundsChangeLabel[metaPlayer]->SetText(text); - m_apFundsChangeLabel[metaPlayer]->SetHAlignment(GUIFont::Centre); - m_apFundsChangeLabel[metaPlayer]->SetVAlignment(GUIFont::Middle); - m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(screenPos.m_X - (m_apFundsChangeLabel[metaPlayer]->GetWidth() / 2), screenPos.m_Y - (m_apFundsChangeLabel[metaPlayer]->GetHeight() / 2)); - // The height is how the things get animated - m_apFundsChangeLabel[metaPlayer]->Resize(m_apFundsChangeLabel[metaPlayer]->GetWidth(), 16); - m_apFundsChangeLabel[metaPlayer]->SetVisible(true); - - // Start off the timer for the animation, which is updated in UpdatePlayerBars() - m_apFundsChangeTimer[metaPlayer].Reset(); - m_apFundsChangeTimer[metaPlayer].SetRealTimeLimitMS(animLengthMS); +void MetagameGUI::PlayerTextIndication(int metaPlayer, std::string text, const Vector& screenPos, double animLengthMS) { + m_apFundsChangeLabel[metaPlayer]->SetText(text); + m_apFundsChangeLabel[metaPlayer]->SetHAlignment(GUIFont::Centre); + m_apFundsChangeLabel[metaPlayer]->SetVAlignment(GUIFont::Middle); + m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(screenPos.m_X - (m_apFundsChangeLabel[metaPlayer]->GetWidth() / 2), screenPos.m_Y - (m_apFundsChangeLabel[metaPlayer]->GetHeight() / 2)); + // The height is how the things get animated + m_apFundsChangeLabel[metaPlayer]->Resize(m_apFundsChangeLabel[metaPlayer]->GetWidth(), 16); + m_apFundsChangeLabel[metaPlayer]->SetVisible(true); + + // Start off the timer for the animation, which is updated in UpdatePlayerBars() + m_apFundsChangeTimer[metaPlayer].Reset(); + m_apFundsChangeTimer[metaPlayer].SetRealTimeLimitMS(animLengthMS); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: FundsChangeIndication ////////////////////////////////////////////////////////////////////////////////////////// // Description: Starts an animation of a label showing funds changing for a player -void MetagameGUI::FundsChangeIndication(int metaPlayer, float change, const Vector &screenPos, double animLengthMS) -{ - char str[256]; - std::snprintf(str, sizeof(str), change >= 1.0 ? "%c +%.0f oz" : (change <= -1.0 ? "%c %.0f oz" : "%c %.0f oz"), -58, change); - m_apFundsChangeLabel[metaPlayer]->SetText(str); - m_apFundsChangeLabel[metaPlayer]->SetHAlignment(GUIFont::Right); - m_apFundsChangeLabel[metaPlayer]->SetVAlignment(GUIFont::Top); - m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(screenPos.m_X - m_apFundsChangeLabel[metaPlayer]->GetWidth(), screenPos.m_Y); - // The height is how the things get animated - m_apFundsChangeLabel[metaPlayer]->Resize(m_apFundsChangeLabel[metaPlayer]->GetWidth(), 16); - m_apFundsChangeLabel[metaPlayer]->SetVisible(true); - - // Start off the timer for the animation, which is updated in UpdatePlayerBars() - m_apFundsChangeTimer[metaPlayer].Reset(); - m_apFundsChangeTimer[metaPlayer].SetRealTimeLimitMS(animLengthMS); +void MetagameGUI::FundsChangeIndication(int metaPlayer, float change, const Vector& screenPos, double animLengthMS) { + char str[256]; + std::snprintf(str, sizeof(str), change >= 1.0 ? "%c +%.0f oz" : (change <= -1.0 ? "%c %.0f oz" : "%c %.0f oz"), -58, change); + m_apFundsChangeLabel[metaPlayer]->SetText(str); + m_apFundsChangeLabel[metaPlayer]->SetHAlignment(GUIFont::Right); + m_apFundsChangeLabel[metaPlayer]->SetVAlignment(GUIFont::Top); + m_apFundsChangeLabel[metaPlayer]->SetPositionAbs(screenPos.m_X - m_apFundsChangeLabel[metaPlayer]->GetWidth(), screenPos.m_Y); + // The height is how the things get animated + m_apFundsChangeLabel[metaPlayer]->Resize(m_apFundsChangeLabel[metaPlayer]->GetWidth(), 16); + m_apFundsChangeLabel[metaPlayer]->SetVisible(true); + + // Start off the timer for the animation, which is updated in UpdatePlayerBars() + m_apFundsChangeTimer[metaPlayer].Reset(); + m_apFundsChangeTimer[metaPlayer].SetRealTimeLimitMS(animLengthMS); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: BrainsChangeIndication ////////////////////////////////////////////////////////////////////////////////////////// // Description: Starts an animation of a label showing brains changing for a metaPlayer -void MetagameGUI::BrainsChangeIndication(int metaPlayer, int change, const Vector &screenPos, int fontAlignment, double animLengthMS) -{ - char str[256]; - // [Brain Icon] [X] Number - // The number to display is adjusted with whether any brains are out and about in the gui animations - std::snprintf(str, sizeof(str), change >= 0 ? "%c+%d" : "%c%d", -48, change); - m_apBrainChangeLabel[metaPlayer]->SetText(str); - - m_apBrainChangeLabel[metaPlayer]->SetHAlignment(fontAlignment); - m_apBrainChangeLabel[metaPlayer]->SetVAlignment(GUIFont::Top); - m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(screenPos.m_X, screenPos.m_Y); - // The height is how the things get animated - m_apBrainChangeLabel[metaPlayer]->Resize(m_apBrainPoolLabel[metaPlayer]->GetWidth(), 16); - m_apBrainChangeLabel[metaPlayer]->SetVisible(true); - - // Start off the timer for the animation, which is updated in UpdatePlayerBars() - m_apBrainsChangeTimer[metaPlayer].Reset(); - m_apBrainsChangeTimer[metaPlayer].SetRealTimeLimitMS(animLengthMS); +void MetagameGUI::BrainsChangeIndication(int metaPlayer, int change, const Vector& screenPos, int fontAlignment, double animLengthMS) { + char str[256]; + // [Brain Icon] [X] Number + // The number to display is adjusted with whether any brains are out and about in the gui animations + std::snprintf(str, sizeof(str), change >= 0 ? "%c+%d" : "%c%d", -48, change); + m_apBrainChangeLabel[metaPlayer]->SetText(str); + + m_apBrainChangeLabel[metaPlayer]->SetHAlignment(fontAlignment); + m_apBrainChangeLabel[metaPlayer]->SetVAlignment(GUIFont::Top); + m_apBrainChangeLabel[metaPlayer]->SetPositionAbs(screenPos.m_X, screenPos.m_Y); + // The height is how the things get animated + m_apBrainChangeLabel[metaPlayer]->Resize(m_apBrainPoolLabel[metaPlayer]->GetWidth(), 16); + m_apBrainChangeLabel[metaPlayer]->SetVisible(true); + + // Start off the timer for the animation, which is updated in UpdatePlayerBars() + m_apBrainsChangeTimer[metaPlayer].Reset(); + m_apBrainsChangeTimer[metaPlayer].SetRealTimeLimitMS(animLengthMS); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: RemoveSiteLine ////////////////////////////////////////////////////////////////////////////////////////// // Description: Removes a specific index siteline out of a vector. -bool MetagameGUI::RemoveSiteLine(std::vector &lineList, int removeIndex) -{ - if (lineList.empty()) - return false; - - int index = 0; - bool removed = false; - for (std::vector::iterator slItr = lineList.begin(); slItr != lineList.end(); ++slItr, ++index) - { - if (index == removeIndex) - { - lineList.erase(slItr); - removed = true; - } - } - return removed; -} +bool MetagameGUI::RemoveSiteLine(std::vector& lineList, int removeIndex) { + if (lineList.empty()) + return false; + int index = 0; + bool removed = false; + for (std::vector::iterator slItr = lineList.begin(); slItr != lineList.end(); ++slItr, ++index) { + if (index == removeIndex) { + lineList.erase(slItr); + removed = true; + } + } + return removed; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetPlayerLineFunds ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gets the total funds of all visible lines of a specific player. -float MetagameGUI::GetPlayerLineFunds(std::vector &lineList, int metaPlayer, bool onlyVisible) -{ - if (metaPlayer < Players::PlayerOne || metaPlayer >= g_MetaMan.m_Players.size()) - return 0; +float MetagameGUI::GetPlayerLineFunds(std::vector& lineList, int metaPlayer, bool onlyVisible) { + if (metaPlayer < Players::PlayerOne || metaPlayer >= g_MetaMan.m_Players.size()) + return 0; - // Figure out the total visible meter funds of this player - float totalFunds = 0; - for (std::vector::iterator slItr = lineList.begin(); slItr != lineList.end(); ++slItr) - if ((*slItr).m_Player == metaPlayer && (!onlyVisible || IsSiteLineVisible(*slItr))) - totalFunds += (*slItr).m_FundsAmount; + // Figure out the total visible meter funds of this player + float totalFunds = 0; + for (std::vector::iterator slItr = lineList.begin(); slItr != lineList.end(); ++slItr) + if ((*slItr).m_Player == metaPlayer && (!onlyVisible || IsSiteLineVisible(*slItr))) + totalFunds += (*slItr).m_FundsAmount; - return totalFunds; + return totalFunds; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: UpdatePlayerLineRatios ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the site line meter ratios of a player based on their fund // amounts and visibilty. -void MetagameGUI::UpdatePlayerLineRatios(std::vector &lineList, int metaPlayer, bool onlyVisible, float total) -{ - if (metaPlayer < Players::PlayerOne || metaPlayer >= g_MetaMan.m_Players.size()) - return; - - // Figure out the total visible meter funds of this player, unless a total already specifically specified - float totalFunds = total > 0 ? total : GetPlayerLineFunds(lineList, metaPlayer, onlyVisible); - - // Now go through the visible ones and set their meter ratios appropriately - float meterStart = 0; - for (std::vector::iterator slItr = lineList.begin(); slItr != lineList.end(); ++slItr) - { - if ((*slItr).m_Player == metaPlayer && (!onlyVisible || IsSiteLineVisible(*slItr))) - { - (*slItr).m_StartMeterAt = meterStart; - (*slItr).m_MeterAmount = (*slItr).m_FundsAmount / totalFunds; - meterStart += (*slItr).m_MeterAmount; - } - } -} +void MetagameGUI::UpdatePlayerLineRatios(std::vector& lineList, int metaPlayer, bool onlyVisible, float total) { + if (metaPlayer < Players::PlayerOne || metaPlayer >= g_MetaMan.m_Players.size()) + return; + // Figure out the total visible meter funds of this player, unless a total already specifically specified + float totalFunds = total > 0 ? total : GetPlayerLineFunds(lineList, metaPlayer, onlyVisible); + + // Now go through the visible ones and set their meter ratios appropriately + float meterStart = 0; + for (std::vector::iterator slItr = lineList.begin(); slItr != lineList.end(); ++slItr) { + if ((*slItr).m_Player == metaPlayer && (!onlyVisible || IsSiteLineVisible(*slItr))) { + (*slItr).m_StartMeterAt = meterStart; + (*slItr).m_MeterAmount = (*slItr).m_FundsAmount / totalFunds; + meterStart += (*slItr).m_MeterAmount; + } + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: DrawGlowLine @@ -6649,162 +5990,151 @@ void MetagameGUI::UpdatePlayerLineRatios(std::vector &lineList, int me // Description: Draws a fancy thick flickering line to point out scene points on the // planet. -void MetagameGUI::DrawGlowLine(BITMAP *drawBitmap, const Vector &start, const Vector &end, int color) -{ +void MetagameGUI::DrawGlowLine(BITMAP* drawBitmap, const Vector& start, const Vector& end, int color) { int blendAmount = 210 + RandomNum(-15, 15); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - line(drawBitmap, start.m_X, start.m_Y, end.m_X, end.m_Y, color); -/* Looks like ass - // Draw the thickener lines thicker in the appropriate directions - if (fabs(end.m_X - start.m_X) > fabs(end.m_Y - start.m_Y)) - { - line(drawBitmap, start.m_X, start.m_Y + 1, end.m_X, end.m_Y + 1, color); - line(drawBitmap, start.m_X, start.m_Y - 1, end.m_X, end.m_Y - 1, color); - } - else - { - line(drawBitmap, start.m_X + 1, start.m_Y, end.m_X + 1, end.m_Y, color); - line(drawBitmap, start.m_X - 1, start.m_Y, end.m_X - 1, end.m_Y, color); - } -*/ + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + line(drawBitmap, start.m_X, start.m_Y, end.m_X, end.m_Y, color); + /* Looks like ass + // Draw the thickener lines thicker in the appropriate directions + if (fabs(end.m_X - start.m_X) > fabs(end.m_Y - start.m_Y)) + { + line(drawBitmap, start.m_X, start.m_Y + 1, end.m_X, end.m_Y + 1, color); + line(drawBitmap, start.m_X, start.m_Y - 1, end.m_X, end.m_Y - 1, color); + } + else + { + line(drawBitmap, start.m_X + 1, start.m_Y, end.m_X + 1, end.m_Y, color); + line(drawBitmap, start.m_X - 1, start.m_Y, end.m_X - 1, end.m_Y, color); + } + */ blendAmount = 45 + RandomNum(-25, 25); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - line(drawBitmap, start.m_X + 1, start.m_Y, end.m_X + 1, end.m_Y, color); - line(drawBitmap, start.m_X - 1, start.m_Y, end.m_X - 1, end.m_Y, color); - line(drawBitmap, start.m_X, start.m_Y + 1, end.m_X, end.m_Y + 1, color); - line(drawBitmap, start.m_X, start.m_Y - 1, end.m_X, end.m_Y - 1, color); + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + line(drawBitmap, start.m_X + 1, start.m_Y, end.m_X + 1, end.m_Y, color); + line(drawBitmap, start.m_X - 1, start.m_Y, end.m_X - 1, end.m_Y, color); + line(drawBitmap, start.m_X, start.m_Y + 1, end.m_X, end.m_Y + 1, color); + line(drawBitmap, start.m_X, start.m_Y - 1, end.m_X, end.m_Y - 1, color); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: DrawScreenLineToSitePoint ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws a fancy thick flickering lines to point out scene points on the // planet, FROM an arbitrary screen point. -bool MetagameGUI::DrawScreenLineToSitePoint(BITMAP *drawBitmap, - const Vector &screenPoint, - const Vector &planetPoint, +bool MetagameGUI::DrawScreenLineToSitePoint(BITMAP* drawBitmap, + const Vector& screenPoint, + const Vector& planetPoint, int color, int onlyFirstSegments, int onlyLastSegments, int channelHeight, float circleSize, - bool squareSite) const -{ - // No part of the line is visible with these params, so just quit - if (onlyFirstSegments == 0 || onlyLastSegments == 0) - return false; - // Detect disabling of the segment controls - if (onlyFirstSegments < 0) - onlyFirstSegments = 100; - if (onlyLastSegments < 0) - onlyLastSegments = 100; - - int totalSegments = 0; - int drawnFirstSegments = 0; - int lastSegmentsToDraw = 0; - int circleRadius = squareSite ? std::floor(6 * circleSize) : std::floor(8 * circleSize); - int chamferSize = CHAMFERSIZE; - Vector chamferPoint1; - Vector chamferPoint2; - Vector sitePos = m_PlanetCenter + planetPoint; - bool siteIsAbove = sitePos.m_Y < screenPoint.m_Y; - float yDirMult = siteIsAbove ? -1.0 : 1.0; - bool twoBends = fabs(sitePos.m_Y - screenPoint.m_Y) < (channelHeight - circleRadius); - bool noBends = (fabs(sitePos.m_X - screenPoint.m_X) < circleRadius);// && ((m_apPlayerBox[player]->GetWidth() * meterAmount * 0.5) >= fabs(sitePos.m_X - screenPoint.m_X)); - Vector firstBend(screenPoint.m_X, twoBends ? (screenPoint.m_Y + channelHeight * yDirMult) : sitePos.m_Y); - Vector secondBend(sitePos.m_X, firstBend.m_Y); - bool siteIsLeft = sitePos.m_X < screenPoint.m_X; - float xDirMult = siteIsLeft ? -1.0 : 1.0; - - // No bends, meaning the mid of the meter goes straight up/down into the site circle - if (noBends) - { - // How many possible segments there are total for this type of line: to site + circle - totalSegments = lastSegmentsToDraw = 1 + 1; - // Draw the line to the site - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, screenPoint + Vector(sitePos.m_X - screenPoint.m_X, 0), sitePos + Vector(0, (circleRadius + 1) * -yDirMult), color); - } - // Extra lines depending on whether there needs to be two bends due to the site being in the 'channel', ie next to the floating player bar - else if (twoBends) - { - // Cap the chamfer size on the second bend appropriately - chamferSize = MIN((firstBend - secondBend).GetMagnitude() - 15, chamferSize); - chamferSize = MIN((secondBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); - // Snap the chamfer to not exist below a minimum size - chamferSize = (chamferSize < 15) ? 0 : chamferSize; - // No inverted chamfer - chamferSize = MAX(0, chamferSize); - chamferPoint1.SetXY(secondBend.m_X + chamferSize * -xDirMult, secondBend.m_Y); - chamferPoint2.SetXY(secondBend.m_X, secondBend.m_Y + chamferSize * -yDirMult); - // How many of the last segments to draw: to first bend + to second bend chamfer + chamfer + to site + circle - totalSegments = lastSegmentsToDraw = 1 + 1 + (int)(chamferSize > 0) + 1 + 1; - // Line to the first bend - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, screenPoint, firstBend, color); - // Line to the second bend, incl the chamfer - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, firstBend, chamferPoint1, color); - if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); - // Line to the site - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector(0, (circleRadius + 1) * yDirMult), color); - } - // Just one bend - else - { - // Cap the chamfer size on the first bend appropriately - chamferSize = MIN((screenPoint - firstBend).GetMagnitude() - 15, chamferSize); - chamferSize = MIN((firstBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); - // Snap the chamfer to not exist below a minimum size - chamferSize = (chamferSize < 15) ? 0 : chamferSize; - // No inverted chamfer - chamferSize = MAX(0, chamferSize); - chamferPoint1.SetXY(screenPoint.m_X, firstBend.m_Y + chamferSize * -yDirMult); - chamferPoint2.SetXY(firstBend.m_X + chamferSize * xDirMult, sitePos.m_Y); - // How many of the last segments to draw: to first bend chamfer + chamfer + to site + circle - totalSegments = lastSegmentsToDraw = 1 + (int)(chamferSize > 0) + 1 + 1; - // Draw line to the first bend, incl the chamfer - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, screenPoint, chamferPoint1, color); - if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); - // Draw line to the site - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector((circleRadius + 1) * -xDirMult, 0), color); - } - - // Draw a circle around the site target - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - { + bool squareSite) const { + // No part of the line is visible with these params, so just quit + if (onlyFirstSegments == 0 || onlyLastSegments == 0) + return false; + // Detect disabling of the segment controls + if (onlyFirstSegments < 0) + onlyFirstSegments = 100; + if (onlyLastSegments < 0) + onlyLastSegments = 100; + + int totalSegments = 0; + int drawnFirstSegments = 0; + int lastSegmentsToDraw = 0; + int circleRadius = squareSite ? std::floor(6 * circleSize) : std::floor(8 * circleSize); + int chamferSize = CHAMFERSIZE; + Vector chamferPoint1; + Vector chamferPoint2; + Vector sitePos = m_PlanetCenter + planetPoint; + bool siteIsAbove = sitePos.m_Y < screenPoint.m_Y; + float yDirMult = siteIsAbove ? -1.0 : 1.0; + bool twoBends = fabs(sitePos.m_Y - screenPoint.m_Y) < (channelHeight - circleRadius); + bool noBends = (fabs(sitePos.m_X - screenPoint.m_X) < circleRadius); // && ((m_apPlayerBox[player]->GetWidth() * meterAmount * 0.5) >= fabs(sitePos.m_X - screenPoint.m_X)); + Vector firstBend(screenPoint.m_X, twoBends ? (screenPoint.m_Y + channelHeight * yDirMult) : sitePos.m_Y); + Vector secondBend(sitePos.m_X, firstBend.m_Y); + bool siteIsLeft = sitePos.m_X < screenPoint.m_X; + float xDirMult = siteIsLeft ? -1.0 : 1.0; + + // No bends, meaning the mid of the meter goes straight up/down into the site circle + if (noBends) { + // How many possible segments there are total for this type of line: to site + circle + totalSegments = lastSegmentsToDraw = 1 + 1; + // Draw the line to the site + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, screenPoint + Vector(sitePos.m_X - screenPoint.m_X, 0), sitePos + Vector(0, (circleRadius + 1) * -yDirMult), color); + } + // Extra lines depending on whether there needs to be two bends due to the site being in the 'channel', ie next to the floating player bar + else if (twoBends) { + // Cap the chamfer size on the second bend appropriately + chamferSize = MIN((firstBend - secondBend).GetMagnitude() - 15, chamferSize); + chamferSize = MIN((secondBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); + // Snap the chamfer to not exist below a minimum size + chamferSize = (chamferSize < 15) ? 0 : chamferSize; + // No inverted chamfer + chamferSize = MAX(0, chamferSize); + chamferPoint1.SetXY(secondBend.m_X + chamferSize * -xDirMult, secondBend.m_Y); + chamferPoint2.SetXY(secondBend.m_X, secondBend.m_Y + chamferSize * -yDirMult); + // How many of the last segments to draw: to first bend + to second bend chamfer + chamfer + to site + circle + totalSegments = lastSegmentsToDraw = 1 + 1 + (int)(chamferSize > 0) + 1 + 1; + // Line to the first bend + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, screenPoint, firstBend, color); + // Line to the second bend, incl the chamfer + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, firstBend, chamferPoint1, color); + if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); + // Line to the site + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector(0, (circleRadius + 1) * yDirMult), color); + } + // Just one bend + else { + // Cap the chamfer size on the first bend appropriately + chamferSize = MIN((screenPoint - firstBend).GetMagnitude() - 15, chamferSize); + chamferSize = MIN((firstBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); + // Snap the chamfer to not exist below a minimum size + chamferSize = (chamferSize < 15) ? 0 : chamferSize; + // No inverted chamfer + chamferSize = MAX(0, chamferSize); + chamferPoint1.SetXY(screenPoint.m_X, firstBend.m_Y + chamferSize * -yDirMult); + chamferPoint2.SetXY(firstBend.m_X + chamferSize * xDirMult, sitePos.m_Y); + // How many of the last segments to draw: to first bend chamfer + chamfer + to site + circle + totalSegments = lastSegmentsToDraw = 1 + (int)(chamferSize > 0) + 1 + 1; + // Draw line to the first bend, incl the chamfer + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, screenPoint, chamferPoint1, color); + if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); + // Draw line to the site + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector((circleRadius + 1) * -xDirMult, 0), color); + } + + // Draw a circle around the site target + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) { int blendAmount = 225 + RandomNum(-20, 20); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - - // If specified, draw a squareSite instead (with chamfered corners) - if (squareSite) - { - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_X + circleRadius, color); - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1 - 1, sitePos.m_X + circleRadius, color); - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius, sitePos.m_X + circleRadius, color); - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius + 1, sitePos.m_X + circleRadius, color); - vline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); - vline(drawBitmap, sitePos.m_X - circleRadius - 1 - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); - vline(drawBitmap, sitePos.m_X + circleRadius, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); - vline(drawBitmap, sitePos.m_X + circleRadius + 1, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); - } - else - { - circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius, color); - circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius - 1, color); - } - } - - return totalSegments <= onlyFirstSegments && totalSegments <= onlyLastSegments; -} + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + + // If specified, draw a squareSite instead (with chamfered corners) + if (squareSite) { + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_X + circleRadius, color); + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1 - 1, sitePos.m_X + circleRadius, color); + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius, sitePos.m_X + circleRadius, color); + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius + 1, sitePos.m_X + circleRadius, color); + vline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); + vline(drawBitmap, sitePos.m_X - circleRadius - 1 - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); + vline(drawBitmap, sitePos.m_X + circleRadius, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); + vline(drawBitmap, sitePos.m_X + circleRadius + 1, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); + } else { + circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius, color); + circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius - 1, color); + } + } + return totalSegments <= onlyFirstSegments && totalSegments <= onlyLastSegments; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: DrawPlayerLineToSitePoint @@ -6812,159 +6142,148 @@ bool MetagameGUI::DrawScreenLineToSitePoint(BITMAP *drawBitmap, // Description: Draws a fancy thick flickering lines to point out scene points on the // planet, FROM a floating player bar, showing a certain ratio. -bool MetagameGUI::DrawPlayerLineToSitePoint(BITMAP *drawBitmap, - int metaPlayer, - float startMeterAt, - float meterAmount, - const Vector &planetPoint, - int color, - int onlyFirstSegments, - int onlyLastSegments, - int channelHeight, - float circleSize, - bool squareSite, - bool drawMeterOverride) const -{ - RTEAssert(metaPlayer >= Players::PlayerOne && metaPlayer < Players::MaxPlayerCount, "Player out of bounds"); - // No part of the line is visible with these params, so just quit - if ((onlyFirstSegments == 0 || onlyLastSegments == 0) && !drawMeterOverride) - return false; - startMeterAt = MAX(0, startMeterAt); - startMeterAt = MIN(1.0, startMeterAt); - if ((startMeterAt + meterAmount) > 1.0) - meterAmount = 1.0 - startMeterAt; - // Detect disabling of the segment controls - if (onlyFirstSegments < 0) - onlyFirstSegments = 100; - if (onlyLastSegments < 0) - onlyLastSegments = 100; - - int totalSegments = 0; - int drawnFirstSegments = 0; - int lastSegmentsToDraw = 0; - int meterHeight = 5; - int circleRadius = squareSite ? std::floor(6 * circleSize) : std::floor(8 * circleSize); - int chamferSize = CHAMFERSIZE; - Vector chamferPoint1; - Vector chamferPoint2; - int boxMidY = m_apPlayerBox[metaPlayer]->GetYPos() + (m_apPlayerBox[metaPlayer]->GetHeight() / 2); - Vector sitePos = m_PlanetCenter + planetPoint; - bool siteIsAbove = sitePos.m_Y < boxMidY; - float yDirMult = siteIsAbove ? -1.0 : 1.0; - bool twoBends = fabs(sitePos.m_Y - boxMidY) < (channelHeight - circleRadius); - Vector startMeter(m_apPlayerBox[metaPlayer]->GetXPos() + (m_apPlayerBox[metaPlayer]->GetWidth() - 1) * startMeterAt + 1, m_apPlayerBox[metaPlayer]->GetYPos() + (siteIsAbove ? 0 : m_apPlayerBox[metaPlayer]->GetHeight())); - Vector endMeter(startMeter.m_X + MAX(0, (m_apPlayerBox[metaPlayer]->GetWidth() - 1) * meterAmount - 2), startMeter.m_Y); - Vector midMeter(startMeter.m_X + MAX(0, (m_apPlayerBox[metaPlayer]->GetWidth() - 1) * meterAmount * 0.5 - 1), startMeter.m_Y + meterHeight * yDirMult); - bool noBends = (fabs(sitePos.m_X - midMeter.m_X) < circleRadius) && ((m_apPlayerBox[metaPlayer]->GetWidth() * meterAmount * 0.5) >= fabs(sitePos.m_X - midMeter.m_X)); - Vector firstBend(midMeter.m_X, twoBends ? (boxMidY + channelHeight * yDirMult) : sitePos.m_Y); - Vector secondBend(sitePos.m_X, firstBend.m_Y); - bool siteIsLeft = sitePos.m_X < midMeter.m_X; - float xDirMult = siteIsLeft ? -1.0 : 1.0; - - // No bends, meaning the mid of the meter goes straight up/down into the site circle - if (noBends) - { - // How many possible segments there are total for this type of line: meter + to site + circle - totalSegments = lastSegmentsToDraw = 1 + 1 + 1; - // Draw the meter - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments) || drawMeterOverride) - { - DrawGlowLine(drawBitmap, startMeter, startMeter + Vector(0, meterHeight * yDirMult), color); - DrawGlowLine(drawBitmap, endMeter, endMeter + Vector(0, meterHeight * yDirMult), color); - DrawGlowLine(drawBitmap, startMeter + Vector(0, meterHeight * yDirMult), endMeter + Vector(0, meterHeight * yDirMult), color); - } - // Draw the line to the site - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, midMeter + Vector(sitePos.m_X - midMeter.m_X, 0), sitePos + Vector(0, (circleRadius + 1) * -yDirMult), color); - } - // Extra lines depending on whether there needs to be two bends due to the site being in the 'channel', ie next to teh floating metaPlayer bar - else if (twoBends) - { - // Cap the chamfer size on the second bend appropriately - chamferSize = MIN((firstBend - secondBend).GetMagnitude() - meterHeight * 3, chamferSize); - chamferSize = MIN((secondBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); - // Snap the chamfer to not exist below a minimum size - chamferSize = (chamferSize < (meterHeight * 3)) ? 0 : chamferSize; - // No inverted chamfer - chamferSize = MAX(0, chamferSize); - chamferPoint1.SetXY(secondBend.m_X + chamferSize * -xDirMult, secondBend.m_Y); - chamferPoint2.SetXY(secondBend.m_X, secondBend.m_Y + chamferSize * -yDirMult); - // How many of the last segments to draw: meter + to first bend + to second bend chamfer + chamfer + to site + circle - totalSegments = lastSegmentsToDraw = 1 + 1 + 1 + (int)(chamferSize > 0) + 1 + 1; - // Draw the meter - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments) || drawMeterOverride) - { - DrawGlowLine(drawBitmap, startMeter, startMeter + Vector(0, meterHeight * yDirMult), color); - DrawGlowLine(drawBitmap, endMeter, endMeter + Vector(0, meterHeight * yDirMult), color); - DrawGlowLine(drawBitmap, startMeter + Vector(0, meterHeight * yDirMult), endMeter + Vector(0, meterHeight * yDirMult), color); - } - // Line to the first bend - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, midMeter, firstBend, color); - // Line to the second bend, incl the chamfer - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, firstBend, chamferPoint1, color); - if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); - // Line to the site - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector(0, (circleRadius + 1) * yDirMult), color); - } - // Just one bend - else - { - // Cap the chamfer size on the first bend appropriately - chamferSize = MIN((midMeter - firstBend).GetMagnitude() - meterHeight * 3, chamferSize); - chamferSize = MIN((firstBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); - // Snap the chamfer to not exist below a minimum size - chamferSize = (chamferSize < (meterHeight * 3)) ? 0 : chamferSize; - // No inverted chamfer - chamferSize = MAX(0, chamferSize); - chamferPoint1.SetXY(midMeter.m_X, firstBend.m_Y + chamferSize * -yDirMult); - chamferPoint2.SetXY(firstBend.m_X + chamferSize * xDirMult, sitePos.m_Y); - // How many of the last segments to draw: meter + to first bend chamfer + chamfer + to site + circle - totalSegments = lastSegmentsToDraw = 1 + 1 + (int)(chamferSize > 0) + 1 + 1; - // Draw the meter - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments) || drawMeterOverride) - { - DrawGlowLine(drawBitmap, startMeter, startMeter + Vector(0, meterHeight * yDirMult), color); - DrawGlowLine(drawBitmap, endMeter, endMeter + Vector(0, meterHeight * yDirMult), color); - DrawGlowLine(drawBitmap, startMeter + Vector(0, meterHeight * yDirMult), endMeter + Vector(0, meterHeight * yDirMult), color); - } - // Draw line to the first bend, incl the chamfer - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, midMeter, chamferPoint1, color); - if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); - // Draw line to the site - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector((circleRadius + 1) * -xDirMult, 0), color); - } - - // Draw a circle around the site target - if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) - { - int blendAmount = 225 + RandomNum(-20, 20); - set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); - - // If specified, draw a squareSite instead (with chamfered corners) - if (squareSite) - { - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_X + circleRadius, color); - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1 - 1, sitePos.m_X + circleRadius, color); - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius, sitePos.m_X + circleRadius, color); - hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius + 1, sitePos.m_X + circleRadius, color); - vline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); - vline(drawBitmap, sitePos.m_X - circleRadius - 1 - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); - vline(drawBitmap, sitePos.m_X + circleRadius, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); - vline(drawBitmap, sitePos.m_X + circleRadius + 1, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); - } - else - { - circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius, color); - circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius - 1, color); - } - } - - return totalSegments <= onlyFirstSegments && totalSegments <= onlyLastSegments; +bool MetagameGUI::DrawPlayerLineToSitePoint(BITMAP* drawBitmap, + int metaPlayer, + float startMeterAt, + float meterAmount, + const Vector& planetPoint, + int color, + int onlyFirstSegments, + int onlyLastSegments, + int channelHeight, + float circleSize, + bool squareSite, + bool drawMeterOverride) const { + RTEAssert(metaPlayer >= Players::PlayerOne && metaPlayer < Players::MaxPlayerCount, "Player out of bounds"); + // No part of the line is visible with these params, so just quit + if ((onlyFirstSegments == 0 || onlyLastSegments == 0) && !drawMeterOverride) + return false; + startMeterAt = MAX(0, startMeterAt); + startMeterAt = MIN(1.0, startMeterAt); + if ((startMeterAt + meterAmount) > 1.0) + meterAmount = 1.0 - startMeterAt; + // Detect disabling of the segment controls + if (onlyFirstSegments < 0) + onlyFirstSegments = 100; + if (onlyLastSegments < 0) + onlyLastSegments = 100; + + int totalSegments = 0; + int drawnFirstSegments = 0; + int lastSegmentsToDraw = 0; + int meterHeight = 5; + int circleRadius = squareSite ? std::floor(6 * circleSize) : std::floor(8 * circleSize); + int chamferSize = CHAMFERSIZE; + Vector chamferPoint1; + Vector chamferPoint2; + int boxMidY = m_apPlayerBox[metaPlayer]->GetYPos() + (m_apPlayerBox[metaPlayer]->GetHeight() / 2); + Vector sitePos = m_PlanetCenter + planetPoint; + bool siteIsAbove = sitePos.m_Y < boxMidY; + float yDirMult = siteIsAbove ? -1.0 : 1.0; + bool twoBends = fabs(sitePos.m_Y - boxMidY) < (channelHeight - circleRadius); + Vector startMeter(m_apPlayerBox[metaPlayer]->GetXPos() + (m_apPlayerBox[metaPlayer]->GetWidth() - 1) * startMeterAt + 1, m_apPlayerBox[metaPlayer]->GetYPos() + (siteIsAbove ? 0 : m_apPlayerBox[metaPlayer]->GetHeight())); + Vector endMeter(startMeter.m_X + MAX(0, (m_apPlayerBox[metaPlayer]->GetWidth() - 1) * meterAmount - 2), startMeter.m_Y); + Vector midMeter(startMeter.m_X + MAX(0, (m_apPlayerBox[metaPlayer]->GetWidth() - 1) * meterAmount * 0.5 - 1), startMeter.m_Y + meterHeight * yDirMult); + bool noBends = (fabs(sitePos.m_X - midMeter.m_X) < circleRadius) && ((m_apPlayerBox[metaPlayer]->GetWidth() * meterAmount * 0.5) >= fabs(sitePos.m_X - midMeter.m_X)); + Vector firstBend(midMeter.m_X, twoBends ? (boxMidY + channelHeight * yDirMult) : sitePos.m_Y); + Vector secondBend(sitePos.m_X, firstBend.m_Y); + bool siteIsLeft = sitePos.m_X < midMeter.m_X; + float xDirMult = siteIsLeft ? -1.0 : 1.0; + + // No bends, meaning the mid of the meter goes straight up/down into the site circle + if (noBends) { + // How many possible segments there are total for this type of line: meter + to site + circle + totalSegments = lastSegmentsToDraw = 1 + 1 + 1; + // Draw the meter + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments) || drawMeterOverride) { + DrawGlowLine(drawBitmap, startMeter, startMeter + Vector(0, meterHeight * yDirMult), color); + DrawGlowLine(drawBitmap, endMeter, endMeter + Vector(0, meterHeight * yDirMult), color); + DrawGlowLine(drawBitmap, startMeter + Vector(0, meterHeight * yDirMult), endMeter + Vector(0, meterHeight * yDirMult), color); + } + // Draw the line to the site + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, midMeter + Vector(sitePos.m_X - midMeter.m_X, 0), sitePos + Vector(0, (circleRadius + 1) * -yDirMult), color); + } + // Extra lines depending on whether there needs to be two bends due to the site being in the 'channel', ie next to teh floating metaPlayer bar + else if (twoBends) { + // Cap the chamfer size on the second bend appropriately + chamferSize = MIN((firstBend - secondBend).GetMagnitude() - meterHeight * 3, chamferSize); + chamferSize = MIN((secondBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); + // Snap the chamfer to not exist below a minimum size + chamferSize = (chamferSize < (meterHeight * 3)) ? 0 : chamferSize; + // No inverted chamfer + chamferSize = MAX(0, chamferSize); + chamferPoint1.SetXY(secondBend.m_X + chamferSize * -xDirMult, secondBend.m_Y); + chamferPoint2.SetXY(secondBend.m_X, secondBend.m_Y + chamferSize * -yDirMult); + // How many of the last segments to draw: meter + to first bend + to second bend chamfer + chamfer + to site + circle + totalSegments = lastSegmentsToDraw = 1 + 1 + 1 + (int)(chamferSize > 0) + 1 + 1; + // Draw the meter + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments) || drawMeterOverride) { + DrawGlowLine(drawBitmap, startMeter, startMeter + Vector(0, meterHeight * yDirMult), color); + DrawGlowLine(drawBitmap, endMeter, endMeter + Vector(0, meterHeight * yDirMult), color); + DrawGlowLine(drawBitmap, startMeter + Vector(0, meterHeight * yDirMult), endMeter + Vector(0, meterHeight * yDirMult), color); + } + // Line to the first bend + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, midMeter, firstBend, color); + // Line to the second bend, incl the chamfer + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, firstBend, chamferPoint1, color); + if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); + // Line to the site + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector(0, (circleRadius + 1) * yDirMult), color); + } + // Just one bend + else { + // Cap the chamfer size on the first bend appropriately + chamferSize = MIN((midMeter - firstBend).GetMagnitude() - meterHeight * 3, chamferSize); + chamferSize = MIN((firstBend - sitePos).GetMagnitude() - circleRadius * 3, chamferSize); + // Snap the chamfer to not exist below a minimum size + chamferSize = (chamferSize < (meterHeight * 3)) ? 0 : chamferSize; + // No inverted chamfer + chamferSize = MAX(0, chamferSize); + chamferPoint1.SetXY(midMeter.m_X, firstBend.m_Y + chamferSize * -yDirMult); + chamferPoint2.SetXY(firstBend.m_X + chamferSize * xDirMult, sitePos.m_Y); + // How many of the last segments to draw: meter + to first bend chamfer + chamfer + to site + circle + totalSegments = lastSegmentsToDraw = 1 + 1 + (int)(chamferSize > 0) + 1 + 1; + // Draw the meter + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments) || drawMeterOverride) { + DrawGlowLine(drawBitmap, startMeter, startMeter + Vector(0, meterHeight * yDirMult), color); + DrawGlowLine(drawBitmap, endMeter, endMeter + Vector(0, meterHeight * yDirMult), color); + DrawGlowLine(drawBitmap, startMeter + Vector(0, meterHeight * yDirMult), endMeter + Vector(0, meterHeight * yDirMult), color); + } + // Draw line to the first bend, incl the chamfer + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, midMeter, chamferPoint1, color); + if (chamferSize > 0 && !(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint1, chamferPoint2, color); + // Draw line to the site + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) + DrawGlowLine(drawBitmap, chamferPoint2, sitePos + Vector((circleRadius + 1) * -xDirMult, 0), color); + } + + // Draw a circle around the site target + if (!(drawnFirstSegments++ >= onlyFirstSegments || lastSegmentsToDraw-- > onlyLastSegments)) { + int blendAmount = 225 + RandomNum(-20, 20); + set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); + + // If specified, draw a squareSite instead (with chamfered corners) + if (squareSite) { + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_X + circleRadius, color); + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1 - 1, sitePos.m_X + circleRadius, color); + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius, sitePos.m_X + circleRadius, color); + hline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y + circleRadius + 1, sitePos.m_X + circleRadius, color); + vline(drawBitmap, sitePos.m_X - circleRadius - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); + vline(drawBitmap, sitePos.m_X - circleRadius - 1 - 1, sitePos.m_Y - circleRadius - 1, sitePos.m_Y + circleRadius, color); + vline(drawBitmap, sitePos.m_X + circleRadius, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); + vline(drawBitmap, sitePos.m_X + circleRadius + 1, sitePos.m_Y + circleRadius, sitePos.m_Y - circleRadius - 1, color); + } else { + circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius, color); + circle(drawBitmap, sitePos.m_X, sitePos.m_Y, circleRadius - 1, color); + } + } + + return totalSegments <= onlyFirstSegments && totalSegments <= onlyLastSegments; } diff --git a/Source/Menus/MetagameGUI.h b/Source/Menus/MetagameGUI.h index 45f0a52dc..a994a39ec 100644 --- a/Source/Menus/MetagameGUI.h +++ b/Source/Menus/MetagameGUI.h @@ -10,7 +10,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -20,1265 +19,1190 @@ struct BITMAP; - -namespace RTE -{ - -class GUIControl; -class GUIScreen; -class GUIInput; -class GUIControlManager; -class GUICollectionBox; -class GUIComboBox; -class GUICheckbox; -class GUITab; -class GUIListBox; -class GUITextBox; -class GUIButton; -class GUILabel; -class GUISlider; -class Entity; -class Scene; -class Activity; -class GAScripted; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: MetagameGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A full menu system that represents the metagame GUI for Cortex Command -// Parent(s): Serializable. -// Class history: 8/22/2008 MetagameGUI Created. - -class MetagameGUI : public Serializable { - - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - - SerializableClassNameGetter - SerializableOverrideMethods - -public: - - enum MenuScreens - { - ROOTBOX = 0, - NEWDIALOG, - LOADDIALOG, - SAVEDIALOG, - MENUDIALOG, - STATSDIALOG, - SCENEINFOBOX, - SCREENCOUNT - }; - - // For storing lines to be drawn upon draw time - struct SiteLine - { - int m_Player; - float m_StartMeterAt; - float m_MeterAmount; - float m_FundsAmount; - float m_FundsTarget; - Vector m_PlanetPoint; - std::string m_SiteName; - // NOT owned here - const Scene *m_pScene; - int m_Color; - int m_OnlyFirstSegments; - int m_OnlyLastSegments; - int m_ChannelHeight; - float m_CircleSize; - bool m_Square; - - SiteLine(int player, - float startMeterAt, - float meterAmount, - const Vector &planetPoint, - std::string siteName, - // Ownership NOT passed in - const Scene *pScene, - int color, - int onlyFirstSegments = -1, - int onlyLastSegments = -1, - int channelHeight = 60, - float circleSize = 1.0f, - bool squareSite = false) - { - m_Player = player; - m_StartMeterAt = startMeterAt; - m_MeterAmount = meterAmount; - m_PlanetPoint = planetPoint; - m_SiteName = siteName; - m_pScene = pScene; - m_Color = color; - m_OnlyFirstSegments = onlyFirstSegments; - m_OnlyLastSegments = onlyLastSegments; - m_ChannelHeight = channelHeight; - m_CircleSize = circleSize; - m_Square = squareSite; - } - }; - - // For storing info about target crosshairs over sites - struct SiteTarget - { - enum SiteTargetStyle - { - CROSSHAIRSSHRINK = 0, - CROSSHAIRSGROW, - CIRCLESHRINK, - CIRCLEGROW, - SQUARESHRINK, - SQUAREGROW, - STYLECOUNT - }; - - Vector m_CenterPos; - float m_AnimProgress; - int m_Style; - int m_Color; - double m_StartTime; - Timer m_AnimTimer; - - SiteTarget() { m_CenterPos.Reset(); m_AnimProgress = 0; m_Style = 0; m_Color = 0; m_StartTime = 0; m_AnimTimer.Reset(); } - - SiteTarget(const Vector ¢erPos, - float animProgress, - int style, - int color, - double startTime = 0) - { - m_CenterPos = centerPos; - m_AnimProgress = animProgress; - m_Style = style; - m_Color = color; - m_StartTime = startTime; - m_AnimTimer.Reset(); - } - - - ////////////////////////////////////////////////////////////////////////////////////////// - // Method: Draw - ////////////////////////////////////////////////////////////////////////////////////////// - // Description: Draws this SiteTarget onto a bitmap of choice. - // Arguments: The bitmap to draw to. - // Return value: None. - - void Draw(BITMAP *drawBitmap) const; - - - }; - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: MetagameGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a MetagameGUI object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - MetagameGUI() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~MetagameGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a MetagameGUI object before deletion -// from system memory. -// Arguments: None. - - ~MetagameGUI() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MetagameGUI object ready for use. -// Arguments: A poitner to a Controller which will control this Menu. Ownership is -// NOT TRANSFERRED! -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(Controller *pController); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire MetagameGUI, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() override { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the MetagameGUI object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetGUIControlManager -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the GUIControlManager owned and used by this. -// Arguments: None. -// Return value: The GUIControlManager. Ownership is not transferred! - - GUIControlManager * GetGUIControlManager(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Enables or disables the menu. This will animate it in and out of view. -// Arguments: Whether to enable or disable the menu. -// Return value: None. - - void SetEnabled(bool enable = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsEnabled -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the menu is enabled or not. -// Arguments: None. -// Return value: None. - - bool IsEnabled() { return m_MenuEnabled == ENABLED || m_MenuEnabled == ENABLING; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SwitchToScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Switches to showing a specific menu screen/mode. -// Arguments: The MenuScreen to switch to. -// Return value: None. - - void SwitchToScreen(int newScreen); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetRoundName -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes a round number into a nice friendly text string. "ONE" for 1 etc -// Arguments: The number of the round to convert to a string. -// Return value: The friendly text string for that round. - - std::string GetRoundName(int roundNumber); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPlanetInfo -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where the planet is on the scren and its other data so the menu -// can overlay properly on it. -// Arguments: The absolute screen coordinates of the planet's center. -// The radius, in screen pixel units, of the planet. -// Return value: None. - - void SetPlanetInfo(const Vector ¢er, float radius) { m_PlanetCenter = center; m_PlanetRadius = radius; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SelectScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets a specific scene as the currently selected one. OWNERSHIP IS NOT TRANSFERRED! -// Arguments: The Scene to set as selected. Ownership is NOT transferred. -// Return value: None. - - void SelectScene(Scene *pScene); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SelectScene -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tries to select a specifically named scene on the metagame field. -// Arguments: The name of the Scene to try to find and select. -// Return value: Whether mission was found and selected. - - bool SelectScene(std::string sceneName); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ContinuePhase -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the player has decided to continue to next phase of the -// round of the current game. -// Arguments: None. -// Return value: Whether the player just decided to continue this frame - - bool ContinuePhase() { return m_ContinuePhase; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ActivityRestarted -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the player has decided to restart an activity this frame. -// All parameters for the new game has been fed into ActivityMan already. -// Arguments: None. -// Return value: Whether the activity should be restarted. - - bool ActivityRestarted() { return m_ActivityRestarted; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ActivityResumed -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the player has decided to resume the current activity. -// Arguments: None. -// Return value: Whether the activity should be resumed. - - bool ActivityResumed() { return m_ActivityResumed; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BackToMain -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the player has decided to go back to the main menu. -// Arguments: None. -// Return value: Whether we should go back to main menu. - - bool BackToMain() { return m_BackToMain; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: QuitProgram -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Reports whether the player has decided to quit the program. -// Arguments: None. -// Return value: Whether the program has been commanded to shit down by the user. - - bool QuitProgram() { return m_Quit; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: StartNewGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Attempts to start a new Metagame using the settings set in the -// New Game dialog box. -// Arguments: None. -// Return value: Whether the game was able to be set up with the current settings. - - bool StartNewGame(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: LoadGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Attempts to load a Metagame from disk using the settings set in the -// Load Game dialog box. -// Arguments: None. -// Return value: Whether the game was able to be loaded with the current settings. - - bool LoadGame(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Just saves out the MetaGame and all its Scene data as-is to a specific -// location. -// Arguments: The name of the save game to create or overwrite here. -// The full path of the ini that we want to save the Metagame state to. -// Whether to load all the scene data that is on disk first so it will -// be re-saved to the new location here. -// Return value: Whether the game was able to be saved there. - - bool SaveGame(std::string saveName, std::string savePath, bool resaveSceneData = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SaveGameFromDialog -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Attempts to save a Metagame to disk using the settings set in the -// Save Game dialog box. -// Arguments: None. -// Return value: Whether the game was able to be saved with the current settings. - - bool SaveGameFromDialog(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Menu each frame -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the menu -// Arguments: The bitmap to draw on. -// Return value: None. - - void Draw(BITMAP *drawBitmap); - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetToStartNewGame -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets internal state of GUI to show 'Start new campaign' screen -// Arguments: None. -// Return value: None. - void SetToStartNewGame(); - - /// - /// Sets where the station is located on the planet orbit. - /// - /// The position of the station on the planet orbit. - void SetStationOrbitPos(const Vector &newStationPos) { m_StationPosOnOrbit = newStationPos; } - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the MetaMan object ready for use -> this is acutally a light -// and not complete version of the one that takes a controller. -// It is only for init after reading stuff from file as a Serializable. -// Arguments: None. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create() override; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateInput -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the user input processing. -// Arguments: None. -// Return value: None. - - void UpdateInput(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: HideAllScreens -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Hides all menu screens, so one can easily be unhidden and shown only. -// Arguments: None. -// Return value: None. - - void HideAllScreens(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: KeepBoxOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes sure a specific box doesn't end up moved completely off-screen. -// Arguments: The GUICollectionBox to adjust, if necessary. -// The amount of margin to allow the box to stay within. If negative, -// the width/height of the box itself are used. -// Return value: None. - - void KeepBoxOnScreen(GUICollectionBox *pBox, int margin = 10); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ChangeAnimMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Changes the animation mode -// Arguments: None. -// Return value: None. - - void ChangeAnimMode(int newMode) { m_AnimMode = newMode; m_AnimModeChange = true; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: NewAnimMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks for and switches off the new animation mode flag -// Arguments: None. -// Return value: None. - - bool NewAnimMode() { bool changed = m_AnimModeChange; m_AnimModeChange = false; return changed; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: CompletedActivity -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Handles what happens after an Activity within the Metagame was -// run and completed fully. -// Arguments: None. -// Return value: None. - - void CompletedActivity(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: AutoResolveOffensive -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Automatically resolves an offensive fight without actually launching -// and going through an Activity. Will randomly determine who won and -// what the consequences are. -// Arguments: The Offsenive Activity to resolve and manipulate accordingly. OWNERSHIP IS NOT TRANSFERRED! -// The Scene this Offensive is supposed to take place on. OWNERSHIP IS NOT TRANSFERRED! -// Whether to check the validity of all players based on whether they -// have brains remaining alive. If false, all active players will be -// instead be flagged as having had brains at some point. -// Return value: Whether the ownership of the relevant Scene changed due to this. - - bool AutoResolveOffensive(GAScripted *pOffensive, Scene *pScene, bool brainCheck = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateSiteRevealing -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the New Site Revealing animation -// Arguments: None. -// Return value: None. - - void UpdateSiteRevealing(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateSiteChangeAnim -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates team ownership change animations, if any. -// Arguments: None. -// Return value: None. - - void UpdateSiteChangeAnim(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateIncomeCounting -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Count Income animation -// Arguments: Whether to just set up the lines and funds as if we had a new round. Also skips changing funds to avoid an income/cost duplication glitch when saving a game at the start of a round. -// Return value: None. - - void UpdateIncomeCounting(bool initOverride = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateHumanPlayerTurn -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates a human player's turn. -// Arguments: Which metaplayer' turn it is -// Return value: None. - - void UpdateHumanPlayerTurn(int metaPlayer); - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateBaseBuilding -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the Base Building animation -// Arguments: None. -// Return value: None. - - void UpdateBaseBuilding(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetupOffensives -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets up the Activities that represent all the offensive actions of -// the teams this round. -// Arguments: None. -// Return value: None. - - void SetupOffensives(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateOffensives -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the offensive actions animation -// Arguments: None. -// Return value: None. - - void UpdateOffensives(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FinalizeOffensive -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Finishes one battle in the UpdateOffensives and moves onto the next. -// Arguments: None. -// Return value: If there are any more battles after the one that was just finalized. - - bool FinalizeOffensive(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: ResetBattleInfo -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Hides and resets all battle info labels and panels -// Arguments: None. -// Return value: None. - - void ResetBattleInfo(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateBattleQuads -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates which player get placed in which quad around a fought-over -// site. -// Arguments: The absolutel screen position of the target site. -// Return value: None. - - void UpdateBattleQuads(Vector targetPos); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePreBattleAttackers -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the animation and display of the info for the current -// offensive battle's attackers being next in line for this round. -// Arguments: The normalized scalar which will set the desired progress of the -// total animation. 0 means nothing is shown, because it is at the start -// of the animation where brain icons start moving around. -// Return value: None. - - void UpdatePreBattleAttackers(float progress); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePreBattleDefenders -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the animation and display of the info for the current -// offensive battle's defenders being next in line for this round. -// Arguments: The normalized scalar which will set the desired progress of the -// total animation. 0 means nothing is shown, because it is at the start -// of the animation where brain icons start moving around. -// Return value: None. - - void UpdatePreBattleDefenders(float progress); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePostBattleRetreaters -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the animation and display of the info for the current -// offensive battle's retreating brains going back to their pools -// Arguments: The normalized scalar which will set the desired progress of the -// total animation. 0 means nothing has happened, because it is at the -// start of the animation where brain icons start moving around. -// Return value: None. - - void UpdatePostBattleRetreaters(float progress); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePostBattleResidents -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the animation and display of the info for the current done -// offensive battle's winning brains going back into the site. -// Arguments: The normalized scalar which will set the desired progress of the -// total animation. 0 means nothing has happened, because it is at the -// start of the animation where brain icons start moving around. -// Return value: None. - - void UpdatePostBattleResidents(float progress); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePlayerActionLines -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the action lines as per what the player has chosen to do -// during the current turn so far. -// Arguments: The metaplayer we want to update the lines for. -// Also add a line for the unallocated funds the player hasn't used for -// anyhting else yet. - NOPE, NOT IMPL YET -// Return value: The meter start that remains after all the lines are added. - - float UpdatePlayerActionLines(int player);//, bool addUnallocated = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateScenesBox -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the contents of the scene selection box. -// Arguments: Whether the selected has changed and should refresh the box completely. -// Return value: None. - - void UpdateScenesBox(bool sceneChanged = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateGameSizeLabels -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the game size labels of the new game dialog -// Arguments: None. -// Return value: None. - - void UpdateGameSizeLabels(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateAISkillSliders -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates AI skill sliders and labels for all players. -// Arguments: Which player's slider was changed. -// Return value: None. - - void UpdateAISkillSliders(int player); - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePlayerSetup -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the player setup controls of the new game dialog -// Arguments: None. -// Return value: None. - - void UpdatePlayerSetup(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePlayerBars -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the floating player bars with current funds, flag, etc. -// Arguments: None. -// Return value: None. - - void UpdatePlayerBars(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdateSiteHoverLabel -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the floating label over a planet site. -// Arguments: Label is visible. -// Text to show above the location. -// The location in planetary coords. -// How high above the location to show the text, adjustment from a good default. -// Return value: None. - - void UpdateSiteNameLabel(bool visible, std::string text = "", const Vector &location = Vector(), float height = 1.0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: PlayerTextIndication -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Starts an animation of a label showing a text string over a player bar -// Arguments: Which player the indication is relevant to -// The string to display. -// Where, in screen coords the change should be indicated. The CENTER of -// the floating label will line up with this pos. -// How long, in MS, that the animation should linger -// Return value: None. - - void PlayerTextIndication(int player, std::string text, const Vector &screenPos, double animLengthMS); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: FundsChangeIndication -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Starts an animation of a label showing funds changing for a player -// Arguments: Which player the change is relevant to -// The change in funds to display. -// Where, in screen coords the change should be indicated. The RIGHTMOST -// UPPER CORNER of the floating label will line up with this pos. -// How long, in MS, that the animation should linger -// Return value: None. - - void FundsChangeIndication(int player, float change, const Vector &screenPos, double animLengthMS); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: BrainsChangeIndication -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Starts an animation of a label showing brains changing for a player -// Arguments: Which player the change is relevant to -// The change in brains to display. -// Where, in screen coords the change should be indicated. The LEFTMOST -// UPPER CORNER of the floating label will line up with this pos. -// How long, in MS, that the animation should linger -// The horizontal font alignment of the change. -// Return value: None. - - void BrainsChangeIndication(int player, int change, const Vector &screenPos, int fontAlignment, double animLengthMS); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: IsSiteLineVisible -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Tells whether a SiteLine can be considered visible. -// Arguments: The SiteLine to check. -// Return value: Whether visible. - - bool IsSiteLineVisible(SiteLine &sl) { return sl.m_OnlyFirstSegments != 0 && sl.m_OnlyLastSegments != 0; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: RemoveSiteLine -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Removes a specific index siteline out of a vector. -// Arguments: The vector of SiteLine:s to remove from. -// The index of the siteline to remove -// Return value: Whether the line was removed or not. - - bool RemoveSiteLine(std::vector &lineList, int removeIndex); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetPlayerLineFunds -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the total funds of all visible lines of a specific player. -// Arguments: A vector with SiteLine:s which may contain other players' lines too. -// Which player's lines to check for. -// Only count the funds of visible lines. -// Return value: The total funds, in oz. - - float GetPlayerLineFunds(std::vector &lineList, int player, bool onlyVisible = true); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: UpdatePlayerLineRatios -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the site line meter ratios of a player based on their fund -// amounts and visibilty. -// Arguments: A vector with SiteLine:s which may contain other players' lines too. -// Which player's lines to update. -// Whetehr to only care about visible lines. -// The total funds to be calculating the ratios against. If negative, -// the total line amounts is what will be used. -// Return value: None. - - void UpdatePlayerLineRatios(std::vector &lineList, int player, bool onlyVisible = true, float total = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawGlowLine -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws a fancy thick flickering line to point out scene points on the -// planet. -// Arguments: The bitmap to draw to. -// The start and end Vector:s for the line, in absolute screen coordinates. -// The color to draw the line in. Use makecol(r, g, b) to create the color -// Return value: None. - - static void DrawGlowLine(BITMAP *drawBitmap, const Vector &start, const Vector &end, int color); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawScreenLineToSitePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws a fancy thick flickering lines to point out scene points on the -// planet, FROM an arbitrary screen point. -// Arguments: The bitmap to draw to. -// The point on the screen to point from, in screen coordinates. -// The point on the planet to point at, in planet coordinates. -// The color of the line. -// How many of the segments from the start (the start of the line) to draw. -// How many of the segments from the end (site circle) to draw. -1 is all. -// The height of the 'channel' above and below that the lines will go around -// the player bar. -// What size factor from 'normal' should the circle's diameter be drawn. -// Return value: Whether all segments of the line were drawn with the segment params. - - bool DrawScreenLineToSitePoint(BITMAP *drawBitmap, - const Vector &screenPoint, - const Vector &planetPoint, - int color, - int onlyFirstSegments = -1, - int onlyLastSegments = -1, - int channelHeight = 80, - float circleSize = 1.0, - bool squareSite = false) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawPlayerLineToSitePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws a fancy thick flickering lines to point out scene points on the -// planet, FROM a floating player bar, showing a certain ratio. -// Arguments: The bitmap to draw to. -// The player whose floating bar we draw from. -// The start percentage of the meter to indicate, from 0 to 1.0 -// The actual percentage of the meter to indicate, from 0 to 1.0 -// The point on the planet to point at, in planet coordinates. -// The color of the line. -// How many of the segments from the start (the player floater) to draw. -// How many of the segments from the end (site circle) to draw. -1 is all. -// The height of the 'channel' above and below that the lines will go around -// the player bar. -// What size factor from 'normal' should the circle's diameter be drawn. -// Whether the circle should instead be a squareSite! -// Whether to draw the meter (FirstSegment == 1) no matter what -// Return value: Whether all segments of the line were drawn with the segment params. - - bool DrawPlayerLineToSitePoint(BITMAP *drawBitmap, - int player, - float startMeterAt, - float meterAmount, - const Vector &planetPoint, - int color, - int onlyFirstSegments = -1, - int onlyLastSegments = -1, - int channelHeight = 60, - float circleSize = 1.0, - bool squareSite = false, - bool drawMeterOverride = false) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: DrawPlayerLineToSitePoint -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws a fancy thick flickering lines to point out scene points on the -// planet, FROM a floating player bar, showing a certain ratio. -// Arguments: The bitmap to draw to. -// The SiteLine struct with all the parameters this needs. -// Whether to draw the meter (FirstSegment == 1) no matter what -// Return value: Whether all segments of the line were drawn with the segment params. - - bool DrawPlayerLineToSitePoint(BITMAP *drawBitmap, const SiteLine &sl, bool drawMeterOverride = false) const { return DrawPlayerLineToSitePoint(drawBitmap, sl.m_Player, sl.m_StartMeterAt, sl.m_MeterAmount, sl.m_PlanetPoint.GetFloored(), sl.m_Color, sl.m_OnlyFirstSegments, sl.m_OnlyLastSegments, sl.m_ChannelHeight, sl.m_CircleSize, sl.m_Square, drawMeterOverride); } - - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: MoveLocationsIntoTheScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Moves any locations closer to the ceonter of the planet if they were left out -// of the screen due to low display resolution. -// Arguments: None. -// Return value: None. - - void MoveLocationsIntoTheScreen(); - - - enum MenuEnabled - { - ENABLING = 0, - ENABLED, - DISABLING, - DISABLED - }; - - enum MetaButtons - { - CONFIRM = 0, - P1CONTROL, - P2CONTROL, - P3CONTROL, - P4CONTROL, - STARTNEW, - LOADNOW, - SAVENOW, - CONTINUE, - SCENEACTION, - DESIGNBASE, - SCANNOW, - SCANLATER, - METABUTTONCOUNT - }; - - enum BlinkMode - { - NOBLINK = 0, - NOFUNDS, - NOCRAFT, - BLINKMODECOUNT - }; - - enum LineAnimMode - { - PAUSEANIM = 0, - TARGETZEROING, - BLINKCIRCLE, - SHRINKCIRCLE, - LINECONNECTFW, - LINECONNECTBW, - LINEDISCONNECTFW, - BLINKMETER, - GROWMETER, - SHRINKMETER, - RETRACTLINES, - SHOWDEFENDERS, - SHOWPOSTBATTLEPAUSE, - SHOWPOSTBATTLEBALANCE, - SHOWPOSTBATTLEBRAINS, - SHOWNEWRESIDENTS, - ANIMMODECOUNT - }; - - int m_RootBoxMaxWidth; //!< The maximum width the root CollectionBox that holds all this menu's GUI elements. This is to constrain this menu to the primary window's display (left-most) while in multi-display fullscreen, otherwise positioning can get stupid. - - // Controller which controls this menu. Not owned - Controller *m_pController; - // GUI Screen for use by the in-game GUI - GUIScreen *m_pGUIScreen; - // Input controller - GUIInput *m_pGUIInput; - // The control manager which holds all the controls - GUIControlManager *m_pGUIController; - // Visibility state of the menu - int m_MenuEnabled; - // Screen selection state - int m_MenuScreen; - // Change in menu screens detected - bool m_ScreenChange; - // Focus state on selecting scenes - int m_SceneFocus; - // Focus change direction - 0 is none, negative is back, positive forward - int m_FocusChange; - // Speed at which the menus appear and disappear - float m_MenuSpeed; - // Notification blink timer - Timer m_BlinkTimer; - // What we're blinking - int m_BlinkMode; - - // GUI Banners - GUIBanner *m_pBannerRedTop; - GUIBanner *m_pBannerRedBottom; - GUIBanner *m_pBannerYellowTop; - GUIBanner *m_pBannerYellowBottom; - - // General-purpose animation timers - Timer m_AnimTimer1; - Timer m_AnimTimer2; - Timer m_AnimTimer3; - - // Currently animated things - int m_AnimMode; - bool m_AnimModeChange; - float m_AnimModeDuration; - int m_AnimMetaPlayer; - int m_AnimDefenseTeam; - bool m_AnimActivityChange; - const Scene *m_pAnimScene; - float m_AnimRatio; - float m_AnimProgress; - float m_AnimTotalFunds; - float m_AnimFundsMax; - float m_AnimFundsMin; - int m_AnimBuildCount; - int m_AnimIncomeLine; - bool m_AnimIncomeLineChange; - int m_AnimActionLine; - bool m_AnimActionLineChange; - int m_AnimSegment; - int m_AnimCountStart; - int m_AnimCountCurrent; - int m_AnimCountEnd; - // Whether the line we're animating managed to connect with the current params - bool m_LineConnected; - // The income-related lines to keep drawing each frame - std::vector m_IncomeSiteLines; - // Indices to the player sitelines that point at the moving station - int m_aStationIncomeLineIndices[Players::MaxPlayerCount]; - // Indices to the player sitelines that point at the their own brain pool counters - int m_aBrainSaleIncomeLineIndices[Players::MaxPlayerCount]; - // Which player are currently showing their player lines. -1 means none - int m_ActivePlayerIncomeLines; - // The action-related lines to keep drawing each frame - std::vector m_ActionSiteLines[Players::MaxPlayerCount]; - // Override to alwasys draw the player action meters, no matter what - bool m_ActionMeterDrawOverride; - // The attack target crosshair info - SiteTarget m_SiteAttackTarget; - // The crosshairs showing new sites - std::vector m_NewSiteIndicators; - // The indicators of sites that just changed ownership - std::vector m_SiteSwitchIndicators; - - // The absolute screen position of the planet center - Vector m_PlanetCenter; - // The screen radius of the planet - float m_PlanetRadius; - - // General game message label - GUILabel *m_pGameMessageLabel; - - // Tooltip box - GUICollectionBox *m_pToolTipBox; - // Label displaying the ToolTip info - GUILabel *m_pToolTipText; - // Timer for detemining when it's time to actually show the tt - Timer m_ToolTipTimer; - // The control that the cursor has hovered over - GUIControl *m_pHoveredControl; - - // Collection boxes of the main screens of the GUI - GUICollectionBox *m_apScreenBox[SCREENCOUNT]; - // The metagame menu buttons - GUIButton *m_apMetaButton[METABUTTONCOUNT]; - - // The confirmation box and its controls - GUICollectionBox *m_pConfirmationBox; - GUILabel *m_pConfirmationLabel; - GUIButton *m_pConfirmationButton; - - // The player floating bars - GUICollectionBox *m_apPlayerBox[Players::MaxPlayerCount]; - // The player flag icon in the floating bars - GUICollectionBox *m_apPlayerTeamBox[Players::MaxPlayerCount]; - // Funds label in the floating bars - GUILabel *m_apPlayerBarLabel[Players::MaxPlayerCount]; - // Brain Pool label next to the floating bars - GUILabel *m_apBrainPoolLabel[Players::MaxPlayerCount]; - // The animated label that shows a message to the player over his bar -// GUILabel *m_apPlayerMessageLabel[Players::MaxPlayerCount]; - // The animated label that shows a change in the funds of a player, animating up or downward - GUILabel *m_apFundsChangeLabel[Players::MaxPlayerCount]; - // The animated label that shows a change in the brain pool of a player, animating up or downward - GUILabel *m_apBrainChangeLabel[Players::MaxPlayerCount]; - - // Timer for animating the message labels going northward -// Timer m_apPlayerMessageTimer[Players::MaxPlayerCount]; - // Timer for animating the change labels going northward - Timer m_apFundsChangeTimer[Players::MaxPlayerCount]; - // Timer for animating the change labels going northward - Timer m_apBrainsChangeTimer[Players::MaxPlayerCount]; - // Previous pos of mouse to calculate dragging - Vector m_PrevMousePos; - - // Battle site display - // The player flag icon that surrrounds the battle sites - GUICollectionBox *m_apPlayerTeamActionBox[Players::MaxPlayerCount]; - // Traveling brain label that ends up around battle sites, showing info - GUILabel *m_apPlayerBrainTravelLabel[Players::MaxPlayerCount]; - // How much funds have been allocated to each player's battle chest for the next battle - float m_aBattleFunds[Players::MaxPlayerCount]; - // Which of the players are currently attacking a place - just used for icons - bool m_aBattleAttacker[Players::MaxPlayerCount]; - // Which of the battling brains are yet graphically destroyed - bool m_aAnimDestroyed[Players::MaxPlayerCount]; - // Where the center of the brain icon is on the traveling brain label - Vector m_aBrainIconPos[Players::MaxPlayerCount]; - // Which quadrant positions of the battle matrix that have been taken by which metaplayer. NOPLAYER means no player (duh) - int m_aQuadTakenBy[4]; - - // Game Phase Box and info - GUICollectionBox *m_pPhaseBox; - GUILabel *m_pPhaseLabel; - // Pre-player-turn hold so player's privacy is protected - bool m_PreTurn; - // Have an incompleted offensive battle to resume - bool m_BattleToResume; - // Still showing the aftermath of a battle before moving onto the next - bool m_PostBattleReview; - // Whether the last battle caused a change in team - bool m_BattleCausedOwnershipChange; - // The previous ownership status of a battled scene. - // It's used to for a period during battle review still show the old ownership until the new one is dramaticlaly revealed - int m_PreBattleTeamOwnership; - - // Hover name label over Scene:s - GUILabel *m_pScenePlanetLabel; - - // Scene info popup mouseover box and controls - GUICollectionBox *m_pSceneInfoPopup; - GUIButton *m_pSceneCloseButton; - GUILabel *m_pSceneNameLabel; - GUICollectionBox *m_pSceneOwnerTeam; - GUILabel *m_pSceneResidentsLabel; - GUILabel *m_pSceneInfoLabel; - GUILabel *m_pSceneBudgetLabel; - GUISlider *m_pSceneBudgetSlider; - GUICollectionBox *m_pSceneBudgetBar; - GUICheckbox *m_pAutoDesignCheckbox; - GUILabel *m_pScanInfoLabel; - - // Currently dragged GUI box - GUICollectionBox *m_pDraggedBox; - // New potential drag is starting - bool m_EngageDrag; - // The scene currently hovered, NOT OWNED - Scene *m_pHoveredScene; - // The scene currently selected, NOT OWNED - Scene *m_pSelectedScene; - // The scene currently being played, NOT OWNED - Scene *m_pPlayingScene; - - // NEW GAME DIALOG - // Game size label and slider - GUILabel *m_pSizeLabel; - GUISlider *m_pSizeSlider; - GUILabel *m_pDifficultyLabel; - GUISlider *m_pDifficultySlider; - GUILabel *m_pGoldLabel; - GUISlider *m_pGoldSlider; - GUILabel *m_pLengthLabel; - GUISlider *m_pLengthSlider; - GUILabel *m_pErrorLabel; - GUIButton *m_apPlayerControlButton[Players::MaxPlayerCount]; - GUIComboBox *m_apPlayerTeamSelect[Players::MaxPlayerCount]; - GUIComboBox *m_apPlayerTechSelect[Players::MaxPlayerCount]; - GUIComboBox *m_apPlayerHandicap[Players::MaxPlayerCount]; - GUITextBox *m_apPlayerNameBox[Players::MaxPlayerCount]; - GUISlider *m_apPlayerAISkillSlider[Players::MaxPlayerCount]; - GUILabel *m_apPlayerAISkillLabel[Players::MaxPlayerCount]; - - // SAVING/LOADING GAME DIALOGS - GUITextBox *m_NewSaveBox; - // The combobox which lists all the games that can be saved over - GUIComboBox *m_pSavesToOverwriteCombo; - GUIComboBox *m_pSavesToLoadCombo; - // Info boxes showing some basic data on a save game - GUILabel *m_pSaveInfoLabel; - GUILabel *m_pLoadInfoLabel; - // Hack to keep the MetaSave Entity that has been selected for load even though confirmation dlg pups up and clears the selection combo - const Entity *m_pSelectedGameToLoad; - - // Whether player decided to continue to the next phase of the game - bool m_ContinuePhase; - // Whether the game was restarted this frame or not - bool m_ActivityRestarted; - // Whether the game was resumed this frame or not - bool m_ActivityResumed; - // How much money both players start with in the new game - int m_StartFunds; - // Which player is CPU managed, if any (-1) - int m_CPUPlayer; - // Difficulty setting - int m_StartDifficulty; - // Whether user has chosen to go back to the main menu - bool m_BackToMain; - // Player selected to quit the program - bool m_Quit; - - Vector m_StationPosOnOrbit; //!< The position of the station on the planet orbit. - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this MetagameGUI, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - MetagameGUI(const MetagameGUI &reference) = delete; - MetagameGUI & operator=(const MetagameGUI &rhs) = delete; - -}; +namespace RTE { + + class GUIControl; + class GUIScreen; + class GUIInput; + class GUIControlManager; + class GUICollectionBox; + class GUIComboBox; + class GUICheckbox; + class GUITab; + class GUIListBox; + class GUITextBox; + class GUIButton; + class GUILabel; + class GUISlider; + class Entity; + class Scene; + class Activity; + class GAScripted; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: MetagameGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A full menu system that represents the metagame GUI for Cortex Command + // Parent(s): Serializable. + // Class history: 8/22/2008 MetagameGUI Created. + + class MetagameGUI : public Serializable { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + SerializableClassNameGetter + SerializableOverrideMethods + + public : + + enum MenuScreens { + ROOTBOX = 0, + NEWDIALOG, + LOADDIALOG, + SAVEDIALOG, + MENUDIALOG, + STATSDIALOG, + SCENEINFOBOX, + SCREENCOUNT + }; + + // For storing lines to be drawn upon draw time + struct SiteLine { + int m_Player; + float m_StartMeterAt; + float m_MeterAmount; + float m_FundsAmount; + float m_FundsTarget; + Vector m_PlanetPoint; + std::string m_SiteName; + // NOT owned here + const Scene* m_pScene; + int m_Color; + int m_OnlyFirstSegments; + int m_OnlyLastSegments; + int m_ChannelHeight; + float m_CircleSize; + bool m_Square; + + SiteLine(int player, + float startMeterAt, + float meterAmount, + const Vector& planetPoint, + std::string siteName, + // Ownership NOT passed in + const Scene* pScene, + int color, + int onlyFirstSegments = -1, + int onlyLastSegments = -1, + int channelHeight = 60, + float circleSize = 1.0f, + bool squareSite = false) { + m_Player = player; + m_StartMeterAt = startMeterAt; + m_MeterAmount = meterAmount; + m_PlanetPoint = planetPoint; + m_SiteName = siteName; + m_pScene = pScene; + m_Color = color; + m_OnlyFirstSegments = onlyFirstSegments; + m_OnlyLastSegments = onlyLastSegments; + m_ChannelHeight = channelHeight; + m_CircleSize = circleSize; + m_Square = squareSite; + } + }; + + // For storing info about target crosshairs over sites + struct SiteTarget { + enum SiteTargetStyle { + CROSSHAIRSSHRINK = 0, + CROSSHAIRSGROW, + CIRCLESHRINK, + CIRCLEGROW, + SQUARESHRINK, + SQUAREGROW, + STYLECOUNT + }; + + Vector m_CenterPos; + float m_AnimProgress; + int m_Style; + int m_Color; + double m_StartTime; + Timer m_AnimTimer; + + SiteTarget() { + m_CenterPos.Reset(); + m_AnimProgress = 0; + m_Style = 0; + m_Color = 0; + m_StartTime = 0; + m_AnimTimer.Reset(); + } + + SiteTarget(const Vector& centerPos, + float animProgress, + int style, + int color, + double startTime = 0) { + m_CenterPos = centerPos; + m_AnimProgress = animProgress; + m_Style = style; + m_Color = color; + m_StartTime = startTime; + m_AnimTimer.Reset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws this SiteTarget onto a bitmap of choice. + // Arguments: The bitmap to draw to. + // Return value: None. + + void Draw(BITMAP* drawBitmap) const; + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: MetagameGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a MetagameGUI object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + MetagameGUI() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~MetagameGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a MetagameGUI object before deletion + // from system memory. + // Arguments: None. + + ~MetagameGUI() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MetagameGUI object ready for use. + // Arguments: A poitner to a Controller which will control this Menu. Ownership is + // NOT TRANSFERRED! + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(Controller* pController); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire MetagameGUI, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() override { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the MetagameGUI object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetGUIControlManager + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the GUIControlManager owned and used by this. + // Arguments: None. + // Return value: The GUIControlManager. Ownership is not transferred! + + GUIControlManager* GetGUIControlManager(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Enables or disables the menu. This will animate it in and out of view. + // Arguments: Whether to enable or disable the menu. + // Return value: None. + + void SetEnabled(bool enable = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsEnabled + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the menu is enabled or not. + // Arguments: None. + // Return value: None. + + bool IsEnabled() { return m_MenuEnabled == ENABLED || m_MenuEnabled == ENABLING; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SwitchToScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Switches to showing a specific menu screen/mode. + // Arguments: The MenuScreen to switch to. + // Return value: None. + + void SwitchToScreen(int newScreen); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetRoundName + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes a round number into a nice friendly text string. "ONE" for 1 etc + // Arguments: The number of the round to convert to a string. + // Return value: The friendly text string for that round. + + std::string GetRoundName(int roundNumber); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPlanetInfo + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where the planet is on the scren and its other data so the menu + // can overlay properly on it. + // Arguments: The absolute screen coordinates of the planet's center. + // The radius, in screen pixel units, of the planet. + // Return value: None. + + void SetPlanetInfo(const Vector& center, float radius) { + m_PlanetCenter = center; + m_PlanetRadius = radius; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SelectScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets a specific scene as the currently selected one. OWNERSHIP IS NOT TRANSFERRED! + // Arguments: The Scene to set as selected. Ownership is NOT transferred. + // Return value: None. + + void SelectScene(Scene* pScene); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SelectScene + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tries to select a specifically named scene on the metagame field. + // Arguments: The name of the Scene to try to find and select. + // Return value: Whether mission was found and selected. + + bool SelectScene(std::string sceneName); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ContinuePhase + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the player has decided to continue to next phase of the + // round of the current game. + // Arguments: None. + // Return value: Whether the player just decided to continue this frame + + bool ContinuePhase() { return m_ContinuePhase; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ActivityRestarted + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the player has decided to restart an activity this frame. + // All parameters for the new game has been fed into ActivityMan already. + // Arguments: None. + // Return value: Whether the activity should be restarted. + + bool ActivityRestarted() { return m_ActivityRestarted; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ActivityResumed + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the player has decided to resume the current activity. + // Arguments: None. + // Return value: Whether the activity should be resumed. + + bool ActivityResumed() { return m_ActivityResumed; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BackToMain + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the player has decided to go back to the main menu. + // Arguments: None. + // Return value: Whether we should go back to main menu. + + bool BackToMain() { return m_BackToMain; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: QuitProgram + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Reports whether the player has decided to quit the program. + // Arguments: None. + // Return value: Whether the program has been commanded to shit down by the user. + + bool QuitProgram() { return m_Quit; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: StartNewGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Attempts to start a new Metagame using the settings set in the + // New Game dialog box. + // Arguments: None. + // Return value: Whether the game was able to be set up with the current settings. + + bool StartNewGame(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: LoadGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Attempts to load a Metagame from disk using the settings set in the + // Load Game dialog box. + // Arguments: None. + // Return value: Whether the game was able to be loaded with the current settings. + + bool LoadGame(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Just saves out the MetaGame and all its Scene data as-is to a specific + // location. + // Arguments: The name of the save game to create or overwrite here. + // The full path of the ini that we want to save the Metagame state to. + // Whether to load all the scene data that is on disk first so it will + // be re-saved to the new location here. + // Return value: Whether the game was able to be saved there. + + bool SaveGame(std::string saveName, std::string savePath, bool resaveSceneData = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SaveGameFromDialog + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Attempts to save a Metagame to disk using the settings set in the + // Save Game dialog box. + // Arguments: None. + // Return value: Whether the game was able to be saved with the current settings. + + bool SaveGameFromDialog(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Menu each frame + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the menu + // Arguments: The bitmap to draw on. + // Return value: None. + + void Draw(BITMAP* drawBitmap); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetToStartNewGame + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets internal state of GUI to show 'Start new campaign' screen + // Arguments: None. + // Return value: None. + void SetToStartNewGame(); + + /// + /// Sets where the station is located on the planet orbit. + /// + /// The position of the station on the planet orbit. + void SetStationOrbitPos(const Vector& newStationPos) { m_StationPosOnOrbit = newStationPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the MetaMan object ready for use -> this is acutally a light + // and not complete version of the one that takes a controller. + // It is only for init after reading stuff from file as a Serializable. + // Arguments: None. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create() override; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateInput + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the user input processing. + // Arguments: None. + // Return value: None. + + void UpdateInput(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: HideAllScreens + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Hides all menu screens, so one can easily be unhidden and shown only. + // Arguments: None. + // Return value: None. + + void HideAllScreens(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: KeepBoxOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes sure a specific box doesn't end up moved completely off-screen. + // Arguments: The GUICollectionBox to adjust, if necessary. + // The amount of margin to allow the box to stay within. If negative, + // the width/height of the box itself are used. + // Return value: None. + + void KeepBoxOnScreen(GUICollectionBox* pBox, int margin = 10); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ChangeAnimMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Changes the animation mode + // Arguments: None. + // Return value: None. + + void ChangeAnimMode(int newMode) { + m_AnimMode = newMode; + m_AnimModeChange = true; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: NewAnimMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks for and switches off the new animation mode flag + // Arguments: None. + // Return value: None. + + bool NewAnimMode() { + bool changed = m_AnimModeChange; + m_AnimModeChange = false; + return changed; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: CompletedActivity + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Handles what happens after an Activity within the Metagame was + // run and completed fully. + // Arguments: None. + // Return value: None. + + void CompletedActivity(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: AutoResolveOffensive + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Automatically resolves an offensive fight without actually launching + // and going through an Activity. Will randomly determine who won and + // what the consequences are. + // Arguments: The Offsenive Activity to resolve and manipulate accordingly. OWNERSHIP IS NOT TRANSFERRED! + // The Scene this Offensive is supposed to take place on. OWNERSHIP IS NOT TRANSFERRED! + // Whether to check the validity of all players based on whether they + // have brains remaining alive. If false, all active players will be + // instead be flagged as having had brains at some point. + // Return value: Whether the ownership of the relevant Scene changed due to this. + + bool AutoResolveOffensive(GAScripted* pOffensive, Scene* pScene, bool brainCheck = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateSiteRevealing + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the New Site Revealing animation + // Arguments: None. + // Return value: None. + + void UpdateSiteRevealing(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateSiteChangeAnim + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates team ownership change animations, if any. + // Arguments: None. + // Return value: None. + + void UpdateSiteChangeAnim(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateIncomeCounting + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Count Income animation + // Arguments: Whether to just set up the lines and funds as if we had a new round. Also skips changing funds to avoid an income/cost duplication glitch when saving a game at the start of a round. + // Return value: None. + + void UpdateIncomeCounting(bool initOverride = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateHumanPlayerTurn + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates a human player's turn. + // Arguments: Which metaplayer' turn it is + // Return value: None. + + void UpdateHumanPlayerTurn(int metaPlayer); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateBaseBuilding + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the Base Building animation + // Arguments: None. + // Return value: None. + + void UpdateBaseBuilding(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetupOffensives + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets up the Activities that represent all the offensive actions of + // the teams this round. + // Arguments: None. + // Return value: None. + + void SetupOffensives(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateOffensives + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the offensive actions animation + // Arguments: None. + // Return value: None. + + void UpdateOffensives(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FinalizeOffensive + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Finishes one battle in the UpdateOffensives and moves onto the next. + // Arguments: None. + // Return value: If there are any more battles after the one that was just finalized. + + bool FinalizeOffensive(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: ResetBattleInfo + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Hides and resets all battle info labels and panels + // Arguments: None. + // Return value: None. + + void ResetBattleInfo(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateBattleQuads + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates which player get placed in which quad around a fought-over + // site. + // Arguments: The absolutel screen position of the target site. + // Return value: None. + + void UpdateBattleQuads(Vector targetPos); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePreBattleAttackers + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the animation and display of the info for the current + // offensive battle's attackers being next in line for this round. + // Arguments: The normalized scalar which will set the desired progress of the + // total animation. 0 means nothing is shown, because it is at the start + // of the animation where brain icons start moving around. + // Return value: None. + + void UpdatePreBattleAttackers(float progress); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePreBattleDefenders + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the animation and display of the info for the current + // offensive battle's defenders being next in line for this round. + // Arguments: The normalized scalar which will set the desired progress of the + // total animation. 0 means nothing is shown, because it is at the start + // of the animation where brain icons start moving around. + // Return value: None. + + void UpdatePreBattleDefenders(float progress); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePostBattleRetreaters + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the animation and display of the info for the current + // offensive battle's retreating brains going back to their pools + // Arguments: The normalized scalar which will set the desired progress of the + // total animation. 0 means nothing has happened, because it is at the + // start of the animation where brain icons start moving around. + // Return value: None. + + void UpdatePostBattleRetreaters(float progress); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePostBattleResidents + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the animation and display of the info for the current done + // offensive battle's winning brains going back into the site. + // Arguments: The normalized scalar which will set the desired progress of the + // total animation. 0 means nothing has happened, because it is at the + // start of the animation where brain icons start moving around. + // Return value: None. + + void UpdatePostBattleResidents(float progress); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePlayerActionLines + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the action lines as per what the player has chosen to do + // during the current turn so far. + // Arguments: The metaplayer we want to update the lines for. + // Also add a line for the unallocated funds the player hasn't used for + // anyhting else yet. - NOPE, NOT IMPL YET + // Return value: The meter start that remains after all the lines are added. + + float UpdatePlayerActionLines(int player); //, bool addUnallocated = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateScenesBox + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the contents of the scene selection box. + // Arguments: Whether the selected has changed and should refresh the box completely. + // Return value: None. + + void UpdateScenesBox(bool sceneChanged = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateGameSizeLabels + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the game size labels of the new game dialog + // Arguments: None. + // Return value: None. + + void UpdateGameSizeLabels(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateAISkillSliders + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates AI skill sliders and labels for all players. + // Arguments: Which player's slider was changed. + // Return value: None. + + void UpdateAISkillSliders(int player); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePlayerSetup + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the player setup controls of the new game dialog + // Arguments: None. + // Return value: None. + + void UpdatePlayerSetup(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePlayerBars + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the floating player bars with current funds, flag, etc. + // Arguments: None. + // Return value: None. + + void UpdatePlayerBars(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdateSiteHoverLabel + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the floating label over a planet site. + // Arguments: Label is visible. + // Text to show above the location. + // The location in planetary coords. + // How high above the location to show the text, adjustment from a good default. + // Return value: None. + + void UpdateSiteNameLabel(bool visible, std::string text = "", const Vector& location = Vector(), float height = 1.0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: PlayerTextIndication + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Starts an animation of a label showing a text string over a player bar + // Arguments: Which player the indication is relevant to + // The string to display. + // Where, in screen coords the change should be indicated. The CENTER of + // the floating label will line up with this pos. + // How long, in MS, that the animation should linger + // Return value: None. + + void PlayerTextIndication(int player, std::string text, const Vector& screenPos, double animLengthMS); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: FundsChangeIndication + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Starts an animation of a label showing funds changing for a player + // Arguments: Which player the change is relevant to + // The change in funds to display. + // Where, in screen coords the change should be indicated. The RIGHTMOST + // UPPER CORNER of the floating label will line up with this pos. + // How long, in MS, that the animation should linger + // Return value: None. + + void FundsChangeIndication(int player, float change, const Vector& screenPos, double animLengthMS); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: BrainsChangeIndication + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Starts an animation of a label showing brains changing for a player + // Arguments: Which player the change is relevant to + // The change in brains to display. + // Where, in screen coords the change should be indicated. The LEFTMOST + // UPPER CORNER of the floating label will line up with this pos. + // How long, in MS, that the animation should linger + // The horizontal font alignment of the change. + // Return value: None. + + void BrainsChangeIndication(int player, int change, const Vector& screenPos, int fontAlignment, double animLengthMS); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: IsSiteLineVisible + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Tells whether a SiteLine can be considered visible. + // Arguments: The SiteLine to check. + // Return value: Whether visible. + + bool IsSiteLineVisible(SiteLine& sl) { return sl.m_OnlyFirstSegments != 0 && sl.m_OnlyLastSegments != 0; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: RemoveSiteLine + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Removes a specific index siteline out of a vector. + // Arguments: The vector of SiteLine:s to remove from. + // The index of the siteline to remove + // Return value: Whether the line was removed or not. + + bool RemoveSiteLine(std::vector& lineList, int removeIndex); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetPlayerLineFunds + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the total funds of all visible lines of a specific player. + // Arguments: A vector with SiteLine:s which may contain other players' lines too. + // Which player's lines to check for. + // Only count the funds of visible lines. + // Return value: The total funds, in oz. + + float GetPlayerLineFunds(std::vector& lineList, int player, bool onlyVisible = true); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: UpdatePlayerLineRatios + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the site line meter ratios of a player based on their fund + // amounts and visibilty. + // Arguments: A vector with SiteLine:s which may contain other players' lines too. + // Which player's lines to update. + // Whetehr to only care about visible lines. + // The total funds to be calculating the ratios against. If negative, + // the total line amounts is what will be used. + // Return value: None. + + void UpdatePlayerLineRatios(std::vector& lineList, int player, bool onlyVisible = true, float total = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawGlowLine + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws a fancy thick flickering line to point out scene points on the + // planet. + // Arguments: The bitmap to draw to. + // The start and end Vector:s for the line, in absolute screen coordinates. + // The color to draw the line in. Use makecol(r, g, b) to create the color + // Return value: None. + + static void DrawGlowLine(BITMAP* drawBitmap, const Vector& start, const Vector& end, int color); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawScreenLineToSitePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws a fancy thick flickering lines to point out scene points on the + // planet, FROM an arbitrary screen point. + // Arguments: The bitmap to draw to. + // The point on the screen to point from, in screen coordinates. + // The point on the planet to point at, in planet coordinates. + // The color of the line. + // How many of the segments from the start (the start of the line) to draw. + // How many of the segments from the end (site circle) to draw. -1 is all. + // The height of the 'channel' above and below that the lines will go around + // the player bar. + // What size factor from 'normal' should the circle's diameter be drawn. + // Return value: Whether all segments of the line were drawn with the segment params. + + bool DrawScreenLineToSitePoint(BITMAP* drawBitmap, + const Vector& screenPoint, + const Vector& planetPoint, + int color, + int onlyFirstSegments = -1, + int onlyLastSegments = -1, + int channelHeight = 80, + float circleSize = 1.0, + bool squareSite = false) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawPlayerLineToSitePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws a fancy thick flickering lines to point out scene points on the + // planet, FROM a floating player bar, showing a certain ratio. + // Arguments: The bitmap to draw to. + // The player whose floating bar we draw from. + // The start percentage of the meter to indicate, from 0 to 1.0 + // The actual percentage of the meter to indicate, from 0 to 1.0 + // The point on the planet to point at, in planet coordinates. + // The color of the line. + // How many of the segments from the start (the player floater) to draw. + // How many of the segments from the end (site circle) to draw. -1 is all. + // The height of the 'channel' above and below that the lines will go around + // the player bar. + // What size factor from 'normal' should the circle's diameter be drawn. + // Whether the circle should instead be a squareSite! + // Whether to draw the meter (FirstSegment == 1) no matter what + // Return value: Whether all segments of the line were drawn with the segment params. + + bool DrawPlayerLineToSitePoint(BITMAP* drawBitmap, + int player, + float startMeterAt, + float meterAmount, + const Vector& planetPoint, + int color, + int onlyFirstSegments = -1, + int onlyLastSegments = -1, + int channelHeight = 60, + float circleSize = 1.0, + bool squareSite = false, + bool drawMeterOverride = false) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: DrawPlayerLineToSitePoint + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws a fancy thick flickering lines to point out scene points on the + // planet, FROM a floating player bar, showing a certain ratio. + // Arguments: The bitmap to draw to. + // The SiteLine struct with all the parameters this needs. + // Whether to draw the meter (FirstSegment == 1) no matter what + // Return value: Whether all segments of the line were drawn with the segment params. + + bool DrawPlayerLineToSitePoint(BITMAP* drawBitmap, const SiteLine& sl, bool drawMeterOverride = false) const { return DrawPlayerLineToSitePoint(drawBitmap, sl.m_Player, sl.m_StartMeterAt, sl.m_MeterAmount, sl.m_PlanetPoint.GetFloored(), sl.m_Color, sl.m_OnlyFirstSegments, sl.m_OnlyLastSegments, sl.m_ChannelHeight, sl.m_CircleSize, sl.m_Square, drawMeterOverride); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: MoveLocationsIntoTheScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Moves any locations closer to the ceonter of the planet if they were left out + // of the screen due to low display resolution. + // Arguments: None. + // Return value: None. + + void MoveLocationsIntoTheScreen(); + + enum MenuEnabled { + ENABLING = 0, + ENABLED, + DISABLING, + DISABLED + }; + + enum MetaButtons { + CONFIRM = 0, + P1CONTROL, + P2CONTROL, + P3CONTROL, + P4CONTROL, + STARTNEW, + LOADNOW, + SAVENOW, + CONTINUE, + SCENEACTION, + DESIGNBASE, + SCANNOW, + SCANLATER, + METABUTTONCOUNT + }; + + enum BlinkMode { + NOBLINK = 0, + NOFUNDS, + NOCRAFT, + BLINKMODECOUNT + }; + + enum LineAnimMode { + PAUSEANIM = 0, + TARGETZEROING, + BLINKCIRCLE, + SHRINKCIRCLE, + LINECONNECTFW, + LINECONNECTBW, + LINEDISCONNECTFW, + BLINKMETER, + GROWMETER, + SHRINKMETER, + RETRACTLINES, + SHOWDEFENDERS, + SHOWPOSTBATTLEPAUSE, + SHOWPOSTBATTLEBALANCE, + SHOWPOSTBATTLEBRAINS, + SHOWNEWRESIDENTS, + ANIMMODECOUNT + }; + + int m_RootBoxMaxWidth; //!< The maximum width the root CollectionBox that holds all this menu's GUI elements. This is to constrain this menu to the primary window's display (left-most) while in multi-display fullscreen, otherwise positioning can get stupid. + + // Controller which controls this menu. Not owned + Controller* m_pController; + // GUI Screen for use by the in-game GUI + GUIScreen* m_pGUIScreen; + // Input controller + GUIInput* m_pGUIInput; + // The control manager which holds all the controls + GUIControlManager* m_pGUIController; + // Visibility state of the menu + int m_MenuEnabled; + // Screen selection state + int m_MenuScreen; + // Change in menu screens detected + bool m_ScreenChange; + // Focus state on selecting scenes + int m_SceneFocus; + // Focus change direction - 0 is none, negative is back, positive forward + int m_FocusChange; + // Speed at which the menus appear and disappear + float m_MenuSpeed; + // Notification blink timer + Timer m_BlinkTimer; + // What we're blinking + int m_BlinkMode; + + // GUI Banners + GUIBanner* m_pBannerRedTop; + GUIBanner* m_pBannerRedBottom; + GUIBanner* m_pBannerYellowTop; + GUIBanner* m_pBannerYellowBottom; + + // General-purpose animation timers + Timer m_AnimTimer1; + Timer m_AnimTimer2; + Timer m_AnimTimer3; + + // Currently animated things + int m_AnimMode; + bool m_AnimModeChange; + float m_AnimModeDuration; + int m_AnimMetaPlayer; + int m_AnimDefenseTeam; + bool m_AnimActivityChange; + const Scene* m_pAnimScene; + float m_AnimRatio; + float m_AnimProgress; + float m_AnimTotalFunds; + float m_AnimFundsMax; + float m_AnimFundsMin; + int m_AnimBuildCount; + int m_AnimIncomeLine; + bool m_AnimIncomeLineChange; + int m_AnimActionLine; + bool m_AnimActionLineChange; + int m_AnimSegment; + int m_AnimCountStart; + int m_AnimCountCurrent; + int m_AnimCountEnd; + // Whether the line we're animating managed to connect with the current params + bool m_LineConnected; + // The income-related lines to keep drawing each frame + std::vector m_IncomeSiteLines; + // Indices to the player sitelines that point at the moving station + int m_aStationIncomeLineIndices[Players::MaxPlayerCount]; + // Indices to the player sitelines that point at the their own brain pool counters + int m_aBrainSaleIncomeLineIndices[Players::MaxPlayerCount]; + // Which player are currently showing their player lines. -1 means none + int m_ActivePlayerIncomeLines; + // The action-related lines to keep drawing each frame + std::vector m_ActionSiteLines[Players::MaxPlayerCount]; + // Override to alwasys draw the player action meters, no matter what + bool m_ActionMeterDrawOverride; + // The attack target crosshair info + SiteTarget m_SiteAttackTarget; + // The crosshairs showing new sites + std::vector m_NewSiteIndicators; + // The indicators of sites that just changed ownership + std::vector m_SiteSwitchIndicators; + + // The absolute screen position of the planet center + Vector m_PlanetCenter; + // The screen radius of the planet + float m_PlanetRadius; + + // General game message label + GUILabel* m_pGameMessageLabel; + + // Tooltip box + GUICollectionBox* m_pToolTipBox; + // Label displaying the ToolTip info + GUILabel* m_pToolTipText; + // Timer for detemining when it's time to actually show the tt + Timer m_ToolTipTimer; + // The control that the cursor has hovered over + GUIControl* m_pHoveredControl; + + // Collection boxes of the main screens of the GUI + GUICollectionBox* m_apScreenBox[SCREENCOUNT]; + // The metagame menu buttons + GUIButton* m_apMetaButton[METABUTTONCOUNT]; + + // The confirmation box and its controls + GUICollectionBox* m_pConfirmationBox; + GUILabel* m_pConfirmationLabel; + GUIButton* m_pConfirmationButton; + + // The player floating bars + GUICollectionBox* m_apPlayerBox[Players::MaxPlayerCount]; + // The player flag icon in the floating bars + GUICollectionBox* m_apPlayerTeamBox[Players::MaxPlayerCount]; + // Funds label in the floating bars + GUILabel* m_apPlayerBarLabel[Players::MaxPlayerCount]; + // Brain Pool label next to the floating bars + GUILabel* m_apBrainPoolLabel[Players::MaxPlayerCount]; + // The animated label that shows a message to the player over his bar + // GUILabel *m_apPlayerMessageLabel[Players::MaxPlayerCount]; + // The animated label that shows a change in the funds of a player, animating up or downward + GUILabel* m_apFundsChangeLabel[Players::MaxPlayerCount]; + // The animated label that shows a change in the brain pool of a player, animating up or downward + GUILabel* m_apBrainChangeLabel[Players::MaxPlayerCount]; + + // Timer for animating the message labels going northward + // Timer m_apPlayerMessageTimer[Players::MaxPlayerCount]; + // Timer for animating the change labels going northward + Timer m_apFundsChangeTimer[Players::MaxPlayerCount]; + // Timer for animating the change labels going northward + Timer m_apBrainsChangeTimer[Players::MaxPlayerCount]; + // Previous pos of mouse to calculate dragging + Vector m_PrevMousePos; + + // Battle site display + // The player flag icon that surrrounds the battle sites + GUICollectionBox* m_apPlayerTeamActionBox[Players::MaxPlayerCount]; + // Traveling brain label that ends up around battle sites, showing info + GUILabel* m_apPlayerBrainTravelLabel[Players::MaxPlayerCount]; + // How much funds have been allocated to each player's battle chest for the next battle + float m_aBattleFunds[Players::MaxPlayerCount]; + // Which of the players are currently attacking a place - just used for icons + bool m_aBattleAttacker[Players::MaxPlayerCount]; + // Which of the battling brains are yet graphically destroyed + bool m_aAnimDestroyed[Players::MaxPlayerCount]; + // Where the center of the brain icon is on the traveling brain label + Vector m_aBrainIconPos[Players::MaxPlayerCount]; + // Which quadrant positions of the battle matrix that have been taken by which metaplayer. NOPLAYER means no player (duh) + int m_aQuadTakenBy[4]; + + // Game Phase Box and info + GUICollectionBox* m_pPhaseBox; + GUILabel* m_pPhaseLabel; + // Pre-player-turn hold so player's privacy is protected + bool m_PreTurn; + // Have an incompleted offensive battle to resume + bool m_BattleToResume; + // Still showing the aftermath of a battle before moving onto the next + bool m_PostBattleReview; + // Whether the last battle caused a change in team + bool m_BattleCausedOwnershipChange; + // The previous ownership status of a battled scene. + // It's used to for a period during battle review still show the old ownership until the new one is dramaticlaly revealed + int m_PreBattleTeamOwnership; + + // Hover name label over Scene:s + GUILabel* m_pScenePlanetLabel; + + // Scene info popup mouseover box and controls + GUICollectionBox* m_pSceneInfoPopup; + GUIButton* m_pSceneCloseButton; + GUILabel* m_pSceneNameLabel; + GUICollectionBox* m_pSceneOwnerTeam; + GUILabel* m_pSceneResidentsLabel; + GUILabel* m_pSceneInfoLabel; + GUILabel* m_pSceneBudgetLabel; + GUISlider* m_pSceneBudgetSlider; + GUICollectionBox* m_pSceneBudgetBar; + GUICheckbox* m_pAutoDesignCheckbox; + GUILabel* m_pScanInfoLabel; + + // Currently dragged GUI box + GUICollectionBox* m_pDraggedBox; + // New potential drag is starting + bool m_EngageDrag; + // The scene currently hovered, NOT OWNED + Scene* m_pHoveredScene; + // The scene currently selected, NOT OWNED + Scene* m_pSelectedScene; + // The scene currently being played, NOT OWNED + Scene* m_pPlayingScene; + + // NEW GAME DIALOG + // Game size label and slider + GUILabel* m_pSizeLabel; + GUISlider* m_pSizeSlider; + GUILabel* m_pDifficultyLabel; + GUISlider* m_pDifficultySlider; + GUILabel* m_pGoldLabel; + GUISlider* m_pGoldSlider; + GUILabel* m_pLengthLabel; + GUISlider* m_pLengthSlider; + GUILabel* m_pErrorLabel; + GUIButton* m_apPlayerControlButton[Players::MaxPlayerCount]; + GUIComboBox* m_apPlayerTeamSelect[Players::MaxPlayerCount]; + GUIComboBox* m_apPlayerTechSelect[Players::MaxPlayerCount]; + GUIComboBox* m_apPlayerHandicap[Players::MaxPlayerCount]; + GUITextBox* m_apPlayerNameBox[Players::MaxPlayerCount]; + GUISlider* m_apPlayerAISkillSlider[Players::MaxPlayerCount]; + GUILabel* m_apPlayerAISkillLabel[Players::MaxPlayerCount]; + + // SAVING/LOADING GAME DIALOGS + GUITextBox* m_NewSaveBox; + // The combobox which lists all the games that can be saved over + GUIComboBox* m_pSavesToOverwriteCombo; + GUIComboBox* m_pSavesToLoadCombo; + // Info boxes showing some basic data on a save game + GUILabel* m_pSaveInfoLabel; + GUILabel* m_pLoadInfoLabel; + // Hack to keep the MetaSave Entity that has been selected for load even though confirmation dlg pups up and clears the selection combo + const Entity* m_pSelectedGameToLoad; + + // Whether player decided to continue to the next phase of the game + bool m_ContinuePhase; + // Whether the game was restarted this frame or not + bool m_ActivityRestarted; + // Whether the game was resumed this frame or not + bool m_ActivityResumed; + // How much money both players start with in the new game + int m_StartFunds; + // Which player is CPU managed, if any (-1) + int m_CPUPlayer; + // Difficulty setting + int m_StartDifficulty; + // Whether user has chosen to go back to the main menu + bool m_BackToMain; + // Player selected to quit the program + bool m_Quit; + + Vector m_StationPosOnOrbit; //!< The position of the station on the planet orbit. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this MetagameGUI, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + MetagameGUI(const MetagameGUI& reference) = delete; + MetagameGUI& operator=(const MetagameGUI& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Menus/ModManagerGUI.cpp b/Source/Menus/ModManagerGUI.cpp index 14d9480d4..e44fa1823 100644 --- a/Source/Menus/ModManagerGUI.cpp +++ b/Source/Menus/ModManagerGUI.cpp @@ -16,23 +16,23 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ModManagerGUI::ModManagerGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu) { + ModManagerGUI::ModManagerGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool createForPauseMenu) { m_GUIControlManager = std::make_unique(); RTEAssert(m_GUIControlManager->Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "MainMenuSubMenuSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuSubMenuSkin.ini"); m_GUIControlManager->Load("Base.rte/GUIs/ModManagerGUI.ini"); int rootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); - GUICollectionBox *rootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); + GUICollectionBox* rootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); rootBox->Resize(rootBoxMaxWidth, g_WindowMan.GetResY()); - GUICollectionBox *modManagerMenuBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxModManager")); + GUICollectionBox* modManagerMenuBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxModManager")); modManagerMenuBox->CenterInParent(true, true); modManagerMenuBox->SetPositionAbs(modManagerMenuBox->GetXPos(), (rootBox->GetHeight() < 540) ? modManagerMenuBox->GetYPos() - 15 : 140); - m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMainMenu")); + m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMainMenu")); if (createForPauseMenu) { m_BackToMainButton->SetSize(120, 20); @@ -40,46 +40,46 @@ namespace RTE { } m_BackToMainButton->SetPositionAbs((rootBox->GetWidth() - m_BackToMainButton->GetWidth()) / 2, modManagerMenuBox->GetYPos() + modManagerMenuBox->GetHeight() + 10); - m_ModsListBox = dynamic_cast(m_GUIControlManager->GetControl("ListBoxMods")); + m_ModsListBox = dynamic_cast(m_GUIControlManager->GetControl("ListBoxMods")); m_ModsListBox->SetMouseScrolling(true); m_ModsListBox->SetScrollBarThickness(15); m_ModsListBox->SetScrollBarPadding(2); - m_ScriptsListBox = dynamic_cast(m_GUIControlManager->GetControl("ListBoxScripts")); + m_ScriptsListBox = dynamic_cast(m_GUIControlManager->GetControl("ListBoxScripts")); m_ScriptsListBox->SetMouseScrolling(true); m_ScriptsListBox->SetScrollBarThickness(15); m_ScriptsListBox->SetScrollBarPadding(2); - m_ToggleModButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonToggleMod")); - m_ToggleScriptButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonToggleScript")); - m_ModOrScriptDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelDescription")); + m_ToggleModButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonToggleMod")); + m_ToggleScriptButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonToggleScript")); + m_ModOrScriptDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelDescription")); m_ModsListFetched = false; m_ScriptsListFetched = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ModManagerGUI::PopulateKnownModsList() { for (int i = 0; i < g_PresetMan.GetTotalModuleCount(); ++i) { if (i >= g_PresetMan.GetOfficialModuleCount() && i < g_PresetMan.GetTotalModuleCount()) { - if (const DataModule *dataModule = g_PresetMan.GetDataModule(i); dataModule && !dataModule->IsUserdata()) { - ModRecord modRecord = { dataModule->GetFileName(), dataModule->GetFriendlyName(), dataModule->GetDescription(), g_SettingsMan.IsModDisabled(dataModule->GetFileName()) }; + if (const DataModule* dataModule = g_PresetMan.GetDataModule(i); dataModule && !dataModule->IsUserdata()) { + ModRecord modRecord = {dataModule->GetFileName(), dataModule->GetFriendlyName(), dataModule->GetDescription(), g_SettingsMan.IsModDisabled(dataModule->GetFileName())}; m_KnownMods.emplace_back(modRecord); } } } // Add missing data from disabled mods settings - for (const auto &[modPath, modDisabled] : g_SettingsMan.GetDisabledModsMap()) { + for (const auto& [modPath, modDisabled]: g_SettingsMan.GetDisabledModsMap()) { bool found = false; - for (const ModRecord &knowModListEntry : m_KnownMods) { + for (const ModRecord& knowModListEntry: m_KnownMods) { if (modPath == knowModListEntry.ModulePath) { found = true; break; } } if (!found) { - ModRecord disabledModRecord = { modPath, "N/A, Module not loaded", "N/A, Module not loaded", modDisabled }; + ModRecord disabledModRecord = {modPath, "N/A, Module not loaded", "N/A, Module not loaded", modDisabled}; m_KnownMods.emplace_back(disabledModRecord); } } @@ -92,15 +92,15 @@ namespace RTE { m_ModsListFetched = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ModManagerGUI::PopulateKnownScriptsList() { - std::list globalScriptList; + std::list globalScriptList; g_PresetMan.GetAllOfType(globalScriptList, "GlobalScript"); - for (Entity *globalScriptListEntry : globalScriptList) { - if (const GlobalScript *globalScript = dynamic_cast(globalScriptListEntry)) { - ScriptRecord scriptRecord = { globalScript->GetModuleAndPresetName(), globalScript->GetDescription(), g_SettingsMan.IsGlobalScriptEnabled(scriptRecord.PresetName) }; + for (Entity* globalScriptListEntry: globalScriptList) { + if (const GlobalScript* globalScript = dynamic_cast(globalScriptListEntry)) { + ScriptRecord scriptRecord = {globalScript->GetModuleAndPresetName(), globalScript->GetDescription(), g_SettingsMan.IsGlobalScriptEnabled(scriptRecord.PresetName)}; m_KnownScripts.emplace_back(scriptRecord); } } @@ -113,14 +113,14 @@ namespace RTE { m_ScriptsListFetched = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ModManagerGUI::ToggleMod() { int index = m_ModsListBox->GetSelectedIndex(); if (index > -1) { - std::unordered_map &disabledModsList = g_SettingsMan.GetDisabledModsMap(); - GUIListPanel::Item *selectedItem = m_ModsListBox->GetSelected(); - ModRecord &modRecord = m_KnownMods.at(selectedItem->m_ExtraIndex); + std::unordered_map& disabledModsList = g_SettingsMan.GetDisabledModsMap(); + GUIListPanel::Item* selectedItem = m_ModsListBox->GetSelected(); + ModRecord& modRecord = m_KnownMods.at(selectedItem->m_ExtraIndex); modRecord.Disabled = !modRecord.Disabled; if (modRecord.Disabled) { @@ -141,14 +141,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ModManagerGUI::ToggleScript() { int index = m_ScriptsListBox->GetSelectedIndex(); if (index > -1) { - std::unordered_map &enabledScriptList = g_SettingsMan.GetEnabledGlobalScriptMap(); - GUIListPanel::Item *selectedItem = m_ScriptsListBox->GetSelected(); - ScriptRecord &scriptRecord = m_KnownScripts.at(selectedItem->m_ExtraIndex); + std::unordered_map& enabledScriptList = g_SettingsMan.GetEnabledGlobalScriptMap(); + GUIListPanel::Item* selectedItem = m_ScriptsListBox->GetSelected(); + ScriptRecord& scriptRecord = m_KnownScripts.at(selectedItem->m_ExtraIndex); scriptRecord.Enabled = !scriptRecord.Enabled; if (scriptRecord.Enabled) { @@ -169,7 +169,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ModManagerGUI::HandleInputEvents() { if (!ListsFetched()) { @@ -189,14 +189,16 @@ namespace RTE { ToggleScript(); } } else if (guiEvent.GetType() == GUIEvent::Notification) { - if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl())) { g_GUISound.SelectionChangeSound()->Play(); } + if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl())) { + g_GUISound.SelectionChangeSound()->Play(); + } if (guiEvent.GetControl() == m_ModsListBox && (guiEvent.GetMsg() == GUIListBox::Select && m_ModsListBox->GetSelectedIndex() > -1)) { - const ModRecord &modRecord = m_KnownMods.at(m_ModsListBox->GetSelected()->m_ExtraIndex); + const ModRecord& modRecord = m_KnownMods.at(m_ModsListBox->GetSelected()->m_ExtraIndex); m_ModOrScriptDescriptionLabel->SetText(modRecord.Description); m_ToggleModButton->SetText(modRecord.Disabled ? "Enable Mod" : "Disable Mod"); } else if (guiEvent.GetControl() == m_ScriptsListBox && (guiEvent.GetMsg() == GUIListBox::Select && m_ScriptsListBox->GetSelectedIndex() > -1)) { - const ScriptRecord &scriptRecord = m_KnownScripts.at(m_ScriptsListBox->GetSelected()->m_ExtraIndex); + const ScriptRecord& scriptRecord = m_KnownScripts.at(m_ScriptsListBox->GetSelected()->m_ExtraIndex); m_ModOrScriptDescriptionLabel->SetText(scriptRecord.Description); m_ToggleScriptButton->SetText(scriptRecord.Enabled ? "Disable Script" : "Enable Script"); } @@ -205,9 +207,9 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ModManagerGUI::Draw() const { m_GUIControlManager->Draw(); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/ModManagerGUI.h b/Source/Menus/ModManagerGUI.h index b9ed1686f..9c3b5f58a 100644 --- a/Source/Menus/ModManagerGUI.h +++ b/Source/Menus/ModManagerGUI.h @@ -16,7 +16,6 @@ namespace RTE { class ModManagerGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a ModManagerGUI object in system memory and make it ready for use. @@ -24,7 +23,7 @@ namespace RTE { /// Pointer to a GUIScreen interface that will be used by this ModManagerGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this ModManagerGUI's GUIControlManager. Ownership is NOT transferred! /// Whether this SettingsGUI is part of ModManagerGUI and should have a slightly different layout. - ModManagerGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu = false); + ModManagerGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool createForPauseMenu = false); #pragma endregion #pragma region Concrete Methods @@ -41,7 +40,6 @@ namespace RTE { #pragma endregion private: - /// /// Struct containing information about a valid mod DataModule. /// @@ -62,7 +60,7 @@ namespace RTE { /// /// ModRecord to compare with. /// Bool with result of the alphabetical comparison. - bool operator<(const ModRecord &rhs) const { return ModulePath < rhs.ModulePath; } + bool operator<(const ModRecord& rhs) const { return ModulePath < rhs.ModulePath; } }; /// @@ -84,7 +82,7 @@ namespace RTE { /// /// ScriptRecord to compare with. /// Bool with result of the alphabetical comparison. - bool operator<(const ScriptRecord &rhs) const { return PresetName < rhs.PresetName; } + bool operator<(const ScriptRecord& rhs) const { return PresetName < rhs.PresetName; } }; std::unique_ptr m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of the ModManagerGUI. @@ -98,12 +96,12 @@ namespace RTE { /// /// GUI elements that compose the Mod Manager menu screen. /// - GUIButton *m_BackToMainButton; - GUIButton *m_ToggleModButton; - GUIButton *m_ToggleScriptButton; - GUIListBox *m_ModsListBox; - GUIListBox *m_ScriptsListBox; - GUILabel *m_ModOrScriptDescriptionLabel; + GUIButton* m_BackToMainButton; + GUIButton* m_ToggleModButton; + GUIButton* m_ToggleScriptButton; + GUIListBox* m_ModsListBox; + GUIListBox* m_ScriptsListBox; + GUILabel* m_ModOrScriptDescriptionLabel; #pragma region Mod and Script Handling /// @@ -134,8 +132,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - ModManagerGUI(const ModManagerGUI &reference) = delete; - ModManagerGUI & operator=(const ModManagerGUI &rhs) = delete; + ModManagerGUI(const ModManagerGUI& reference) = delete; + ModManagerGUI& operator=(const ModManagerGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/MultiplayerGameGUI.cpp b/Source/Menus/MultiplayerGameGUI.cpp index 7d179476c..733b237de 100644 --- a/Source/Menus/MultiplayerGameGUI.cpp +++ b/Source/Menus/MultiplayerGameGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -15,7 +14,6 @@ #include "FrameMan.h" - using namespace std; using namespace RTE; @@ -25,37 +23,32 @@ using namespace RTE; // Description: Clears all the member variables of this MultiplayerGameGUI, effectively // resetting the members of this abstraction level only. -void MultiplayerGameGUI::Clear() -{ +void MultiplayerGameGUI::Clear() { m_pController = 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the MultiplayerGameGUI object ready for use. -int MultiplayerGameGUI::Create(Controller *pController) -{ +int MultiplayerGameGUI::Create(Controller* pController) { AAssert(pController, "No controller sent to MultiplayerGameGUI on creation!"); m_pController = pController; // Allocate and (re)create the Editor GUIs - //m_pPieMenu = new PieMenuGUI(); - //m_pPieMenu->Create(pController); + // m_pPieMenu = new PieMenuGUI(); + // m_pPieMenu->Create(pController); return 0; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the MultiplayerGameGUI object. -void MultiplayerGameGUI::Destroy() -{ +void MultiplayerGameGUI::Destroy() { Clear(); } @@ -64,18 +57,13 @@ void MultiplayerGameGUI::Destroy() ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void MultiplayerGameGUI::Update() -{ +void MultiplayerGameGUI::Update() { } - ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the menu -void MultiplayerGameGUI::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) const -{ +void MultiplayerGameGUI::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) const { } - - diff --git a/Source/Menus/MultiplayerGameGUI.h b/Source/Menus/MultiplayerGameGUI.h index 4ea16e688..c79902c2c 100644 --- a/Source/Menus/MultiplayerGameGUI.h +++ b/Source/Menus/MultiplayerGameGUI.h @@ -4,10 +4,9 @@ ////////////////////////////////////////////////////////////////////////////////////////// // File: MultiplayerGameGUI.h ////////////////////////////////////////////////////////////////////////////////////////// -// Description: +// Description: // Project: GUI Library -// Author(s): - +// Author(s): ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -19,9 +18,7 @@ struct BITMAP; - -namespace RTE -{ +namespace RTE { class SceneObject; class ObjectPickerGUI; class PieMenuGUI; @@ -29,9 +26,9 @@ namespace RTE ////////////////////////////////////////////////////////////////////////////////////////// // Class: MultiplayerGameGUI ////////////////////////////////////////////////////////////////////////////////////////// - // Description: + // Description: // Parent(s): None. - // Class history: + // Class history: class MultiplayerGameGUI { @@ -40,13 +37,11 @@ namespace RTE public: // Different modes of this editor - enum GUIMode - { + enum GUIMode { INACTIVE = 0, ACTIVE = 1 }; - ////////////////////////////////////////////////////////////////////////////////////////// // Constructor: MultiplayerGameGUI ////////////////////////////////////////////////////////////////////////////////////////// @@ -56,7 +51,6 @@ namespace RTE MultiplayerGameGUI() { Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Destructor: ~MultiplayerGameGUI ////////////////////////////////////////////////////////////////////////////////////////// @@ -66,7 +60,6 @@ namespace RTE ~MultiplayerGameGUI() { Destroy(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// @@ -82,8 +75,7 @@ namespace RTE // Return value: An error return value signaling sucess or any particular failure. // Anything below 0 is an error signal. - int Create(Controller *pController); - + int Create(Controller* pController); ////////////////////////////////////////////////////////////////////////////////////////// // Method: Reset @@ -93,8 +85,7 @@ namespace RTE // Arguments: None. // Return value: None. - void Reset() { Clear(); } - + void Reset() { Clear(); } ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy @@ -105,7 +96,6 @@ namespace RTE void Destroy(); - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Update ////////////////////////////////////////////////////////////////////////////////////////// @@ -113,7 +103,7 @@ namespace RTE // Arguments: None. // Return value: None. - void Update(); + void Update(); ////////////////////////////////////////////////////////////////////////////////////////// // Method: Draw @@ -123,21 +113,19 @@ namespace RTE // The absolute position of the target bitmap's upper left corner in the scene. // Return value: None. - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) const; + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) const; ////////////////////////////////////////////////////////////////////////////////////////// // Protected member variable and method declarations protected: - // Controller which conrols this menu. Not owned - Controller *m_pController; + Controller* m_pController; ////////////////////////////////////////////////////////////////////////////////////////// // Private member variable and method declarations private: - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Clear ////////////////////////////////////////////////////////////////////////////////////////// @@ -148,13 +136,11 @@ namespace RTE void Clear(); - // Disallow the use of some implicit methods. - MultiplayerGameGUI(const MultiplayerGameGUI &reference); - MultiplayerGameGUI & operator=(const MultiplayerGameGUI &rhs); - + MultiplayerGameGUI(const MultiplayerGameGUI& reference); + MultiplayerGameGUI& operator=(const MultiplayerGameGUI& rhs); }; } // namespace RTE -#endif // File +#endif // File diff --git a/Source/Menus/ObjectPickerGUI.cpp b/Source/Menus/ObjectPickerGUI.cpp index 3db530a6c..07d017db4 100644 --- a/Source/Menus/ObjectPickerGUI.cpp +++ b/Source/Menus/ObjectPickerGUI.cpp @@ -25,9 +25,9 @@ namespace RTE { - BITMAP *ObjectPickerGUI::s_Cursor = nullptr; + BITMAP* ObjectPickerGUI::s_Cursor = nullptr; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::Clear() { m_GUIScreen = nullptr; @@ -58,15 +58,21 @@ namespace RTE { m_ExpandedModules[0] = true; // Base.rte is always expanded } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ObjectPickerGUI::Create(Controller *controller, int whichModuleSpace, const std::string_view &onlyOfType) { + int ObjectPickerGUI::Create(Controller* controller, int whichModuleSpace, const std::string_view& onlyOfType) { RTEAssert(controller, "No controller sent to ObjectPickerGUI on creation!"); m_Controller = controller; - if (!m_GUIScreen) { m_GUIScreen = std::make_unique(g_FrameMan.GetBackBuffer8()); } - if (!m_GUIInput) { m_GUIInput = std::make_unique(controller->GetPlayer()); } - if (!m_GUIControlManager) { m_GUIControlManager = std::make_unique(); } + if (!m_GUIScreen) { + m_GUIScreen = std::make_unique(g_FrameMan.GetBackBuffer8()); + } + if (!m_GUIInput) { + m_GUIInput = std::make_unique(controller->GetPlayer()); + } + if (!m_GUIControlManager) { + m_GUIControlManager = std::make_unique(); + } RTEAssert(m_GUIControlManager->Create(m_GUIScreen.get(), m_GUIInput.get(), "Base.rte/GUIs/Skins", "DefaultSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/DefaultSkin.ini"); m_GUIControlManager->Load("Base.rte/GUIs/ObjectPickerGUI.ini"); @@ -78,21 +84,23 @@ namespace RTE { } if (g_FrameMan.IsInMultiplayerMode()) { - dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_FrameMan.GetPlayerFrameBufferWidth(controller->GetPlayer()), g_FrameMan.GetPlayerFrameBufferHeight(controller->GetPlayer())); + dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_FrameMan.GetPlayerFrameBufferWidth(controller->GetPlayer()), g_FrameMan.GetPlayerFrameBufferHeight(controller->GetPlayer())); } else { - dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); + dynamic_cast(m_GUIControlManager->GetControl("base"))->SetSize(g_WindowMan.GetResX(), g_WindowMan.GetResY()); } - if (!m_ParentBox) { m_ParentBox = dynamic_cast(m_GUIControlManager->GetControl("PickerGUIBox")); } + if (!m_ParentBox) { + m_ParentBox = dynamic_cast(m_GUIControlManager->GetControl("PickerGUIBox")); + } m_ParentBox->SetPositionAbs(g_FrameMan.GetPlayerFrameBufferWidth(m_Controller->GetPlayer()), 0); m_ParentBox->SetEnabled(false); m_ParentBox->SetVisible(false); - m_GroupsList = dynamic_cast(m_GUIControlManager->GetControl("GroupsLB")); + m_GroupsList = dynamic_cast(m_GUIControlManager->GetControl("GroupsLB")); m_GroupsList->EnableScrollbars(false, true); m_GroupsList->SetScrollBarThickness(13); m_GroupsList->SetAlternateDrawMode(false); m_GroupsList->SetMultiSelect(false); - m_ObjectsList = dynamic_cast(m_GUIControlManager->GetControl("ObjectsLB")); + m_ObjectsList = dynamic_cast(m_GUIControlManager->GetControl("ObjectsLB")); m_ObjectsList->EnableScrollbars(false, true); m_ObjectsList->SetScrollBarThickness(13); m_ObjectsList->SetAlternateDrawMode(true); @@ -106,8 +114,8 @@ namespace RTE { } if (!m_PopupBox) { - m_PopupBox = dynamic_cast(m_GUIControlManager->GetControl("BuyGUIPopup")); - m_PopupText = dynamic_cast(m_GUIControlManager->GetControl("PopupText")); + m_PopupBox = dynamic_cast(m_GUIControlManager->GetControl("BuyGUIPopup")); + m_PopupText = dynamic_cast(m_GUIControlManager->GetControl("PopupText")); m_PopupText->SetFont(m_GUIControlManager->GetSkin()->GetFont("FontSmall.png")); // Never enable the popup box because it steals focus and causes other windows to think the cursor left them @@ -121,7 +129,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::SetEnabled(bool enable) { if (enable && m_PickerState != PickerState::Enabled && m_PickerState != PickerState::Enabling) { @@ -143,7 +151,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::SetNativeTechModule(int whichModule) { if (whichModule >= 0 && whichModule < g_PresetMan.GetTotalModuleCount()) { @@ -152,8 +160,8 @@ namespace RTE { SetObjectsListModuleGroupExpanded(m_NativeTechModuleID); if (!g_SettingsMan.FactionBuyMenuThemesDisabled()) { - if (const DataModule *techModule = g_PresetMan.GetDataModule(whichModule); techModule->IsFaction()) { - const DataModule::BuyMenuTheme &techBuyMenuTheme = techModule->GetFactionBuyMenuTheme(); + if (const DataModule* techModule = g_PresetMan.GetDataModule(whichModule); techModule->IsFaction()) { + const DataModule::BuyMenuTheme& techBuyMenuTheme = techModule->GetFactionBuyMenuTheme(); if (!techBuyMenuTheme.SkinFilePath.empty()) { // Not specifying the skin file directory allows us to load image files from the whole working directory in the skin file instead of just the specified directory. @@ -164,14 +172,16 @@ namespace RTE { m_GUIControlManager->GetSkin()->GetValue("DescriptionBoxText", "Font", &themeDescriptionBoxTextFont); m_PopupText->SetFont(m_GUIControlManager->GetSkin()->GetFont(themeDescriptionBoxTextFont)); } - if (techBuyMenuTheme.BackgroundColorIndex >= 0) { m_ParentBox->SetDrawColor(std::clamp(techBuyMenuTheme.BackgroundColorIndex, 0, 255)); } + if (techBuyMenuTheme.BackgroundColorIndex >= 0) { + m_ParentBox->SetDrawColor(std::clamp(techBuyMenuTheme.BackgroundColorIndex, 0, 255)); + } } } } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ObjectPickerGUI::SetListFocus(PickerFocus listToFocusOn) { if (listToFocusOn == m_PickerFocus) { @@ -191,10 +201,10 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool ObjectPickerGUI::SelectGroupByName(const std::string_view &groupName) { - for (const GUIListPanel::Item *groupListItem : *m_GroupsList->GetItemList()) { + bool ObjectPickerGUI::SelectGroupByName(const std::string_view& groupName) { + for (const GUIListPanel::Item* groupListItem: *m_GroupsList->GetItemList()) { if (groupListItem->m_Name == groupName) { SelectGroupByIndex(groupListItem->m_ID); SetListFocus(PickerFocus::ObjectList); @@ -204,7 +214,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::SelectGroupByIndex(int groupIndex, bool updateObjectsList) { m_SelectedGroupIndex = (groupIndex < 0) ? m_ShownGroupIndex : groupIndex; @@ -219,42 +229,50 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::SelectNextOrPrevGroup(bool selectPrev) { int groupIndex = m_SelectedGroupIndex; if (selectPrev) { groupIndex--; - if (groupIndex < 0) { groupIndex = m_GroupsList->GetItemList()->size() - 1; } + if (groupIndex < 0) { + groupIndex = m_GroupsList->GetItemList()->size() - 1; + } } else { groupIndex++; - if (groupIndex >= m_GroupsList->GetItemList()->size()) { groupIndex = 0; } + if (groupIndex >= m_GroupsList->GetItemList()->size()) { + groupIndex = 0; + } } SelectGroupByIndex(groupIndex); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::UpdateGroupsList() { m_GroupsList->ClearList(); - bool showAssemblySchemes = dynamic_cast(g_ActivityMan.GetActivity()); + bool showAssemblySchemes = dynamic_cast(g_ActivityMan.GetActivity()); std::list groupList; g_PresetMan.GetModuleSpaceGroups(groupList, m_ModuleSpaceID, m_ShowType); - for (const std::string &groupListEntry : groupList) { - std::list objectList; + for (const std::string& groupListEntry: groupList) { + std::list objectList; g_PresetMan.GetAllOfGroupInModuleSpace(objectList, groupListEntry, m_ShowType, m_ModuleSpaceID); bool onlyAssembliesInGroup = true; bool onlyAssemblySchemesInGroup = true; bool hasObjectsToShow = false; - for (Entity *objectListEntry : objectList) { - if (!dynamic_cast(objectListEntry)) { onlyAssembliesInGroup = false; } - if (!dynamic_cast(objectListEntry)) { onlyAssemblySchemesInGroup = false; } + for (Entity* objectListEntry: objectList) { + if (!dynamic_cast(objectListEntry)) { + onlyAssembliesInGroup = false; + } + if (!dynamic_cast(objectListEntry)) { + onlyAssemblySchemesInGroup = false; + } - const SceneObject *sceneObject = dynamic_cast(objectListEntry); + const SceneObject* sceneObject = dynamic_cast(objectListEntry); if (sceneObject && sceneObject->IsBuyable() && !sceneObject->IsBuyableInBuyMenuOnly() && !sceneObject->IsBuyableInScriptOnly()) { hasObjectsToShow = true; break; @@ -262,17 +280,19 @@ namespace RTE { } // If this group is in the SettingsMan list of always visible assembly groups, then force the onlyAssembliesInGroup flag off so this group is always shown if (onlyAssembliesInGroup) { - for (const std::string &assemblyGroup : g_SettingsMan.GetVisibleAssemblyGroupsList()) { + for (const std::string& assemblyGroup: g_SettingsMan.GetVisibleAssemblyGroupsList()) { if (groupListEntry == assemblyGroup) { onlyAssembliesInGroup = false; break; } } } - if (!objectList.empty() && hasObjectsToShow && (!onlyAssembliesInGroup || groupListEntry == "Assemblies") && (!onlyAssemblySchemesInGroup || showAssemblySchemes)) { m_GroupsList->AddItem(groupListEntry); } + if (!objectList.empty() && hasObjectsToShow && (!onlyAssembliesInGroup || groupListEntry == "Assemblies") && (!onlyAssemblySchemesInGroup || showAssemblySchemes)) { + m_GroupsList->AddItem(groupListEntry); + } } - if (const GUIListPanel::Item *listItem = m_GroupsList->GetItem(0)) { + if (const GUIListPanel::Item* listItem = m_GroupsList->GetItem(0)) { m_GroupsList->ScrollToTop(); m_SelectedGroupIndex = 0; m_GroupsList->SetSelectedIndex(m_SelectedGroupIndex); @@ -280,48 +300,54 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const SceneObject * ObjectPickerGUI::GetSelectedObject() { - if (const GUIListPanel::Item *selectedItem = m_ObjectsList->GetSelected()) { - return dynamic_cast(selectedItem->m_pEntity); + const SceneObject* ObjectPickerGUI::GetSelectedObject() { + if (const GUIListPanel::Item* selectedItem = m_ObjectsList->GetSelected()) { + return dynamic_cast(selectedItem->m_pEntity); } return nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::SelectObjectByIndex(int objectIndex, bool playSelectionSound) { m_SelectedObjectIndex = objectIndex; m_ObjectsList->SetSelectedIndex(m_SelectedObjectIndex); - if (playSelectionSound) { g_GUISound.SelectionChangeSound()->Play(m_Controller->GetPlayer()); } + if (playSelectionSound) { + g_GUISound.SelectionChangeSound()->Play(m_Controller->GetPlayer()); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::SelectNextOrPrevObject(bool getPrev) { int objectIndex = m_SelectedObjectIndex; if (getPrev) { objectIndex--; - if (objectIndex < 0) { objectIndex = m_ObjectsList->GetItemList()->size() - 1; } + if (objectIndex < 0) { + objectIndex = m_ObjectsList->GetItemList()->size() - 1; + } } else { objectIndex++; - if (objectIndex >= m_ObjectsList->GetItemList()->size()) { objectIndex = 0; } + if (objectIndex >= m_ObjectsList->GetItemList()->size()) { + objectIndex = 0; + } } SelectObjectByIndex(objectIndex); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::AddObjectsListModuleGroup(int moduleID) { - const DataModule *dataModule = g_PresetMan.GetDataModule(moduleID); + const DataModule* dataModule = g_PresetMan.GetDataModule(moduleID); std::string moduleName = dataModule->GetFriendlyName(); std::transform(moduleName.begin(), moduleName.end(), moduleName.begin(), ::toupper); - GUIBitmap *dataModuleIcon = dataModule->GetIcon() ? new AllegroBitmap(dataModule->GetIcon()) : nullptr; + GUIBitmap* dataModuleIcon = dataModule->GetIcon() ? new AllegroBitmap(dataModule->GetIcon()) : nullptr; m_ObjectsList->AddItem(moduleName, m_ExpandedModules.at(moduleID) ? "-" : "+", dataModuleIcon, nullptr, moduleID); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::SetObjectsListModuleGroupExpanded(int moduleID, bool expanded) { if (moduleID > 0 && moduleID < m_ExpandedModules.size()) { @@ -332,7 +358,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::ToggleObjectsListModuleGroupExpansion(int moduleID) { if (moduleID > 0 && moduleID < m_ExpandedModules.size()) { @@ -342,22 +368,26 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::ShowDescriptionPopupBox() { std::string description = ""; - GUIListPanel::Item *objectListItem = m_ObjectsList->GetSelected(); + GUIListPanel::Item* objectListItem = m_ObjectsList->GetSelected(); if (objectListItem && objectListItem->m_pEntity && !objectListItem->m_pEntity->GetDescription().empty()) { description = objectListItem->m_pEntity->GetDescription(); } else if (objectListItem && objectListItem->m_ExtraIndex >= 0) { - const DataModule *dataModule = g_PresetMan.GetDataModule(objectListItem->m_ExtraIndex); - if (dataModule && !dataModule->GetDescription().empty()) { description = dataModule->GetDescription(); } + const DataModule* dataModule = g_PresetMan.GetDataModule(objectListItem->m_ExtraIndex); + if (dataModule && !dataModule->GetDescription().empty()) { + description = dataModule->GetDescription(); + } } if (!description.empty()) { m_PopupBox->SetEnabled(false); m_PopupBox->SetVisible(true); m_PopupBox->SetPositionAbs(m_ObjectsList->GetXPos() - m_PopupBox->GetWidth() + 4, m_ObjectsList->GetYPos() + m_ObjectsList->GetStackHeight(objectListItem) - m_ObjectsList->GetScrollVerticalValue()); - if (m_PopupBox->GetYPos() + m_PopupBox->GetHeight() > m_ParentBox->GetHeight()) { m_PopupBox->SetPositionAbs(m_PopupBox->GetXPos(), m_ParentBox->GetHeight() - m_PopupBox->GetHeight()); } + if (m_PopupBox->GetYPos() + m_PopupBox->GetHeight() > m_ParentBox->GetHeight()) { + m_PopupBox->SetPositionAbs(m_PopupBox->GetXPos(), m_ParentBox->GetHeight() - m_PopupBox->GetHeight()); + } m_PopupText->SetHAlignment(GUIFont::Left); m_PopupText->SetText(description); @@ -365,13 +395,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::UpdateObjectsList(bool selectTop) { m_ObjectsList->ClearList(); - std::vector> moduleList(g_PresetMan.GetTotalModuleCount(), std::list()); + std::vector> moduleList(g_PresetMan.GetTotalModuleCount(), std::list()); - if (const GUIListPanel::Item *groupListItem = m_GroupsList->GetSelected()) { + if (const GUIListPanel::Item* groupListItem = m_GroupsList->GetSelected()) { if (m_ModuleSpaceID < 0) { if (g_SettingsMan.ShowForeignItems() || m_NativeTechModuleID <= 0) { for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) { @@ -379,7 +409,9 @@ namespace RTE { } } else { for (int moduleID = 0; moduleID < moduleList.size(); ++moduleID) { - if (moduleID == 0 || moduleID == m_NativeTechModuleID || g_PresetMan.GetDataModule(moduleID)->IsMerchant()) { g_PresetMan.GetAllOfGroup(moduleList.at(moduleID), groupListItem->m_Name, m_ShowType, moduleID); } + if (moduleID == 0 || moduleID == m_NativeTechModuleID || g_PresetMan.GetDataModule(moduleID)->IsMerchant()) { + g_PresetMan.GetAllOfGroup(moduleList.at(moduleID), groupListItem->m_Name, m_ShowType, moduleID); + } } } } else { @@ -394,16 +426,20 @@ namespace RTE { if (moduleList.at(moduleID).empty()) { continue; } - std::list objectList; - for (Entity *moduleListEntryEntity : moduleList.at(moduleID)) { - SceneObject *sceneObject = dynamic_cast(moduleListEntryEntity); - if (sceneObject && sceneObject->IsBuyable() && !sceneObject->IsBuyableInBuyMenuOnly() && !sceneObject->IsBuyableInScriptOnly()) { objectList.emplace_back(sceneObject); } + std::list objectList; + for (Entity* moduleListEntryEntity: moduleList.at(moduleID)) { + SceneObject* sceneObject = dynamic_cast(moduleListEntryEntity); + if (sceneObject && sceneObject->IsBuyable() && !sceneObject->IsBuyableInBuyMenuOnly() && !sceneObject->IsBuyableInScriptOnly()) { + objectList.emplace_back(sceneObject); + } } if (!objectList.empty()) { - if (moduleID != 0) { AddObjectsListModuleGroup(moduleID); } + if (moduleID != 0) { + AddObjectsListModuleGroup(moduleID); + } if (moduleID == 0 || m_ExpandedModules.at(moduleID)) { - for (SceneObject *objectListEntry : objectList) { - GUIBitmap *objectIcon = new AllegroBitmap(objectListEntry->GetGraphicalIcon()); + for (SceneObject* objectListEntry: objectList) { + GUIBitmap* objectIcon = new AllegroBitmap(objectListEntry->GetGraphicalIcon()); m_ObjectsList->AddItem(objectListEntry->GetPresetName(), objectListEntry->GetGoldValueString(m_NativeTechModuleID, m_ForeignCostMult), objectIcon, objectListEntry); } } @@ -416,23 +452,29 @@ namespace RTE { SelectObjectByIndex(m_SelectedObjectIndex, false); m_ObjectsList->ScrollToSelected(); } - if (const GUIListPanel::Item *selectedItem = m_ObjectsList->GetSelected()) { m_PickedObject = dynamic_cast(selectedItem->m_pEntity); } + if (const GUIListPanel::Item* selectedItem = m_ObjectsList->GetSelected()) { + m_PickedObject = dynamic_cast(selectedItem->m_pEntity); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::Update() { m_PopupBox->SetVisible(false); - if (m_PickerState != PickerState::Enabled && m_PickerState != PickerState::Disabled) { AnimateOpenClose(); } - if (m_PickerState == PickerState::Enabled || m_PickerState == PickerState::Enabling) { m_GUIControlManager->Update(true); } + if (m_PickerState != PickerState::Enabled && m_PickerState != PickerState::Disabled) { + AnimateOpenClose(); + } + if (m_PickerState == PickerState::Enabled || m_PickerState == PickerState::Enabling) { + m_GUIControlManager->Update(true); + } if (m_PickerState == PickerState::Enabled) { m_GUIControlManager->EnableMouse(m_Controller->IsMouseControlled()); m_PickedObject = nullptr; if (HandleInput()) { - if (const GUIListPanel::Item *selectedItem = m_ObjectsList->GetSelected()) { - m_PickedObject = dynamic_cast(selectedItem->m_pEntity); + if (const GUIListPanel::Item* selectedItem = m_ObjectsList->GetSelected()) { + m_PickedObject = dynamic_cast(selectedItem->m_pEntity); if (m_PickedObject) { g_GUISound.ObjectPickedSound()->Play(m_Controller->GetPlayer()); SetEnabled(false); @@ -440,15 +482,19 @@ namespace RTE { } return; } - if (m_PickerFocus == PickerFocus::ObjectList) { ShowDescriptionPopupBox(); } + if (m_PickerFocus == PickerFocus::ObjectList) { + ShowDescriptionPopupBox(); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ObjectPickerGUI::HandleInput() { bool objectPickedOrPickerClosed = false; - if (m_Controller->IsMouseControlled()) { objectPickedOrPickerClosed = HandleMouseEvents(); } + if (m_Controller->IsMouseControlled()) { + objectPickedOrPickerClosed = HandleMouseEvents(); + } if (!objectPickedOrPickerClosed && !m_Controller->IsState(ControlState::PRESS_SECONDARY)) { bool pressUp = m_Controller->IsState(ControlState::PRESS_UP); @@ -493,7 +539,7 @@ namespace RTE { } else if (pressScrollDown) { m_ObjectsList->ScrollDown(); } else if (m_Controller->IsState(ControlState::PRESS_FACEBUTTON)) { - if (const GUIListPanel::Item *objectListItem = m_ObjectsList->GetSelected()) { + if (const GUIListPanel::Item* objectListItem = m_ObjectsList->GetSelected()) { if (objectListItem->m_ExtraIndex >= 0) { ToggleObjectsListModuleGroupExpansion(objectListItem->m_ExtraIndex); } else { @@ -510,7 +556,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ObjectPickerGUI::HandleMouseEvents() { int mousePosX; @@ -524,8 +570,10 @@ namespace RTE { if (guiEvent.GetMsg() == GUIListBox::MouseDown && (guiEvent.GetData() & GUIListBox::MOUSE_LEFT)) { SelectGroupByIndex(m_GroupsList->GetSelectedIndex()); } else if (guiEvent.GetMsg() == GUIListBox::MouseMove) { - const GUIListPanel::Item *groupListItem = m_GroupsList->GetItem(mousePosX, mousePosY); - if (groupListItem && m_SelectedGroupIndex != groupListItem->m_ID) { SelectGroupByIndex(groupListItem->m_ID, false); } + const GUIListPanel::Item* groupListItem = m_GroupsList->GetItem(mousePosX, mousePosY); + if (groupListItem && m_SelectedGroupIndex != groupListItem->m_ID) { + SelectGroupByIndex(groupListItem->m_ID, false); + } } else if (guiEvent.GetMsg() == GUIListBox::MouseEnter) { SetListFocus(PickerFocus::GroupList); } else if (guiEvent.GetMsg() == GUIListBox::MouseLeave && m_SelectedGroupIndex != m_ShownGroupIndex) { @@ -534,7 +582,7 @@ namespace RTE { } else if (guiEvent.GetControl() == m_ObjectsList) { if (guiEvent.GetMsg() == GUIListBox::MouseDown && (guiEvent.GetData() & GUIListBox::MOUSE_LEFT)) { m_ObjectsList->ScrollToSelected(); - if (const GUIListPanel::Item *objectListItem = m_ObjectsList->GetSelected()) { + if (const GUIListPanel::Item* objectListItem = m_ObjectsList->GetSelected()) { if (objectListItem->m_ExtraIndex >= 0) { ToggleObjectsListModuleGroupExpansion(objectListItem->m_ExtraIndex); } else if (objectListItem->m_pEntity) { @@ -543,8 +591,10 @@ namespace RTE { } } } else if (guiEvent.GetMsg() == GUIListBox::MouseMove) { - const GUIListPanel::Item *objectListItem = m_ObjectsList->GetItem(mousePosX, mousePosY); - if (objectListItem && m_SelectedObjectIndex != objectListItem->m_ID) { SelectObjectByIndex(objectListItem->m_ID); } + const GUIListPanel::Item* objectListItem = m_ObjectsList->GetItem(mousePosX, mousePosY); + if (objectListItem && m_SelectedObjectIndex != objectListItem->m_ID) { + SelectObjectByIndex(objectListItem->m_ID); + } } else if (guiEvent.GetMsg() == GUIListBox::MouseEnter) { SetListFocus(PickerFocus::ObjectList); } @@ -558,7 +608,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ObjectPickerGUI::AnimateOpenClose() { if (m_PickerState == PickerState::Enabling) { @@ -591,9 +641,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ObjectPickerGUI::Draw(BITMAP *drawBitmap) const { + void ObjectPickerGUI::Draw(BITMAP* drawBitmap) const { AllegroScreen drawScreen(drawBitmap); m_GUIControlManager->Draw(&drawScreen); if (IsEnabled() && m_Controller->IsMouseControlled()) { @@ -607,4 +657,4 @@ namespace RTE { } } } -} +} // namespace RTE diff --git a/Source/Menus/ObjectPickerGUI.h b/Source/Menus/ObjectPickerGUI.h index 876963e53..39182e2e2 100644 --- a/Source/Menus/ObjectPickerGUI.h +++ b/Source/Menus/ObjectPickerGUI.h @@ -22,7 +22,6 @@ namespace RTE { class ObjectPickerGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a ObjectPickerGUI object in system memory. Create() should be called before using the object. @@ -36,7 +35,7 @@ namespace RTE { /// Which DataModule space to be picking from. -1 means pick from all objects loaded in all DataModules. /// Which lowest common denominator type to be showing. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(Controller *controller, int whichModuleSpace = -1, const std::string_view &onlyOfType = "All"); + int Create(Controller* controller, int whichModuleSpace = -1, const std::string_view& onlyOfType = "All"); #pragma endregion #pragma region Destruction @@ -69,7 +68,7 @@ namespace RTE { /// Sets the controller used by this. The ownership of the controller is NOT transferred! /// /// The new controller for this menu. Ownership is NOT transferred! - void SetController(Controller *controller) { m_Controller = controller; } + void SetController(Controller* controller) { m_Controller = controller; } /// /// Sets where on the screen that this GUI is being drawn to. If upper left corner, then 0, 0. This will affect the way the mouse is positioned etc. @@ -82,13 +81,21 @@ namespace RTE { /// Sets which DataModule space to be picking objects from. If -1, then let the player pick from all loaded modules. /// /// The ID of the module to let the player pick objects from. All official module objects will always be presented, in addition to the one passed in here. - void SetModuleSpace(int newModuleSpaceID = -1) { if (newModuleSpaceID != m_ModuleSpaceID) { m_ModuleSpaceID = newModuleSpaceID; UpdateGroupsList(); } } + void SetModuleSpace(int newModuleSpaceID = -1) { + if (newModuleSpaceID != m_ModuleSpaceID) { + m_ModuleSpaceID = newModuleSpaceID; + UpdateGroupsList(); + } + } /// /// Sets which DataModule space to be picking objects from. If -1, then let the player pick from all loaded modules. /// /// The ID of the module to let the player pick objects from. All official module objects will always be presented, in addition to the one passed in here. - void ShowOnlyType(const std::string_view &showType = "All") { m_ShowType = showType; UpdateGroupsList(); } + void ShowOnlyType(const std::string_view& showType = "All") { + m_ShowType = showType; + UpdateGroupsList(); + } /// /// Sets which DataModule ID should be treated as the native tech of the user of this menu. @@ -108,7 +115,7 @@ namespace RTE { /// /// The name of the group to select in the picker. /// Whether the group was found and switched to successfully. - bool SelectGroupByName(const std::string_view &groupName); + bool SelectGroupByName(const std::string_view& groupName); #pragma endregion #pragma region Object Picking Handling @@ -116,25 +123,33 @@ namespace RTE { /// Gets the next object in the objects list, even if the picker is disabled. /// /// The next object in the picker list, looping around if necessary. If the next object is an invalid SceneObject (e.g. a module subgroup) then this will recurse until a valid object is found. - const SceneObject * GetNextObject() { SelectNextOrPrevObject(false); const SceneObject *object = GetSelectedObject(); return object ? object : GetNextObject(); } + const SceneObject* GetNextObject() { + SelectNextOrPrevObject(false); + const SceneObject* object = GetSelectedObject(); + return object ? object : GetNextObject(); + } /// /// Gets the previous object in the objects list, even if the picker is disabled. /// /// The previous object in the picker list, looping around if necessary. If the previous object is an invalid SceneObject (e.g. a module subgroup) then this will recurse until a valid object is found. - const SceneObject * GetPrevObject() { SelectNextOrPrevObject(true); const SceneObject *object = GetSelectedObject(); return object ? object : GetPrevObject(); } + const SceneObject* GetPrevObject() { + SelectNextOrPrevObject(true); + const SceneObject* object = GetSelectedObject(); + return object ? object : GetPrevObject(); + } /// /// Reports whether and which object has been picked by the player. There may be an object picked even when the player is not done with the picker, as scrolling through objects (but not mousing over them) picks them. /// /// A pointer to the object picked by the player, or nullptr if none was picked. Ownership is NOT transferred! - const SceneObject * ObjectPicked() const { return m_PickedObject; } + const SceneObject* ObjectPicked() const { return m_PickedObject; } /// /// Reports whether the player has finished using the picker, and the final picked object is returned. /// /// The object the player picked before they closed the picker, or nullptr if none was picked. Ownership is NOT transferred!< / returns> - const SceneObject * DonePicking() const { return (!IsEnabled() && m_PickedObject) ? m_PickedObject : nullptr; } + const SceneObject* DonePicking() const { return (!IsEnabled() && m_PickedObject) ? m_PickedObject : nullptr; } #pragma endregion #pragma region Concrete Methods @@ -147,33 +162,40 @@ namespace RTE { /// Draws the ObjectPickerGUI to the specified BITMAP. /// /// The BITMAP to draw on. - void Draw(BITMAP *drawBitmap) const; + void Draw(BITMAP* drawBitmap) const; #pragma endregion private: - /// /// Enumeration for ObjectPicker states when enabling/disabling the ObjectPicker. /// - enum class PickerState { Enabling, Enabled, Disabling, Disabled }; + enum class PickerState { + Enabling, + Enabled, + Disabling, + Disabled + }; /// /// Enumeration for the ObjectPicker columns ListBox focus states. /// - enum class PickerFocus { GroupList, ObjectList }; + enum class PickerFocus { + GroupList, + ObjectList + }; - static BITMAP *s_Cursor; //!< The cursor image shared by all pickers. + static BITMAP* s_Cursor; //!< The cursor image shared by all pickers. std::unique_ptr m_GUIScreen; //!< The GUIScreen interface that will be used by this ObjectPickerGUI's GUIControlManager. std::unique_ptr m_GUIInput; //!< The GUIInput interface that will be used by this ObjectPickerGUI's GUIControlManager. std::unique_ptr m_GUIControlManager; //!< The control manager which holds all the controls. - GUICollectionBox *m_ParentBox; //!< Collection box of the picker GUI. - GUICollectionBox *m_PopupBox; //!< Collection box of the buy popups that contain information about items. - GUILabel *m_PopupText; //!< Label displaying the item popup description. - GUIListBox *m_GroupsList; //!< The ListBox which lists all the groups. - GUIListBox *m_ObjectsList; //!< The ListBox which lists all the objects in the currently selected group. + GUICollectionBox* m_ParentBox; //!< Collection box of the picker GUI. + GUICollectionBox* m_PopupBox; //!< Collection box of the buy popups that contain information about items. + GUILabel* m_PopupText; //!< Label displaying the item popup description. + GUIListBox* m_GroupsList; //!< The ListBox which lists all the groups. + GUIListBox* m_ObjectsList; //!< The ListBox which lists all the objects in the currently selected group. - Controller *m_Controller; //!< Controller which controls this menu. Not owned. + Controller* m_Controller; //!< Controller which controls this menu. Not owned. PickerState m_PickerState; //!< Visibility state of the object picker. PickerFocus m_PickerFocus; //!< The currently focused list in the Picker. @@ -187,7 +209,7 @@ namespace RTE { int m_ShownGroupIndex; //!< Which group in the groups list is currently showing it's objects list. int m_SelectedGroupIndex; //!< Which group in the groups list box we have selected. int m_SelectedObjectIndex; //!< Which object in the objects list box we have selected. - const SceneObject *m_PickedObject; //!< Currently picked object. This may be a valid object even if the player is not done with the picker, as scrolling through objects (but not mousing over them) picks them. Not owned by this. + const SceneObject* m_PickedObject; //!< Currently picked object. This may be a valid object even if the player is not done with the picker, as scrolling through objects (but not mousing over them) picks them. Not owned by this. Timer m_RepeatStartTimer; //!< Measures the time to when to start repeating inputs when they're held down. Timer m_RepeatTimer; //!< Measures the interval between input repeats. @@ -228,7 +250,7 @@ namespace RTE { /// Gets the SceneObject from the currently selected index in the objects list. Ownership is NOT transferred! /// /// The SceneObject of the currently selected index in the objects list. Nullptr if no valid object is selected (eg. a module subgroup). - const SceneObject * GetSelectedObject(); + const SceneObject* GetSelectedObject(); /// /// Selects the specified object index in the objects list. @@ -299,8 +321,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - ObjectPickerGUI(const ObjectPickerGUI &reference) = delete; - ObjectPickerGUI & operator=(const ObjectPickerGUI &rhs) = delete; + ObjectPickerGUI(const ObjectPickerGUI& reference) = delete; + ObjectPickerGUI& operator=(const ObjectPickerGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/PauseMenuGUI.cpp b/Source/Menus/PauseMenuGUI.cpp index d80298547..a748ea4f3 100644 --- a/Source/Menus/PauseMenuGUI.cpp +++ b/Source/Menus/PauseMenuGUI.cpp @@ -21,7 +21,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PauseMenuGUI::Clear() { m_GUIControlManager = nullptr; @@ -49,25 +49,25 @@ namespace RTE { m_PauseMenuButtons.fill(nullptr); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PauseMenuGUI::Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput) { + void PauseMenuGUI::Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput) { m_GUIControlManager = std::make_unique(); RTEAssert(m_GUIControlManager->Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "MainMenuScreenSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuScreenSkin.ini"); m_GUIControlManager->Load("Base.rte/GUIs/PauseMenuGUI.ini"); int rootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); - dynamic_cast(m_GUIControlManager->GetControl("root"))->Resize(rootBoxMaxWidth, g_WindowMan.GetResY()); + dynamic_cast(m_GUIControlManager->GetControl("root"))->Resize(rootBoxMaxWidth, g_WindowMan.GetResY()); - m_PauseMenuBox = dynamic_cast(m_GUIControlManager->GetControl("PauseScreen")); + m_PauseMenuBox = dynamic_cast(m_GUIControlManager->GetControl("PauseScreen")); m_PauseMenuBox->CenterInParent(true, true); - m_PauseMenuButtons[PauseMenuButton::BackToMainButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMain")); - m_PauseMenuButtons[PauseMenuButton::SaveOrLoadGameButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonSaveOrLoadGame")); - m_PauseMenuButtons[PauseMenuButton::SettingsButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonSettings")); - m_PauseMenuButtons[PauseMenuButton::ModManagerButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonModManager")); - m_PauseMenuButtons[PauseMenuButton::ResumeButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonResume")); + m_PauseMenuButtons[PauseMenuButton::BackToMainButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMain")); + m_PauseMenuButtons[PauseMenuButton::SaveOrLoadGameButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonSaveOrLoadGame")); + m_PauseMenuButtons[PauseMenuButton::SettingsButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonSettings")); + m_PauseMenuButtons[PauseMenuButton::ModManagerButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonModManager")); + m_PauseMenuButtons[PauseMenuButton::ResumeButton] = dynamic_cast(m_GUIControlManager->GetControl("ButtonResume")); for (size_t pauseMenuButton = 0; pauseMenuButton < m_PauseMenuButtons.size(); ++pauseMenuButton) { std::string buttonText = m_PauseMenuButtons[pauseMenuButton]->GetText(); @@ -84,7 +84,7 @@ namespace RTE { if (m_BackdropBitmap) { destroy_bitmap(m_BackdropBitmap); } - const BITMAP *backbuffer = g_FrameMan.GetBackBuffer32(); + const BITMAP* backbuffer = g_FrameMan.GetBackBuffer32(); m_BackdropBitmap = create_bitmap_ex(FrameMan::c_BPP, backbuffer->w, backbuffer->h); unsigned int halfTransBlack = makeacol32(0, 0, 0, 96); clear_to_color(m_BackdropBitmap, halfTransBlack); @@ -94,9 +94,9 @@ namespace RTE { m_ModManagerMenu = std::make_unique(guiScreen, guiInput, true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PauseMenuGUI::SetBackButtonTargetName(const std::string &menuName) { + void PauseMenuGUI::SetBackButtonTargetName(const std::string& menuName) { std::string newButtonText = "Back to " + menuName + " Menu"; std::transform(newButtonText.begin(), newButtonText.end(), newButtonText.begin(), ::toupper); @@ -111,17 +111,17 @@ namespace RTE { m_PauseMenuButtons[PauseMenuButton::BackToMainButton]->CenterInParent(true, false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PauseMenuGUI::EnableOrDisablePauseMenuFeatures() { bool disableModManager = true; - if (const Activity *activity = g_ActivityMan.GetActivity(); activity) { + if (const Activity* activity = g_ActivityMan.GetActivity(); activity) { disableModManager = activity->GetClassName() != "GAScripted"; } if (m_ModManagerButtonDisabled != disableModManager) { - GUIButton *modManagerButton = m_PauseMenuButtons[PauseMenuButton::ModManagerButton]; + GUIButton* modManagerButton = m_PauseMenuButtons[PauseMenuButton::ModManagerButton]; modManagerButton->SetEnabled(!disableModManager); modManagerButton->SetVisible(!disableModManager); @@ -135,7 +135,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PauseMenuGUI::SetActiveMenuScreen(PauseMenuScreen screenToShow, bool playButtonPressSound) { if (screenToShow != m_ActiveMenuScreen) { @@ -149,7 +149,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// PauseMenuGUI::PauseMenuUpdateResult PauseMenuGUI::Update() { m_UpdateResult = PauseMenuUpdateResult::NoEvent; @@ -183,7 +183,7 @@ namespace RTE { return m_UpdateResult; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PauseMenuGUI::HandleBackNavigation(bool backButtonPressed) { if (!m_ActiveDialogBox && (backButtonPressed || g_UInputMan.KeyPressed(SDLK_ESCAPE))) { @@ -205,14 +205,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool PauseMenuGUI::HandleInputEvents() { if (m_ActiveMenuScreen == PauseMenuScreen::MainScreen) { int mousePosX; int mousePosY; m_GUIControlManager->GetManager()->GetInputController()->GetMousePosition(&mousePosX, &mousePosY); - UpdateHoveredButton(dynamic_cast(m_GUIControlManager->GetControlUnderPoint(mousePosX, mousePosY, m_PauseMenuBox, 1))); + UpdateHoveredButton(dynamic_cast(m_GUIControlManager->GetControlUnderPoint(mousePosX, mousePosY, m_PauseMenuBox, 1))); } m_GUIControlManager->Update(); @@ -232,16 +232,16 @@ namespace RTE { m_UpdateResult = PauseMenuUpdateResult::BackToMain; } } - if (guiEvent.GetType() == GUIEvent::Notification && (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl()))) { + if (guiEvent.GetType() == GUIEvent::Notification && (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl()))) { g_GUISound.SelectionChangeSound()->Play(); } } return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PauseMenuGUI::UpdateHoveredButton(const GUIButton *hoveredButton) { + void PauseMenuGUI::UpdateHoveredButton(const GUIButton* hoveredButton) { int hoveredButtonIndex = -1; if (hoveredButton) { hoveredButtonIndex = std::distance(m_PauseMenuButtons.begin(), std::find(m_PauseMenuButtons.begin(), m_PauseMenuButtons.end(), hoveredButton)); @@ -261,7 +261,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PauseMenuGUI::BlinkResumeButton() { if (m_HoveredButton && m_HoveredButton == m_PauseMenuButtons[PauseMenuButton::ResumeButton]) { @@ -271,7 +271,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PauseMenuGUI::Draw() { g_WindowMan.DrawPostProcessBuffer(); @@ -298,4 +298,4 @@ namespace RTE { } m_GUIControlManager->DrawMouse(); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/PauseMenuGUI.h b/Source/Menus/PauseMenuGUI.h index f1278b723..98e1f0b29 100644 --- a/Source/Menus/PauseMenuGUI.h +++ b/Source/Menus/PauseMenuGUI.h @@ -22,7 +22,6 @@ namespace RTE { class PauseMenuGUI { public: - /// /// Enumeration for the results of the PauseMenuGUI input and event update. /// @@ -38,14 +37,17 @@ namespace RTE { /// /// Pointer to a GUIScreen interface that will be used by this PauseMenuGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this PauseMenuGUI's GUIControlManager. Ownership is NOT transferred! - PauseMenuGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput) { Clear(); Create(guiScreen, guiInput); } + PauseMenuGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput) { + Clear(); + Create(guiScreen, guiInput); + } /// /// Makes the PauseMenuGUI object ready for use. /// /// Pointer to a GUIScreen interface that will be used by this PauseMenuGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this PauseMenuGUI's GUIControlManager. Ownership is NOT transferred! - void Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput); + void Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput); #pragma endregion #pragma region Setters @@ -53,7 +55,7 @@ namespace RTE { /// Sets the "Back to Main Menu" button text to the menu we will be going back to. /// /// The target menu name, e.g. "Conquest" will result in "Back to Conquest Menu". - void SetBackButtonTargetName(const std::string &menuName); + void SetBackButtonTargetName(const std::string& menuName); #pragma endregion #pragma region Concrete Methods @@ -75,7 +77,6 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for the different sub-menu screens of the pause menu. /// @@ -100,9 +101,9 @@ namespace RTE { }; std::unique_ptr m_GUIControlManager; //!< The GUIControlManager which owns all the GUIControls of the PauseMenuGUI. - GUICollectionBox *m_ActiveDialogBox; // The currently active GUICollectionBox in any of the pause menu screens that acts as a dialog box and requires drawing an overlay. + GUICollectionBox* m_ActiveDialogBox; // The currently active GUICollectionBox in any of the pause menu screens that acts as a dialog box and requires drawing an overlay. - BITMAP *m_BackdropBitmap; ///!< Bitmap to store half transparent black overlay. + BITMAP* m_BackdropBitmap; ///!< Bitmap to store half transparent black overlay. PauseMenuScreen m_ActiveMenuScreen; //!< The currently active pause menu screen that is being updated and drawn to the screen. See PauseMenuScreen enumeration. PauseMenuUpdateResult m_UpdateResult; //!< The result of the PauseMenuGUI update. See PauseMenuUpdateResult enumeration. @@ -117,7 +118,7 @@ namespace RTE { // Right now the way this works is the font graphic has different character visuals for uppercase and lowercase and the visual change happens by applying the appropriate case string when hovering/unhovering. std::array m_ButtonHoveredText; //!< Array containing uppercase strings of the pause menu buttons text that are used to display the larger font when a button is hovered over. std::array m_ButtonUnhoveredText; //!< Array containing lowercase strings of the pause menu buttons text that are used to display the smaller font when a button is not hovered over. - GUIButton *m_HoveredButton; //!< The currently hovered pause menu button. + GUIButton* m_HoveredButton; //!< The currently hovered pause menu button. int m_PrevHoveredButtonIndex; //!< The index of the previously hovered pause menu button in the main menu button array. bool m_SavingButtonsDisabled; //!< Whether the save and load buttons are disabled and hidden. @@ -126,8 +127,8 @@ namespace RTE { /// /// GUI elements that compose the pause menu screen. /// - GUICollectionBox *m_PauseMenuBox; - std::array m_PauseMenuButtons; + GUICollectionBox* m_PauseMenuBox; + std::array m_PauseMenuButtons; #pragma region Menu Screen Handling /// @@ -155,7 +156,7 @@ namespace RTE { /// Updates the currently hovered button text to give the hovered visual and updates the previously hovered button to remove the hovered visual. /// /// Pointer to the currently hovered button, if any. Acquired by GUIControlManager::GetControlUnderPoint. - void UpdateHoveredButton(const GUIButton *hoveredButton); + void UpdateHoveredButton(const GUIButton* hoveredButton); /// /// Animates (blinking) the resume game button. @@ -169,8 +170,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - PauseMenuGUI(const PauseMenuGUI &reference) = delete; - PauseMenuGUI & operator=(const PauseMenuGUI &rhs) = delete; + PauseMenuGUI(const PauseMenuGUI& reference) = delete; + PauseMenuGUI& operator=(const PauseMenuGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SaveLoadMenuGUI.cpp b/Source/Menus/SaveLoadMenuGUI.cpp index 7dd7aaa75..1a39491e5 100644 --- a/Source/Menus/SaveLoadMenuGUI.cpp +++ b/Source/Menus/SaveLoadMenuGUI.cpp @@ -21,19 +21,19 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SaveLoadMenuGUI::SaveLoadMenuGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu) { + SaveLoadMenuGUI::SaveLoadMenuGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool createForPauseMenu) { m_GUIControlManager = std::make_unique(); RTEAssert(m_GUIControlManager->Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "MainMenuSubMenuSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuSubMenuSkin.ini"); m_GUIControlManager->Load("Base.rte/GUIs/SaveLoadMenuGUI.ini"); int rootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); - GUICollectionBox *rootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); + GUICollectionBox* rootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); rootBox->Resize(rootBoxMaxWidth, g_WindowMan.GetResY()); - m_SaveGameMenuBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSaveGameMenu")); + m_SaveGameMenuBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSaveGameMenu")); m_SaveGameMenuBox->CenterInParent(true, true); m_SaveGameMenuBox->SetPositionAbs(m_SaveGameMenuBox->GetXPos(), (rootBox->GetHeight() < 540) ? m_SaveGameMenuBox->GetYPos() - 15 : 140); @@ -41,9 +41,9 @@ namespace RTE { m_OrderByComboBox->AddItem("Name"); m_OrderByComboBox->AddItem("Date"); m_OrderByComboBox->AddItem("Activity"); - m_OrderByComboBox->SetSelectedIndex(1); //order by Date by default + m_OrderByComboBox->SetSelectedIndex(1); // order by Date by default - m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMainMenu")); + m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMainMenu")); if (createForPauseMenu) { m_BackToMainButton->SetSize(120, 20); @@ -51,39 +51,39 @@ namespace RTE { } m_BackToMainButton->SetPositionAbs((rootBox->GetWidth() - m_BackToMainButton->GetWidth()) / 2, m_SaveGameMenuBox->GetYPos() + m_SaveGameMenuBox->GetHeight() + 10); - m_SaveGamesListBox = dynamic_cast(m_GUIControlManager->GetControl("ListBoxSaveGames")); + m_SaveGamesListBox = dynamic_cast(m_GUIControlManager->GetControl("ListBoxSaveGames")); m_SaveGamesListBox->SetFont(m_GUIControlManager->GetSkin()->GetFont("FontConsoleMonospace.png")); m_SaveGamesListBox->SetMouseScrolling(true); m_SaveGamesListBox->SetScrollBarThickness(15); m_SaveGamesListBox->SetScrollBarPadding(2); - m_SaveGameName = dynamic_cast(m_GUIControlManager->GetControl("SaveGameName")); - m_LoadButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonLoad")); - m_CreateButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCreate")); - m_OverwriteButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonOverwrite")); - m_DeleteButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonDelete")); - m_ActivityCannotBeSavedLabel = dynamic_cast(m_GUIControlManager->GetControl("ActivityCannotBeSavedWarning")); + m_SaveGameName = dynamic_cast(m_GUIControlManager->GetControl("SaveGameName")); + m_LoadButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonLoad")); + m_CreateButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCreate")); + m_OverwriteButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonOverwrite")); + m_DeleteButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonDelete")); + m_ActivityCannotBeSavedLabel = dynamic_cast(m_GUIControlManager->GetControl("ActivityCannotBeSavedWarning")); - m_ConfirmationBox = dynamic_cast(m_GUIControlManager->GetControl("ConfirmDialog")); + m_ConfirmationBox = dynamic_cast(m_GUIControlManager->GetControl("ConfirmDialog")); m_ConfirmationBox->CenterInParent(true, true); - m_ConfirmationLabel = dynamic_cast(m_GUIControlManager->GetControl("ConfirmLabel")); - m_ConfirmationButton = dynamic_cast(m_GUIControlManager->GetControl("ConfirmButton")); - m_CancelButton = dynamic_cast(m_GUIControlManager->GetControl("CancelButton")); + m_ConfirmationLabel = dynamic_cast(m_GUIControlManager->GetControl("ConfirmLabel")); + m_ConfirmationButton = dynamic_cast(m_GUIControlManager->GetControl("ConfirmButton")); + m_CancelButton = dynamic_cast(m_GUIControlManager->GetControl("CancelButton")); SwitchToConfirmDialogMode(ConfirmDialogMode::None); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SaveLoadMenuGUI::PopulateSaveGamesList() { m_SaveGames.clear(); m_SaveGameName->SetText(""); - + m_GUIControlManager->GetManager()->SetFocus(nullptr); std::string saveFilePath = g_PresetMan.GetFullModulePath(c_UserScriptedSavesModuleName) + "/"; - for (const auto &entry : std::filesystem::directory_iterator(saveFilePath)) { + for (const auto& entry: std::filesystem::directory_iterator(saveFilePath)) { if (entry.is_directory()) { SaveRecord record; record.SavePath = entry.path(); @@ -93,42 +93,41 @@ namespace RTE { } std::for_each(std::execution::par_unseq, - m_SaveGames.begin(), m_SaveGames.end(), - [](SaveRecord &record) { - Reader reader(record.SavePath.string() + "/Save.ini", true, nullptr, true); - - bool readActivity = false; - bool readSceneName = false; - - GAScripted activity; - - std::string originalScenePresetName; - while (reader.NextProperty()) { - std::string propName = reader.ReadPropName(); - if (propName == "Activity") { - reader >> activity; - readActivity = true; - } else if (propName == "OriginalScenePresetName") { - reader >> originalScenePresetName; - readSceneName = true; - } - - if (readActivity && readSceneName) { - break; - } - } - - record.Activity = activity.GetPresetName(); - record.Scene = originalScenePresetName; - }); + m_SaveGames.begin(), m_SaveGames.end(), + [](SaveRecord& record) { + Reader reader(record.SavePath.string() + "/Save.ini", true, nullptr, true); + + bool readActivity = false; + bool readSceneName = false; + + GAScripted activity; + + std::string originalScenePresetName; + while (reader.NextProperty()) { + std::string propName = reader.ReadPropName(); + if (propName == "Activity") { + reader >> activity; + readActivity = true; + } else if (propName == "OriginalScenePresetName") { + reader >> originalScenePresetName; + readSceneName = true; + } + + if (readActivity && readSceneName) { + break; + } + } + + record.Activity = activity.GetPresetName(); + record.Scene = originalScenePresetName; + }); UpdateSaveGamesGUIList(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SaveLoadMenuGUI::UpdateSaveGamesGUIList() - { + void SaveLoadMenuGUI::UpdateSaveGamesGUIList() { const std::string& currentOrder = m_OrderByComboBox->GetSelectedItem()->m_Name; if (currentOrder == "Name") { std::stable_sort(m_SaveGames.begin(), m_SaveGames.end(), [](const SaveRecord& lhs, const SaveRecord& rhs) { return lhs.SavePath.stem().string() < rhs.SavePath.stem().string(); }); @@ -140,7 +139,7 @@ namespace RTE { m_SaveGamesListBox->ClearList(); for (int i = 0; i < m_SaveGames.size(); i++) { - const SaveRecord &save = m_SaveGames[i]; + const SaveRecord& save = m_SaveGames[i]; std::stringstream saveNameText; saveNameText << std::left << std::setfill(' ') << std::setw(32) << save.SavePath.stem().string(); @@ -149,16 +148,16 @@ namespace RTE { #if defined(_MSC_VER) || __GNUC__ > 12 const auto saveFsTime = std::chrono::clock_cast(save.SaveDate); const auto saveTime = std::chrono::system_clock::to_time_t(saveFsTime); -#else +#else // TODO - kill this monstrosity when we move to GCC13 auto saveFsTime = std::chrono::system_clock::time_point(save.SaveDate.time_since_epoch()); - #ifdef _WIN32 +#ifdef _WIN32 // Windows epoch time are the number of seconds since... 1601-01-01 00:00:00. Seriously. saveFsTime -= std::chrono::seconds(11644473600LL); - #elif defined(__GLIBCXX__) +#elif defined(__GLIBCXX__) // libstdc++ file_clock epoch is 2174-01-01 00:00:00 for reasons saveFsTime += std::chrono::seconds(6437664000LL); - #endif +#endif const auto saveTime = std::chrono::system_clock::to_time_t(saveFsTime); #endif const auto saveTimeLocal = std::localtime(&saveTime); @@ -172,7 +171,7 @@ namespace RTE { m_SaveGamesListBox->ScrollToTop(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SaveLoadMenuGUI::LoadSave() { bool success = g_ActivityMan.LoadAndLaunchGame(m_SaveGameName->GetText()); @@ -186,7 +185,7 @@ namespace RTE { return success; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SaveLoadMenuGUI::CreateSave() { bool success = g_ActivityMan.SaveCurrentGame(m_SaveGameName->GetText()); @@ -199,7 +198,7 @@ namespace RTE { PopulateSaveGamesList(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SaveLoadMenuGUI::DeleteSave() { std::string saveFilePath = g_PresetMan.GetFullModulePath(c_UserScriptedSavesModuleName) + "/" + m_SaveGameName->GetText(); @@ -210,7 +209,7 @@ namespace RTE { PopulateSaveGamesList(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SaveLoadMenuGUI::UpdateButtonEnabledStates() { bool allowSave = g_ActivityMan.GetActivity() && g_ActivityMan.GetActivity()->GetAllowsUserSaving() && m_SaveGameName->GetText() != ""; @@ -243,7 +242,7 @@ namespace RTE { m_ActivityCannotBeSavedLabel->SetVisible(g_ActivityMan.GetActivity() && !g_ActivityMan.GetActivity()->GetAllowsUserSaving()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SaveLoadMenuGUI::SwitchToConfirmDialogMode(ConfirmDialogMode mode) { m_ConfirmDialogMode = mode; @@ -254,18 +253,18 @@ namespace RTE { m_ConfirmationBox->SetVisible(dialogOpen); switch (m_ConfirmDialogMode) { - case ConfirmDialogMode::ConfirmOverwrite: - m_ConfirmationLabel->SetText("Are you sure you want to overwrite this savegame?"); - break; - case ConfirmDialogMode::ConfirmDelete: - m_ConfirmationLabel->SetText("Are you sure you want to delete this savegame?"); - break; + case ConfirmDialogMode::ConfirmOverwrite: + m_ConfirmationLabel->SetText("Are you sure you want to overwrite this savegame?"); + break; + case ConfirmDialogMode::ConfirmDelete: + m_ConfirmationLabel->SetText("Are you sure you want to delete this savegame?"); + break; } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool SaveLoadMenuGUI::HandleInputEvents(PauseMenuGUI *pauseMenu) { + bool SaveLoadMenuGUI::HandleInputEvents(PauseMenuGUI* pauseMenu) { m_GUIControlManager->Update(); GUIEvent guiEvent; @@ -286,24 +285,24 @@ namespace RTE { SwitchToConfirmDialogMode(ConfirmDialogMode::ConfirmDelete); } else if (guiEvent.GetControl() == m_ConfirmationButton) { switch (m_ConfirmDialogMode) { - case ConfirmDialogMode::ConfirmOverwrite: - CreateSave(); - break; - case ConfirmDialogMode::ConfirmDelete: - DeleteSave(); - break; + case ConfirmDialogMode::ConfirmOverwrite: + CreateSave(); + break; + case ConfirmDialogMode::ConfirmDelete: + DeleteSave(); + break; } SwitchToConfirmDialogMode(ConfirmDialogMode::None); } else if (guiEvent.GetControl() == m_CancelButton) { SwitchToConfirmDialogMode(ConfirmDialogMode::None); } } else if (guiEvent.GetType() == GUIEvent::Notification) { - if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl())) { - g_GUISound.SelectionChangeSound()->Play(); + if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl())) { + g_GUISound.SelectionChangeSound()->Play(); } if (guiEvent.GetControl() == m_SaveGamesListBox && (guiEvent.GetMsg() == GUIListBox::Select && m_SaveGamesListBox->GetSelectedIndex() > -1)) { - const SaveRecord &record = m_SaveGames[m_SaveGamesListBox->GetSelected()->m_ExtraIndex]; + const SaveRecord& record = m_SaveGames[m_SaveGamesListBox->GetSelected()->m_ExtraIndex]; m_SaveGameName->SetText(record.SavePath.stem().string()); } @@ -318,16 +317,16 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SaveLoadMenuGUI::Refresh() { PopulateSaveGamesList(); UpdateButtonEnabledStates(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SaveLoadMenuGUI::Draw() const { m_GUIControlManager->Draw(); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/SaveLoadMenuGUI.h b/Source/Menus/SaveLoadMenuGUI.h index 3b95328de..448e7ca3c 100644 --- a/Source/Menus/SaveLoadMenuGUI.h +++ b/Source/Menus/SaveLoadMenuGUI.h @@ -23,7 +23,6 @@ namespace RTE { class SaveLoadMenuGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SaveLoadMenuGUI object in system memory and make it ready for use. @@ -31,7 +30,7 @@ namespace RTE { /// Pointer to a GUIScreen interface that will be used by this SaveLoadMenuGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this SaveLoadMenuGUI's GUIControlManager. Ownership is NOT transferred! /// Whether this SettingsGUI is part of SaveLoadMenuGUI and should have a slightly different layout. - SaveLoadMenuGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu = false); + SaveLoadMenuGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool createForPauseMenu = false); #pragma endregion #pragma region Concrete Methods @@ -40,7 +39,7 @@ namespace RTE { /// /// Pointer to the pause menu, if we're being called from the pause menu. Ownership is NOT transferred! /// Whether the player requested to return to the main menu. - bool HandleInputEvents(PauseMenuGUI *pauseMenu = nullptr); + bool HandleInputEvents(PauseMenuGUI* pauseMenu = nullptr); /// /// Causes a refresh of the save files. @@ -79,23 +78,23 @@ namespace RTE { /// /// GUI elements that compose the Mod Manager menu screen. /// - GUICollectionBox *m_SaveGameMenuBox; - GUIButton *m_BackToMainButton; - GUITextBox *m_SaveGameName; - GUIButton *m_LoadButton; - GUIButton *m_CreateButton; - GUIButton *m_OverwriteButton; - GUIButton *m_DeleteButton; - GUIListBox *m_SaveGamesListBox; - GUILabel *m_ActivityCannotBeSavedLabel; - GUIComboBox *m_OrderByComboBox; + GUICollectionBox* m_SaveGameMenuBox; + GUIButton* m_BackToMainButton; + GUITextBox* m_SaveGameName; + GUIButton* m_LoadButton; + GUIButton* m_CreateButton; + GUIButton* m_OverwriteButton; + GUIButton* m_DeleteButton; + GUIListBox* m_SaveGamesListBox; + GUILabel* m_ActivityCannotBeSavedLabel; + GUIComboBox* m_OrderByComboBox; // The confirmation box and its controls ConfirmDialogMode m_ConfirmDialogMode; - GUICollectionBox *m_ConfirmationBox; - GUILabel *m_ConfirmationLabel; + GUICollectionBox* m_ConfirmationBox; + GUILabel* m_ConfirmationLabel; GUIButton* m_ConfirmationButton; - GUIButton *m_CancelButton; + GUIButton* m_CancelButton; #pragma region Savegame Handling /// @@ -142,8 +141,8 @@ namespace RTE { void SwitchToConfirmDialogMode(ConfirmDialogMode mode); // Disallow the use of some implicit methods. - SaveLoadMenuGUI(const SaveLoadMenuGUI &reference) = delete; - SaveLoadMenuGUI & operator=(const SaveLoadMenuGUI &rhs) = delete; + SaveLoadMenuGUI(const SaveLoadMenuGUI& reference) = delete; + SaveLoadMenuGUI& operator=(const SaveLoadMenuGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/ScenarioActivityConfigGUI.cpp b/Source/Menus/ScenarioActivityConfigGUI.cpp index f73b40c94..272fda0dd 100644 --- a/Source/Menus/ScenarioActivityConfigGUI.cpp +++ b/Source/Menus/ScenarioActivityConfigGUI.cpp @@ -19,56 +19,57 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ScenarioActivityConfigGUI::ScenarioActivityConfigGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { - m_ActivityConfigBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxActivityConfig")); + ScenarioActivityConfigGUI::ScenarioActivityConfigGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { + m_ActivityConfigBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxActivityConfig")); m_ActivityConfigBox->CenterInParent(true, true); m_ActivityConfigBox->SetVisible(false); - m_CancelConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCancelConfig")); + m_CancelConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCancelConfig")); - m_ActivityDifficultyLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelActivityDifficultyValue")); - m_ActivityDifficultySlider = dynamic_cast(m_GUIControlManager->GetControl("SliderActivityDifficulty")); - m_StartingGoldLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelStartingGoldValue")); - m_StartingGoldSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderStartingGold")); + m_ActivityDifficultyLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelActivityDifficultyValue")); + m_ActivityDifficultySlider = dynamic_cast(m_GUIControlManager->GetControl("SliderActivityDifficulty")); + m_StartingGoldLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelStartingGoldValue")); + m_StartingGoldSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderStartingGold")); - m_RequireClearPathToOrbitCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxRequireClearPathToOrbit")); - m_FogOfWarCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxFogOfWar")); - m_DeployUnitsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxDeployUnits")); + m_RequireClearPathToOrbitCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxRequireClearPathToOrbit")); + m_FogOfWarCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxFogOfWar")); + m_DeployUnitsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxDeployUnits")); - m_PlayersAndTeamsConfigBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPlayersAndTeamsConfig")); - m_TeamIconBoxes[TeamRows::DisabledTeam] = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxDisabledTeamIcon")); - m_TeamNameLabels[TeamRows::DisabledTeam] = dynamic_cast(m_GUIControlManager->GetControl("LabelDisabledTeam")); + m_PlayersAndTeamsConfigBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPlayersAndTeamsConfig")); + m_TeamIconBoxes[TeamRows::DisabledTeam] = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxDisabledTeamIcon")); + m_TeamNameLabels[TeamRows::DisabledTeam] = dynamic_cast(m_GUIControlManager->GetControl("LabelDisabledTeam")); - GUILabel *teamTechLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelTeamTech")); + GUILabel* teamTechLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelTeamTech")); for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { std::string teamNumber = std::to_string(team + 1); - m_TeamIconBoxes[team] = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxTeam" + teamNumber + "Icon")); - m_TeamNameLabels[team] = dynamic_cast(m_GUIControlManager->GetControl("LabelTeam" + teamNumber)); + m_TeamIconBoxes[team] = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxTeam" + teamNumber + "Icon")); + m_TeamNameLabels[team] = dynamic_cast(m_GUIControlManager->GetControl("LabelTeam" + teamNumber)); - m_TeamTechComboBoxes[team] = dynamic_cast(m_GUIControlManager->GetControl("ComboBoxTeam" + teamNumber + "Tech")); + m_TeamTechComboBoxes[team] = dynamic_cast(m_GUIControlManager->GetControl("ComboBoxTeam" + teamNumber + "Tech")); m_TeamTechComboBoxes[team]->Move(teamTechLabel->GetXPos(), teamTechLabel->GetYPos() + teamTechLabel->GetHeight() + 5 + (25 * (team + 1))); m_TeamTechComboBoxes[team]->SetVisible(false); - m_TeamAISkillSliders[team] = dynamic_cast(m_GUIControlManager->GetControl("SliderTeam" + teamNumber + "AISkill")); + m_TeamAISkillSliders[team] = dynamic_cast(m_GUIControlManager->GetControl("SliderTeam" + teamNumber + "AISkill")); m_TeamAISkillSliders[team]->SetValue(Activity::AISkillSetting::DefaultSkill); - m_TeamAISkillLabels[team] = dynamic_cast(m_GUIControlManager->GetControl("LabelTeam" + teamNumber + "AISkill")); + m_TeamAISkillLabels[team] = dynamic_cast(m_GUIControlManager->GetControl("LabelTeam" + teamNumber + "AISkill")); m_TeamAISkillLabels[team]->SetText(Activity::GetAISkillString(m_TeamAISkillSliders[team]->GetValue())); } for (int player = Players::PlayerOne; player < PlayerColumns::PlayerColumnCount; ++player) { for (int team = Activity::Teams::TeamOne; team < TeamRows::TeamRowCount; ++team) { - m_PlayerBoxes[player][team] = dynamic_cast(m_GUIControlManager->GetControl("P" + std::to_string(player + 1) + "T" + std::to_string(team + 1) + "Box")); + m_PlayerBoxes[player][team] = dynamic_cast(m_GUIControlManager->GetControl("P" + std::to_string(player + 1) + "T" + std::to_string(team + 1) + "Box")); } } - m_CPULockLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelCPUTeamLock")); - m_StartErrorLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelStartError")); - m_StartGameButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonStartGame")); + m_CPULockLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelCPUTeamLock")); + m_StartErrorLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelStartError")); + m_StartGameButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonStartGame")); m_TechListFetched = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioActivityConfigGUI::PopulateTechComboBoxes() { for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { @@ -76,7 +77,7 @@ namespace RTE { m_TeamTechComboBoxes[team]->GetListPanel()->AddItem("-Random-", "", nullptr, nullptr, -1); } for (int moduleID = 0; moduleID < g_PresetMan.GetTotalModuleCount(); ++moduleID) { - if (const DataModule *dataModule = g_PresetMan.GetDataModule(moduleID)) { + if (const DataModule* dataModule = g_PresetMan.GetDataModule(moduleID)) { if (dataModule->IsFaction()) { for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { m_TeamTechComboBoxes[team]->GetListPanel()->AddItem(dataModule->GetFriendlyName(), "", nullptr, nullptr, moduleID); @@ -89,21 +90,21 @@ namespace RTE { m_TechListFetched = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ScenarioActivityConfigGUI::IsEnabled() const { return m_ActivityConfigBox->GetEnabled() && m_ActivityConfigBox->GetVisible(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioActivityConfigGUI::SetEnabled(bool enable, const Activity *selectedActivity, Scene *selectedScene) { + void ScenarioActivityConfigGUI::SetEnabled(bool enable, const Activity* selectedActivity, Scene* selectedScene) { m_ActivityConfigBox->SetEnabled(enable); m_ActivityConfigBox->SetVisible(enable); bool selectingPreviousActivityWithManuallyAdjustedGold = m_StartingGoldAdjustedManually && m_PreviouslySelectedActivity == selectedActivity; if (enable) { - m_SelectedActivity = dynamic_cast(selectedActivity); + m_SelectedActivity = dynamic_cast(selectedActivity); m_SelectedScene = selectedScene; RTEAssert(m_SelectedActivity && m_SelectedScene, "Trying to start a scenario game without an Activity or a Scene!"); } else { @@ -116,7 +117,9 @@ namespace RTE { m_TeamTechComboBoxes[team]->SetVisible(enable); } if (enable && m_SelectedActivity && m_SelectedScene) { - if (!m_TechListFetched) { PopulateTechComboBoxes(); } + if (!m_TechListFetched) { + PopulateTechComboBoxes(); + } int startingGoldOverride = selectingPreviousActivityWithManuallyAdjustedGold ? m_StartingGoldSlider->GetValue() : -1; ResetActivityConfigBox(); @@ -129,7 +132,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioActivityConfigGUI::ResetActivityConfigBox() { m_ActivityDifficultyLabel->SetText(" " + Activity::GetDifficultyString(m_ActivityDifficultySlider->GetValue())); @@ -156,7 +159,9 @@ namespace RTE { m_PlayerBoxes[player][team]->SetDrawColor(c_GUIColorBlue); } if (player < Players::MaxPlayerCount) { - if (const Icon *playerDeviceIcon = g_UInputMan.GetSchemeIcon(player)) { m_PlayerBoxes[player][TeamRows::DisabledTeam]->SetDrawImage(new AllegroBitmap(playerDeviceIcon->GetBitmaps32()[0])); } + if (const Icon* playerDeviceIcon = g_UInputMan.GetSchemeIcon(player)) { + m_PlayerBoxes[player][TeamRows::DisabledTeam]->SetDrawImage(new AllegroBitmap(playerDeviceIcon->GetBitmaps32()[0])); + } m_PlayerBoxes[player][TeamRows::DisabledTeam]->SetDrawType(GUICollectionBox::Image); } else { int cpuInitialTeam = TeamRows::DisabledTeam; @@ -169,33 +174,41 @@ namespace RTE { m_CPULockLabel->SetVisible(false); } m_PlayerBoxes.at(player).at(cpuInitialTeam)->SetDrawType(GUICollectionBox::Image); - if (const Icon *cpuIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU"))) { m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(cpuInitialTeam)->SetDrawImage(new AllegroBitmap(cpuIcon->GetBitmaps32()[0])); } + if (const Icon* cpuIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU"))) { + m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(cpuInitialTeam)->SetDrawImage(new AllegroBitmap(cpuIcon->GetBitmaps32()[0])); + } } } for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { - const Icon *teamIcon = nullptr; + const Icon* teamIcon = nullptr; if (m_SelectedActivity->TeamActive(team)) { teamIcon = m_SelectedActivity->GetTeamIcon(team); - if (!teamIcon) { teamIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Team " + std::to_string(team + 1) + " Default")); } + if (!teamIcon) { + teamIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Team " + std::to_string(team + 1) + " Default")); + } m_TeamNameLabels.at(team)->SetText(m_SelectedActivity->GetTeamName(team)); } else { - teamIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Locked Team")); + teamIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Locked Team")); m_TeamNameLabels.at(team)->SetText("Unavailable"); } - if (teamIcon) { m_TeamIconBoxes.at(team)->SetDrawImage(new AllegroBitmap(teamIcon->GetBitmaps32()[0])); } + if (teamIcon) { + m_TeamIconBoxes.at(team)->SetDrawImage(new AllegroBitmap(teamIcon->GetBitmaps32()[0])); + } m_TeamTechComboBoxes.at(team)->SetVisible(m_SelectedActivity->TeamActive(team)); m_TeamAISkillSliders.at(team)->SetVisible(m_SelectedActivity->TeamActive(team)); m_TeamAISkillLabels.at(team)->SetVisible(m_SelectedActivity->TeamActive(team)); } - if (const Icon *disabledTeamIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Disabled Team"))) { m_TeamIconBoxes.at(TeamRows::DisabledTeam)->SetDrawImage(new AllegroBitmap(disabledTeamIcon->GetBitmaps32()[0])); } + if (const Icon* disabledTeamIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Disabled Team"))) { + m_TeamIconBoxes.at(TeamRows::DisabledTeam)->SetDrawImage(new AllegroBitmap(disabledTeamIcon->GetBitmaps32()[0])); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioActivityConfigGUI::StartGame() { - GameActivity *gameActivity = dynamic_cast(m_SelectedActivity->Clone()); + GameActivity* gameActivity = dynamic_cast(m_SelectedActivity->Clone()); gameActivity->SetDifficulty(m_ActivityDifficultySlider->GetValue()); gameActivity->SetStartingGold((m_StartingGoldSlider->GetValue() == m_StartingGoldSlider->GetMaximum()) ? 1000000000 : static_cast(std::floor(m_StartingGoldSlider->GetValue()))); @@ -219,7 +232,7 @@ namespace RTE { } for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; ++team) { - if (const GUIListPanel::Item *techItem = m_TeamTechComboBoxes.at(team)->GetSelectedItem()) { + if (const GUIListPanel::Item* techItem = m_TeamTechComboBoxes.at(team)->GetSelectedItem()) { if (techItem->m_ExtraIndex == -2) { gameActivity->SetTeamTech(team, "-All-"); } else if (techItem->m_ExtraIndex == -1) { @@ -234,7 +247,7 @@ namespace RTE { g_ActivityMan.SetStartActivity(gameActivity); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ScenarioActivityConfigGUI::Update(int mouseX, int mouseY) { UpdatePlayerTeamSetupCell(mouseX, mouseY); @@ -254,7 +267,9 @@ namespace RTE { } } } - if (foundPlayer) { teamsWithPlayers++; } + if (foundPlayer) { + teamsWithPlayers++; + } } } @@ -273,12 +288,14 @@ namespace RTE { m_StartErrorLabel->SetVisible(!errorMessage.empty()); m_StartGameButton->SetVisible(errorMessage.empty()); - if (m_StartGameButton->GetVisible()) { m_GUIControlManager->GetManager()->SetFocus(m_StartGameButtonBlinkTimer.AlternateReal(500) ? m_StartGameButton : nullptr); } + if (m_StartGameButton->GetVisible()) { + m_GUIControlManager->GetManager()->SetFocus(m_StartGameButtonBlinkTimer.AlternateReal(500) ? m_StartGameButton : nullptr); + } return HandleInputEvents(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioActivityConfigGUI::UpdateStartingGoldSliderAndLabel() { if (!m_StartingGoldAdjustedManually) { @@ -310,10 +327,10 @@ namespace RTE { m_StartingGoldLabel->SetText(goldString); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioActivityConfigGUI::UpdatePlayerTeamSetupCell(int mouseX, int mouseY) { - if (const GUICollectionBox *hoveredCell = dynamic_cast(m_GUIControlManager->GetControlUnderPoint(mouseX, mouseY, m_PlayersAndTeamsConfigBox, 1))) { + if (const GUICollectionBox* hoveredCell = dynamic_cast(m_GUIControlManager->GetControlUnderPoint(mouseX, mouseY, m_PlayersAndTeamsConfigBox, 1))) { int hoveredPlayer = PlayerColumns::PlayerColumnCount; int hoveredTeam = TeamRows::TeamRowCount; for (int player = Players::PlayerOne; player < PlayerColumns::PlayerColumnCount; ++player) { @@ -337,12 +354,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioActivityConfigGUI::HandleClickOnPlayerTeamSetupCell(int clickedPlayer, int clickedTeam) { m_PlayerBoxes.at(clickedPlayer).at(clickedTeam)->SetDrawType(GUICollectionBox::Image); - const Icon *playerIcon = (clickedPlayer != PlayerColumns::PlayerCPU) ? g_UInputMan.GetSchemeIcon(clickedPlayer) : dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); - if (playerIcon) { m_PlayerBoxes.at(clickedPlayer).at(clickedTeam)->SetDrawImage(new AllegroBitmap(playerIcon->GetBitmaps32()[0])); } + const Icon* playerIcon = (clickedPlayer != PlayerColumns::PlayerCPU) ? g_UInputMan.GetSchemeIcon(clickedPlayer) : dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); + if (playerIcon) { + m_PlayerBoxes.at(clickedPlayer).at(clickedTeam)->SetDrawImage(new AllegroBitmap(playerIcon->GetBitmaps32()[0])); + } if (clickedPlayer == PlayerColumns::PlayerCPU) { if (clickedTeam == TeamRows::DisabledTeam) { @@ -371,7 +390,9 @@ namespace RTE { m_PlayerBoxes.at(humanPlayer).at(clickedTeam)->SetDrawColor(c_GUIColorBlue); m_PlayerBoxes.at(humanPlayer).at(TeamRows::DisabledTeam)->SetDrawType(GUICollectionBox::Image); playerIcon = g_UInputMan.GetSchemeIcon(humanPlayer); - if (playerIcon) { m_PlayerBoxes.at(humanPlayer).at(TeamRows::DisabledTeam)->SetDrawImage(new AllegroBitmap(playerIcon->GetBitmaps32()[0])); } + if (playerIcon) { + m_PlayerBoxes.at(humanPlayer).at(TeamRows::DisabledTeam)->SetDrawImage(new AllegroBitmap(playerIcon->GetBitmaps32()[0])); + } } } } else if (clickedPlayer != PlayerColumns::PlayerCPU && clickedTeam != TeamRows::DisabledTeam && m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(clickedTeam)->GetDrawType() == GUICollectionBox::Image) { @@ -380,18 +401,22 @@ namespace RTE { int cpuTeamCount = 0; for (int teamToCount = Activity::Teams::TeamOne; teamToCount < TeamRows::DisabledTeam; ++teamToCount) { - if (m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(teamToCount)->GetDrawType() == GUICollectionBox::Image) { cpuTeamCount++; } + if (m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(teamToCount)->GetDrawType() == GUICollectionBox::Image) { + cpuTeamCount++; + } } if (cpuTeamCount == 0) { m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(TeamRows::DisabledTeam)->SetDrawType(GUICollectionBox::Image); - playerIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); - if (playerIcon) { m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(TeamRows::DisabledTeam)->SetDrawImage(new AllegroBitmap(playerIcon->GetBitmaps32()[0])); } + playerIcon = dynamic_cast(g_PresetMan.GetEntityPreset("Icon", "Device CPU")); + if (playerIcon) { + m_PlayerBoxes.at(PlayerColumns::PlayerCPU).at(TeamRows::DisabledTeam)->SetDrawImage(new AllegroBitmap(playerIcon->GetBitmaps32()[0])); + } } } g_GUISound.FocusChangeSound()->Play(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ScenarioActivityConfigGUI::HandleInputEvents() { GUIEvent guiEvent; @@ -409,13 +434,19 @@ namespace RTE { } else if (guiEvent.GetType() == GUIEvent::Notification) { if (guiEvent.GetControl() == m_ActivityDifficultySlider) { m_ActivityDifficultyLabel->SetText(" " + Activity::GetDifficultyString(m_ActivityDifficultySlider->GetValue())); - if (!m_StartingGoldAdjustedManually) { UpdateStartingGoldSliderAndLabel(); } + if (!m_StartingGoldAdjustedManually) { + UpdateStartingGoldSliderAndLabel(); + } } else if (guiEvent.GetControl() == m_StartingGoldSlider) { - if (guiEvent.GetMsg() == GUISlider::Clicked) { m_StartingGoldAdjustedManually = true; } + if (guiEvent.GetMsg() == GUISlider::Clicked) { + m_StartingGoldAdjustedManually = true; + } UpdateStartingGoldSliderAndLabel(); } else if (guiEvent.GetMsg() == GUISlider::Changed) { for (int team = Activity::Teams::TeamOne; team < Activity::Teams::MaxTeamCount; team++) { - if (guiEvent.GetControl() == m_TeamAISkillSliders.at(team)) { m_TeamAISkillLabels.at(team)->SetText(Activity::GetAISkillString(m_TeamAISkillSliders.at(team)->GetValue())); } + if (guiEvent.GetControl() == m_TeamAISkillSliders.at(team)) { + m_TeamAISkillLabels.at(team)->SetText(Activity::GetAISkillString(m_TeamAISkillSliders.at(team)->GetValue())); + } } } } @@ -423,7 +454,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioActivityConfigGUI::Draw() { m_GUIControlManager->Draw(); @@ -451,7 +482,9 @@ namespace RTE { for (int team = Activity::Teams::MaxTeamCount - 1; team >= Activity::Teams::TeamOne; --team) { if (m_TeamTechComboBoxes.at(team)->GetVisible()) { m_TeamTechComboBoxes.at(team)->Draw(m_GUIControlManager->GetScreen()); - if (m_TeamTechComboBoxes.at(team)->IsDropped()) { m_TeamTechComboBoxes.at(team)->GetListPanel()->Draw(m_GUIControlManager->GetScreen()); } + if (m_TeamTechComboBoxes.at(team)->IsDropped()) { + m_TeamTechComboBoxes.at(team)->GetListPanel()->Draw(m_GUIControlManager->GetScreen()); + } } if (m_TeamAISkillSliders.at(team)->GetVisible()) { m_TeamAISkillSliders.at(team)->Draw(m_GUIControlManager->GetScreen()); @@ -459,4 +492,4 @@ namespace RTE { } } } -} +} // namespace RTE diff --git a/Source/Menus/ScenarioActivityConfigGUI.h b/Source/Menus/ScenarioActivityConfigGUI.h index c9a4f3ef6..a175bd2c8 100644 --- a/Source/Menus/ScenarioActivityConfigGUI.h +++ b/Source/Menus/ScenarioActivityConfigGUI.h @@ -22,13 +22,12 @@ namespace RTE { class ScenarioActivityConfigGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a ScenarioActivityConfigGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this ScenarioActivityConfigGUI. Ownership is NOT transferred! - explicit ScenarioActivityConfigGUI(GUIControlManager *parentControlManager); + explicit ScenarioActivityConfigGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Getters and Setters @@ -44,7 +43,7 @@ namespace RTE { /// Show and enable or hide and disable the ScenarioActivityConfigGUI. /// Pointer to the Activity this ScenarioActivityConfigGUI will be configuring for. /// Pointer to the Scene the passed in Activity will be using. - void SetEnabled(bool enable, const Activity *selectedActivity = nullptr, Scene *selectedScene = nullptr); + void SetEnabled(bool enable, const Activity* selectedActivity = nullptr, Scene* selectedScene = nullptr); #pragma endregion #pragma region Concrete Methods @@ -63,22 +62,27 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for all the player columns in the player setup box. "Extends" the Players enumeration by adding an entry for the CPU player. /// - enum PlayerColumns { PlayerCPU = Players::MaxPlayerCount, PlayerColumnCount }; + enum PlayerColumns { + PlayerCPU = Players::MaxPlayerCount, + PlayerColumnCount + }; /// /// Enumeration for all the team rows in the player setup box. "Extends" the Teams enumeration by adding an entry for unused (disabled) Team. /// - enum TeamRows { DisabledTeam = Activity::Teams::MaxTeamCount, TeamRowCount }; + enum TeamRows { + DisabledTeam = Activity::Teams::MaxTeamCount, + TeamRowCount + }; - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. - const GameActivity *m_SelectedActivity; //!< The Activity this ScenarioActivityConfigGUI is configuring. - const GameActivity *m_PreviouslySelectedActivity; //!< The Activity this ScenarioActivityConfigGUI was configuring last, before it got was disabled. - Scene *m_SelectedScene; //!< The Scene the selected Activity will be using. + const GameActivity* m_SelectedActivity; //!< The Activity this ScenarioActivityConfigGUI is configuring. + const GameActivity* m_PreviouslySelectedActivity; //!< The Activity this ScenarioActivityConfigGUI was configuring last, before it got was disabled. + Scene* m_SelectedScene; //!< The Scene the selected Activity will be using. int m_LockedCPUTeam = Activity::Teams::NoTeam; //!< Which team the CPU is locked to, if any. bool m_StartingGoldAdjustedManually; //!< Whether the player adjusted the starting gold, meaning it should stop automatically adjusting to the difficulty setting default starting gold where applicable. @@ -90,25 +94,25 @@ namespace RTE { /// /// GUI elements that compose the Activity setup box. /// - GUICollectionBox *m_ActivityConfigBox; - GUILabel *m_StartErrorLabel; - GUIButton *m_StartGameButton; - GUIButton *m_CancelConfigButton; - GUILabel *m_ActivityDifficultyLabel; - GUISlider *m_ActivityDifficultySlider; - GUILabel *m_StartingGoldLabel; - GUISlider *m_StartingGoldSlider; - GUICheckbox *m_RequireClearPathToOrbitCheckbox; - GUICheckbox *m_FogOfWarCheckbox; - GUICheckbox *m_DeployUnitsCheckbox; - GUILabel *m_CPULockLabel; - GUICollectionBox *m_PlayersAndTeamsConfigBox; - std::array m_TeamIconBoxes; - std::array m_TeamNameLabels; - std::array, PlayerColumns::PlayerColumnCount> m_PlayerBoxes; - std::array m_TeamTechComboBoxes; - std::array m_TeamAISkillLabels; - std::array m_TeamAISkillSliders; + GUICollectionBox* m_ActivityConfigBox; + GUILabel* m_StartErrorLabel; + GUIButton* m_StartGameButton; + GUIButton* m_CancelConfigButton; + GUILabel* m_ActivityDifficultyLabel; + GUISlider* m_ActivityDifficultySlider; + GUILabel* m_StartingGoldLabel; + GUISlider* m_StartingGoldSlider; + GUICheckbox* m_RequireClearPathToOrbitCheckbox; + GUICheckbox* m_FogOfWarCheckbox; + GUICheckbox* m_DeployUnitsCheckbox; + GUILabel* m_CPULockLabel; + GUICollectionBox* m_PlayersAndTeamsConfigBox; + std::array m_TeamIconBoxes; + std::array m_TeamNameLabels; + std::array, PlayerColumns::PlayerColumnCount> m_PlayerBoxes; + std::array m_TeamTechComboBoxes; + std::array m_TeamAISkillLabels; + std::array m_TeamAISkillSliders; #pragma region Activity Configuration Screen Handling /// @@ -154,8 +158,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - ScenarioActivityConfigGUI(const ScenarioActivityConfigGUI &reference) = delete; - ScenarioActivityConfigGUI & operator=(const ScenarioActivityConfigGUI &rhs) = delete; + ScenarioActivityConfigGUI(const ScenarioActivityConfigGUI& reference) = delete; + ScenarioActivityConfigGUI& operator=(const ScenarioActivityConfigGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/ScenarioGUI.cpp b/Source/Menus/ScenarioGUI.cpp index 0f3fc89dd..f86bce452 100644 --- a/Source/Menus/ScenarioGUI.cpp +++ b/Source/Menus/ScenarioGUI.cpp @@ -23,7 +23,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::Clear() { m_RootBoxMaxWidth = 0; @@ -51,25 +51,25 @@ namespace RTE { m_DrawDefaultScenePreview = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioGUI::Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput) { + void ScenarioGUI::Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput) { m_GUIControlManager = std::make_unique(); RTEAssert(m_GUIControlManager->Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "MainMenuSubMenuSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuSubMenuSkin.ini"); m_GUIControlManager->Load("Base.rte/GUIs/ScenarioGUI.ini"); m_RootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); - m_RootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); + m_RootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); m_RootBox->Resize(m_RootBoxMaxWidth, g_WindowMan.GetResY()); - m_ActivityConfigBoxRootBox = dynamic_cast(m_GUIControlManager->GetControl("ConfigRoot")); + m_ActivityConfigBoxRootBox = dynamic_cast(m_GUIControlManager->GetControl("ConfigRoot")); m_ActivityConfigBoxRootBox->Resize(m_RootBox->GetWidth(), m_RootBox->GetHeight()); - m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("BackToMainButton")); + m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("BackToMainButton")); m_BackToMainButton->SetPositionRel(m_RootBox->GetWidth() - m_BackToMainButton->GetWidth() - 16, m_RootBox->GetHeight() - m_BackToMainButton->GetHeight() - 22); - m_ResumeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonResume")); + m_ResumeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonResume")); m_ResumeButton->SetPositionRel(m_RootBox->GetWidth() - m_ResumeButton->GetWidth() - 16, m_RootBox->GetHeight() - m_ResumeButton->GetHeight() - 47); - m_SitePointNameLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneNameOnPlanet")); + m_SitePointNameLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneNameOnPlanet")); CreateActivityInfoBox(); CreateSceneInfoBox(); @@ -77,28 +77,28 @@ namespace RTE { m_ActivityConfigBox = std::make_unique(m_GUIControlManager.get()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::CreateActivityInfoBox() { - m_ActivityInfoBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxActivityInfo")); + m_ActivityInfoBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxActivityInfo")); m_ActivityInfoBox->SetPositionRel(16, 16); - m_ActivitySelectComboBox = dynamic_cast(m_GUIControlManager->GetControl("ComboBoxActivitySelect")); + m_ActivitySelectComboBox = dynamic_cast(m_GUIControlManager->GetControl("ComboBoxActivitySelect")); m_ActivitySelectComboBox->Move(m_ActivityInfoBox->GetXPos() + 8, m_ActivityInfoBox->GetYPos() + 25); - m_ActivityDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelActivityDescription")); + m_ActivityDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelActivityDescription")); m_ActivityDescriptionLabel->SetFont(m_GUIControlManager->GetSkin()->GetFont("FontSmall.png")); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::CreateSceneInfoBox() { - m_SceneInfoBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSceneInfo")); + m_SceneInfoBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSceneInfo")); m_SceneInfoBox->SetPositionRel(m_RootBox->GetWidth() - m_SceneInfoBox->GetWidth() - 16, 16); - m_SceneBoxCloseButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCloseSceneBox")); - m_SceneNameLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneName")); - m_SceneDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneDescription")); + m_SceneBoxCloseButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCloseSceneBox")); + m_SceneNameLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneName")); + m_SceneDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneDescription")); m_SceneDescriptionLabel->SetFont(m_GUIControlManager->GetSkin()->GetFont("FontSmall.png")); - m_ScenePreviewImageBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxScenePreview")); - m_StartActivityConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonStartActivityConfig")); + m_ScenePreviewImageBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxScenePreview")); + m_StartActivityConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonStartActivityConfig")); m_DefaultScenePreview.Create(ContentFile("Base.rte/GUIs/DefaultPreview.png"), 5); m_DefaultScenePreview.SetSpriteAnimMode(SpriteAnimMode::ALWAYSLOOP); @@ -109,18 +109,20 @@ namespace RTE { m_ScenePreviewBitmap->Create(c_ScenePreviewWidth, c_ScenePreviewHeight, 32); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioGUI::SetEnabled(const Vector ¢er, float radius) { + void ScenarioGUI::SetEnabled(const Vector& center, float radius) { bool centerChanged = (center != m_PlanetCenter); m_PlanetCenter = center; m_PlanetRadius = radius; - if (centerChanged) { CalculateLinesToSitePoint(); } + if (centerChanged) { + CalculateLinesToSitePoint(); + } FetchActivitiesAndScenesLists(); // Only show the resume button if the current Activity is a GameActivity. Editor or Multiplayer Activities are resumed from the main menu, so the resume button shouldn't show for them. - const GameActivity *currentActivity = dynamic_cast(g_ActivityMan.GetActivity()); + const GameActivity* currentActivity = dynamic_cast(g_ActivityMan.GetActivity()); m_ResumeButton->SetVisible(currentActivity && (currentActivity->GetActivityState() == Activity::Running || currentActivity->GetActivityState() == Activity::Editing)); m_ActivityInfoBox->SetVisible(true); @@ -128,23 +130,25 @@ namespace RTE { m_ScenePreviewAnimTimer.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::SetDraggedBox(int mouseX, int mouseY) { - GUICollectionBox *hoveredBox = dynamic_cast(m_GUIControlManager->GetControlUnderPoint(mouseX, mouseY, m_RootBox, 1)); - const GUIControl *hoveredControl = m_GUIControlManager->GetControlUnderPoint(mouseX, mouseY, hoveredBox, 1); - bool nonDragControl = (dynamic_cast(hoveredControl) || dynamic_cast(hoveredControl)); - if (hoveredBox && !nonDragControl && !m_DraggedBox && !m_ActivitySelectComboBox->IsDropped()) { m_DraggedBox = hoveredBox; } + GUICollectionBox* hoveredBox = dynamic_cast(m_GUIControlManager->GetControlUnderPoint(mouseX, mouseY, m_RootBox, 1)); + const GUIControl* hoveredControl = m_GUIControlManager->GetControlUnderPoint(mouseX, mouseY, hoveredBox, 1); + bool nonDragControl = (dynamic_cast(hoveredControl) || dynamic_cast(hoveredControl)); + if (hoveredBox && !nonDragControl && !m_DraggedBox && !m_ActivitySelectComboBox->IsDropped()) { + m_DraggedBox = hoveredBox; + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioGUI::SetSelectedActivity(const Activity *newSelectedActivity) { + void ScenarioGUI::SetSelectedActivity(const Activity* newSelectedActivity) { m_SelectedActivity = newSelectedActivity; m_ActivityScenes = nullptr; if (m_SelectedActivity) { - for (auto &[activity, sceneList] : m_ScenarioActivities) { + for (auto& [activity, sceneList]: m_ScenarioActivities) { if (activity == m_SelectedActivity) { m_ActivityScenes = &sceneList; break; @@ -164,14 +168,14 @@ namespace RTE { m_ActivityInfoBox->Resize(m_ActivityInfoBox->GetWidth(), m_ActivityDescriptionLabel->ResizeHeightToFit() + 60); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioGUI::SetSelectedScene(Scene *newSelectedScene) { + void ScenarioGUI::SetSelectedScene(Scene* newSelectedScene) { m_SelectedScene = newSelectedScene; if (m_SelectedScene) { m_SceneInfoBox->SetVisible(true); - if (BITMAP *preview = m_SelectedScene->GetPreviewBitmap()) { + if (BITMAP* preview = m_SelectedScene->GetPreviewBitmap()) { clear_to_color(m_ScenePreviewBitmap->GetBitmap(), ColorKeys::g_MaskColor); draw_sprite(m_ScenePreviewBitmap->GetBitmap(), preview, 0, 0); m_ScenePreviewImageBox->SetDrawImage(new AllegroBitmap(m_ScenePreviewBitmap->GetBitmap())); @@ -198,7 +202,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::DragBox(int mouseX, int mouseY) { if (m_DraggedBox) { @@ -215,33 +219,37 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::FetchActivitiesAndScenesLists() { int prevSelectedActivityIndex = m_ActivitySelectComboBox->GetSelectedIndex(); - Scene *prevSelectedScene = m_SelectedScene; + Scene* prevSelectedScene = m_SelectedScene; m_ActivitySelectComboBox->ClearList(); m_ScenarioActivities.clear(); m_ActivityScenes = nullptr; - std::list presetList; + std::list presetList; g_PresetMan.GetAllOfType(presetList, "Scene"); - std::vector filteredScenes; - for (Entity *presetEntity : presetList) { - Scene *presetScene = dynamic_cast(presetEntity); - if (presetScene && !presetScene->GetLocation().IsZero() && !presetScene->IsMetagameInternal() && !presetScene->IsSavedGameInternal() && (presetScene->GetMetasceneParent().empty() || g_SettingsMan.ShowMetascenes())) { filteredScenes.emplace_back(presetScene); } + std::vector filteredScenes; + for (Entity* presetEntity: presetList) { + Scene* presetScene = dynamic_cast(presetEntity); + if (presetScene && !presetScene->GetLocation().IsZero() && !presetScene->IsMetagameInternal() && !presetScene->IsSavedGameInternal() && (presetScene->GetMetasceneParent().empty() || g_SettingsMan.ShowMetascenes())) { + filteredScenes.emplace_back(presetScene); + } } AdjustSitePointOffsetsOnPlanet(filteredScenes); presetList.clear(); g_PresetMan.GetAllOfType(presetList, "Activity"); int index = 0; - for (Entity *presetEntity : presetList) { - if (GameActivity *presetActivity = dynamic_cast(presetEntity)) { - std::pair> activityAndCompatibleScenes(presetActivity, std::vector()); - for (Scene *filteredScene : filteredScenes) { - if (presetActivity->SceneIsCompatible(filteredScene)) { activityAndCompatibleScenes.second.emplace_back(filteredScene); } + for (Entity* presetEntity: presetList) { + if (GameActivity* presetActivity = dynamic_cast(presetEntity)) { + std::pair> activityAndCompatibleScenes(presetActivity, std::vector()); + for (Scene* filteredScene: filteredScenes) { + if (presetActivity->SceneIsCompatible(filteredScene)) { + activityAndCompatibleScenes.second.emplace_back(filteredScene); + } } m_ScenarioActivities.insert(activityAndCompatibleScenes); // Add to the activity selection ComboBox and attach the activity pointer, not passing in ownership. @@ -256,15 +264,17 @@ namespace RTE { } if (prevSelectedActivityIndex >= 0) { m_ActivitySelectComboBox->SetSelectedIndex(prevSelectedActivityIndex); - SetSelectedActivity(dynamic_cast(m_ActivitySelectComboBox->GetSelectedItem()->m_pEntity)); - if (prevSelectedScene) { SetSelectedScene(prevSelectedScene); } + SetSelectedActivity(dynamic_cast(m_ActivitySelectComboBox->GetSelectedItem()->m_pEntity)); + if (prevSelectedScene) { + SetSelectedScene(prevSelectedScene); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioGUI::AdjustSitePointOffsetsOnPlanet(const std::vector &sceneList) const { - for (Scene *sceneListEntry : sceneList) { + void ScenarioGUI::AdjustSitePointOffsetsOnPlanet(const std::vector& sceneList) const { + for (Scene* sceneListEntry: sceneList) { int sceneYPos = (m_PlanetCenter + sceneListEntry->GetLocation() + sceneListEntry->GetLocationOffset()).GetFloorIntY(); if (std::abs(sceneListEntry->GetLocation().GetY()) < m_PlanetRadius + 100 && std::abs(sceneListEntry->GetLocation().GetX()) < m_PlanetRadius + 100) { if (sceneYPos < 10) { @@ -281,8 +291,8 @@ namespace RTE { bool foundOverlap = true; while (foundOverlap) { foundOverlap = false; - for (Scene *sceneListEntry1 : sceneList) { - for (const Scene *sceneListEntry2 : sceneList) { + for (Scene* sceneListEntry1: sceneList) { + for (const Scene* sceneListEntry2: sceneList) { if (sceneListEntry1 != sceneListEntry2) { Vector pos1 = sceneListEntry1->GetLocation() + sceneListEntry1->GetLocationOffset(); Vector pos2 = sceneListEntry2->GetLocation() + sceneListEntry2->GetLocationOffset(); @@ -317,7 +327,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::CalculateLinesToSitePoint() { m_LineToSitePoints.clear(); @@ -359,10 +369,14 @@ namespace RTE { chamferSize = std::min(std::abs(sceneBoxEdge.GetFloorIntX() - sitePos.GetFloorIntX()) - minSiteDistance, std::abs(sceneBoxEdge.GetFloorIntY() - sitePos.GetFloorIntY()) - minStraightLength); chamferSize = std::min(chamferSize, maxChamferSize); - if (chamferSize < minChamferSize) { chamferSize = 0; } + if (chamferSize < minChamferSize) { + chamferSize = 0; + } m_LineToSitePoints.emplace_back(Vector(bendPoint.GetX(), bendPoint.GetY() + static_cast(chamferSize) * -yDirMult)); - if (chamferSize > 0) { m_LineToSitePoints.emplace_back(Vector(bendPoint.GetX() + static_cast(chamferSize) * xDirMult, bendPoint.GetY())); } + if (chamferSize > 0) { + m_LineToSitePoints.emplace_back(Vector(bendPoint.GetX() + static_cast(chamferSize) * xDirMult, bendPoint.GetY())); + } m_LineToSitePoints.emplace_back(sitePos + Vector((static_cast(circleRadius + 1)) * -xDirMult, 0)); } else { // Two bends. extraLength ensures that there will be straight lines coming out of the site and the box, and that they are nearly as short as possible. @@ -373,16 +387,20 @@ namespace RTE { chamferSize = std::min(std::abs(sceneBoxEdge.GetFloorIntX() - sitePos.GetFloorIntX()) - minSiteDistance, std::abs(secondBend.GetFloorIntY() - sitePos.GetFloorIntY()) - minSiteDistance); chamferSize = std::min(chamferSize, maxChamferSize); - if (chamferSize < minChamferSize) { chamferSize = 0; } + if (chamferSize < minChamferSize) { + chamferSize = 0; + } m_LineToSitePoints.emplace_back(firstBend); m_LineToSitePoints.emplace_back(Vector(secondBend.GetX() + static_cast(chamferSize) * -xDirMult, secondBend.GetY())); - if (chamferSize > 0) { m_LineToSitePoints.emplace_back(Vector(secondBend.GetX(), secondBend.GetY() + static_cast(chamferSize) * -yDirMult)); } + if (chamferSize > 0) { + m_LineToSitePoints.emplace_back(Vector(secondBend.GetX(), secondBend.GetY() + static_cast(chamferSize) * -yDirMult)); + } m_LineToSitePoints.emplace_back(sitePos + Vector(0, (static_cast(circleRadius + 1)) * yDirMult)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ScenarioGUI::ScenarioMenuUpdateResult ScenarioGUI::Update() { m_UpdateResult = ScenarioMenuUpdateResult::NoEvent; @@ -421,26 +439,30 @@ namespace RTE { } // Only show the resume button if the current Activity is a GameActivity. Editor or Multiplayer Activities are resumed from the main menu, so the resume button shouldn't show for them. - const GameActivity *currentActivity = dynamic_cast(g_ActivityMan.GetActivity()); + const GameActivity* currentActivity = dynamic_cast(g_ActivityMan.GetActivity()); m_ResumeButton->SetVisible(currentActivity && (currentActivity->GetActivityState() == Activity::Running || currentActivity->GetActivityState() == Activity::Editing)); - if (m_ResumeButton->GetVisible()) { m_GUIControlManager->GetManager()->SetFocus((m_BlinkTimer.AlternateReal(500)) ? m_ResumeButton : nullptr); } + if (m_ResumeButton->GetVisible()) { + m_GUIControlManager->GetManager()->SetFocus((m_BlinkTimer.AlternateReal(500)) ? m_ResumeButton : nullptr); + } } else { m_RootBox->SetVisible(false); m_ActivityConfigBoxRootBox->SetVisible(true); - if (m_ActivityConfigBox->Update(mousePosX, mousePosY)) { m_UpdateResult = ScenarioMenuUpdateResult::ActivityStarted; } + if (m_ActivityConfigBox->Update(mousePosX, mousePosY)) { + m_UpdateResult = ScenarioMenuUpdateResult::ActivityStarted; + } } return m_UpdateResult; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::UpdateHoveredSitePointLabel(int mouseX, int mouseY) { bool foundAnyHover = false; if (m_ActivityScenes && !m_DraggedBox && !m_ActivityInfoBox->PointInside(mouseX, mouseY) && !m_SceneInfoBox->PointInside(mouseX, mouseY)) { - Scene *candidateScene = nullptr; + Scene* candidateScene = nullptr; float sqrShortestDistance = 10.0F * 10.0F; - for (Scene *activityScene : *m_ActivityScenes) { + for (Scene* activityScene: *m_ActivityScenes) { float sqrDistance = (m_PlanetCenter + activityScene->GetLocation() + activityScene->GetLocationOffset() - Vector(static_cast(mouseX), static_cast(mouseY))).GetSqrMagnitude(); if (sqrDistance < sqrShortestDistance) { sqrShortestDistance = sqrDistance; @@ -467,7 +489,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::HandleInputEvents(int mouseX, int mouseY) { GUIEvent guiEvent; @@ -487,11 +509,13 @@ namespace RTE { m_ActivityConfigBox->SetEnabled(true, m_SelectedActivity, m_SelectedScene); } } else if (guiEvent.GetType() == GUIEvent::Notification) { - if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl())) { g_GUISound.SelectionChangeSound()->Play(); } + if (guiEvent.GetMsg() == GUIButton::Focused && dynamic_cast(guiEvent.GetControl())) { + g_GUISound.SelectionChangeSound()->Play(); + } if (guiEvent.GetMsg() == GUIComboBox::Closed && guiEvent.GetControl() == m_ActivitySelectComboBox) { g_GUISound.ItemChangeSound()->Play(); - SetSelectedActivity((m_ActivitySelectComboBox->GetSelectedItem()) ? dynamic_cast(m_ActivitySelectComboBox->GetSelectedItem()->m_pEntity) : nullptr); + SetSelectedActivity((m_ActivitySelectComboBox->GetSelectedItem()) ? dynamic_cast(m_ActivitySelectComboBox->GetSelectedItem()->m_pEntity) : nullptr); } } } @@ -505,11 +529,13 @@ namespace RTE { } else if (g_UInputMan.MenuButtonReleased(UInputMan::MenuCursorButtons::MENU_PRIMARY)) { m_DraggedBox = nullptr; } - if (g_UInputMan.MenuButtonHeld(UInputMan::MenuCursorButtons::MENU_PRIMARY)) { DragBox(mouseX, mouseY); } + if (g_UInputMan.MenuButtonHeld(UInputMan::MenuCursorButtons::MENU_PRIMARY)) { + DragBox(mouseX, mouseY); + } m_PrevMousePos.SetXY(static_cast(mouseX), static_cast(mouseY)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ScenarioGUI::Draw() const { // Early return to avoid single frame flicker before title screen goes into fadeout. @@ -520,22 +546,26 @@ namespace RTE { if (m_ActivityScenes) { drawing_mode(DRAW_MODE_TRANS, nullptr, 0, 0); DrawSitePoints(g_FrameMan.GetBackBuffer32()); - if (m_SelectedScene && m_SceneInfoBox->GetVisible()) { DrawLinesToSitePoint(g_FrameMan.GetBackBuffer32()); } + if (m_SelectedScene && m_SceneInfoBox->GetVisible()) { + DrawLinesToSitePoint(g_FrameMan.GetBackBuffer32()); + } drawing_mode(DRAW_MODE_SOLID, nullptr, 0, 0); } m_GUIControlManager->Draw(); - if (m_DrawDefaultScenePreview && m_SceneInfoBox->GetVisible()) { m_DefaultScenePreview.Draw(g_FrameMan.GetBackBuffer32()); } + if (m_DrawDefaultScenePreview && m_SceneInfoBox->GetVisible()) { + m_DefaultScenePreview.Draw(g_FrameMan.GetBackBuffer32()); + } } else { m_ActivityConfigBox->Draw(); } m_GUIControlManager->DrawMouse(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioGUI::DrawSitePoints(BITMAP *drawBitmap) const { + void ScenarioGUI::DrawSitePoints(BITMAP* drawBitmap) const { int blendAmount = 0; - for (const Scene *scenePointer : *m_ActivityScenes) { + for (const Scene* scenePointer: *m_ActivityScenes) { int drawColor = 0; if (scenePointer->GetModuleID() == g_PresetMan.GetModuleID("Base.rte")) { drawColor = c_GUIColorYellow; @@ -559,9 +589,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ScenarioGUI::DrawLinesToSitePoint(BITMAP *drawBitmap) const { + void ScenarioGUI::DrawLinesToSitePoint(BITMAP* drawBitmap) const { int blendAmount = 0; int drawColor = c_GUIColorWhite; @@ -597,4 +627,4 @@ namespace RTE { set_screen_blender(blendAmount, blendAmount, blendAmount, blendAmount); circle(drawBitmap, sitePosX, sitePosY, circleRadius - 1, drawColor); } -} +} // namespace RTE diff --git a/Source/Menus/ScenarioGUI.h b/Source/Menus/ScenarioGUI.h index 19d6a3d62..62ba79d98 100644 --- a/Source/Menus/ScenarioGUI.h +++ b/Source/Menus/ScenarioGUI.h @@ -23,7 +23,6 @@ namespace RTE { class ScenarioGUI { public: - /// /// Enumeration for the results of the ScenarioGUI input and event update. /// @@ -40,14 +39,17 @@ namespace RTE { /// /// Pointer to a GUIScreen interface that will be used by this ScenarioGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this ScenarioGUI's GUIControlManager. Ownership is NOT transferred! - ScenarioGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput) { Clear(); Create(guiScreen, guiInput); } + ScenarioGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput) { + Clear(); + Create(guiScreen, guiInput); + } /// /// Makes the ScenarioGUI object ready for use. /// /// Pointer to a GUIScreen interface that will be used by this ScenarioGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this ScenarioGUI's GUIControlManager. Ownership is NOT transferred! - void Create(AllegroScreen *guiScreen, GUIInputWrapper *guiInput); + void Create(AllegroScreen* guiScreen, GUIInputWrapper* guiInput); #pragma endregion #pragma region Setters @@ -56,7 +58,7 @@ namespace RTE { /// /// The absolute screen coordinates of the planet's center. /// The radius, in screen pixel units, of the planet. - void SetEnabled(const Vector ¢er, float radius); + void SetEnabled(const Vector& center, float radius); #pragma endregion #pragma region Concrete Methods @@ -73,24 +75,23 @@ namespace RTE { #pragma endregion private: - int m_RootBoxMaxWidth; //!< The maximum width the root CollectionBox that holds all this menu's GUI elements. This is to constrain this menu to the primary window's display (left-most) while in multi-display fullscreen, otherwise positioning can get stupid. std::unique_ptr m_GUIControlManager; //!< The GUIControlManager which owns all the GUIControls of the ScenarioGUI. ScenarioMenuUpdateResult m_UpdateResult; //!< The result of the ScenarioGUI update. See ScenarioMenuUpdateResult enumeration. - std::map> m_ScenarioActivities; //!< The map of Activities and the Scenes compatible with each, neither of which are owned here. - const Activity *m_SelectedActivity; //!< The currently selected Activity. Not owned. + std::map> m_ScenarioActivities; //!< The map of Activities and the Scenes compatible with each, neither of which are owned here. + const Activity* m_SelectedActivity; //!< The currently selected Activity. Not owned. - std::vector *m_ActivityScenes; //!< Pointer to the current set of Scenes being displayed. Not owned, and neither are the Scenes. - Scene *m_SelectedScene; //!< The scene preset currently selected. Not owned. - Scene *m_HoveredScene; //!< The scene preset currently hovered. Not owned. + std::vector* m_ActivityScenes; //!< Pointer to the current set of Scenes being displayed. Not owned, and neither are the Scenes. + Scene* m_SelectedScene; //!< The scene preset currently selected. Not owned. + Scene* m_HoveredScene; //!< The scene preset currently hovered. Not owned. Vector m_PlanetCenter; //!< The absolute screen position of the planet center. float m_PlanetRadius; //!< The screen radius of the planet. std::vector m_LineToSitePoints; //!< Collection of points that form lines from a screen point to the selected site point. - GUICollectionBox *m_DraggedBox; //!< Currently dragged GUI box. + GUICollectionBox* m_DraggedBox; //!< Currently dragged GUI box. Vector m_PrevMousePos; //!< Previous position of the mouse to calculate dragging. Timer m_BlinkTimer; //!< Timer for blinking the resume and config start buttons. @@ -104,21 +105,21 @@ namespace RTE { /// /// GUI elements that compose the scenario menu screen. /// - GUICollectionBox *m_RootBox; - GUICollectionBox *m_ActivityConfigBoxRootBox; - GUIButton *m_BackToMainButton; - GUIButton *m_ResumeButton; - GUICollectionBox *m_ActivityInfoBox; - GUIComboBox *m_ActivitySelectComboBox; - GUILabel *m_ActivityDescriptionLabel; - GUICollectionBox *m_SceneInfoBox; - GUIButton *m_SceneBoxCloseButton; - GUILabel *m_SceneNameLabel; - GUILabel *m_SceneDescriptionLabel; - GUICollectionBox *m_ScenePreviewImageBox; + GUICollectionBox* m_RootBox; + GUICollectionBox* m_ActivityConfigBoxRootBox; + GUIButton* m_BackToMainButton; + GUIButton* m_ResumeButton; + GUICollectionBox* m_ActivityInfoBox; + GUIComboBox* m_ActivitySelectComboBox; + GUILabel* m_ActivityDescriptionLabel; + GUICollectionBox* m_SceneInfoBox; + GUIButton* m_SceneBoxCloseButton; + GUILabel* m_SceneNameLabel; + GUILabel* m_SceneDescriptionLabel; + GUICollectionBox* m_ScenePreviewImageBox; std::unique_ptr m_ScenePreviewBitmap; - GUIButton *m_StartActivityConfigButton; - GUILabel *m_SitePointNameLabel; + GUIButton* m_StartActivityConfigButton; + GUILabel* m_SitePointNameLabel; #pragma region Create Breakdown /// @@ -144,13 +145,13 @@ namespace RTE { /// Sets the selected Activity, refreshes the compatible Scenes on the planet and updates the Activity info box appropriately. /// /// The new selected Activity. - void SetSelectedActivity(const Activity *newSelectedActivity); + void SetSelectedActivity(const Activity* newSelectedActivity); /// /// Sets the currently selected Scene and updates the Scene info box appropriately. /// /// The new selected Scene. - void SetSelectedScene(Scene *newSelectedScene); + void SetSelectedScene(Scene* newSelectedScene); /// /// Moves the CollectionBox that is selected as being dragged, if any. @@ -168,7 +169,7 @@ namespace RTE { /// Adjusts the positions of the site points on the planet if they don't fit the screen or overlap. /// /// Vector of Scenes to adjust positions for. - void AdjustSitePointOffsetsOnPlanet(const std::vector &sceneList) const; + void AdjustSitePointOffsetsOnPlanet(const std::vector& sceneList) const; /// /// Calculates how to draw lines from the Scene info box to the selected site point on the planet. @@ -197,13 +198,13 @@ namespace RTE { /// Draws the site points on top of the planet. /// /// The bitmap to draw on. - void DrawSitePoints(BITMAP *drawBitmap) const; + void DrawSitePoints(BITMAP* drawBitmap) const; /// /// Draws fancy thick flickering lines from the Scene info box to the selected scene point on the planet. /// /// The bitmap to draw to. - void DrawLinesToSitePoint(BITMAP *drawBitmap) const; + void DrawLinesToSitePoint(BITMAP* drawBitmap) const; #pragma endregion /// @@ -212,8 +213,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - ScenarioGUI(const ScenarioGUI &reference) = delete; - ScenarioGUI & operator=(const ScenarioGUI &rhs) = delete; + ScenarioGUI(const ScenarioGUI& reference) = delete; + ScenarioGUI& operator=(const ScenarioGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SceneEditorGUI.cpp b/Source/Menus/SceneEditorGUI.cpp index c63a8ba4f..c67438e80 100644 --- a/Source/Menus/SceneEditorGUI.cpp +++ b/Source/Menus/SceneEditorGUI.cpp @@ -7,7 +7,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -43,8 +42,8 @@ using namespace RTE; #define BLUEPRINTREVEALRATE 150 #define BLUEPRINTREVEALPAUSE 1500 -BITMAP *SceneEditorGUI::s_pValidPathDot = 0; -BITMAP *SceneEditorGUI::s_pInvalidPathDot = 0; +BITMAP* SceneEditorGUI::s_pValidPathDot = 0; +BITMAP* SceneEditorGUI::s_pInvalidPathDot = 0; ////////////////////////////////////////////////////////////////////////////////////////// // Method: Clear @@ -52,141 +51,136 @@ BITMAP *SceneEditorGUI::s_pInvalidPathDot = 0; // Description: Clears all the member variables of this SceneEditorGUI, effectively // resetting the members of this abstraction level only. -void SceneEditorGUI::Clear() -{ - m_pController = 0; - m_FeatureSet = INGAMEEDIT; - m_EditMade = false; - m_EditorGUIMode = PICKINGOBJECT; - m_PreviousMode = ADDINGOBJECT; - m_ModeChanged = true; - m_BlinkTimer.Reset(); - m_BlinkMode = NOBLINK; - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - m_RevealTimer.Reset(); - m_RevealIndex = 0; +void SceneEditorGUI::Clear() { + m_pController = 0; + m_FeatureSet = INGAMEEDIT; + m_EditMade = false; + m_EditorGUIMode = PICKINGOBJECT; + m_PreviousMode = ADDINGOBJECT; + m_ModeChanged = true; + m_BlinkTimer.Reset(); + m_BlinkMode = NOBLINK; + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + m_RevealTimer.Reset(); + m_RevealIndex = 0; m_PieMenu = nullptr; - m_pPicker = 0; - m_NativeTechModule = 0; - m_ForeignCostMult = 4.0; - m_GridSnapping = true; - m_CursorPos.Reset(); - m_CursorOffset.Reset(); - m_CursorInAir = true; - m_FacingLeft = false; - m_PlaceTeam = Activity::TeamOne; - m_pCurrentObject = 0; - m_ObjectListOrder = -1; - m_DrawCurrentObject = true; - m_pObjectToBlink = 0; - m_BrainSkyPath.clear(); - m_BrainSkyPathCost = 0; + m_pPicker = 0; + m_NativeTechModule = 0; + m_ForeignCostMult = 4.0; + m_GridSnapping = true; + m_CursorPos.Reset(); + m_CursorOffset.Reset(); + m_CursorInAir = true; + m_FacingLeft = false; + m_PlaceTeam = Activity::TeamOne; + m_pCurrentObject = 0; + m_ObjectListOrder = -1; + m_DrawCurrentObject = true; + m_pObjectToBlink = 0; + m_BrainSkyPath.clear(); + m_BrainSkyPathCost = 0; m_RequireClearPathToOrbit = false; - m_PathRequest.reset(); + m_PathRequest.reset(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: Create ////////////////////////////////////////////////////////////////////////////////////////// // Description: Makes the SceneEditorGUI object ready for use. -int SceneEditorGUI::Create(Controller *pController, FeatureSets featureSet, int whichModuleSpace, int nativeTechModule, float foreignCostMult) -{ - RTEAssert(pController, "No controller sent to SceneEditorGUI on creation!"); - m_pController = pController; +int SceneEditorGUI::Create(Controller* pController, FeatureSets featureSet, int whichModuleSpace, int nativeTechModule, float foreignCostMult) { + RTEAssert(pController, "No controller sent to SceneEditorGUI on creation!"); + m_pController = pController; SetFeatureSet(featureSet); - // Update the brain path - UpdateBrainPath(); - - // Allocate and (re)create the Editor GUIs - if (!m_pPicker) - m_pPicker = new ObjectPickerGUI(); - else - m_pPicker->Reset(); - m_pPicker->Create(pController, whichModuleSpace); - - m_NativeTechModule = nativeTechModule; - m_ForeignCostMult = foreignCostMult; - // Also apply these to the picker - m_pPicker->SetNativeTechModule(m_NativeTechModule); - m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); - - // Cursor init - m_CursorPos = g_SceneMan.GetSceneDim() / 2; - - // Set initial focus, category std::list, and label settings - m_EditorGUIMode = PICKINGOBJECT; - m_ModeChanged = true; - m_pCurrentObject = 0; - - // Reset repeat timers - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - m_RevealTimer.Reset(); - m_RevealTimer.SetRealTimeLimitMS(100); - - //Check if we need to check for a clear path to orbit + // Update the brain path + UpdateBrainPath(); + + // Allocate and (re)create the Editor GUIs + if (!m_pPicker) + m_pPicker = new ObjectPickerGUI(); + else + m_pPicker->Reset(); + m_pPicker->Create(pController, whichModuleSpace); + + m_NativeTechModule = nativeTechModule; + m_ForeignCostMult = foreignCostMult; + // Also apply these to the picker + m_pPicker->SetNativeTechModule(m_NativeTechModule); + m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); + + // Cursor init + m_CursorPos = g_SceneMan.GetSceneDim() / 2; + + // Set initial focus, category std::list, and label settings + m_EditorGUIMode = PICKINGOBJECT; + m_ModeChanged = true; + m_pCurrentObject = 0; + + // Reset repeat timers + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); + m_RevealTimer.Reset(); + m_RevealTimer.SetRealTimeLimitMS(100); + + // Check if we need to check for a clear path to orbit m_RequireClearPathToOrbit = false; - GameActivity * gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); - if (gameActivity) { - m_RequireClearPathToOrbit = gameActivity->GetRequireClearPathToOrbit(); - } + GameActivity* gameActivity = dynamic_cast(g_ActivityMan.GetActivity()); + if (gameActivity) { + m_RequireClearPathToOrbit = gameActivity->GetRequireClearPathToOrbit(); + } // Always disable clear path requirement in scene editor - SceneEditor * editorActivity = dynamic_cast(g_ActivityMan.GetActivity()); - if (editorActivity) { - m_RequireClearPathToOrbit = false; - } - - // Only load the static dot bitmaps once - if (!s_pValidPathDot) { - ContentFile dotFile("Base.rte/GUIs/Indicators/PathDotValid.png"); - s_pValidPathDot = dotFile.GetAsBitmap(); - dotFile.SetDataPath("Base.rte/GUIs/Indicators/PathDotInvalid.png"); - s_pInvalidPathDot = dotFile.GetAsBitmap(); - } - - return 0; -} + SceneEditor* editorActivity = dynamic_cast(g_ActivityMan.GetActivity()); + if (editorActivity) { + m_RequireClearPathToOrbit = false; + } + + // Only load the static dot bitmaps once + if (!s_pValidPathDot) { + ContentFile dotFile("Base.rte/GUIs/Indicators/PathDotValid.png"); + s_pValidPathDot = dotFile.GetAsBitmap(); + dotFile.SetDataPath("Base.rte/GUIs/Indicators/PathDotInvalid.png"); + s_pInvalidPathDot = dotFile.GetAsBitmap(); + } + return 0; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: Destroy ////////////////////////////////////////////////////////////////////////////////////////// // Description: Destroys and resets (through Clear()) the SceneEditorGUI object. -void SceneEditorGUI::Destroy() -{ - delete m_pPicker; +void SceneEditorGUI::Destroy() { + delete m_pPicker; - delete m_pCurrentObject; + delete m_pCurrentObject; - Clear(); + Clear(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetController ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the controller used by this. The ownership of the controller is // NOT transferred! -void SceneEditorGUI::SetController(Controller *pController) -{ - m_pController = pController; +void SceneEditorGUI::SetController(Controller* pController) { + m_pController = pController; m_PieMenu->SetMenuController(pController); - m_pPicker->SetController(pController); + m_pPicker->SetController(pController); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SceneEditorGUI::SetFeatureSet(SceneEditorGUI::FeatureSets newFeatureSet) { m_FeatureSet = newFeatureSet; - if (m_PieMenu) { m_PieMenu = nullptr; } + if (m_PieMenu) { + m_PieMenu = nullptr; + } std::string pieMenuName; switch (m_FeatureSet) { case FeatureSets::ONLOADEDIT: @@ -204,14 +198,13 @@ void SceneEditorGUI::SetFeatureSet(SceneEditorGUI::FeatureSets newFeatureSet) { default: RTEAbort("Unhandled SceneEditorGUI FeatureSet when setting up PieMenu."); } - m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", pieMenuName)->Clone())); - //m_PieMenu->Create(); + m_PieMenu = std::unique_ptr(dynamic_cast(g_PresetMan.GetEntityPreset("PieMenu", pieMenuName)->Clone())); + // m_PieMenu->Create(); m_PieMenu->SetMenuController(m_pController); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetPosOnScreen ////////////////////////////////////////////////////////////////////////////////////////// @@ -219,95 +212,81 @@ void SceneEditorGUI::SetFeatureSet(SceneEditorGUI::FeatureSets newFeatureSet) { // left corner, then 0, 0. This will affect the way the mouse is positioned // etc. -void SceneEditorGUI::SetPosOnScreen(int newPosX, int newPosY) -{ - m_pPicker->SetPosOnScreen(newPosX, newPosY); +void SceneEditorGUI::SetPosOnScreen(int newPosX, int newPosY) { + m_pPicker->SetPosOnScreen(newPosX, newPosY); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetCurrentObject ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the new Object to be held at the cursor of this Editor. Ownership // IS transferred! -bool SceneEditorGUI::SetCurrentObject(SceneObject *pNewObject) -{ - if (m_pCurrentObject == pNewObject) - return true; +bool SceneEditorGUI::SetCurrentObject(SceneObject* pNewObject) { + if (m_pCurrentObject == pNewObject) + return true; - // Replace the current object with the new one - delete m_pCurrentObject; - m_pCurrentObject = pNewObject; + // Replace the current object with the new one + delete m_pCurrentObject; + m_pCurrentObject = pNewObject; - if (!m_pCurrentObject) - return false; - - m_pCurrentObject->SetTeam(m_FeatureSet == ONLOADEDIT ? m_PlaceTeam : m_pController->GetTeam()); - m_pCurrentObject->SetPlacedByPlayer(m_pController->GetPlayer()); + if (!m_pCurrentObject) + return false; - // Disable any controller, if an actor - if (Actor *pActor = dynamic_cast(m_pCurrentObject)) - { - pActor->GetController()->SetDisabled(true); - pActor->SetStatus(Actor::INACTIVE); - } + m_pCurrentObject->SetTeam(m_FeatureSet == ONLOADEDIT ? m_PlaceTeam : m_pController->GetTeam()); + m_pCurrentObject->SetPlacedByPlayer(m_pController->GetPlayer()); + // Disable any controller, if an actor + if (Actor* pActor = dynamic_cast(m_pCurrentObject)) { + pActor->GetController()->SetDisabled(true); + pActor->SetStatus(Actor::INACTIVE); + } - return true; + return true; } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: GetActivatedPieSlice ////////////////////////////////////////////////////////////////////////////////////////// // Description: Gets any Pie menu slice command activated last update. PieSlice::SliceType SceneEditorGUI::GetActivatedPieSlice() const { - return m_PieMenu->GetPieCommand(); + return m_PieMenu->GetPieCommand(); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetModuleSpace ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets which DataModule space to be picking objects from. If -1, then // let the player pick from all loaded modules. -void SceneEditorGUI::SetModuleSpace(int moduleSpaceID) -{ - m_pPicker->SetModuleSpace(moduleSpaceID); +void SceneEditorGUI::SetModuleSpace(int moduleSpaceID) { + m_pPicker->SetModuleSpace(moduleSpaceID); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetNativeTechModule ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets which DataModule ID should be treated as the native tech of the // user of this menu. -void SceneEditorGUI::SetNativeTechModule(int whichModule) -{ - if (whichModule >= 0 && whichModule < g_PresetMan.GetTotalModuleCount()) - { - m_NativeTechModule = whichModule; - m_pPicker->SetNativeTechModule(m_NativeTechModule); - } +void SceneEditorGUI::SetNativeTechModule(int whichModule) { + if (whichModule >= 0 && whichModule < g_PresetMan.GetTotalModuleCount()) { + m_NativeTechModule = whichModule; + m_pPicker->SetNativeTechModule(m_NativeTechModule); + } } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: SetForeignCostMultiplier ////////////////////////////////////////////////////////////////////////////////////////// // Description: Sets the multiplier of the cost of any foreign Tech items. -void SceneEditorGUI::SetForeignCostMultiplier(float newMultiplier) -{ - m_ForeignCostMult = newMultiplier; - m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); +void SceneEditorGUI::SetForeignCostMultiplier(float newMultiplier) { + m_ForeignCostMult = newMultiplier; + m_pPicker->SetForeignCostMultiplier(m_ForeignCostMult); } - ////////////////////////////////////////////////////////////////////////////////////////// // Method: TestBrainResidence ////////////////////////////////////////////////////////////////////////////////////////// @@ -317,177 +296,166 @@ void SceneEditorGUI::SetForeignCostMultiplier(float newMultiplier) // current resident brain if the current placement is no bueno. It also // removes the faulty brain from residence in the scene! -bool SceneEditorGUI::TestBrainResidence(bool noBrainIsOK) -{ - // Do we have a resident at all? - SceneObject *pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); - - // If not, can we find an unassigned brain and make it the resident? - if (!pBrain) - { - pBrain = g_MovableMan.GetUnassignedBrain(g_ActivityMan.GetActivity()->GetTeamOfPlayer(m_pController->GetPlayer())); - // Found one, so make it the resident brain (passing ownership) and remove it from the sim - if (pBrain) - { - g_SceneMan.GetScene()->SetResidentBrain(m_pController->GetPlayer(), pBrain); - g_MovableMan.RemoveMO(dynamic_cast(pBrain)); - } - } - - // We do we have a resident brain now, so let's check that it's in a legit spot - if (pBrain) - { - // Got to update the pathfinding graphs so the latest terrain is used for the below tests - g_SceneMan.GetScene()->UpdatePathFinding(); +bool SceneEditorGUI::TestBrainResidence(bool noBrainIsOK) { + // Do we have a resident at all? + SceneObject* pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); + + // If not, can we find an unassigned brain and make it the resident? + if (!pBrain) { + pBrain = g_MovableMan.GetUnassignedBrain(g_ActivityMan.GetActivity()->GetTeamOfPlayer(m_pController->GetPlayer())); + // Found one, so make it the resident brain (passing ownership) and remove it from the sim + if (pBrain) { + g_SceneMan.GetScene()->SetResidentBrain(m_pController->GetPlayer(), pBrain); + g_MovableMan.RemoveMO(dynamic_cast(pBrain)); + } + } + + // We do we have a resident brain now, so let's check that it's in a legit spot + if (pBrain) { + // Got to update the pathfinding graphs so the latest terrain is used for the below tests + g_SceneMan.GetScene()->UpdatePathFinding(); UpdateBrainSkyPathAndCost(pBrain->GetPos()); - } - else - { - // No brain found, so we better place one - if (!noBrainIsOK) - { - m_EditorGUIMode = INSTALLINGBRAIN; - m_ModeChanged = true; - UpdateBrainPath(); - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - return false; - } - - // Block on our path request completing - while (m_PathRequest && !m_PathRequest->complete) {}; + } else { + // No brain found, so we better place one + if (!noBrainIsOK) { + m_EditorGUIMode = INSTALLINGBRAIN; + m_ModeChanged = true; + UpdateBrainPath(); + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + return false; + } + + // Block on our path request completing + while (m_PathRequest && !m_PathRequest->complete) {}; // Nope! Not valid spot for this brain we found, need to force user to re-place it - if (m_BrainSkyPathCost > MAXBRAINPATHCOST && m_RequireClearPathToOrbit) - { - // Jump to where the bad brain is - m_CursorPos = pBrain->GetPos(); - // Put the resident clone as the current object we need to place - SetCurrentObject(dynamic_cast(pBrain->Clone())); - // Get rid of the resident - it can't be helped there - g_SceneMan.GetScene()->SetResidentBrain(m_pController->GetPlayer(), 0); - // Switch to brain placement mode - m_EditorGUIMode = INSTALLINGBRAIN; - m_ModeChanged = true; - UpdateBrainPath(); - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - return false; - } - - // Brain is fine, leave it be - return true; -} + if (m_BrainSkyPathCost > MAXBRAINPATHCOST && m_RequireClearPathToOrbit) { + // Jump to where the bad brain is + m_CursorPos = pBrain->GetPos(); + // Put the resident clone as the current object we need to place + SetCurrentObject(dynamic_cast(pBrain->Clone())); + // Get rid of the resident - it can't be helped there + g_SceneMan.GetScene()->SetResidentBrain(m_pController->GetPlayer(), 0); + // Switch to brain placement mode + m_EditorGUIMode = INSTALLINGBRAIN; + m_ModeChanged = true; + UpdateBrainPath(); + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + return false; + } + // Brain is fine, leave it be + return true; +} ////////////////////////////////////////////////////////////////////////////////////////// // Method: Update ////////////////////////////////////////////////////////////////////////////////////////// // Description: Updates the state of this Menu each frame -void SceneEditorGUI::Update() -{ - // Update the user controller -// m_pController->Update(); - - m_EditMade = false; - m_pObjectToBlink = 0; - // Which set of placed objects in the scene we're editing - int editedSet = m_FeatureSet == ONLOADEDIT ? Scene::PLACEONLOAD : (m_FeatureSet == AIPLANEDIT ? Scene::AIPLAN : Scene::BLUEPRINT); - - //////////////////////////////////////////// - // Blinking logic -/* - if (m_BlinkMode == OBJECTBLINK) - { - m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); - } - else if (m_BlinkMode == NOCRAFT) - { - bool blink = m_BlinkTimer.AlternateSim(250); - m_pCraftLabel->SetVisible(blink); - m_pCraftBox->SetVisible(blink); - } - - // Time out the blinker - if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) - { - m_pCostLabel->SetVisible(true); - m_pCraftLabel->SetVisible(true); - m_pCraftBox->SetVisible(true); - m_BlinkMode = NOBLINK; - } -*/ +void SceneEditorGUI::Update() { + // Update the user controller + // m_pController->Update(); + + m_EditMade = false; + m_pObjectToBlink = 0; + // Which set of placed objects in the scene we're editing + int editedSet = m_FeatureSet == ONLOADEDIT ? Scene::PLACEONLOAD : (m_FeatureSet == AIPLANEDIT ? Scene::AIPLAN : Scene::BLUEPRINT); + + //////////////////////////////////////////// + // Blinking logic + /* + if (m_BlinkMode == OBJECTBLINK) + { + m_pCostLabel->SetVisible(m_BlinkTimer.AlternateSim(250)); + } + else if (m_BlinkMode == NOCRAFT) + { + bool blink = m_BlinkTimer.AlternateSim(250); + m_pCraftLabel->SetVisible(blink); + m_pCraftBox->SetVisible(blink); + } + + // Time out the blinker + if (m_BlinkMode != NOBLINK && m_BlinkTimer.IsPastSimMS(1500)) + { + m_pCostLabel->SetVisible(true); + m_pCraftLabel->SetVisible(true); + m_pCraftBox->SetVisible(true); + m_BlinkMode = NOBLINK; + } + */ if (m_pCurrentObject && m_EditorGUIMode != PICKINGOBJECT && g_PresetMan.GetReloadEntityPresetCalledThisUpdate()) { - m_pCurrentObject = dynamic_cast(g_PresetMan.GetEntityPreset(m_pCurrentObject->GetClassName(), m_pCurrentObject->GetPresetName(), m_pCurrentObject->GetModuleName())->Clone()); + m_pCurrentObject = dynamic_cast(g_PresetMan.GetEntityPreset(m_pCurrentObject->GetClassName(), m_pCurrentObject->GetPresetName(), m_pCurrentObject->GetModuleName())->Clone()); + } + + ///////////////////////////////////////////// + // Repeating input logic + + bool pressLeft = m_pController->IsState(PRESS_LEFT); + bool pressRight = m_pController->IsState(PRESS_RIGHT); + bool pressUp = m_pController->IsState(PRESS_UP); + bool pressDown = m_pController->IsState(PRESS_DOWN); + + // If no direciton is held down, then cancel the repeating + if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) { + m_RepeatStartTimer.Reset(); + m_RepeatTimer.Reset(); } - ///////////////////////////////////////////// - // Repeating input logic - - bool pressLeft = m_pController->IsState(PRESS_LEFT); - bool pressRight = m_pController->IsState(PRESS_RIGHT); - bool pressUp = m_pController->IsState(PRESS_UP); - bool pressDown = m_pController->IsState(PRESS_DOWN); - - // If no direciton is held down, then cancel the repeating - if (!(m_pController->IsState(MOVE_RIGHT) || m_pController->IsState(MOVE_LEFT) || m_pController->IsState(MOVE_UP) || m_pController->IsState(MOVE_DOWN))) - { - m_RepeatStartTimer.Reset(); - m_RepeatTimer.Reset(); - } - - // Check if any direction has been held for the starting amount of time to get into repeat mode - if (m_RepeatStartTimer.IsPastRealMS(200)) - { - // Check for the repeat interval - if (m_RepeatTimer.IsPastRealMS(30)) - { - if (m_pController->IsState(MOVE_RIGHT)) - pressRight = true; - else if (m_pController->IsState(MOVE_LEFT)) - pressLeft = true; - - if (m_pController->IsState(MOVE_UP)) - pressUp = true; - else if (m_pController->IsState(MOVE_DOWN)) - pressDown = true; - - m_RepeatTimer.Reset(); - } - } - - /////////////////////////////////////////////// - // Analog cursor input - - Vector analogInput; - if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) - analogInput = m_pController->GetAnalogMove(); -// else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) -// analogInput = m_pController->GetAnalogAim(); - - ///////////////////////////////////////////// - // PIE MENU + // Check if any direction has been held for the starting amount of time to get into repeat mode + if (m_RepeatStartTimer.IsPastRealMS(200)) { + // Check for the repeat interval + if (m_RepeatTimer.IsPastRealMS(30)) { + if (m_pController->IsState(MOVE_RIGHT)) + pressRight = true; + else if (m_pController->IsState(MOVE_LEFT)) + pressLeft = true; + + if (m_pController->IsState(MOVE_UP)) + pressUp = true; + else if (m_pController->IsState(MOVE_DOWN)) + pressDown = true; + + m_RepeatTimer.Reset(); + } + } + + /////////////////////////////////////////////// + // Analog cursor input + + Vector analogInput; + if (m_pController->GetAnalogMove().MagnitudeIsGreaterThan(0.1F)) + analogInput = m_pController->GetAnalogMove(); + // else if (m_pController->GetAnalogAim().MagnitudeIsGreaterThan(0.1F)) + // analogInput = m_pController->GetAnalogAim(); + + ///////////////////////////////////////////// + // PIE MENU m_PieMenu->Update(); - // Show the pie menu only when the secondary button is held down - if (m_pController->IsState(PIE_MENU_ACTIVE) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGOBJECT) { - m_PieMenu->SetEnabled(true); - m_PieMenu->SetPos(m_GridSnapping ? g_SceneMan.SnapPosition(m_CursorPos) : m_CursorPos); + // Show the pie menu only when the secondary button is held down + if (m_pController->IsState(PIE_MENU_ACTIVE) && m_EditorGUIMode != INACTIVE && m_EditorGUIMode != PICKINGOBJECT) { + m_PieMenu->SetEnabled(true); + m_PieMenu->SetPos(m_GridSnapping ? g_SceneMan.SnapPosition(m_CursorPos) : m_CursorPos); - std::array infrontAndBehindPieSlices = { m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorInFront), m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorBehind) }; - for (PieSlice* pieSlice : infrontAndBehindPieSlices) { - if (pieSlice) { pieSlice->SetEnabled(m_EditorGUIMode == ADDINGOBJECT); } - } - } else { - m_PieMenu->SetEnabled(false); - } + std::array infrontAndBehindPieSlices = {m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorInFront), m_PieMenu->GetFirstPieSliceByType(PieSlice::SliceType::EditorBehind)}; + for (PieSlice* pieSlice: infrontAndBehindPieSlices) { + if (pieSlice) { + pieSlice->SetEnabled(m_EditorGUIMode == ADDINGOBJECT); + } + } + } else { + m_PieMenu->SetEnabled(false); + } - /////////////////////////////////////// - // Handle pie menu selections + /////////////////////////////////////// + // Handle pie menu selections - if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { + if (m_PieMenu->GetPieCommand() != PieSlice::SliceType::NoType) { if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorPick) { m_EditorGUIMode = PICKINGOBJECT; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorMove) { @@ -499,11 +467,11 @@ void SceneEditorGUI::Update() } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorDone) { m_EditorGUIMode = DONEEDITING; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorInFront) { - m_PreviousMode = m_EditorGUIMode; - m_EditorGUIMode = PLACEINFRONT; - } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorBehind) { - m_PreviousMode = m_EditorGUIMode; - m_EditorGUIMode = PLACEBEHIND; + m_PreviousMode = m_EditorGUIMode; + m_EditorGUIMode = PLACEINFRONT; + } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorBehind) { + m_PreviousMode = m_EditorGUIMode; + m_EditorGUIMode = PLACEBEHIND; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorTeam1) { m_PlaceTeam = Activity::TeamOne; } else if (m_PieMenu->GetPieCommand() == PieSlice::SliceType::EditorTeam2) { @@ -517,397 +485,353 @@ void SceneEditorGUI::Update() SetFeatureSet(m_FeatureSet == FeatureSets::ONLOADEDIT ? FeatureSets::AIPLANEDIT : FeatureSets::ONLOADEDIT); } - UpdateBrainPath(); - m_ModeChanged = true; - } - - ////////////////////////////////////////// - // Picker logic - - // Enable or disable the picker - m_pPicker->SetEnabled(m_EditorGUIMode == PICKINGOBJECT); - - // Update the picker GUI - m_pPicker->Update(); - - if (m_EditorGUIMode == PICKINGOBJECT && m_pPicker->ObjectPicked()) - { - // Assign a copy of the picked object to be the currently held one. - if (SetCurrentObject(dynamic_cast(m_pPicker->ObjectPicked()->Clone()))) - { - // Set the team - if (m_FeatureSet != ONLOADEDIT) - m_pCurrentObject->SetTeam(m_pController->GetTeam()); - // Set the std::list order to be at the end so new objects are added there - m_ObjectListOrder = -1; - // Update the object - m_pCurrentObject->FullUpdate(); - // Update the path to the brain, or clear it if there's none - UpdateBrainPath(); - - // If done picking, revert to moving object mode - if (m_pPicker->DonePicking()) - { - // If picked a Brain Actor, then enter install brain mode. Allow to use deployments in brain mode only while editing in-game - if (m_pCurrentObject->IsInGroup("Brains") && (m_FeatureSet == INGAMEEDIT || !dynamic_cast(m_pCurrentObject))) + UpdateBrainPath(); + m_ModeChanged = true; + } + + ////////////////////////////////////////// + // Picker logic + + // Enable or disable the picker + m_pPicker->SetEnabled(m_EditorGUIMode == PICKINGOBJECT); + + // Update the picker GUI + m_pPicker->Update(); + + if (m_EditorGUIMode == PICKINGOBJECT && m_pPicker->ObjectPicked()) { + // Assign a copy of the picked object to be the currently held one. + if (SetCurrentObject(dynamic_cast(m_pPicker->ObjectPicked()->Clone()))) { + // Set the team + if (m_FeatureSet != ONLOADEDIT) + m_pCurrentObject->SetTeam(m_pController->GetTeam()); + // Set the std::list order to be at the end so new objects are added there + m_ObjectListOrder = -1; + // Update the object + m_pCurrentObject->FullUpdate(); + // Update the path to the brain, or clear it if there's none + UpdateBrainPath(); + + // If done picking, revert to moving object mode + if (m_pPicker->DonePicking()) { + // If picked a Brain Actor, then enter install brain mode. Allow to use deployments in brain mode only while editing in-game + if (m_pCurrentObject->IsInGroup("Brains") && (m_FeatureSet == INGAMEEDIT || !dynamic_cast(m_pCurrentObject))) m_EditorGUIMode = INSTALLINGBRAIN; - else - m_EditorGUIMode = ADDINGOBJECT; - - UpdateBrainPath(); - m_ModeChanged = true; - } - } - } - - if (!m_pPicker->IsVisible()) - g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - else - g_FrameMan.SetScreenText("Pick what you want to place next", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - ///////////////////////////////////// - // ADDING OBJECT MODE - - if (m_EditorGUIMode == ADDINGOBJECT && !m_PieMenu->IsEnabled()) - { - if (m_ModeChanged) - { - - m_ModeChanged = false; - } - g_FrameMan.SetScreenText("Click to ADD a new object - Drag for precision", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - - m_DrawCurrentObject = true; - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput * 8; - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= SCENESNAPSIZE; - if (pressRight) - m_CursorPos.m_X += SCENESNAPSIZE; - if (pressDown) - m_CursorPos.m_Y += SCENESNAPSIZE; - if (pressLeft) - m_CursorPos.m_X -= SCENESNAPSIZE; - // Re-enable snapping only when the cursor is moved again - if (pressUp || pressRight || pressDown || pressLeft) - m_GridSnapping = true; - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - - // Mousewheel is used as shortcut for getting next and prev items in teh picker's object std::list - if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(ControlState::ACTOR_NEXT)) - { - // Assign a copy of the next picked object to be the currently held one. - const SceneObject *pNewObject = m_pPicker->GetPrevObject(); - if (pNewObject) - { - // Set and update the cursor object - if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) - m_pCurrentObject->FullUpdate(); - } - } - else if (m_pController->IsState(SCROLL_DOWN) || m_pController->IsState(ControlState::ACTOR_PREV)) - { - // Assign a copy of the next picked object to be the currently held one. - const SceneObject *pNewObject = m_pPicker->GetNextObject(); - if (pNewObject) - { - // Set and update the object - if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) - m_pCurrentObject->FullUpdate(); - } - } - - // Start the timer when the button is first pressed, and when the picker has deactivated - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - m_BlinkTimer.Reset(); - m_EditorGUIMode = PLACINGOBJECT; - m_PreviousMode = ADDINGOBJECT; - m_ModeChanged = true; - g_GUISound.PlacementBlip()->Play(m_pController->GetPlayer()); - } - - // Apply the team to the current actor, if applicable - if (m_pCurrentObject && m_DrawCurrentObject) - { - // Set the team of SceneObject based on what's been selected - // Only if full featured mode, otherwise it's based on the controller when placed - if (m_FeatureSet == ONLOADEDIT) - m_pCurrentObject->SetTeam(m_PlaceTeam); - } - } - - ///////////////////////////////////// - // INSTALLING BRAIN MODE - - if (m_EditorGUIMode == INSTALLINGBRAIN && !m_PieMenu->IsEnabled()) - { - if (m_ModeChanged) - { - // Check if we already have a resident brain to replace/re-place - SceneObject *pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); - if (pBrain) - { - // Fly over to where the brain was previously found - SetCursorPos(pBrain->GetPos()); - // If the brain in hand is not appropriate replacement, then just use the resident brain as a copy to re-place it - if (!m_pCurrentObject->IsInGroup("Brains")) - { - // Make sure the player's resident brain is the one being held in cursor - SetCurrentObject(dynamic_cast(pBrain->Clone())); - // Clear the brain of the scene; it will be reinstated when we place it again -// NOPE, keep it here in case placing the brain goes awry - it won't be drawn anyway -// g_SceneMan.GetScene()->SetResidentBrain(m_pController->GetPlayer(), 0); - } - } - // Ok, so no resident brain - do we have one in hand already?? - else if (m_pCurrentObject && m_pCurrentObject->IsInGroup("Brains")) - { - // Continue with placing it as per usual - ; - } - // Pick a brain to install if no one existed already in scene or in hand - else - { - m_pPicker->SelectGroupByName("Brains"); - m_EditorGUIMode = PICKINGOBJECT; - m_ModeChanged = true; - UpdateBrainPath(); - } - - m_ModeChanged = false; - } - g_FrameMan.SetScreenText("Click to INSTALL your governor brain with a clear path to orbit - Drag for precision", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - m_DrawCurrentObject = true; - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput * 8; - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - // Re-enable snapping only when the cursor is moved again - m_GridSnapping = true; - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= SCENESNAPSIZE; - if (pressRight) - m_CursorPos.m_X += SCENESNAPSIZE; - if (pressDown) - m_CursorPos.m_Y += SCENESNAPSIZE; - if (pressLeft) - m_CursorPos.m_X -= SCENESNAPSIZE; - // Re-enable snapping only when the cursor is moved again - if (pressUp || pressRight || pressDown || pressLeft) - m_GridSnapping = true; - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - - // Check brain position validity with pathfinding and show a path to the sky + else + m_EditorGUIMode = ADDINGOBJECT; + + UpdateBrainPath(); + m_ModeChanged = true; + } + } + } + + if (!m_pPicker->IsVisible()) + g_CameraMan.SetScreenOcclusion(Vector(), g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + else + g_FrameMan.SetScreenText("Pick what you want to place next", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + ///////////////////////////////////// + // ADDING OBJECT MODE + + if (m_EditorGUIMode == ADDINGOBJECT && !m_PieMenu->IsEnabled()) { + if (m_ModeChanged) { + + m_ModeChanged = false; + } + g_FrameMan.SetScreenText("Click to ADD a new object - Drag for precision", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + m_DrawCurrentObject = true; + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) { + m_CursorPos += analogInput * 8; + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= SCENESNAPSIZE; + if (pressRight) + m_CursorPos.m_X += SCENESNAPSIZE; + if (pressDown) + m_CursorPos.m_Y += SCENESNAPSIZE; + if (pressLeft) + m_CursorPos.m_X -= SCENESNAPSIZE; + // Re-enable snapping only when the cursor is moved again + if (pressUp || pressRight || pressDown || pressLeft) + m_GridSnapping = true; + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + + // Mousewheel is used as shortcut for getting next and prev items in teh picker's object std::list + if (m_pController->IsState(SCROLL_UP) || m_pController->IsState(ControlState::ACTOR_NEXT)) { + // Assign a copy of the next picked object to be the currently held one. + const SceneObject* pNewObject = m_pPicker->GetPrevObject(); + if (pNewObject) { + // Set and update the cursor object + if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) + m_pCurrentObject->FullUpdate(); + } + } else if (m_pController->IsState(SCROLL_DOWN) || m_pController->IsState(ControlState::ACTOR_PREV)) { + // Assign a copy of the next picked object to be the currently held one. + const SceneObject* pNewObject = m_pPicker->GetNextObject(); + if (pNewObject) { + // Set and update the object + if (SetCurrentObject(dynamic_cast(pNewObject->Clone()))) + m_pCurrentObject->FullUpdate(); + } + } + + // Start the timer when the button is first pressed, and when the picker has deactivated + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + m_BlinkTimer.Reset(); + m_EditorGUIMode = PLACINGOBJECT; + m_PreviousMode = ADDINGOBJECT; + m_ModeChanged = true; + g_GUISound.PlacementBlip()->Play(m_pController->GetPlayer()); + } + + // Apply the team to the current actor, if applicable + if (m_pCurrentObject && m_DrawCurrentObject) { + // Set the team of SceneObject based on what's been selected + // Only if full featured mode, otherwise it's based on the controller when placed + if (m_FeatureSet == ONLOADEDIT) + m_pCurrentObject->SetTeam(m_PlaceTeam); + } + } + + ///////////////////////////////////// + // INSTALLING BRAIN MODE + + if (m_EditorGUIMode == INSTALLINGBRAIN && !m_PieMenu->IsEnabled()) { + if (m_ModeChanged) { + // Check if we already have a resident brain to replace/re-place + SceneObject* pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); + if (pBrain) { + // Fly over to where the brain was previously found + SetCursorPos(pBrain->GetPos()); + // If the brain in hand is not appropriate replacement, then just use the resident brain as a copy to re-place it + if (!m_pCurrentObject->IsInGroup("Brains")) { + // Make sure the player's resident brain is the one being held in cursor + SetCurrentObject(dynamic_cast(pBrain->Clone())); + // Clear the brain of the scene; it will be reinstated when we place it again + // NOPE, keep it here in case placing the brain goes awry - it won't be drawn anyway + // g_SceneMan.GetScene()->SetResidentBrain(m_pController->GetPlayer(), 0); + } + } + // Ok, so no resident brain - do we have one in hand already?? + else if (m_pCurrentObject && m_pCurrentObject->IsInGroup("Brains")) { + // Continue with placing it as per usual + ; + } + // Pick a brain to install if no one existed already in scene or in hand + else { + m_pPicker->SelectGroupByName("Brains"); + m_EditorGUIMode = PICKINGOBJECT; + m_ModeChanged = true; + UpdateBrainPath(); + } + + m_ModeChanged = false; + } + g_FrameMan.SetScreenText("Click to INSTALL your governor brain with a clear path to orbit - Drag for precision", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + m_DrawCurrentObject = true; + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) { + m_CursorPos += analogInput * 8; + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + // Re-enable snapping only when the cursor is moved again + m_GridSnapping = true; + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= SCENESNAPSIZE; + if (pressRight) + m_CursorPos.m_X += SCENESNAPSIZE; + if (pressDown) + m_CursorPos.m_Y += SCENESNAPSIZE; + if (pressLeft) + m_CursorPos.m_X -= SCENESNAPSIZE; + // Re-enable snapping only when the cursor is moved again + if (pressUp || pressRight || pressDown || pressLeft) + m_GridSnapping = true; + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + + // Check brain position validity with pathfinding and show a path to the sky UpdateBrainSkyPathAndCost(m_CursorPos); -/* - // Process the new path we now have, if any - if (!m_BrainSkyPath.empty()) - { - // Smash all airborne waypoints down to just above the ground, except for when it makes the path intersect terrain or it is the final destination - std::list::iterator finalItr = m_BrainSkyPath.end(); - finalItr--; - Vector smashedPoint; - Vector previousPoint = *(m_BrainSkyPath.begin()); - std::list::iterator nextItr = m_BrainSkyPath.begin(); - for (std::list::iterator lItr = m_BrainSkyPath.begin(); lItr != finalItr; ++lItr) - { - nextItr++; - smashedPoint = g_SceneMan.MovePointToGround((*lItr), 20, 10); - Vector notUsed; - - // Only smash if the new location doesn't cause the path to intersect hard terrain ahead or behind of it - // Try three times to halve the height to see if that won't intersect - for (int i = 0; i < 3; i++) - { - if (!g_SceneMan.CastStrengthRay(previousPoint, smashedPoint - previousPoint, 5, notUsed, 3, g_MaterialDoor) && - nextItr != m_BrainSkyPath.end() && !g_SceneMan.CastStrengthRay(smashedPoint, (*nextItr) - smashedPoint, 5, notUsed, 3, g_MaterialDoor)) - { - (*lItr) = smashedPoint; - break; - } - else - smashedPoint.m_Y -= ((smashedPoint.m_Y - (*lItr).m_Y) / 2); - } - - previousPoint = (*lItr); - } - } -*/ - // Start the timer when the button is first pressed, and when the picker has deactivated - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - m_BlinkTimer.Reset(); - m_EditorGUIMode = PLACINGOBJECT; - m_PreviousMode = INSTALLINGBRAIN; - m_ModeChanged = true; - g_GUISound.PlacementBlip()->Play(m_pController->GetPlayer()); - } - - // Apply the team to the current actor, if applicable - if (m_pCurrentObject && m_DrawCurrentObject) - { - // Set the team of SceneObject based on what's been selected - // Only if full featured mode, otherwise it's based on the controller when placed - if (m_FeatureSet == ONLOADEDIT) - m_pCurrentObject->SetTeam(m_PlaceTeam); - } - } - - ///////////////////////////////////////////////////////////// - // PLACING MODE - - else if (m_EditorGUIMode == PLACINGOBJECT) - { - if (m_ModeChanged) - { - - m_ModeChanged = false; - } - - if (m_PreviousMode == MOVINGOBJECT) - g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - else if (m_PreviousMode == INSTALLINGBRAIN) - g_FrameMan.SetScreenText("Release to INSTALL the governor brain - Tap other button to cancel", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - else - g_FrameMan.SetScreenText("Release to ADD the new object - Tap other button to cancel", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // Check brain position validity with pathfinding and show a path to the sky - if (m_PreviousMode == INSTALLINGBRAIN) { UpdateBrainSkyPathAndCost(m_CursorPos); } - - m_DrawCurrentObject = true; - - // Freeze when first pressing down and grid snapping is still engaged - if (!(m_pController->IsState(PRIMARY_ACTION) && m_GridSnapping)) - { - if (!analogInput.IsZero()) - { - m_CursorPos += analogInput; - m_FacingLeft = analogInput.m_X < 0 || (m_FacingLeft && analogInput.m_X == 0); - } - // Try the mouse - else if (!m_pController->GetMouseMovement().IsZero()) - { - m_CursorPos += m_pController->GetMouseMovement(); - m_FacingLeft = m_pController->GetMouseMovement().m_X < 0 || (m_FacingLeft && m_pController->GetMouseMovement().m_X == 0); - } - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= 1; - if (pressRight) - { - m_CursorPos.m_X += 1; - m_FacingLeft = false; - } - if (pressDown) - m_CursorPos.m_Y += 1; - if (pressLeft) - { - m_CursorPos.m_X -= 1; - m_FacingLeft = true; - } - } - - // Detect whether the cursor is in the air, or if it's overlapping some terrain - Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); - m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; - // Also check that it isn't over unseen areas, can't place there - m_CursorInAir = m_CursorInAir && !g_SceneMan.IsUnseen(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY(), m_pController->GetTeam()); - } - - // Constrain the cursor to only be within specific scene areas -// TODO: THIS!!! - - // Disable snapping after a small interval of holding down the button, to avoid unintentional nudges when just placing on the grid - if (m_pController->IsState(PRIMARY_ACTION) && m_BlinkTimer.IsPastRealMS(333) && m_GridSnapping) - { - m_GridSnapping = false; - m_CursorPos = g_SceneMan.SnapPosition(m_CursorPos); - } - - // Cancel placing if secondary button is pressed - if (m_pController->IsState(PRESS_SECONDARY) || m_pController->IsState(PIE_MENU_ACTIVE)) - { - m_EditorGUIMode = m_PreviousMode; - m_ModeChanged = true; - } - // If previous mode was moving, tear the gib loose if the button is released to soo - else if (m_PreviousMode == MOVINGOBJECT && m_pController->IsState(RELEASE_PRIMARY) && !m_BlinkTimer.IsPastRealMS(150)) - { - m_EditorGUIMode = ADDINGOBJECT; - m_ModeChanged = true; - } - // Only place if the picker and pie menus are completely out of view, to avoid immediate placing after picking - else if (m_pCurrentObject && m_pController->IsState(RELEASE_PRIMARY) && !m_pPicker->IsVisible()) - { - m_pCurrentObject->FullUpdate(); - - // Placing governor brain, which actually just puts it back into the resident brain roster - if (m_PreviousMode == INSTALLINGBRAIN) - { - // Force our path request to complete so we know whether we can place or not - while (m_PathRequest && !m_PathRequest->complete) {}; - - // Only place if the brain has a clear path to the sky! - if (m_BrainSkyPathCost <= MAXBRAINPATHCOST || !m_RequireClearPathToOrbit) - { + /* + // Process the new path we now have, if any + if (!m_BrainSkyPath.empty()) + { + // Smash all airborne waypoints down to just above the ground, except for when it makes the path intersect terrain or it is the final destination + std::list::iterator finalItr = m_BrainSkyPath.end(); + finalItr--; + Vector smashedPoint; + Vector previousPoint = *(m_BrainSkyPath.begin()); + std::list::iterator nextItr = m_BrainSkyPath.begin(); + for (std::list::iterator lItr = m_BrainSkyPath.begin(); lItr != finalItr; ++lItr) + { + nextItr++; + smashedPoint = g_SceneMan.MovePointToGround((*lItr), 20, 10); + Vector notUsed; + + // Only smash if the new location doesn't cause the path to intersect hard terrain ahead or behind of it + // Try three times to halve the height to see if that won't intersect + for (int i = 0; i < 3; i++) + { + if (!g_SceneMan.CastStrengthRay(previousPoint, smashedPoint - previousPoint, 5, notUsed, 3, g_MaterialDoor) && + nextItr != m_BrainSkyPath.end() && !g_SceneMan.CastStrengthRay(smashedPoint, (*nextItr) - smashedPoint, 5, notUsed, 3, g_MaterialDoor)) + { + (*lItr) = smashedPoint; + break; + } + else + smashedPoint.m_Y -= ((smashedPoint.m_Y - (*lItr).m_Y) / 2); + } + + previousPoint = (*lItr); + } + } + */ + // Start the timer when the button is first pressed, and when the picker has deactivated + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + m_BlinkTimer.Reset(); + m_EditorGUIMode = PLACINGOBJECT; + m_PreviousMode = INSTALLINGBRAIN; + m_ModeChanged = true; + g_GUISound.PlacementBlip()->Play(m_pController->GetPlayer()); + } + + // Apply the team to the current actor, if applicable + if (m_pCurrentObject && m_DrawCurrentObject) { + // Set the team of SceneObject based on what's been selected + // Only if full featured mode, otherwise it's based on the controller when placed + if (m_FeatureSet == ONLOADEDIT) + m_pCurrentObject->SetTeam(m_PlaceTeam); + } + } + + ///////////////////////////////////////////////////////////// + // PLACING MODE + + else if (m_EditorGUIMode == PLACINGOBJECT) { + if (m_ModeChanged) { + + m_ModeChanged = false; + } + + if (m_PreviousMode == MOVINGOBJECT) + g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + else if (m_PreviousMode == INSTALLINGBRAIN) + g_FrameMan.SetScreenText("Release to INSTALL the governor brain - Tap other button to cancel", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + else + g_FrameMan.SetScreenText("Release to ADD the new object - Tap other button to cancel", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // Check brain position validity with pathfinding and show a path to the sky + if (m_PreviousMode == INSTALLINGBRAIN) { + UpdateBrainSkyPathAndCost(m_CursorPos); + } + + m_DrawCurrentObject = true; + + // Freeze when first pressing down and grid snapping is still engaged + if (!(m_pController->IsState(PRIMARY_ACTION) && m_GridSnapping)) { + if (!analogInput.IsZero()) { + m_CursorPos += analogInput; + m_FacingLeft = analogInput.m_X < 0 || (m_FacingLeft && analogInput.m_X == 0); + } + // Try the mouse + else if (!m_pController->GetMouseMovement().IsZero()) { + m_CursorPos += m_pController->GetMouseMovement(); + m_FacingLeft = m_pController->GetMouseMovement().m_X < 0 || (m_FacingLeft && m_pController->GetMouseMovement().m_X == 0); + } + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= 1; + if (pressRight) { + m_CursorPos.m_X += 1; + m_FacingLeft = false; + } + if (pressDown) + m_CursorPos.m_Y += 1; + if (pressLeft) { + m_CursorPos.m_X -= 1; + m_FacingLeft = true; + } + } + + // Detect whether the cursor is in the air, or if it's overlapping some terrain + Vector snappedPos = g_SceneMan.SnapPosition(m_CursorPos, m_GridSnapping); + m_CursorInAir = g_SceneMan.GetTerrMatter(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY()) == g_MaterialAir; + // Also check that it isn't over unseen areas, can't place there + m_CursorInAir = m_CursorInAir && !g_SceneMan.IsUnseen(snappedPos.GetFloorIntX(), snappedPos.GetFloorIntY(), m_pController->GetTeam()); + } + + // Constrain the cursor to only be within specific scene areas + // TODO: THIS!!! + + // Disable snapping after a small interval of holding down the button, to avoid unintentional nudges when just placing on the grid + if (m_pController->IsState(PRIMARY_ACTION) && m_BlinkTimer.IsPastRealMS(333) && m_GridSnapping) { + m_GridSnapping = false; + m_CursorPos = g_SceneMan.SnapPosition(m_CursorPos); + } + + // Cancel placing if secondary button is pressed + if (m_pController->IsState(PRESS_SECONDARY) || m_pController->IsState(PIE_MENU_ACTIVE)) { + m_EditorGUIMode = m_PreviousMode; + m_ModeChanged = true; + } + // If previous mode was moving, tear the gib loose if the button is released to soo + else if (m_PreviousMode == MOVINGOBJECT && m_pController->IsState(RELEASE_PRIMARY) && !m_BlinkTimer.IsPastRealMS(150)) { + m_EditorGUIMode = ADDINGOBJECT; + m_ModeChanged = true; + } + // Only place if the picker and pie menus are completely out of view, to avoid immediate placing after picking + else if (m_pCurrentObject && m_pController->IsState(RELEASE_PRIMARY) && !m_pPicker->IsVisible()) { + m_pCurrentObject->FullUpdate(); + + // Placing governor brain, which actually just puts it back into the resident brain roster + if (m_PreviousMode == INSTALLINGBRAIN) { + // Force our path request to complete so we know whether we can place or not + while (m_PathRequest && !m_PathRequest->complete) {}; + + // Only place if the brain has a clear path to the sky! + if (m_BrainSkyPathCost <= MAXBRAINPATHCOST || !m_RequireClearPathToOrbit) { bool placeBrain = true; // Brain deployment's are translated into the appropriate loadout and put in place in the scene // but only while editing ingame - Deployment *pDep = dynamic_cast(m_pCurrentObject); - if (pDep) - { - if (m_FeatureSet == INGAMEEDIT) - { + Deployment* pDep = dynamic_cast(m_pCurrentObject); + if (pDep) { + if (m_FeatureSet == INGAMEEDIT) { float cost; - Actor *pActor = pDep->CreateDeployedActor(pDep->GetPlacedByPlayer(), cost); - if (pActor && pActor->IsInGroup("Brains")) - { + Actor* pActor = pDep->CreateDeployedActor(pDep->GetPlacedByPlayer(), cost); + if (pActor && pActor->IsInGroup("Brains")) { delete m_pCurrentObject; m_pCurrentObject = pActor; } else { @@ -918,12 +842,11 @@ void SceneEditorGUI::Update() } } - if (placeBrain) - { + if (placeBrain) { // Place and let go (passing ownership) of the new governor brain g_SceneMan.GetScene()->SetResidentBrain(m_pController->GetPlayer(), m_pCurrentObject); - // NO! This deletes the brain we just passed ownership of! just let go, man - // SetCurrentObject(0); + // NO! This deletes the brain we just passed ownership of! just let go, man + // SetCurrentObject(0); m_pCurrentObject = 0; // Nothing in cursor now, so force to pick somehting else to place right away m_EditorGUIMode = PICKINGOBJECT; @@ -937,62 +860,54 @@ void SceneEditorGUI::Update() UpdateBrainPath(); g_GUISound.PlacementThud()->Play(m_pController->GetPlayer()); } - } - // If no clear path to the sky, just reject the placment and keep the brain in hand - else - { - g_FrameMan.ClearScreenText(g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - g_FrameMan.SetScreenText("Your brain can only be placed with a clear access path to orbit!", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer()), 333, 3500); - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - } - // Non-brain thing is being placed - else - { - // If we're not editing in-game, then just add to the placed objects std::list - if (m_FeatureSet != INGAMEEDIT) - { - //If true we need to place object in the end, if false, then it was already given to an actor + } + // If no clear path to the sky, just reject the placment and keep the brain in hand + else { + g_FrameMan.ClearScreenText(g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + g_FrameMan.SetScreenText("Your brain can only be placed with a clear access path to orbit!", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer()), 333, 3500); + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + } + // Non-brain thing is being placed + else { + // If we're not editing in-game, then just add to the placed objects std::list + if (m_FeatureSet != INGAMEEDIT) { + // If true we need to place object in the end, if false, then it was already given to an actor bool toPlace = true; - //If we're placing an item then give that item to actor instead of dropping it nearby - HeldDevice *pHeldDevice = dynamic_cast(m_pCurrentObject); - if (pHeldDevice) - if (dynamic_cast(pHeldDevice) || dynamic_cast(pHeldDevice)) - { + // If we're placing an item then give that item to actor instead of dropping it nearby + HeldDevice* pHeldDevice = dynamic_cast(m_pCurrentObject); + if (pHeldDevice) + if (dynamic_cast(pHeldDevice) || dynamic_cast(pHeldDevice)) { int objectListPosition = -1; - //Find out if we have AHuman under the cursor - const SceneObject *pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &objectListPosition); - const Actor *pAHuman = 0; + // Find out if we have AHuman under the cursor + const SceneObject* pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &objectListPosition); + const Actor* pAHuman = 0; // Looks like we got nothing, search for actors in range then if (!pPickedSceneObject) - pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); + pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); - if (pPickedSceneObject) - { - pAHuman = dynamic_cast(pPickedSceneObject); + if (pPickedSceneObject) { + pAHuman = dynamic_cast(pPickedSceneObject); - if (!pAHuman) - { + if (!pAHuman) { // Maybe we clicked the underlying bunker module, search for actor in range - pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); + pPickedSceneObject = g_SceneMan.GetScene()->PickPlacedActorInRange(editedSet, m_CursorPos, 20, &objectListPosition); if (pPickedSceneObject) - pAHuman = dynamic_cast(pPickedSceneObject); + pAHuman = dynamic_cast(pPickedSceneObject); } - if (pAHuman) - { - //Create a new AHuman instead of old one, give him an item, and delete old AHuman - SceneObject * pNewObject = dynamic_cast(pPickedSceneObject->Clone()); + if (pAHuman) { + // Create a new AHuman instead of old one, give him an item, and delete old AHuman + SceneObject* pNewObject = dynamic_cast(pPickedSceneObject->Clone()); g_SceneMan.GetScene()->RemovePlacedObject(editedSet, objectListPosition); - AHuman *pAHuman = dynamic_cast(pNewObject); - if (pAHuman) - { - pAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); + AHuman* pAHuman = dynamic_cast(pNewObject); + if (pAHuman) { + pAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); pAHuman->FlashWhite(150); } @@ -1002,19 +917,14 @@ void SceneEditorGUI::Update() g_GUISound.PlacementThud()->Play(m_pController->GetPlayer()); toPlace = false; } - } - else - { - //No human? Look for brains robots then - SceneObject *pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); - if (pBrain) - { - if (g_SceneMan.ShortestDistance(pBrain->GetPos(), m_CursorPos,true).MagnitudeIsLessThan(20.0F)) - { - AHuman * pBrainAHuman = dynamic_cast(pBrain); - if (pBrainAHuman) - { - pBrainAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); + } else { + // No human? Look for brains robots then + SceneObject* pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); + if (pBrain) { + if (g_SceneMan.ShortestDistance(pBrain->GetPos(), m_CursorPos, true).MagnitudeIsLessThan(20.0F)) { + AHuman* pBrainAHuman = dynamic_cast(pBrain); + if (pBrainAHuman) { + pBrainAHuman->AddInventoryItem(dynamic_cast(m_pCurrentObject->Clone())); pBrainAHuman->FlashWhite(150); m_EditMade = true; g_GUISound.PlacementThud()->Play(m_pController->GetPlayer()); @@ -1025,88 +935,80 @@ void SceneEditorGUI::Update() } } - if (toPlace) - { - g_SceneMan.GetScene()->AddPlacedObject(editedSet, dynamic_cast(m_pCurrentObject->Clone()), m_ObjectListOrder); + if (toPlace) { + g_SceneMan.GetScene()->AddPlacedObject(editedSet, dynamic_cast(m_pCurrentObject->Clone()), m_ObjectListOrder); // Increment the std::list order so we place over last placed item if (m_ObjectListOrder >= 0) m_ObjectListOrder++; g_GUISound.PlacementThud()->Play(m_pController->GetPlayer()); m_EditMade = true; } - } - // If in-game editing, then place into the sim - else - { - // Check if team can afford the placed object and if so, deduct the cost - if (g_ActivityMan.GetActivity()->GetTeamFunds(m_pController->GetTeam()) < m_pCurrentObject->GetTotalValue(m_NativeTechModule, m_ForeignCostMult)) - { - g_FrameMan.ClearScreenText(g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - g_FrameMan.SetScreenText("You can't afford to place that!", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer()), 333, 1500); - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - else - { -// TODO: Experimental! clean up this messiness - SceneObject *pPlacedClone = dynamic_cast(m_pCurrentObject->Clone()); - pPlacedClone->SetTeam(m_pController->GetTeam()); - - TerrainObject *pTO = dynamic_cast(pPlacedClone); - if (pTO) - { - // Deduct the cost from team funds - g_ActivityMan.GetActivity()->ChangeTeamFunds(-m_pCurrentObject->GetTotalValue(m_NativeTechModule, m_ForeignCostMult), m_pController->GetTeam()); + } + // If in-game editing, then place into the sim + else { + // Check if team can afford the placed object and if so, deduct the cost + if (g_ActivityMan.GetActivity()->GetTeamFunds(m_pController->GetTeam()) < m_pCurrentObject->GetTotalValue(m_NativeTechModule, m_ForeignCostMult)) { + g_FrameMan.ClearScreenText(g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + g_FrameMan.SetScreenText("You can't afford to place that!", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer()), 333, 1500); + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } else { + // TODO: Experimental! clean up this messiness + SceneObject* pPlacedClone = dynamic_cast(m_pCurrentObject->Clone()); + pPlacedClone->SetTeam(m_pController->GetTeam()); + + TerrainObject* pTO = dynamic_cast(pPlacedClone); + if (pTO) { + // Deduct the cost from team funds + g_ActivityMan.GetActivity()->ChangeTeamFunds(-m_pCurrentObject->GetTotalValue(m_NativeTechModule, m_ForeignCostMult), m_pController->GetTeam()); pTO->PlaceOnTerrain(g_SceneMan.GetTerrain()); g_SceneMan.GetTerrain()->CleanAir(); Vector terrainObjectPos = pTO->GetPos() + pTO->GetBitmapOffset(); - if (pTO->HasBGColorBitmap()) { g_SceneMan.RegisterTerrainChange(terrainObjectPos.GetFloorIntX(), terrainObjectPos.GetFloorIntY(), pTO->GetBitmapWidth(), pTO->GetBitmapHeight(), ColorKeys::g_MaskColor, true); } - if (pTO->HasFGColorBitmap()) { g_SceneMan.RegisterTerrainChange(terrainObjectPos.GetFloorIntX(), terrainObjectPos.GetFloorIntY(), pTO->GetBitmapWidth(), pTO->GetBitmapHeight(), ColorKeys::g_MaskColor, false); } - -// TODO: Make IsBrain function to see if one was placed - if (pTO->GetPresetName() == "Brain Vault") - { - // Register the brain as this player's - // g_ActivityMan.GetActivity()->SetPlayerBrain(pBrain, m_pController->GetPlayer()); - m_EditorGUIMode = PICKINGOBJECT; - m_ModeChanged = true; - } - - delete pPlacedClone; - pPlacedClone = 0; - g_GUISound.PlacementThud()->Play(m_pController->GetPlayer()); - g_GUISound.PlacementGravel()->Play(m_pController->GetPlayer()); - m_EditMade = true; - } - // Only place if the cursor is clear of terrain obstructions - else if (m_CursorInAir) - { + if (pTO->HasBGColorBitmap()) { + g_SceneMan.RegisterTerrainChange(terrainObjectPos.GetFloorIntX(), terrainObjectPos.GetFloorIntY(), pTO->GetBitmapWidth(), pTO->GetBitmapHeight(), ColorKeys::g_MaskColor, true); + } + if (pTO->HasFGColorBitmap()) { + g_SceneMan.RegisterTerrainChange(terrainObjectPos.GetFloorIntX(), terrainObjectPos.GetFloorIntY(), pTO->GetBitmapWidth(), pTO->GetBitmapHeight(), ColorKeys::g_MaskColor, false); + } + + // TODO: Make IsBrain function to see if one was placed + if (pTO->GetPresetName() == "Brain Vault") { + // Register the brain as this player's + // g_ActivityMan.GetActivity()->SetPlayerBrain(pBrain, m_pController->GetPlayer()); + m_EditorGUIMode = PICKINGOBJECT; + m_ModeChanged = true; + } + + delete pPlacedClone; + pPlacedClone = 0; + g_GUISound.PlacementThud()->Play(m_pController->GetPlayer()); + g_GUISound.PlacementGravel()->Play(m_pController->GetPlayer()); + m_EditMade = true; + } + // Only place if the cursor is clear of terrain obstructions + else if (m_CursorInAir) { float value = m_pCurrentObject->GetTotalValue(m_NativeTechModule, m_ForeignCostMult); // Deployment:s are translated into the appropriate loadout and put in place in the scene - Deployment *pDep = dynamic_cast(pPlacedClone); - if (pDep) - { + Deployment* pDep = dynamic_cast(pPlacedClone); + if (pDep) { // Ownership IS transferred here; pass it along into the MovableMan float cost = 0; - Actor *pActor = pDep->CreateDeployedActor(pDep->GetPlacedByPlayer(), cost); - if (pActor) - { + Actor* pActor = pDep->CreateDeployedActor(pDep->GetPlacedByPlayer(), cost); + if (pActor) { value = cost; g_MovableMan.AddActor(pActor); } // Just a simple Device in the Deployment? - else - { + else { value = cost; // Get the Item/Device and add to scene, passing ownership - SceneObject *pObject = pDep->CreateDeployedObject(pDep->GetPlacedByPlayer(), cost); - MovableObject *pMO = dynamic_cast(pObject); + SceneObject* pObject = pDep->CreateDeployedObject(pDep->GetPlacedByPlayer(), cost); + MovableObject* pMO = dynamic_cast(pObject); if (pMO) g_MovableMan.AddMO(pMO); - else - { + else { delete pObject; pObject = 0; } @@ -1118,534 +1020,474 @@ void SceneEditorGUI::Update() m_EditMade = true; } - // Deduct the cost from team funds - g_ActivityMan.GetActivity()->ChangeTeamFunds(-value, m_pController->GetTeam()); - - Actor *pActor = dynamic_cast(pPlacedClone); - HeldDevice *pDevice = 0; - if (pActor) - { - g_MovableMan.AddActor(pActor); - m_EditMade = true; - } - else if (pDevice = dynamic_cast(pPlacedClone)) - { + // Deduct the cost from team funds + g_ActivityMan.GetActivity()->ChangeTeamFunds(-value, m_pController->GetTeam()); + + Actor* pActor = dynamic_cast(pPlacedClone); + HeldDevice* pDevice = 0; + if (pActor) { + g_MovableMan.AddActor(pActor); + m_EditMade = true; + } else if (pDevice = dynamic_cast(pPlacedClone)) { // If we have a friendly actor or brain nearby then give him an item instead of placing it bool toPlace = true; Vector distanceToActor; - Actor *pNearestActor = g_MovableMan.GetClosestTeamActor(m_pController->GetTeam(), m_pController->GetPlayer(), pPlacedClone->GetPos(), 20, distanceToActor); + Actor* pNearestActor = g_MovableMan.GetClosestTeamActor(m_pController->GetTeam(), m_pController->GetPlayer(), pPlacedClone->GetPos(), 20, distanceToActor); // If we could not find an ordinary actor, then look for brain actor - if (!pNearestActor) - { + if (!pNearestActor) { // Find a brain and check if it's close enough - SceneObject *pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); - if (pBrain) - { - if (g_SceneMan.ShortestDistance(pBrain->GetPos(), pPlacedClone->GetPos(),true).MagnitudeIsLessThan(20.0F)) - { - AHuman * pBrainAHuman = dynamic_cast(pBrain); - if (pBrainAHuman) - { + SceneObject* pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); + if (pBrain) { + if (g_SceneMan.ShortestDistance(pBrain->GetPos(), pPlacedClone->GetPos(), true).MagnitudeIsLessThan(20.0F)) { + AHuman* pBrainAHuman = dynamic_cast(pBrain); + if (pBrainAHuman) { pNearestActor = pBrainAHuman; } } } } - //If we have any AHuman actor then give it an item - if (pNearestActor) - { - AHuman * pNearestAHuman = dynamic_cast(pNearestActor); - if (pNearestAHuman) - { + // If we have any AHuman actor then give it an item + if (pNearestActor) { + AHuman* pNearestAHuman = dynamic_cast(pNearestActor); + if (pNearestAHuman) { pNearestAHuman->AddInventoryItem(pDevice); - //TODO: Resident brain remains white when flashed, don't know how to avoid that. Better than nothing though + // TODO: Resident brain remains white when flashed, don't know how to avoid that. Better than nothing though pNearestAHuman->FlashWhite(150); toPlace = false; m_EditMade = true; } } - if (toPlace) - { - g_MovableMan.AddItem(pDevice); - m_EditMade = true; + if (toPlace) { + g_MovableMan.AddItem(pDevice); + m_EditMade = true; } - } - // Something else - else - { - MovableObject *pObj = dynamic_cast(pPlacedClone); - if (pObj) - g_MovableMan.AddParticle(pObj); - m_EditMade = true; - } - } - // Something was wrong with placement - else - { - delete pPlacedClone; - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - } - } - } -// TEMP REMOVE WEHN YOU CLEAN UP THE ABOVE HARDCODED BRAIN PLACEMENT - if (m_EditorGUIMode != PICKINGOBJECT) -// TEMP REMOVE ABOVE - // Go back to previous mode - m_EditorGUIMode = m_PreviousMode; - m_ModeChanged = true; - } - - // Set the facing of AHumans based on right/left cursor movements -// TODO: Improve - Actor *pActor = dynamic_cast(m_pCurrentObject); - if (pActor && dynamic_cast(pActor) || dynamic_cast(pActor)) - pActor->SetHFlipped(m_FacingLeft); - - Deployment *pDeployment = dynamic_cast(m_pCurrentObject); + } + // Something else + else { + MovableObject* pObj = dynamic_cast(pPlacedClone); + if (pObj) + g_MovableMan.AddParticle(pObj); + m_EditMade = true; + } + } + // Something was wrong with placement + else { + delete pPlacedClone; + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + } + } + } + // TEMP REMOVE WEHN YOU CLEAN UP THE ABOVE HARDCODED BRAIN PLACEMENT + if (m_EditorGUIMode != PICKINGOBJECT) + // TEMP REMOVE ABOVE + // Go back to previous mode + m_EditorGUIMode = m_PreviousMode; + m_ModeChanged = true; + } + + // Set the facing of AHumans based on right/left cursor movements + // TODO: Improve + Actor* pActor = dynamic_cast(m_pCurrentObject); + if (pActor && dynamic_cast(pActor) || dynamic_cast(pActor)) + pActor->SetHFlipped(m_FacingLeft); + + Deployment* pDeployment = dynamic_cast(m_pCurrentObject); if (pDeployment) pDeployment->SetHFlipped(m_FacingLeft); - } - - ///////////////////////////////////////////////////////////// - // POINTING AT MODES - - else if ((m_EditorGUIMode == MOVINGOBJECT || m_EditorGUIMode == DELETINGOBJECT || m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) && !m_PieMenu->IsEnabled()) - { - m_DrawCurrentObject = false; - - // Trap the mouse cursor - g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); - - // Move the cursor according to analog or mouse input - if (!analogInput.IsZero()) - m_CursorPos += analogInput * 4; - else if (!m_pController->GetMouseMovement().IsZero()) - m_CursorPos += m_pController->GetMouseMovement() / 2; - // Digital input? - else - { - if (pressUp) - m_CursorPos.m_Y -= 1; - if (pressRight) - m_CursorPos.m_X += 1; - if (pressDown) - m_CursorPos.m_Y += 1; - if (pressLeft) - m_CursorPos.m_X -= 1; - } - - ///////////////////////////////// - // MOVING OBJECT MODE - - if (m_EditorGUIMode == MOVINGOBJECT) - { - if (m_ModeChanged) - { - - m_ModeChanged = false; - } - g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // Pick an object under the cursor and start moving it - if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) - { - const SceneObject *pPicked = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder); - if (pPicked) - { - // Grab the position and a copy of the the object itself before killing it from the scene - SetCurrentObject(dynamic_cast(pPicked->Clone())); - m_CursorOffset = m_CursorPos - m_pCurrentObject->GetPos(); - g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); - m_EditMade = true; - - // Go to placing mode to move it around - m_EditorGUIMode = PLACINGOBJECT; - m_PreviousMode = MOVINGOBJECT; - m_ModeChanged = true; - m_BlinkTimer.Reset(); - g_GUISound.PlacementBlip()->Play(m_pController->GetPlayer()); - g_GUISound.PlacementGravel()->Play(m_pController->GetPlayer()); - } - else - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - } - - //////////////////////////// - // REMOVING OBJECT MODE - - else if (m_EditorGUIMode == DELETINGOBJECT) - { - if (m_ModeChanged) - { - - m_ModeChanged = false; - } - g_FrameMan.SetScreenText("Click and hold to select an object - release to DELETE it", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // When primary is held down, pick object and show which one will be nuked if released - if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) - { - m_pObjectToBlink = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos); - } - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - if (g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder)) - { - // Nuke it! - g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); - m_EditMade = true; -// TODO: Add awesome destruction sound here - } - else - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - } - - ///////////////////////////////////// - // PLACE IN FRONT AND BEHIND OF MODES - - else if (m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) - { - if (m_ModeChanged) - { - - m_ModeChanged = false; - } - if (m_EditorGUIMode == PLACEINFRONT) - g_FrameMan.SetScreenText(m_FeatureSet == ONLOADEDIT ? "Click an object to place the next one IN FRONT of it" : "Click an object to place the next one AFTER it in the build order", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - else if (m_EditorGUIMode == PLACEBEHIND) - g_FrameMan.SetScreenText(m_FeatureSet == ONLOADEDIT ? "Click an object to place the next one BEHIND it" : "Click an object to insert the next one BEFORE it in the build order", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - - // When primary is held down, pick object and show which one will be nuked if released - if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) - { - m_pObjectToBlink = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos); - } - else if (m_pController->IsState(RELEASE_PRIMARY)) - { - if (g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder)) - { - // Adjust the next std::list order to be in front if applicable (it's automatically behind if same order index) - if (m_EditorGUIMode == PLACEINFRONT) - m_ObjectListOrder++; - - // Go back to previous mode - m_EditorGUIMode = m_PreviousMode; - m_ModeChanged = true; - } - else - g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); - } - } - } - else if (m_EditorGUIMode == DONEEDITING) - { - // Check first that the brain is in a good spot if finishing up a base edit - if (m_FeatureSet != ONLOADEDIT) - TestBrainResidence(); -// if (m_FeatureSet != ONLOADEDIT) -// g_FrameMan.SetScreenText("DONE editing, wait for all other players to finish too...", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - } - - // Remove cursor offset if not applicable anymore - if (m_EditorGUIMode != PLACINGOBJECT) - m_CursorOffset.Reset(); - - // Keep the cursor position within the world - g_SceneMan.ForceBounds(m_CursorPos); -// TODO: make setscrolltarget with 'sloppy' target - // Scroll to the cursor's scene position - g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); - // Apply the cursor position to the currently held object - if (m_pCurrentObject && m_DrawCurrentObject) - { - m_pCurrentObject->SetPos(g_SceneMan.SnapPosition(m_CursorPos - m_CursorOffset, m_GridSnapping)); - // If an actor, set it to be inactive so it doesn't scan around and reveal unseen areas - if (Actor *pCurrentActor = dynamic_cast(m_pCurrentObject)) - { - pCurrentActor->SetStatus(Actor::INACTIVE); - pCurrentActor->GetController()->SetDisabled(true); - } - m_pCurrentObject->FullUpdate(); - } - - // Animate the reveal index so it is clear which order blueprint things are placed/built - if (m_RevealTimer.IsPastRealTimeLimit()) - { - // Make the animation stop at full built and only reset after the pause - if (m_RevealTimer.GetRealTimeLimitMS() > (BLUEPRINTREVEALRATE * 2)) - m_RevealIndex = 0; - else - m_RevealIndex++; - - // Loop - if (m_RevealIndex >= g_SceneMan.GetScene()->GetPlacedObjects(m_FeatureSet == BLUEPRINTEDIT ? Scene::BLUEPRINT : Scene::AIPLAN)->size()) - // Set a long time when reset so the animation won't look so spazzy if there's only a few objects yet - m_RevealTimer.SetRealTimeLimitMS(BLUEPRINTREVEALPAUSE); - else - m_RevealTimer.SetRealTimeLimitMS(BLUEPRINTREVEALRATE); - - m_RevealTimer.Reset(); - } -} + } + + ///////////////////////////////////////////////////////////// + // POINTING AT MODES + + else if ((m_EditorGUIMode == MOVINGOBJECT || m_EditorGUIMode == DELETINGOBJECT || m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) && !m_PieMenu->IsEnabled()) { + m_DrawCurrentObject = false; + + // Trap the mouse cursor + g_UInputMan.TrapMousePos(true, m_pController->GetPlayer()); + + // Move the cursor according to analog or mouse input + if (!analogInput.IsZero()) + m_CursorPos += analogInput * 4; + else if (!m_pController->GetMouseMovement().IsZero()) + m_CursorPos += m_pController->GetMouseMovement() / 2; + // Digital input? + else { + if (pressUp) + m_CursorPos.m_Y -= 1; + if (pressRight) + m_CursorPos.m_X += 1; + if (pressDown) + m_CursorPos.m_Y += 1; + if (pressLeft) + m_CursorPos.m_X -= 1; + } + + ///////////////////////////////// + // MOVING OBJECT MODE + + if (m_EditorGUIMode == MOVINGOBJECT) { + if (m_ModeChanged) { + + m_ModeChanged = false; + } + g_FrameMan.SetScreenText("Click and drag on a placed object to MOVE it - Click quickly to DETACH", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // Pick an object under the cursor and start moving it + if (m_pController->IsState(PRESS_PRIMARY) && !m_pPicker->IsVisible()) { + const SceneObject* pPicked = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder); + if (pPicked) { + // Grab the position and a copy of the the object itself before killing it from the scene + SetCurrentObject(dynamic_cast(pPicked->Clone())); + m_CursorOffset = m_CursorPos - m_pCurrentObject->GetPos(); + g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); + m_EditMade = true; + + // Go to placing mode to move it around + m_EditorGUIMode = PLACINGOBJECT; + m_PreviousMode = MOVINGOBJECT; + m_ModeChanged = true; + m_BlinkTimer.Reset(); + g_GUISound.PlacementBlip()->Play(m_pController->GetPlayer()); + g_GUISound.PlacementGravel()->Play(m_pController->GetPlayer()); + } else + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + } + + //////////////////////////// + // REMOVING OBJECT MODE + + else if (m_EditorGUIMode == DELETINGOBJECT) { + if (m_ModeChanged) { + + m_ModeChanged = false; + } + g_FrameMan.SetScreenText("Click and hold to select an object - release to DELETE it", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // When primary is held down, pick object and show which one will be nuked if released + if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) { + m_pObjectToBlink = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos); + } else if (m_pController->IsState(RELEASE_PRIMARY)) { + if (g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder)) { + // Nuke it! + g_SceneMan.GetScene()->RemovePlacedObject(editedSet, m_ObjectListOrder); + m_EditMade = true; + // TODO: Add awesome destruction sound here + } else + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + } + + ///////////////////////////////////// + // PLACE IN FRONT AND BEHIND OF MODES + + else if (m_EditorGUIMode == PLACEINFRONT || m_EditorGUIMode == PLACEBEHIND) { + if (m_ModeChanged) { + + m_ModeChanged = false; + } + if (m_EditorGUIMode == PLACEINFRONT) + g_FrameMan.SetScreenText(m_FeatureSet == ONLOADEDIT ? "Click an object to place the next one IN FRONT of it" : "Click an object to place the next one AFTER it in the build order", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + else if (m_EditorGUIMode == PLACEBEHIND) + g_FrameMan.SetScreenText(m_FeatureSet == ONLOADEDIT ? "Click an object to place the next one BEHIND it" : "Click an object to insert the next one BEFORE it in the build order", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + + // When primary is held down, pick object and show which one will be nuked if released + if (m_pController->IsState(PRIMARY_ACTION) && !m_pPicker->IsVisible()) { + m_pObjectToBlink = g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos); + } else if (m_pController->IsState(RELEASE_PRIMARY)) { + if (g_SceneMan.GetScene()->PickPlacedObject(editedSet, m_CursorPos, &m_ObjectListOrder)) { + // Adjust the next std::list order to be in front if applicable (it's automatically behind if same order index) + if (m_EditorGUIMode == PLACEINFRONT) + m_ObjectListOrder++; + + // Go back to previous mode + m_EditorGUIMode = m_PreviousMode; + m_ModeChanged = true; + } else + g_GUISound.UserErrorSound()->Play(m_pController->GetPlayer()); + } + } + } else if (m_EditorGUIMode == DONEEDITING) { + // Check first that the brain is in a good spot if finishing up a base edit + if (m_FeatureSet != ONLOADEDIT) + TestBrainResidence(); + // if (m_FeatureSet != ONLOADEDIT) + // g_FrameMan.SetScreenText("DONE editing, wait for all other players to finish too...", g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + } + + // Remove cursor offset if not applicable anymore + if (m_EditorGUIMode != PLACINGOBJECT) + m_CursorOffset.Reset(); + + // Keep the cursor position within the world + g_SceneMan.ForceBounds(m_CursorPos); + // TODO: make setscrolltarget with 'sloppy' target + // Scroll to the cursor's scene position + g_CameraMan.SetScrollTarget(m_CursorPos, 0.3, g_ActivityMan.GetActivity()->ScreenOfPlayer(m_pController->GetPlayer())); + // Apply the cursor position to the currently held object + if (m_pCurrentObject && m_DrawCurrentObject) { + m_pCurrentObject->SetPos(g_SceneMan.SnapPosition(m_CursorPos - m_CursorOffset, m_GridSnapping)); + // If an actor, set it to be inactive so it doesn't scan around and reveal unseen areas + if (Actor* pCurrentActor = dynamic_cast(m_pCurrentObject)) { + pCurrentActor->SetStatus(Actor::INACTIVE); + pCurrentActor->GetController()->SetDisabled(true); + } + m_pCurrentObject->FullUpdate(); + } + // Animate the reveal index so it is clear which order blueprint things are placed/built + if (m_RevealTimer.IsPastRealTimeLimit()) { + // Make the animation stop at full built and only reset after the pause + if (m_RevealTimer.GetRealTimeLimitMS() > (BLUEPRINTREVEALRATE * 2)) + m_RevealIndex = 0; + else + m_RevealIndex++; + + // Loop + if (m_RevealIndex >= g_SceneMan.GetScene()->GetPlacedObjects(m_FeatureSet == BLUEPRINTEDIT ? Scene::BLUEPRINT : Scene::AIPLAN)->size()) + // Set a long time when reset so the animation won't look so spazzy if there's only a few objects yet + m_RevealTimer.SetRealTimeLimitMS(BLUEPRINTREVEALPAUSE); + else + m_RevealTimer.SetRealTimeLimitMS(BLUEPRINTREVEALRATE); + + m_RevealTimer.Reset(); + } +} ////////////////////////////////////////////////////////////////////////////////////////// // Virtual Method: Draw ////////////////////////////////////////////////////////////////////////////////////////// // Description: Draws the menu -void SceneEditorGUI::Draw(BITMAP *pTargetBitmap, const Vector &targetPos) const -{ - // Done, so don't draw the UI - if (m_EditorGUIMode == DONEEDITING) - return; - - // The get a std::list of the currently edited set of placed objects in the Scene - const std::list *pSceneObjectList = 0; - if (m_FeatureSet == ONLOADEDIT) - pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); - else if (m_FeatureSet == BLUEPRINTEDIT) - { - pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::BLUEPRINT); - // Draw the 'original' set of placed scene objects as solid before the blueprints - const std::list *pOriginalsList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); - for (std::list::const_iterator itr = pOriginalsList->begin(); itr != pOriginalsList->end(); ++itr) - { - (*itr)->Draw(pTargetBitmap, targetPos); - // Draw basic HUD if an actor - Actor *pActor = dynamic_cast(*itr); -// if (pActor) -// pActor->DrawHUD(pTargetBitmap, targetPos); - } - } - else if (m_FeatureSet == AIPLANEDIT) - { - pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::AIPLAN); - // Draw the 'original' set of placed scene objects as solid before the planned base - const std::list *pOriginalsList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); - for (std::list::const_iterator itr = pOriginalsList->begin(); itr != pOriginalsList->end(); ++itr) - { - (*itr)->Draw(pTargetBitmap, targetPos); - // Draw basic HUD if an actor - Actor *pActor = dynamic_cast(*itr); -// if (pActor) -// pActor->DrawHUD(pTargetBitmap, targetPos); - } - } - - // Draw the set of currently edited objects already placed in the Scene - if (pSceneObjectList) - { - // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene - int i = 0; - Actor *pActor = 0; -// HeldDevice *pDevice = 0; - for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr, ++i) - { - // Draw the currently held object into the order of the std::list if it is to be placed inside - if (m_pCurrentObject && m_DrawCurrentObject && i == m_ObjectListOrder) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); - pActor = dynamic_cast(m_pCurrentObject); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - - // Is the placed object an actor? - pActor = dynamic_cast(*itr); -// pItem = dynamic_cast(*itr); - - // Blink trans if we are supposed to blink this one - if ((*itr) == m_pObjectToBlink) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); - } - // Drawing of already placed objects that aren't highlighted or anything - else - { - // In Base edit mode, draw them alternatingly transparent and solid to show that they're just designs - if (m_FeatureSet == BLUEPRINTEDIT || m_FeatureSet == AIPLANEDIT) - { -// if (((int)m_BlinkTimer.GetElapsedRealTimeMS() % 2000) > 1750) -// if (m_BlinkTimer.AlternateReal(1000)) - // Animate the ghosted into appearing solid in the build order to make the order clear - if (i >= m_RevealIndex) - { - g_FrameMan.SetTransTableFromPreset(pActor ? TransparencyPreset::MoreTrans : TransparencyPreset::HalfTrans); - (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); - } - // Show as non-transparent half the time to still give benefits of WYSIWYG - else - (*itr)->Draw(pTargetBitmap, targetPos); - } - // In full scene edit mode, we want to give a WYSIWYG view - else - { - (*itr)->Draw(pTargetBitmap, targetPos); - - //Draw team marks for doors, deployments and assemblies - Deployment *pDeployment = dynamic_cast(*itr); +void SceneEditorGUI::Draw(BITMAP* pTargetBitmap, const Vector& targetPos) const { + // Done, so don't draw the UI + if (m_EditorGUIMode == DONEEDITING) + return; + + // The get a std::list of the currently edited set of placed objects in the Scene + const std::list* pSceneObjectList = 0; + if (m_FeatureSet == ONLOADEDIT) + pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); + else if (m_FeatureSet == BLUEPRINTEDIT) { + pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::BLUEPRINT); + // Draw the 'original' set of placed scene objects as solid before the blueprints + const std::list* pOriginalsList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); + for (std::list::const_iterator itr = pOriginalsList->begin(); itr != pOriginalsList->end(); ++itr) { + (*itr)->Draw(pTargetBitmap, targetPos); + // Draw basic HUD if an actor + Actor* pActor = dynamic_cast(*itr); + // if (pActor) + // pActor->DrawHUD(pTargetBitmap, targetPos); + } + } else if (m_FeatureSet == AIPLANEDIT) { + pSceneObjectList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::AIPLAN); + // Draw the 'original' set of placed scene objects as solid before the planned base + const std::list* pOriginalsList = g_SceneMan.GetScene()->GetPlacedObjects(Scene::PLACEONLOAD); + for (std::list::const_iterator itr = pOriginalsList->begin(); itr != pOriginalsList->end(); ++itr) { + (*itr)->Draw(pTargetBitmap, targetPos); + // Draw basic HUD if an actor + Actor* pActor = dynamic_cast(*itr); + // if (pActor) + // pActor->DrawHUD(pTargetBitmap, targetPos); + } + } + + // Draw the set of currently edited objects already placed in the Scene + if (pSceneObjectList) { + // Draw all already placed Objects, and the currently held one in the order it is about to be placed in the scene + int i = 0; + Actor* pActor = 0; + // HeldDevice *pDevice = 0; + for (std::list::const_iterator itr = pSceneObjectList->begin(); itr != pSceneObjectList->end(); ++itr, ++i) { + // Draw the currently held object into the order of the std::list if it is to be placed inside + if (m_pCurrentObject && m_DrawCurrentObject && i == m_ObjectListOrder) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); + pActor = dynamic_cast(m_pCurrentObject); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + + // Is the placed object an actor? + pActor = dynamic_cast(*itr); + // pItem = dynamic_cast(*itr); + + // Blink trans if we are supposed to blink this one + if ((*itr) == m_pObjectToBlink) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); + } + // Drawing of already placed objects that aren't highlighted or anything + else { + // In Base edit mode, draw them alternatingly transparent and solid to show that they're just designs + if (m_FeatureSet == BLUEPRINTEDIT || m_FeatureSet == AIPLANEDIT) { + // if (((int)m_BlinkTimer.GetElapsedRealTimeMS() % 2000) > 1750) + // if (m_BlinkTimer.AlternateReal(1000)) + // Animate the ghosted into appearing solid in the build order to make the order clear + if (i >= m_RevealIndex) { + g_FrameMan.SetTransTableFromPreset(pActor ? TransparencyPreset::MoreTrans : TransparencyPreset::HalfTrans); + (*itr)->Draw(pTargetBitmap, targetPos, g_DrawTrans); + } + // Show as non-transparent half the time to still give benefits of WYSIWYG + else + (*itr)->Draw(pTargetBitmap, targetPos); + } + // In full scene edit mode, we want to give a WYSIWYG view + else { + (*itr)->Draw(pTargetBitmap, targetPos); + + // Draw team marks for doors, deployments and assemblies + Deployment* pDeployment = dynamic_cast(*itr); if (pDeployment) (*itr)->DrawTeamMark(pTargetBitmap, targetPos); // Works for both doors and bunker assemblies - TerrainObject *pTObject = dynamic_cast(*itr); + TerrainObject* pTObject = dynamic_cast(*itr); if (pTObject && !pTObject->GetChildObjects().empty()) (*itr)->DrawTeamMark(pTargetBitmap, targetPos); - BunkerAssemblyScheme *pBA = dynamic_cast(*itr); + BunkerAssemblyScheme* pBA = dynamic_cast(*itr); if (pBA) (*itr)->DrawTeamMark(pTargetBitmap, targetPos); - } - } - - // Draw basic HUD if an actor - don't do this for blueprints.. it is confusing - if (pActor && m_FeatureSet != BLUEPRINTEDIT && m_FeatureSet != AIPLANEDIT) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - } - - // Draw the path between brain and sky, backwards so the dot spacing can be even and they don't crawl as the guy approaches - // Always draw the path so the player can see what he would be blocking off when building - if (m_RequireClearPathToOrbit && !m_BrainSkyPath.empty()) - { - int skipPhase = 0; - std::list::const_reverse_iterator lLast = m_BrainSkyPath.rbegin(); - std::list::const_reverse_iterator lItr = m_BrainSkyPath.rbegin(); - for (; lItr != m_BrainSkyPath.rend(); ++lItr) - { - // Draw these backwards so the skip phase works - skipPhase = g_FrameMan.DrawDotLine(pTargetBitmap, (*lLast) - targetPos, (*lItr) - targetPos, m_BrainSkyPathCost <= MAXBRAINPATHCOST ? s_pValidPathDot : s_pInvalidPathDot, 16, skipPhase, true); - lLast = lItr; - } - } - - // Draw the currently placed brain, if any, UNLESS it's being re-placed atm - if ((m_pCurrentObject && !m_pCurrentObject->IsInGroup("Brains")) && m_EditorGUIMode != INSTALLINGBRAIN && !(m_EditorGUIMode == PLACINGOBJECT && m_PreviousMode == INSTALLINGBRAIN)) - { - SceneObject *pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); - if (pBrain) - { - pBrain->Draw(pTargetBitmap, targetPos); - // Draw basic HUD if an actor - Actor *pActor = dynamic_cast(pBrain); - if (pActor) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - } - - // Draw picking object crosshairs and not the selected object - if (!m_DrawCurrentObject) - { - Vector center = m_CursorPos - targetPos; - putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); - hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); - vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); - } - // If the held object will be placed at the end of the std::list, draw it last to the scene, transperent blinking - else if (m_pCurrentObject && (m_ObjectListOrder < 0 || (pSceneObjectList && m_ObjectListOrder == pSceneObjectList->size()))) - { - g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); - m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); - Actor *pActor = dynamic_cast(m_pCurrentObject); - if (pActor && m_FeatureSet != BLUEPRINTEDIT && m_FeatureSet != AIPLANEDIT) - pActor->DrawHUD(pTargetBitmap, targetPos); - } - - m_pPicker->Draw(pTargetBitmap); - - // Draw the pie menu + } + + // Draw basic HUD if an actor - don't do this for blueprints.. it is confusing + if (pActor && m_FeatureSet != BLUEPRINTEDIT && m_FeatureSet != AIPLANEDIT) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + } + + // Draw the path between brain and sky, backwards so the dot spacing can be even and they don't crawl as the guy approaches + // Always draw the path so the player can see what he would be blocking off when building + if (m_RequireClearPathToOrbit && !m_BrainSkyPath.empty()) { + int skipPhase = 0; + std::list::const_reverse_iterator lLast = m_BrainSkyPath.rbegin(); + std::list::const_reverse_iterator lItr = m_BrainSkyPath.rbegin(); + for (; lItr != m_BrainSkyPath.rend(); ++lItr) { + // Draw these backwards so the skip phase works + skipPhase = g_FrameMan.DrawDotLine(pTargetBitmap, (*lLast) - targetPos, (*lItr) - targetPos, m_BrainSkyPathCost <= MAXBRAINPATHCOST ? s_pValidPathDot : s_pInvalidPathDot, 16, skipPhase, true); + lLast = lItr; + } + } + + // Draw the currently placed brain, if any, UNLESS it's being re-placed atm + if ((m_pCurrentObject && !m_pCurrentObject->IsInGroup("Brains")) && m_EditorGUIMode != INSTALLINGBRAIN && !(m_EditorGUIMode == PLACINGOBJECT && m_PreviousMode == INSTALLINGBRAIN)) { + SceneObject* pBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer()); + if (pBrain) { + pBrain->Draw(pTargetBitmap, targetPos); + // Draw basic HUD if an actor + Actor* pActor = dynamic_cast(pBrain); + if (pActor) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + } + + // Draw picking object crosshairs and not the selected object + if (!m_DrawCurrentObject) { + Vector center = m_CursorPos - targetPos; + putpixel(pTargetBitmap, center.m_X, center.m_Y, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X - 5, center.m_Y, center.m_X - 2, g_YellowGlowColor); + hline(pTargetBitmap, center.m_X + 5, center.m_Y, center.m_X + 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y - 5, center.m_Y - 2, g_YellowGlowColor); + vline(pTargetBitmap, center.m_X, center.m_Y + 5, center.m_Y + 2, g_YellowGlowColor); + } + // If the held object will be placed at the end of the std::list, draw it last to the scene, transperent blinking + else if (m_pCurrentObject && (m_ObjectListOrder < 0 || (pSceneObjectList && m_ObjectListOrder == pSceneObjectList->size()))) { + g_FrameMan.SetTransTableFromPreset(m_BlinkTimer.AlternateReal(333) || m_EditorGUIMode == PLACINGOBJECT ? TransparencyPreset::LessTrans : TransparencyPreset::HalfTrans); + m_pCurrentObject->Draw(pTargetBitmap, targetPos, g_DrawTrans); + Actor* pActor = dynamic_cast(m_pCurrentObject); + if (pActor && m_FeatureSet != BLUEPRINTEDIT && m_FeatureSet != AIPLANEDIT) + pActor->DrawHUD(pTargetBitmap, targetPos); + } + + m_pPicker->Draw(pTargetBitmap); + + // Draw the pie menu m_PieMenu->Draw(pTargetBitmap, targetPos); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SceneEditorGUI::UpdateBrainSkyPathAndCost(Vector brainPos) { - if (!m_RequireClearPathToOrbit) { - m_PathRequest.reset(); - return; - } - - if (m_PathRequest) { - if (!m_PathRequest->complete) { - // Wait for the request to complete - return; - } - - if (g_SceneMan.GetScene()->PositionsAreTheSamePathNode(const_cast(m_PathRequest->targetPos), brainPos)) { - // No need to recalculate - return; - } - } - - Vector orbitPos; - - int staticPos; - int checkPos; - int lengthToCheck; - - // If the ceiling directly above is blocked, search the surroundings for gaps. - Directions orbitDirection = g_SceneMan.GetTerrain()->GetOrbitDirection(); - switch (orbitDirection) { - default: - case Directions::Up: - checkPos = brainPos.GetFloorIntX(); - staticPos = 0; - lengthToCheck = g_SceneMan.GetSceneWidth(); - break; - case Directions::Down: - checkPos = brainPos.GetFloorIntX(); - staticPos = g_SceneMan.GetSceneHeight(); - lengthToCheck = g_SceneMan.GetSceneWidth(); - break; - case Directions::Left: - checkPos = brainPos.GetFloorIntY(); - staticPos = 0; - lengthToCheck = g_SceneMan.GetSceneHeight(); - break; - case Directions::Right: - checkPos = brainPos.GetFloorIntY(); - staticPos = g_SceneMan.GetSceneWidth(); - lengthToCheck = g_SceneMan.GetSceneHeight(); - break; - } - - auto getVector = [&](int pos) { - switch (orbitDirection) { - default: - case Directions::Up: - return Vector(pos, 0); - case Directions::Down: - return Vector(pos, g_SceneMan.GetSceneHeight()); - case Directions::Left: - return Vector(0, pos); - case Directions::Right: - return Vector(g_SceneMan.GetSceneWidth(), pos); - } - }; - - int offset = 0; + if (!m_RequireClearPathToOrbit) { + m_PathRequest.reset(); + return; + } + + if (m_PathRequest) { + if (!m_PathRequest->complete) { + // Wait for the request to complete + return; + } + + if (g_SceneMan.GetScene()->PositionsAreTheSamePathNode(const_cast(m_PathRequest->targetPos), brainPos)) { + // No need to recalculate + return; + } + } + + Vector orbitPos; + + int staticPos; + int checkPos; + int lengthToCheck; + + // If the ceiling directly above is blocked, search the surroundings for gaps. + Directions orbitDirection = g_SceneMan.GetTerrain()->GetOrbitDirection(); + switch (orbitDirection) { + default: + case Directions::Up: + checkPos = brainPos.GetFloorIntX(); + staticPos = 0; + lengthToCheck = g_SceneMan.GetSceneWidth(); + break; + case Directions::Down: + checkPos = brainPos.GetFloorIntX(); + staticPos = g_SceneMan.GetSceneHeight(); + lengthToCheck = g_SceneMan.GetSceneWidth(); + break; + case Directions::Left: + checkPos = brainPos.GetFloorIntY(); + staticPos = 0; + lengthToCheck = g_SceneMan.GetSceneHeight(); + break; + case Directions::Right: + checkPos = brainPos.GetFloorIntY(); + staticPos = g_SceneMan.GetSceneWidth(); + lengthToCheck = g_SceneMan.GetSceneHeight(); + break; + } + + auto getVector = [&](int pos) { + switch (orbitDirection) { + default: + case Directions::Up: + return Vector(pos, 0); + case Directions::Down: + return Vector(pos, g_SceneMan.GetSceneHeight()); + case Directions::Left: + return Vector(0, pos); + case Directions::Right: + return Vector(g_SceneMan.GetSceneWidth(), pos); + } + }; + + int offset = 0; int spacing = 20; for (int i = 0; i < lengthToCheck / spacing; i++) { - int offsetCheckPos = checkPos + offset; - orbitPos = getVector(offsetCheckPos); - if (!g_SceneMan.IsWithinBounds(orbitPos.GetFloorIntX(), orbitPos.GetFloorIntY())) { - offset *= -1; - offsetCheckPos = checkPos + offset; - orbitPos = getVector(offsetCheckPos); - } + int offsetCheckPos = checkPos + offset; + orbitPos = getVector(offsetCheckPos); + if (!g_SceneMan.IsWithinBounds(orbitPos.GetFloorIntX(), orbitPos.GetFloorIntY())) { + offset *= -1; + offsetCheckPos = checkPos + offset; + orbitPos = getVector(offsetCheckPos); + } if (g_SceneMan.GetTerrMatter(orbitPos.GetFloorIntX(), orbitPos.GetFloorIntY()) == g_MaterialAir) { break; @@ -1655,11 +1497,11 @@ void SceneEditorGUI::UpdateBrainSkyPathAndCost(Vector brainPos) { } Activity::Teams team = static_cast(g_ActivityMan.GetActivity()->GetTeamOfPlayer(m_pController->GetPlayer())); - m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(orbitPos, brainPos, c_PathFindingDefaultDigStrength, team, - [&](std::shared_ptr pathRequest) { - m_BrainSkyPath = const_cast&>(pathRequest->path); - m_BrainSkyPathCost = pathRequest->totalCost; - }); + m_PathRequest = g_SceneMan.GetScene()->CalculatePathAsync(orbitPos, brainPos, c_PathFindingDefaultDigStrength, team, + [&](std::shared_ptr pathRequest) { + m_BrainSkyPath = const_cast&>(pathRequest->path); + m_BrainSkyPathCost = pathRequest->totalCost; + }); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1667,7 +1509,7 @@ void SceneEditorGUI::UpdateBrainSkyPathAndCost(Vector brainPos) { bool SceneEditorGUI::UpdateBrainPath() { if (m_pCurrentObject && m_pCurrentObject->IsInGroup("Brains")) { UpdateBrainSkyPathAndCost(m_CursorPos); - } else if (SceneObject *residentBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer())) { + } else if (SceneObject* residentBrain = g_SceneMan.GetScene()->GetResidentBrain(m_pController->GetPlayer())) { UpdateBrainSkyPathAndCost(residentBrain->GetPos()); } else { m_BrainSkyPath.clear(); @@ -1675,4 +1517,4 @@ bool SceneEditorGUI::UpdateBrainPath() { return false; } return true; -} \ No newline at end of file +} diff --git a/Source/Menus/SceneEditorGUI.h b/Source/Menus/SceneEditorGUI.h index fff12a00a..cffd30ba1 100644 --- a/Source/Menus/SceneEditorGUI.h +++ b/Source/Menus/SceneEditorGUI.h @@ -10,7 +10,6 @@ // dtabar@datarealms.com // http://www.datarealms.com - ////////////////////////////////////////////////////////////////////////////////////////// // Inclusions of header files @@ -23,398 +22,364 @@ struct BITMAP; - -namespace RTE -{ - -class SceneObject; -class ObjectPickerGUI; -class PieMenu; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Class: SceneEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: A full menu system that represents the scene editing GUI for Cortex Command -// Parent(s): None. -// Class history: 7/08/2007 SceneEditorGUI Created. - -class SceneEditorGUI { - -////////////////////////////////////////////////////////////////////////////////////////// -// Public member variable, method and friend function declarations - -public: - - enum FeatureSets - { - ONLOADEDIT = 0, - BLUEPRINTEDIT, - AIPLANEDIT, - INGAMEEDIT - }; - - // Different modes of this editor - enum EditorGUIMode - { - INACTIVE = 0, - PICKINGOBJECT, - ADDINGOBJECT, - INSTALLINGBRAIN, - PLACINGOBJECT, - MOVINGOBJECT, - DELETINGOBJECT, - PLACEINFRONT, - PLACEBEHIND, - DONEEDITING, - EDITORGUIMODECOUNT - }; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructor: SceneEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Constructor method used to instantiate a SceneEditorGUI object in system -// memory. Create() should be called before using the object. -// Arguments: None. - - SceneEditorGUI() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Destructor: ~SceneEditorGUI -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destructor method used to clean up a SceneEditorGUI object before deletion -// from system memory. -// Arguments: None. - - ~SceneEditorGUI() { Destroy(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Create -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Makes the SceneEditorGUI object ready for use. -// Arguments: A poitner to a Controller which will control this Menu. Ownership is -// NOT TRANSFERRED! -// Whether the editor should have all the features enabled, like load/save -// and undo capabilities. -// Which module space that this eidtor will be able to pick objects from. -// -1 means all modules. -// Which Tech module that will be presented as the native one to the player. -// The multiplier of all foreign techs' costs. -// Return value: An error return value signaling sucess or any particular failure. -// Anything below 0 is an error signal. - - int Create(Controller *pController, FeatureSets featureSet = INGAMEEDIT, int whichModuleSpace = -1, int nativeTechModule = 0, float foreignCostMult = 1.0); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Reset -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Resets the entire SceneEditorGUI, including its inherited members, to -// their default settings or values. -// Arguments: None. -// Return value: None. - - void Reset() { Clear(); } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Destroy -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Destroys and resets (through Clear()) the SceneEditorGUI object. -// Arguments: None. -// Return value: None. - - void Destroy(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetController -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the controller used by this. The ownership of the controller is -// NOT transferred! -// Arguments: The new controller for this menu. Ownership is NOT transferred -// Return value: None. - - void SetController(Controller *pController); - - /// - /// Sets the FeatureSet for this SceneEditorGUI, and sets up the PieMenu accordingly. - /// - /// The new FeatureSet for this SceneEditorGUI. - void SetFeatureSet(SceneEditorGUI::FeatureSets newFeatureSet); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetPosOnScreen -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets where on the screen that this GUI is being drawn to. If upper -// left corner, then 0, 0. This will affect the way the mouse is positioned -// etc. -// Arguments: The new screen position of this entire GUI. - - void SetPosOnScreen(int newPosX, int newPosY); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCursorPos -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the absolute scene coordinates of the cursor of this Editor. -// Arguments: The new cursor position in absolute scene units. -// Return value: None. - - void SetCursorPos(const Vector &newCursorPos) { m_CursorPos = newCursorPos; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetCurrentObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the new Object to be held at the cursor of this Editor. Ownership -// IS transferred! -// Arguments: The new Object to be held by the cursor. Ownership IS transferred! -// Return value: Whether the cursor holds a valid object after setting. - - bool SetCurrentObject(SceneObject *pNewObject); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetActivatedPieSlice -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets any Pie menu slice command activated last update. -// Arguments: None. -// Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. - - PieSlice::SliceType GetActivatedPieSlice() const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetCurrentObject -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the currently held Object in the cursor of this Editor. Ownership -// IS NOT transferred! -// Arguments: None. -// Return value: The currently held object, if any. OWNERSHIP IS NOT TRANSFERRED! - - const SceneObject * GetCurrentObject() const { return m_pCurrentObject; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the current mode of this editor. -// Arguments: The new mode to set to, see the EditorGUIMode enum. -// Return value: None. - - void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: GetEditorMode -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Gets the current mode of this editor. -// Arguments: None. -// Return value: The current mode this is set to; see the EditorGUIMode enum. - - EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetModuleSpace -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which DataModule space to be picking objects from. If -1, then -// let the player pick from all loaded modules. -// Arguments: The ID of the module to let the player pick objects from. All official -// modules' objects will alwayws be presented, in addition to the one -// passed in here. -// Return value: None. - - void SetModuleSpace(int moduleSpaceID = -1); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetNativeTechModule -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets which DataModule ID should be treated as the native tech of the -// user of this menu. -// Arguments: The module ID to set as the native one. 0 means everything is native. -// Return value: None. - - void SetNativeTechModule(int whichModule); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: SetForeignCostMultiplier -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Sets the multiplier of the cost of any foreign Tech items. -// Arguments: The scalar multiplier of the costs of foreign Tech items. -// Return value: None. - - void SetForeignCostMultiplier(float newMultiplier); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: EditMade -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Shows whether an edit on the scene was made in the last Update. -// Arguments: None. -// Return value: Whether any edit was made. - - bool EditMade() const { return m_EditMade; } - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: TestBrainResidence -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Checks whether the resident brain is currently placed into a valid -// location in this scene, based on whether there is a clear path to the -// sky above it. This forces the editor into place brain mode with the -// current resident brain if the current placement is no bueno. It also -// removes the faulty brain from residence in the scene! -// Arguments: Whether it's OK if we dont' have a brain right now - ie don't force -// into isntallation mode if no brain was found. -// Return value: Whether a resident brain was found, AND found in a valid location! - - bool TestBrainResidence(bool noBrainIsOK = false); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Update -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Updates the state of this Menu each frame -// Arguments: None. -// Return value: None. - - void Update(); - - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Draw -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Draws the editor -// Arguments: The bitmap to draw on. -// The absolute position of the target bitmap's upper left corner in the scene. -// Return value: None. - - void Draw(BITMAP *pTargetBitmap, const Vector &targetPos = Vector()) const; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Protected member variable and method declarations - -protected: - - /// - /// Updates the path to the current brain in the cursor or resident in the scene, if any. If there's none, the path is cleared. - /// - /// Whether a brain was found in the cursor or the scene. - bool UpdateBrainPath(); - - /// - /// Updates the path from the designated position to orbit, and its cost. - /// - /// The designated position of the brain. - void UpdateBrainSkyPathAndCost(Vector brainPos); - - - enum BlinkMode - { - NOBLINK = 0, - OBJECTBLINKON, - OBJECTBLINKOFF, - BLINKMODECOUNT - }; - - // Controller which conrols this menu. Not owned - Controller *m_pController; - // Full featured or the in-game version, or the base building mode - int m_FeatureSet; - // Whether an edit was made to the Scene in the last Update - bool m_EditMade; - // The current mode of the whole GUI. See EditorGUIMode enum. - EditorGUIMode m_EditorGUIMode; - // The previous mode of the whole GUI, to go back to when the current mode is done in some cases - EditorGUIMode m_PreviousMode; - // Whether the editor mode has changed - bool m_ModeChanged; - // Notification blink timer - Timer m_BlinkTimer; - // What we're blinking - int m_BlinkMode; - // Measures the time to when to start repeating inputs when they're held down - Timer m_RepeatStartTimer; - // Measures the interval between input repeats - Timer m_RepeatTimer; - // Measures the interval between graphically revealing objects - Timer m_RevealTimer; - // The index which keeps track of the point in the build queue that blueprint objects go from being ghosted to revealed - int m_RevealIndex; - // Whether we need a clear path to orbit to place brain - bool m_RequireClearPathToOrbit; - - std::unique_ptr m_PieMenu; //!< The PieMenu for this SceneEditorGUI. - // The object picker - ObjectPickerGUI *m_pPicker; - // The ID of the DataModule that contains the native Tech of the Player using this menu - int m_NativeTechModule; - // The multiplier of costs of any foreign tech items - float m_ForeignCostMult; - // Grid snapping enabled - bool m_GridSnapping; - // Current cursor position, in absolute scene coordinates - Vector m_CursorPos; - // The offset from the current object's position to the cursor, if any - Vector m_CursorOffset; - // Cursor position in free air, or over something - bool m_CursorInAir; - // SceneObject facing left or not when placing - bool m_FacingLeft; - // The team of the placed SceneObject:s - int m_PlaceTeam; - // Currently held object. This is what is attached to the cursor and will be placed when the fire button is pressed - // OWNED by this. - SceneObject *m_pCurrentObject; - // Where in the scene's list order the next object should be placed. If -1, then place at the end of the list. - int m_ObjectListOrder; - // Whether to draw the currently held object - bool m_DrawCurrentObject; - // Currently placed scene object to make blink when drawing it. NOT OWNED. - const SceneObject *m_pObjectToBlink; - // Path found between brain pos and the sky to make sure fair brain placement - std::list m_BrainSkyPath; - // The cost of the path from the current position of the brain to the sky - float m_BrainSkyPathCost; - // Valid brain path line dots - static BITMAP *s_pValidPathDot; - // Invalid brain path line dots - static BITMAP *s_pInvalidPathDot; - // The current pathfinding request - std::shared_ptr m_PathRequest; - - -////////////////////////////////////////////////////////////////////////////////////////// -// Private member variable and method declarations - -private: - -////////////////////////////////////////////////////////////////////////////////////////// -// Method: Clear -////////////////////////////////////////////////////////////////////////////////////////// -// Description: Clears all the member variables of this SceneEditorGUI, effectively -// resetting the members of this abstraction level only. -// Arguments: None. -// Return value: None. - - void Clear(); - - - // Disallow the use of some implicit methods. - SceneEditorGUI(const SceneEditorGUI &reference) = delete; - SceneEditorGUI & operator=(const SceneEditorGUI &rhs) = delete; - -}; +namespace RTE { + + class SceneObject; + class ObjectPickerGUI; + class PieMenu; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Class: SceneEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: A full menu system that represents the scene editing GUI for Cortex Command + // Parent(s): None. + // Class history: 7/08/2007 SceneEditorGUI Created. + + class SceneEditorGUI { + + ////////////////////////////////////////////////////////////////////////////////////////// + // Public member variable, method and friend function declarations + + public: + enum FeatureSets { + ONLOADEDIT = 0, + BLUEPRINTEDIT, + AIPLANEDIT, + INGAMEEDIT + }; + + // Different modes of this editor + enum EditorGUIMode { + INACTIVE = 0, + PICKINGOBJECT, + ADDINGOBJECT, + INSTALLINGBRAIN, + PLACINGOBJECT, + MOVINGOBJECT, + DELETINGOBJECT, + PLACEINFRONT, + PLACEBEHIND, + DONEEDITING, + EDITORGUIMODECOUNT + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Constructor: SceneEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Constructor method used to instantiate a SceneEditorGUI object in system + // memory. Create() should be called before using the object. + // Arguments: None. + + SceneEditorGUI() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Destructor: ~SceneEditorGUI + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destructor method used to clean up a SceneEditorGUI object before deletion + // from system memory. + // Arguments: None. + + ~SceneEditorGUI() { Destroy(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Create + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Makes the SceneEditorGUI object ready for use. + // Arguments: A poitner to a Controller which will control this Menu. Ownership is + // NOT TRANSFERRED! + // Whether the editor should have all the features enabled, like load/save + // and undo capabilities. + // Which module space that this eidtor will be able to pick objects from. + // -1 means all modules. + // Which Tech module that will be presented as the native one to the player. + // The multiplier of all foreign techs' costs. + // Return value: An error return value signaling sucess or any particular failure. + // Anything below 0 is an error signal. + + int Create(Controller* pController, FeatureSets featureSet = INGAMEEDIT, int whichModuleSpace = -1, int nativeTechModule = 0, float foreignCostMult = 1.0); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Reset + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Resets the entire SceneEditorGUI, including its inherited members, to + // their default settings or values. + // Arguments: None. + // Return value: None. + + void Reset() { Clear(); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Destroy + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Destroys and resets (through Clear()) the SceneEditorGUI object. + // Arguments: None. + // Return value: None. + + void Destroy(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetController + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the controller used by this. The ownership of the controller is + // NOT transferred! + // Arguments: The new controller for this menu. Ownership is NOT transferred + // Return value: None. + + void SetController(Controller* pController); + + /// + /// Sets the FeatureSet for this SceneEditorGUI, and sets up the PieMenu accordingly. + /// + /// The new FeatureSet for this SceneEditorGUI. + void SetFeatureSet(SceneEditorGUI::FeatureSets newFeatureSet); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetPosOnScreen + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets where on the screen that this GUI is being drawn to. If upper + // left corner, then 0, 0. This will affect the way the mouse is positioned + // etc. + // Arguments: The new screen position of this entire GUI. + + void SetPosOnScreen(int newPosX, int newPosY); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCursorPos + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the absolute scene coordinates of the cursor of this Editor. + // Arguments: The new cursor position in absolute scene units. + // Return value: None. + + void SetCursorPos(const Vector& newCursorPos) { m_CursorPos = newCursorPos; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetCurrentObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the new Object to be held at the cursor of this Editor. Ownership + // IS transferred! + // Arguments: The new Object to be held by the cursor. Ownership IS transferred! + // Return value: Whether the cursor holds a valid object after setting. + + bool SetCurrentObject(SceneObject* pNewObject); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetActivatedPieSlice + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets any Pie menu slice command activated last update. + // Arguments: None. + // Return value: The enum'd int of any slice activated. See the PieSlice::SliceType enum. + + PieSlice::SliceType GetActivatedPieSlice() const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetCurrentObject + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the currently held Object in the cursor of this Editor. Ownership + // IS NOT transferred! + // Arguments: None. + // Return value: The currently held object, if any. OWNERSHIP IS NOT TRANSFERRED! + + const SceneObject* GetCurrentObject() const { return m_pCurrentObject; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the current mode of this editor. + // Arguments: The new mode to set to, see the EditorGUIMode enum. + // Return value: None. + + void SetEditorGUIMode(EditorGUIMode newMode) { m_EditorGUIMode = newMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: GetEditorMode + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Gets the current mode of this editor. + // Arguments: None. + // Return value: The current mode this is set to; see the EditorGUIMode enum. + + EditorGUIMode GetEditorGUIMode() const { return m_EditorGUIMode; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetModuleSpace + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which DataModule space to be picking objects from. If -1, then + // let the player pick from all loaded modules. + // Arguments: The ID of the module to let the player pick objects from. All official + // modules' objects will alwayws be presented, in addition to the one + // passed in here. + // Return value: None. + + void SetModuleSpace(int moduleSpaceID = -1); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetNativeTechModule + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets which DataModule ID should be treated as the native tech of the + // user of this menu. + // Arguments: The module ID to set as the native one. 0 means everything is native. + // Return value: None. + + void SetNativeTechModule(int whichModule); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: SetForeignCostMultiplier + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Sets the multiplier of the cost of any foreign Tech items. + // Arguments: The scalar multiplier of the costs of foreign Tech items. + // Return value: None. + + void SetForeignCostMultiplier(float newMultiplier); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: EditMade + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Shows whether an edit on the scene was made in the last Update. + // Arguments: None. + // Return value: Whether any edit was made. + + bool EditMade() const { return m_EditMade; } + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: TestBrainResidence + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Checks whether the resident brain is currently placed into a valid + // location in this scene, based on whether there is a clear path to the + // sky above it. This forces the editor into place brain mode with the + // current resident brain if the current placement is no bueno. It also + // removes the faulty brain from residence in the scene! + // Arguments: Whether it's OK if we dont' have a brain right now - ie don't force + // into isntallation mode if no brain was found. + // Return value: Whether a resident brain was found, AND found in a valid location! + + bool TestBrainResidence(bool noBrainIsOK = false); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Update + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Updates the state of this Menu each frame + // Arguments: None. + // Return value: None. + + void Update(); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Draw + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Draws the editor + // Arguments: The bitmap to draw on. + // The absolute position of the target bitmap's upper left corner in the scene. + // Return value: None. + + void Draw(BITMAP* pTargetBitmap, const Vector& targetPos = Vector()) const; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Protected member variable and method declarations + + protected: + /// + /// Updates the path to the current brain in the cursor or resident in the scene, if any. If there's none, the path is cleared. + /// + /// Whether a brain was found in the cursor or the scene. + bool UpdateBrainPath(); + + /// + /// Updates the path from the designated position to orbit, and its cost. + /// + /// The designated position of the brain. + void UpdateBrainSkyPathAndCost(Vector brainPos); + + enum BlinkMode { + NOBLINK = 0, + OBJECTBLINKON, + OBJECTBLINKOFF, + BLINKMODECOUNT + }; + + // Controller which conrols this menu. Not owned + Controller* m_pController; + // Full featured or the in-game version, or the base building mode + int m_FeatureSet; + // Whether an edit was made to the Scene in the last Update + bool m_EditMade; + // The current mode of the whole GUI. See EditorGUIMode enum. + EditorGUIMode m_EditorGUIMode; + // The previous mode of the whole GUI, to go back to when the current mode is done in some cases + EditorGUIMode m_PreviousMode; + // Whether the editor mode has changed + bool m_ModeChanged; + // Notification blink timer + Timer m_BlinkTimer; + // What we're blinking + int m_BlinkMode; + // Measures the time to when to start repeating inputs when they're held down + Timer m_RepeatStartTimer; + // Measures the interval between input repeats + Timer m_RepeatTimer; + // Measures the interval between graphically revealing objects + Timer m_RevealTimer; + // The index which keeps track of the point in the build queue that blueprint objects go from being ghosted to revealed + int m_RevealIndex; + // Whether we need a clear path to orbit to place brain + bool m_RequireClearPathToOrbit; + + std::unique_ptr m_PieMenu; //!< The PieMenu for this SceneEditorGUI. + // The object picker + ObjectPickerGUI* m_pPicker; + // The ID of the DataModule that contains the native Tech of the Player using this menu + int m_NativeTechModule; + // The multiplier of costs of any foreign tech items + float m_ForeignCostMult; + // Grid snapping enabled + bool m_GridSnapping; + // Current cursor position, in absolute scene coordinates + Vector m_CursorPos; + // The offset from the current object's position to the cursor, if any + Vector m_CursorOffset; + // Cursor position in free air, or over something + bool m_CursorInAir; + // SceneObject facing left or not when placing + bool m_FacingLeft; + // The team of the placed SceneObject:s + int m_PlaceTeam; + // Currently held object. This is what is attached to the cursor and will be placed when the fire button is pressed + // OWNED by this. + SceneObject* m_pCurrentObject; + // Where in the scene's list order the next object should be placed. If -1, then place at the end of the list. + int m_ObjectListOrder; + // Whether to draw the currently held object + bool m_DrawCurrentObject; + // Currently placed scene object to make blink when drawing it. NOT OWNED. + const SceneObject* m_pObjectToBlink; + // Path found between brain pos and the sky to make sure fair brain placement + std::list m_BrainSkyPath; + // The cost of the path from the current position of the brain to the sky + float m_BrainSkyPathCost; + // Valid brain path line dots + static BITMAP* s_pValidPathDot; + // Invalid brain path line dots + static BITMAP* s_pInvalidPathDot; + // The current pathfinding request + std::shared_ptr m_PathRequest; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private member variable and method declarations + + private: + ////////////////////////////////////////////////////////////////////////////////////////// + // Method: Clear + ////////////////////////////////////////////////////////////////////////////////////////// + // Description: Clears all the member variables of this SceneEditorGUI, effectively + // resetting the members of this abstraction level only. + // Arguments: None. + // Return value: None. + + void Clear(); + + // Disallow the use of some implicit methods. + SceneEditorGUI(const SceneEditorGUI& reference) = delete; + SceneEditorGUI& operator=(const SceneEditorGUI& rhs) = delete; + }; } // namespace RTE -#endif // File \ No newline at end of file +#endif // File diff --git a/Source/Menus/SettingsAudioGUI.cpp b/Source/Menus/SettingsAudioGUI.cpp index 176dd4dd8..e0dbd816a 100644 --- a/Source/Menus/SettingsAudioGUI.cpp +++ b/Source/Menus/SettingsAudioGUI.cpp @@ -9,24 +9,25 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsAudioGUI::SettingsAudioGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { - m_AudioSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxAudioSettings")); + SettingsAudioGUI::SettingsAudioGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { + m_AudioSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxAudioSettings")); - m_MasterVolumeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelMasterVolume")); - m_MasterVolumeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderMasterVolume")); - m_MasterMuteCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMuteMaster")); + m_MasterVolumeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelMasterVolume")); + m_MasterVolumeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderMasterVolume")); + m_MasterMuteCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMuteMaster")); m_MasterMuteCheckbox->SetCheck(g_AudioMan.GetMasterMuted()); - m_MusicVolumeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelMusicVolume")); - m_MusicVolumeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderMusicVolume")); - m_MusicMuteCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMuteMusic")); + m_MusicVolumeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelMusicVolume")); + m_MusicVolumeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderMusicVolume")); + m_MusicMuteCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMuteMusic")); m_MusicMuteCheckbox->SetCheck(g_AudioMan.GetMusicMuted()); - m_SoundVolumeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSoundVolume")); - m_SoundVolumeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderSoundVolume")); - m_SoundMuteCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMuteSound")); + m_SoundVolumeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSoundVolume")); + m_SoundVolumeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderSoundVolume")); + m_SoundMuteCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMuteSound")); m_SoundMuteCheckbox->SetCheck(g_AudioMan.GetSoundsMuted()); UpdateMasterVolumeControls(); @@ -34,14 +35,14 @@ namespace RTE { UpdateSoundVolumeControls(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsAudioGUI::SetEnabled(bool enable) const { m_AudioSettingsBox->SetVisible(enable); m_AudioSettingsBox->SetEnabled(enable); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsAudioGUI::UpdateMasterVolumeControls() { int masterVolume = static_cast(std::round(g_AudioMan.GetMasterVolume() * 100)); @@ -49,7 +50,7 @@ namespace RTE { m_MasterVolumeSlider->SetValue(masterVolume); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsAudioGUI::UpdateMusicVolumeControls() { int musicVolume = static_cast(std::round(g_AudioMan.GetMusicVolume() * 100)); @@ -57,7 +58,7 @@ namespace RTE { m_MusicVolumeSlider->SetValue(musicVolume); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsAudioGUI::UpdateSoundVolumeControls() { int soundVolume = static_cast(std::round(g_AudioMan.GetSoundsVolume() * 100)); @@ -65,13 +66,15 @@ namespace RTE { m_SoundVolumeSlider->SetValue(soundVolume); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsAudioGUI::HandleInputEvents(GUIEvent &guiEvent) { + void SettingsAudioGUI::HandleInputEvents(GUIEvent& guiEvent) { if (guiEvent.GetType() == GUIEvent::Notification) { if (guiEvent.GetControl() == m_MasterVolumeSlider) { float newMasterVolume = static_cast(m_MasterVolumeSlider->GetValue()) / 100.0F; - if (newMasterVolume != g_AudioMan.GetSoundsVolume() && !g_GUISound.TestSound()->IsBeingPlayed()) { g_GUISound.TestSound()->Play(); } + if (newMasterVolume != g_AudioMan.GetSoundsVolume() && !g_GUISound.TestSound()->IsBeingPlayed()) { + g_GUISound.TestSound()->Play(); + } g_AudioMan.SetMasterVolume(newMasterVolume); UpdateMasterVolumeControls(); } else if (guiEvent.GetControl() == m_MusicVolumeSlider) { @@ -79,7 +82,9 @@ namespace RTE { UpdateMusicVolumeControls(); } else if (guiEvent.GetControl() == m_SoundVolumeSlider) { float newSoundVolume = static_cast(m_SoundVolumeSlider->GetValue()) / 100.0F; - if (newSoundVolume != g_AudioMan.GetSoundsVolume() && !g_GUISound.TestSound()->IsBeingPlayed()) { g_GUISound.TestSound()->Play(); } + if (newSoundVolume != g_AudioMan.GetSoundsVolume() && !g_GUISound.TestSound()->IsBeingPlayed()) { + g_GUISound.TestSound()->Play(); + } g_AudioMan.SetSoundsVolume(newSoundVolume); UpdateSoundVolumeControls(); } else if (guiEvent.GetControl() == m_MasterMuteCheckbox) { @@ -91,4 +96,4 @@ namespace RTE { } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/SettingsAudioGUI.h b/Source/Menus/SettingsAudioGUI.h index 0be6275db..9e89a3092 100644 --- a/Source/Menus/SettingsAudioGUI.h +++ b/Source/Menus/SettingsAudioGUI.h @@ -16,13 +16,12 @@ namespace RTE { class SettingsAudioGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsAudioGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this SettingsAudioGUI. Ownership is NOT transferred! - explicit SettingsAudioGUI(GUIControlManager *parentControlManager); + explicit SettingsAudioGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Concrete Methods @@ -36,26 +35,25 @@ namespace RTE { /// Handles the player interaction with the AudioVideoGUI GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandleInputEvents(GUIEvent &guiEvent); + void HandleInputEvents(GUIEvent& guiEvent); #pragma endregion private: - - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. /// /// GUI elements that compose the audio settings menu screen. /// - GUICollectionBox *m_AudioSettingsBox; - GUILabel *m_MasterVolumeLabel; - GUISlider *m_MasterVolumeSlider; - GUICheckbox *m_MasterMuteCheckbox; - GUILabel *m_MusicVolumeLabel; - GUISlider *m_MusicVolumeSlider; - GUICheckbox *m_MusicMuteCheckbox; - GUILabel *m_SoundVolumeLabel; - GUISlider *m_SoundVolumeSlider; - GUICheckbox *m_SoundMuteCheckbox; + GUICollectionBox* m_AudioSettingsBox; + GUILabel* m_MasterVolumeLabel; + GUISlider* m_MasterVolumeSlider; + GUICheckbox* m_MasterMuteCheckbox; + GUILabel* m_MusicVolumeLabel; + GUISlider* m_MusicVolumeSlider; + GUICheckbox* m_MusicMuteCheckbox; + GUILabel* m_SoundVolumeLabel; + GUISlider* m_SoundVolumeSlider; + GUICheckbox* m_SoundMuteCheckbox; #pragma region Audio Settings Handling /// @@ -75,8 +73,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - SettingsAudioGUI(const SettingsAudioGUI &reference) = delete; - SettingsAudioGUI & operator=(const SettingsAudioGUI &rhs) = delete; + SettingsAudioGUI(const SettingsAudioGUI& reference) = delete; + SettingsAudioGUI& operator=(const SettingsAudioGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SettingsGUI.cpp b/Source/Menus/SettingsGUI.cpp index 5cc5040e6..44e5c39cb 100644 --- a/Source/Menus/SettingsGUI.cpp +++ b/Source/Menus/SettingsGUI.cpp @@ -10,30 +10,32 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsGUI::SettingsGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu) { + SettingsGUI::SettingsGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool createForPauseMenu) { m_GUIControlManager = std::make_unique(); RTEAssert(m_GUIControlManager->Create(guiScreen, guiInput, "Base.rte/GUIs/Skins/Menus", "MainMenuSubMenuSkin.ini"), "Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/Menus/MainMenuSubMenuSkin.ini"); m_GUIControlManager->Load(createForPauseMenu ? "Base.rte/GUIs/SettingsPauseGUI.ini" : "Base.rte/GUIs/SettingsGUI.ini"); int rootBoxMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); - GUICollectionBox *rootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); + GUICollectionBox* rootBox = dynamic_cast(m_GUIControlManager->GetControl("root")); rootBox->Resize(rootBoxMaxWidth, g_WindowMan.GetResY()); - m_SettingsTabberBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSettingsBase")); + m_SettingsTabberBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSettingsBase")); m_SettingsTabberBox->SetPositionAbs((rootBox->GetWidth() - m_SettingsTabberBox->GetWidth()) / 2, 140); - if (rootBox->GetHeight() < 540) { m_SettingsTabberBox->CenterInParent(true, true); } + if (rootBox->GetHeight() < 540) { + m_SettingsTabberBox->CenterInParent(true, true); + } - m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMainMenu")); + m_BackToMainButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonBackToMainMenu")); m_BackToMainButton->SetPositionAbs((rootBox->GetWidth() - m_BackToMainButton->GetWidth()) / 2, m_SettingsTabberBox->GetYPos() + m_SettingsTabberBox->GetHeight() + 10); - m_SettingsMenuTabs[SettingsMenuScreen::VideoSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabVideoSettings")); - m_SettingsMenuTabs[SettingsMenuScreen::AudioSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabAudioSettings")); - m_SettingsMenuTabs[SettingsMenuScreen::InputSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabInputSettings")); - m_SettingsMenuTabs[SettingsMenuScreen::GameplaySettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabGameplaySettings")); - m_SettingsMenuTabs[SettingsMenuScreen::MiscSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabMiscSettings")); + m_SettingsMenuTabs[SettingsMenuScreen::VideoSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabVideoSettings")); + m_SettingsMenuTabs[SettingsMenuScreen::AudioSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabAudioSettings")); + m_SettingsMenuTabs[SettingsMenuScreen::InputSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabInputSettings")); + m_SettingsMenuTabs[SettingsMenuScreen::GameplaySettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabGameplaySettings")); + m_SettingsMenuTabs[SettingsMenuScreen::MiscSettingsMenu] = dynamic_cast(m_GUIControlManager->GetControl("TabMiscSettings")); m_VideoSettingsMenu = std::make_unique(m_GUIControlManager.get()); m_AudioSettingsMenu = std::make_unique(m_GUIControlManager.get()); @@ -52,10 +54,10 @@ namespace RTE { m_SettingsMenuTabs[m_ActiveSettingsMenuScreen]->SetCheck(true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUICollectionBox * SettingsGUI::GetActiveDialogBox() const { - GUICollectionBox *activeDialogBox = nullptr; + GUICollectionBox* SettingsGUI::GetActiveDialogBox() const { + GUICollectionBox* activeDialogBox = nullptr; switch (m_ActiveSettingsMenuScreen) { case SettingsMenuScreen::VideoSettingsMenu: activeDialogBox = m_VideoSettingsMenu->GetActiveDialogBox(); @@ -71,7 +73,7 @@ namespace RTE { return activeDialogBox; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGUI::CloseActiveDialogBox() const { switch (m_ActiveSettingsMenuScreen) { @@ -88,16 +90,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGUI::DisableSettingsMenuNavigation(bool disable) const { m_BackToMainButton->SetEnabled(!disable); - for (GUITab *settingsTabberTab : m_SettingsMenuTabs) { + for (GUITab* settingsTabberTab: m_SettingsMenuTabs) { settingsTabberTab->SetEnabled(!disable); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGUI::SetActiveSettingsMenuScreen(SettingsMenuScreen activeMenu, bool playButtonPressSound) { m_VideoSettingsMenu->SetEnabled(false); @@ -130,10 +132,12 @@ namespace RTE { // Remove focus so the tab hovered graphic is removed after being pressed, otherwise it remains stuck on the active tab. m_GUIControlManager->GetManager()->SetFocus(nullptr); - if (playButtonPressSound) { g_GUISound.BackButtonPressSound()->Play(); } + if (playButtonPressSound) { + g_GUISound.BackButtonPressSound()->Play(); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsGUI::HandleInputEvents() { m_GUIControlManager->Update(); @@ -146,7 +150,9 @@ namespace RTE { return true; } } else if (guiEvent.GetType() == GUIEvent::Notification) { - if ((guiEvent.GetMsg() == GUIButton::Focused) && dynamic_cast(guiEvent.GetControl()) || (guiEvent.GetMsg() == GUITab::Hovered && dynamic_cast(guiEvent.GetControl()))) { g_GUISound.SelectionChangeSound()->Play(); } + if ((guiEvent.GetMsg() == GUIButton::Focused) && dynamic_cast(guiEvent.GetControl()) || (guiEvent.GetMsg() == GUITab::Hovered && dynamic_cast(guiEvent.GetControl()))) { + g_GUISound.SelectionChangeSound()->Play(); + } if (guiEvent.GetMsg() == GUITab::UnPushed) { if (guiEvent.GetControl() == m_SettingsMenuTabs[SettingsMenuScreen::VideoSettingsMenu]) { @@ -194,10 +200,10 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGUI::Draw() const { m_GUIControlManager->Draw(); m_GUIControlManager->DrawMouse(); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/SettingsGUI.h b/Source/Menus/SettingsGUI.h index 5c5d1e04e..dd6534195 100644 --- a/Source/Menus/SettingsGUI.h +++ b/Source/Menus/SettingsGUI.h @@ -21,7 +21,6 @@ namespace RTE { class SettingsGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsGUI object in system memory and make it ready for use. @@ -29,7 +28,7 @@ namespace RTE { /// Pointer to a GUIScreen interface that will be used by this SettingsGUI's GUIControlManager. Ownership is NOT transferred! /// Pointer to a GUIInput interface that will be used by this SettingsGUI's GUIControlManager. Ownership is NOT transferred! /// Whether this SettingsGUI is part of PauseMenuGUI and should have a slightly different layout. - SettingsGUI(AllegroScreen *guiScreen, GUIInputWrapper *guiInput, bool createForPauseMenu = false); + SettingsGUI(AllegroScreen* guiScreen, GUIInputWrapper* guiInput, bool createForPauseMenu = false); #pragma endregion #pragma region Getters @@ -37,7 +36,7 @@ namespace RTE { /// Gets the currently active GUICollectionBox of this SettingsGUI or any of its sub-menus that acts as a dialog box and requires disabling navigation and drawing an overlay. /// /// Pointer to the GUICollectionBox that is the currently active dialog box. Ownership is NOT transferred! - GUICollectionBox * GetActiveDialogBox() const; + GUICollectionBox* GetActiveDialogBox() const; #pragma endregion #pragma region Concrete Methods @@ -64,7 +63,6 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for the different sub-menu screens of the settings menu. /// @@ -90,9 +88,9 @@ namespace RTE { /// /// GUI elements that compose the settings menu screen. /// - GUICollectionBox *m_SettingsTabberBox; - GUIButton *m_BackToMainButton; - std::array m_SettingsMenuTabs; + GUICollectionBox* m_SettingsTabberBox; + GUIButton* m_BackToMainButton; + std::array m_SettingsMenuTabs; #pragma region Settings Menu Handling /// @@ -109,8 +107,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - SettingsGUI(const SettingsGUI &reference) = delete; - SettingsGUI & operator=(const SettingsGUI &rhs) = delete; + SettingsGUI(const SettingsGUI& reference) = delete; + SettingsGUI& operator=(const SettingsGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SettingsGameplayGUI.cpp b/Source/Menus/SettingsGameplayGUI.cpp index e11a0ee94..e000041f6 100644 --- a/Source/Menus/SettingsGameplayGUI.cpp +++ b/Source/Menus/SettingsGameplayGUI.cpp @@ -12,43 +12,44 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsGameplayGUI::SettingsGameplayGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { - m_GameplaySettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxGameplaySettings")); + SettingsGameplayGUI::SettingsGameplayGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { + m_GameplaySettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxGameplaySettings")); - m_FlashOnBrainDamageCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxFlashOnBrainDamage")); + m_FlashOnBrainDamageCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxFlashOnBrainDamage")); m_FlashOnBrainDamageCheckbox->SetCheck(g_SettingsMan.FlashOnBrainDamage()); - m_BlipOnRevealUnseenCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxBlipOnRevealUnseen")); + m_BlipOnRevealUnseenCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxBlipOnRevealUnseen")); m_BlipOnRevealUnseenCheckbox->SetCheck(g_SettingsMan.BlipOnRevealUnseen()); - m_ShowForeignItemsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowForeignItems")); + m_ShowForeignItemsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowForeignItems")); m_ShowForeignItemsCheckbox->SetCheck(g_SettingsMan.ShowForeignItems()); - m_EnableCrabBombsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxCrabBombs")); + m_EnableCrabBombsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxCrabBombs")); m_EnableCrabBombsCheckbox->SetCheck(g_SettingsMan.CrabBombsEnabled()); - m_EndlessMetaGameCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxEndlessMetaGame")); + m_EndlessMetaGameCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxEndlessMetaGame")); m_EndlessMetaGameCheckbox->SetCheck(g_SettingsMan.EndlessMetaGameMode()); - m_ShowEnemyHUDCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxEnemyHUD")); + m_ShowEnemyHUDCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxEnemyHUD")); m_ShowEnemyHUDCheckbox->SetCheck(g_SettingsMan.ShowEnemyHUD()); - m_EnableSmartBuyMenuNavigationCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxSmartBuyMenuNavigation")); + m_EnableSmartBuyMenuNavigationCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxSmartBuyMenuNavigation")); m_EnableSmartBuyMenuNavigationCheckbox->SetCheck(g_SettingsMan.SmartBuyMenuNavigationEnabled()); - m_MaxUnheldItemsTextbox = dynamic_cast(m_GUIControlManager->GetControl("TextboxMaxUnheldItems")); + m_MaxUnheldItemsTextbox = dynamic_cast(m_GUIControlManager->GetControl("TextboxMaxUnheldItems")); m_MaxUnheldItemsTextbox->SetText(std::to_string(g_MovableMan.GetMaxDroppedItems())); m_MaxUnheldItemsTextbox->SetNumericOnly(true); m_MaxUnheldItemsTextbox->SetMaxTextLength(2); - m_CrabBombThresholdTextbox = dynamic_cast(m_GUIControlManager->GetControl("TextboxCrabBombThreshold")); + m_CrabBombThresholdTextbox = dynamic_cast(m_GUIControlManager->GetControl("TextboxCrabBombThreshold")); m_CrabBombThresholdTextbox->SetText(std::to_string(g_SettingsMan.GetCrabBombThreshold())); m_CrabBombThresholdTextbox->SetNumericOnly(true); m_CrabBombThresholdTextbox->SetMaxTextLength(3); - m_UnheldItemsHUDDisplayRangeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderUnheldItemsHUDRange")); + m_UnheldItemsHUDDisplayRangeSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderUnheldItemsHUDRange")); int unheldItemsHUDDisplayRangeValue = static_cast(g_SettingsMan.GetUnheldItemsHUDDisplayRange()); if (unheldItemsHUDDisplayRangeValue == 0) { m_UnheldItemsHUDDisplayRangeSlider->SetValue(m_UnheldItemsHUDDisplayRangeSlider->GetMinimum()); @@ -57,13 +58,13 @@ namespace RTE { } else { m_UnheldItemsHUDDisplayRangeSlider->SetValue(static_cast(g_SettingsMan.GetUnheldItemsHUDDisplayRange() / c_PPM)); } - m_UnheldItemsHUDDisplayRangeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelUnheldItemsHUDRangeValue")); + m_UnheldItemsHUDDisplayRangeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelUnheldItemsHUDRangeValue")); UpdateUnheldItemsHUDDisplayRange(); - m_AlwaysDisplayUnheldItemsInStrategicModeCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxAlwaysShowUnheldItemsInStrategicMode")); + m_AlwaysDisplayUnheldItemsInStrategicModeCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxAlwaysShowUnheldItemsInStrategicMode")); m_AlwaysDisplayUnheldItemsInStrategicModeCheckbox->SetCheck(g_SettingsMan.AlwaysDisplayUnheldItemsInStrategicMode()); - m_ScreenShakeStrengthSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderScreenShakeStrength")); + m_ScreenShakeStrengthSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderScreenShakeStrength")); int screenShakeStrengthValue = static_cast(g_CameraMan.GetScreenShakeStrength() * 100.0F); if (screenShakeStrengthValue == 0) { m_ScreenShakeStrengthSlider->SetValue(m_ScreenShakeStrengthSlider->GetMinimum()); @@ -72,11 +73,11 @@ namespace RTE { } else { m_ScreenShakeStrengthSlider->SetValue(static_cast(g_CameraMan.GetScreenShakeStrength() * 100.0F)); } - m_ScreenShakeStrengthLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelScreenShakeStrengthValue")); + m_ScreenShakeStrengthLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelScreenShakeStrengthValue")); UpdateScreenShakeStrength(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGameplayGUI::SetEnabled(bool enable) { m_GameplaySettingsBox->SetVisible(enable); @@ -88,24 +89,30 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGameplayGUI::UpdateMaxUnheldItemsTextbox() { - if (m_MaxUnheldItemsTextbox->GetText().empty()) { m_MaxUnheldItemsTextbox->SetText(std::to_string(g_MovableMan.GetMaxDroppedItems())); } + if (m_MaxUnheldItemsTextbox->GetText().empty()) { + m_MaxUnheldItemsTextbox->SetText(std::to_string(g_MovableMan.GetMaxDroppedItems())); + } g_MovableMan.SetMaxDroppedItems(std::stoi(m_MaxUnheldItemsTextbox->GetText())); m_GameplaySettingsBox->SetFocus(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGameplayGUI::UpdateCrabBombThresholdTextbox() { - if (m_CrabBombThresholdTextbox->GetText().empty()) { m_CrabBombThresholdTextbox->SetText(std::to_string(g_SettingsMan.GetCrabBombThreshold())); } - if (std::stoi(m_CrabBombThresholdTextbox->GetText()) == 0) { m_CrabBombThresholdTextbox->SetText("1"); } + if (m_CrabBombThresholdTextbox->GetText().empty()) { + m_CrabBombThresholdTextbox->SetText(std::to_string(g_SettingsMan.GetCrabBombThreshold())); + } + if (std::stoi(m_CrabBombThresholdTextbox->GetText()) == 0) { + m_CrabBombThresholdTextbox->SetText("1"); + } g_SettingsMan.SetCrabBombThreshold(std::stoi(m_CrabBombThresholdTextbox->GetText())); m_GameplaySettingsBox->SetFocus(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGameplayGUI::UpdateUnheldItemsHUDDisplayRange() { int newValue = m_UnheldItemsHUDDisplayRangeSlider->GetValue(); @@ -121,7 +128,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsGameplayGUI::UpdateScreenShakeStrength() { int newValue = m_ScreenShakeStrengthSlider->GetValue(); @@ -129,9 +136,9 @@ namespace RTE { g_CameraMan.SetScreenShakeStrength(static_cast(newValue) / 100.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsGameplayGUI::HandleInputEvents(GUIEvent &guiEvent) { + void SettingsGameplayGUI::HandleInputEvents(GUIEvent& guiEvent) { if (guiEvent.GetType() == GUIEvent::Notification) { if (guiEvent.GetControl() == m_FlashOnBrainDamageCheckbox) { g_SettingsMan.SetFlashOnBrainDamage(m_FlashOnBrainDamageCheckbox->GetCheck()); @@ -157,11 +164,11 @@ namespace RTE { UpdateScreenShakeStrength(); } else if (guiEvent.GetControl() == m_AlwaysDisplayUnheldItemsInStrategicModeCheckbox) { g_SettingsMan.SetAlwaysDisplayUnheldItemsInStrategicMode(m_AlwaysDisplayUnheldItemsInStrategicModeCheckbox->GetCheck()); - // Update both textboxes when clicking the main CollectionBox, otherwise clicking off focused textboxes does not remove their focus or update the setting values and they will still capture keyboard input. + // Update both textboxes when clicking the main CollectionBox, otherwise clicking off focused textboxes does not remove their focus or update the setting values and they will still capture keyboard input. } else if (guiEvent.GetControl() == m_GameplaySettingsBox && guiEvent.GetMsg() == GUICollectionBox::Clicked && !m_GameplaySettingsBox->HasFocus()) { UpdateMaxUnheldItemsTextbox(); UpdateCrabBombThresholdTextbox(); } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/SettingsGameplayGUI.h b/Source/Menus/SettingsGameplayGUI.h index 446bef4ca..f2f76e9ef 100644 --- a/Source/Menus/SettingsGameplayGUI.h +++ b/Source/Menus/SettingsGameplayGUI.h @@ -17,13 +17,12 @@ namespace RTE { class SettingsGameplayGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsGameplayGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this SettingsGameplayGUI. Ownership is NOT transferred! - explicit SettingsGameplayGUI(GUIControlManager *parentControlManager); + explicit SettingsGameplayGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Concrete Methods @@ -37,34 +36,33 @@ namespace RTE { /// Handles the player interaction with the SettingsInputGUI GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandleInputEvents(GUIEvent &guiEvent); + void HandleInputEvents(GUIEvent& guiEvent); #pragma endregion private: - - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. /// /// GUI elements that compose the gameplay settings menu screen. /// - GUICollectionBox *m_GameplaySettingsBox; - GUICheckbox *m_FlashOnBrainDamageCheckbox; - GUICheckbox *m_BlipOnRevealUnseenCheckbox; - GUICheckbox *m_ShowForeignItemsCheckbox; - GUICheckbox *m_EnableCrabBombsCheckbox; - GUICheckbox *m_EndlessMetaGameCheckbox; - GUICheckbox *m_ShowEnemyHUDCheckbox; - GUICheckbox *m_EnableSmartBuyMenuNavigationCheckbox; - GUITextBox *m_MaxUnheldItemsTextbox; - GUITextBox *m_CrabBombThresholdTextbox; + GUICollectionBox* m_GameplaySettingsBox; + GUICheckbox* m_FlashOnBrainDamageCheckbox; + GUICheckbox* m_BlipOnRevealUnseenCheckbox; + GUICheckbox* m_ShowForeignItemsCheckbox; + GUICheckbox* m_EnableCrabBombsCheckbox; + GUICheckbox* m_EndlessMetaGameCheckbox; + GUICheckbox* m_ShowEnemyHUDCheckbox; + GUICheckbox* m_EnableSmartBuyMenuNavigationCheckbox; + GUITextBox* m_MaxUnheldItemsTextbox; + GUITextBox* m_CrabBombThresholdTextbox; - GUISlider *m_UnheldItemsHUDDisplayRangeSlider; - GUILabel *m_UnheldItemsHUDDisplayRangeLabel; + GUISlider* m_UnheldItemsHUDDisplayRangeSlider; + GUILabel* m_UnheldItemsHUDDisplayRangeLabel; - GUICheckbox *m_AlwaysDisplayUnheldItemsInStrategicModeCheckbox; + GUICheckbox* m_AlwaysDisplayUnheldItemsInStrategicModeCheckbox; - GUISlider *m_ScreenShakeStrengthSlider; - GUILabel *m_ScreenShakeStrengthLabel; + GUISlider* m_ScreenShakeStrengthSlider; + GUILabel* m_ScreenShakeStrengthLabel; #pragma region Gameplay Settings Handling /// @@ -89,8 +87,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - SettingsGameplayGUI(const SettingsGameplayGUI &reference) = delete; - SettingsGameplayGUI & operator=(const SettingsGameplayGUI &rhs) = delete; + SettingsGameplayGUI(const SettingsGameplayGUI& reference) = delete; + SettingsGameplayGUI& operator=(const SettingsGameplayGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SettingsInputGUI.cpp b/Source/Menus/SettingsInputGUI.cpp index bf5606b30..1cb04c1ef 100644 --- a/Source/Menus/SettingsInputGUI.cpp +++ b/Source/Menus/SettingsInputGUI.cpp @@ -10,27 +10,28 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsInputGUI::SettingsInputGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { - m_InputSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxInputSettings")); + SettingsInputGUI::SettingsInputGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { + m_InputSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxInputSettings")); for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { std::string playerNum = std::to_string(player + 1); - m_PlayerInputSettingsBoxes[player].SelectedDeviceLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelP" + playerNum + "SelectedDevice")); + m_PlayerInputSettingsBoxes[player].SelectedDeviceLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelP" + playerNum + "SelectedDevice")); - m_PlayerInputSettingsBoxes[player].NextDeviceButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "NextDevice")); - m_PlayerInputSettingsBoxes[player].PrevDeviceButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "PrevDevice")); - m_PlayerInputSettingsBoxes[player].ConfigureControlsButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "Config")); - m_PlayerInputSettingsBoxes[player].ResetControlsButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "Clear")); + m_PlayerInputSettingsBoxes[player].NextDeviceButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "NextDevice")); + m_PlayerInputSettingsBoxes[player].PrevDeviceButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "PrevDevice")); + m_PlayerInputSettingsBoxes[player].ConfigureControlsButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "Config")); + m_PlayerInputSettingsBoxes[player].ResetControlsButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonP" + playerNum + "Clear")); - m_PlayerInputSettingsBoxes[player].SensitivityLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelP" + playerNum + "Sensitivity")); - m_PlayerInputSettingsBoxes[player].SensitivitySlider = dynamic_cast(m_GUIControlManager->GetControl("SliderP" + playerNum + "Sensitivity")); + m_PlayerInputSettingsBoxes[player].SensitivityLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelP" + playerNum + "Sensitivity")); + m_PlayerInputSettingsBoxes[player].SensitivitySlider = dynamic_cast(m_GUIControlManager->GetControl("SliderP" + playerNum + "Sensitivity")); - m_PlayerInputSettingsBoxes[player].DeadZoneControlsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxP" + playerNum + "DeadzoneControls")); - m_PlayerInputSettingsBoxes[player].CircleDeadZoneRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioP" + playerNum + "DeadzoneCircle")); - m_PlayerInputSettingsBoxes[player].SquareDeadZoneRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioP" + playerNum + "DeadzoneSquare")); + m_PlayerInputSettingsBoxes[player].DeadZoneControlsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxP" + playerNum + "DeadzoneControls")); + m_PlayerInputSettingsBoxes[player].CircleDeadZoneRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioP" + playerNum + "DeadzoneCircle")); + m_PlayerInputSettingsBoxes[player].SquareDeadZoneRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioP" + playerNum + "DeadzoneSquare")); } for (int player = Players::PlayerOne; player < Players::MaxPlayerCount; ++player) { UpdatePlayerSelectedDeviceLabel(player); @@ -39,26 +40,30 @@ namespace RTE { m_InputMappingConfigMenu = std::make_unique(parentControlManager); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputGUI::SetEnabled(bool enable) const { m_InputSettingsBox->SetVisible(enable); m_InputSettingsBox->SetEnabled(enable); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputGUI::ResetPlayerInputSettings(int player) { if (m_PlayerInputSettingsBoxes.at(player).ResetControlsButton->GetText() == "Reset") { // Only one player's reset button can be pending confirmation at a time, so cancel any other pending confirmations. for (int otherPlayer = Players::PlayerOne; otherPlayer < Players::MaxPlayerCount; ++otherPlayer) { - if (otherPlayer != player) { m_PlayerInputSettingsBoxes.at(otherPlayer).ResetControlsButton->SetText("Reset"); } + if (otherPlayer != player) { + m_PlayerInputSettingsBoxes.at(otherPlayer).ResetControlsButton->SetText("Reset"); + } } m_PlayerInputSettingsBoxes.at(player).ResetControlsButton->SetText("CONFIRM?"); } else { - InputScheme *playerControlScheme = g_UInputMan.GetControlScheme(player); + InputScheme* playerControlScheme = g_UInputMan.GetControlScheme(player); playerControlScheme->ResetToPlayerDefaults(static_cast(player)); - if (playerControlScheme->GetDevice() == InputDevice::DEVICE_MOUSE_KEYB) { g_UInputMan.SetMouseSensitivity(0.6F); } + if (playerControlScheme->GetDevice() == InputDevice::DEVICE_MOUSE_KEYB) { + g_UInputMan.SetMouseSensitivity(0.6F); + } UpdatePlayerSelectedDeviceLabel(player); ShowOrHidePlayerInputDeviceSensitivityControls(player); @@ -69,24 +74,28 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputGUI::SetPlayerNextOrPrevInputDevice(int player, bool nextDevice) { int currentDevice = static_cast(g_UInputMan.GetControlScheme(player)->GetDevice()); if (nextDevice) { currentDevice++; - if (currentDevice >= InputDevice::DEVICE_COUNT) { currentDevice = InputDevice::DEVICE_KEYB_ONLY; } + if (currentDevice >= InputDevice::DEVICE_COUNT) { + currentDevice = InputDevice::DEVICE_KEYB_ONLY; + } } else { currentDevice--; - if (currentDevice < InputDevice::DEVICE_KEYB_ONLY) { currentDevice = InputDevice::DEVICE_GAMEPAD_4; } + if (currentDevice < InputDevice::DEVICE_KEYB_ONLY) { + currentDevice = InputDevice::DEVICE_GAMEPAD_4; + } } g_UInputMan.GetControlScheme(player)->SetDevice(static_cast(currentDevice)); UpdatePlayerSelectedDeviceLabel(player); ShowOrHidePlayerInputDeviceSensitivityControls(player); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputGUI::UpdatePlayerSelectedDeviceLabel(int player) { std::string deviceLabel; @@ -116,7 +125,7 @@ namespace RTE { m_PlayerInputSettingsBoxes.at(player).SelectedDeviceLabel->SetText(deviceLabel); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputGUI::ShowOrHidePlayerInputDeviceSensitivityControls(int player) { m_PlayerInputSettingsBoxes.at(player).SensitivityLabel->SetVisible(false); @@ -149,7 +158,7 @@ namespace RTE { UpdatePlayerInputSensitivityControlValues(player); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputGUI::UpdatePlayerInputSensitivityControlValues(int player) { switch (g_UInputMan.GetControlScheme(player)->GetDevice()) { @@ -183,9 +192,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsInputGUI::HandleInputEvents(GUIEvent &guiEvent) { + void SettingsInputGUI::HandleInputEvents(GUIEvent& guiEvent) { if (m_InputMappingConfigMenu->IsEnabled()) { m_InputMappingConfigMenu->HandleInputEvents(guiEvent); return; @@ -221,4 +230,4 @@ namespace RTE { } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/SettingsInputGUI.h b/Source/Menus/SettingsInputGUI.h index 79df3264f..23a6bb5d8 100644 --- a/Source/Menus/SettingsInputGUI.h +++ b/Source/Menus/SettingsInputGUI.h @@ -22,13 +22,12 @@ namespace RTE { class SettingsInputGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsInputGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this SettingsInputGUI. Ownership is NOT transferred! - explicit SettingsInputGUI(GUIControlManager *parentControlManager); + explicit SettingsInputGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Getters and Setters @@ -42,7 +41,7 @@ namespace RTE { /// Gets the currently active GUICollectionBox that acts as a dialog box and requires disabling navigation and drawing an overlay. /// /// Pointer to the GUICollectionBox that is the currently active dialog box, if any. Ownership is NOT transferred! - GUICollectionBox * GetActiveDialogBox() const { return m_InputMappingConfigMenu->GetActiveDialogBox(); } + GUICollectionBox* GetActiveDialogBox() const { return m_InputMappingConfigMenu->GetActiveDialogBox(); } /// /// Closes the currently active GUICollectionBox that acts as a dialog box by hiding it. If the active dialog box is a sub-menu, disables it. @@ -79,35 +78,34 @@ namespace RTE { /// Handles the player interaction with the SettingsInputGUI GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandleInputEvents(GUIEvent &guiEvent); + void HandleInputEvents(GUIEvent& guiEvent); #pragma endregion private: - /// /// Struct containing GUI elements that compose the input settings box of a player. /// struct PlayerInputSettingsBox { - GUILabel *SelectedDeviceLabel; - GUIButton *NextDeviceButton; - GUIButton *PrevDeviceButton; - GUIButton *ConfigureControlsButton; - GUIButton *ResetControlsButton; - GUILabel *SensitivityLabel; - GUISlider *SensitivitySlider; - GUICollectionBox *DeadZoneControlsBox; - GUIRadioButton *CircleDeadZoneRadioButton; - GUIRadioButton *SquareDeadZoneRadioButton; + GUILabel* SelectedDeviceLabel; + GUIButton* NextDeviceButton; + GUIButton* PrevDeviceButton; + GUIButton* ConfigureControlsButton; + GUIButton* ResetControlsButton; + GUILabel* SensitivityLabel; + GUISlider* SensitivitySlider; + GUICollectionBox* DeadZoneControlsBox; + GUIRadioButton* CircleDeadZoneRadioButton; + GUIRadioButton* SquareDeadZoneRadioButton; }; - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. std::unique_ptr m_InputMappingConfigMenu; //!< The input mapping configuration sub-menu. /// /// GUI elements that compose the input settings menu screen. /// - GUICollectionBox *m_InputSettingsBox; + GUICollectionBox* m_InputSettingsBox; std::array m_PlayerInputSettingsBoxes; #pragma region Input Settings Handling @@ -144,8 +142,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - SettingsInputGUI(const SettingsInputGUI &reference) = delete; - SettingsInputGUI & operator=(const SettingsInputGUI &rhs) = delete; + SettingsInputGUI(const SettingsInputGUI& reference) = delete; + SettingsInputGUI& operator=(const SettingsInputGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SettingsInputMappingGUI.cpp b/Source/Menus/SettingsInputMappingGUI.cpp index 420d64868..c345a3f38 100644 --- a/Source/Menus/SettingsInputMappingGUI.cpp +++ b/Source/Menus/SettingsInputMappingGUI.cpp @@ -10,36 +10,37 @@ namespace RTE { - std::array SettingsInputMappingGUI::m_InputElementsUsedByMouse = { InputElements::INPUT_FIRE, InputElements::INPUT_PIEMENU_ANALOG, InputElements::INPUT_AIM, InputElements::INPUT_AIM_UP, InputElements::INPUT_AIM_DOWN, InputElements::INPUT_AIM_LEFT, InputElements::INPUT_AIM_RIGHT }; + std::array SettingsInputMappingGUI::m_InputElementsUsedByMouse = {InputElements::INPUT_FIRE, InputElements::INPUT_PIEMENU_ANALOG, InputElements::INPUT_AIM, InputElements::INPUT_AIM_UP, InputElements::INPUT_AIM_DOWN, InputElements::INPUT_AIM_LEFT, InputElements::INPUT_AIM_RIGHT}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsInputMappingGUI::SettingsInputMappingGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { - m_InputMappingSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPlayerInputMapping")); + SettingsInputMappingGUI::SettingsInputMappingGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { + m_InputMappingSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPlayerInputMapping")); m_InputMappingSettingsBox->SetVisible(false); - m_InputMappingSettingsLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelPlayerInputMappingTitle")); - m_CloseMappingBoxButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCloseMappingBox")); - m_RunConfigWizardButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonRunConfigWizard")); + m_InputMappingSettingsLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelPlayerInputMappingTitle")); + m_CloseMappingBoxButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCloseMappingBox")); + m_RunConfigWizardButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonRunConfigWizard")); - m_InputMapScrollingBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxScrollingMappingBox")); - m_InputMapScrollingBoxScrollbar = dynamic_cast(m_GUIControlManager->GetControl("ScrollbarScrollingMappingBox")); + m_InputMapScrollingBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxScrollingMappingBox")); + m_InputMapScrollingBoxScrollbar = dynamic_cast(m_GUIControlManager->GetControl("ScrollbarScrollingMappingBox")); m_InputMapScrollingBoxScrollbar->SetMaximum(m_InputMapScrollingBox->GetHeight()); m_InputMapScrollingBoxScrollbar->SetPageSize(m_InputMapScrollingBoxScrollbar->GetMaximum() / 2); m_LastInputMapScrollingBoxScrollbarValue = m_InputMapScrollingBoxScrollbar->GetValue(); for (int i = 0; i < InputElements::INPUT_COUNT; ++i) { - m_InputMapLabel[i] = dynamic_cast(m_GUIControlManager->GetControl("LabelInputName" + std::to_string(i + 1))); + m_InputMapLabel[i] = dynamic_cast(m_GUIControlManager->GetControl("LabelInputName" + std::to_string(i + 1))); m_InputMapLabel[i]->SetText(c_InputElementNames[i]); - m_InputMapButton[i] = dynamic_cast(m_GUIControlManager->GetControl("ButtonInputKey" + std::to_string(i + 1))); + m_InputMapButton[i] = dynamic_cast(m_GUIControlManager->GetControl("ButtonInputKey" + std::to_string(i + 1))); } - m_InputMappingCaptureBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxInputCapture")); + m_InputMappingCaptureBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxInputCapture")); m_InputMappingCaptureBox->SetVisible(false); - GUICollectionBox *settingsRootBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSettingsBase")); + GUICollectionBox* settingsRootBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSettingsBase")); m_InputMappingCaptureBox->SetPositionAbs(settingsRootBox->GetXPos() + ((settingsRootBox->GetWidth() - m_InputMappingCaptureBox->GetWidth()) / 2), settingsRootBox->GetYPos() + ((settingsRootBox->GetHeight() - m_InputMappingCaptureBox->GetHeight()) / 2)); - m_InputElementCapturingInputNameLabel = dynamic_cast(m_GUIControlManager->GetControl("ButtonLabelInputMappingName")); + m_InputElementCapturingInputNameLabel = dynamic_cast(m_GUIControlManager->GetControl("ButtonLabelInputMappingName")); m_InputConfigWizardMenu = std::make_unique(parentControlManager); @@ -49,13 +50,13 @@ namespace RTE { m_InputElementCapturingInput = InputElements::INPUT_COUNT; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingGUI::IsEnabled() const { return m_InputMappingSettingsBox->GetVisible() && m_InputMappingSettingsBox->GetEnabled(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingGUI::SetEnabled(bool enable, int player) { m_InputMappingSettingsBox->SetVisible(enable); @@ -75,9 +76,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUICollectionBox * SettingsInputMappingGUI::GetActiveDialogBox() const { + GUICollectionBox* SettingsInputMappingGUI::GetActiveDialogBox() const { if (m_InputConfigWizardMenu->IsEnabled()) { return m_InputConfigWizardMenu->GetActiveDialogBox(); } else if (m_InputMappingCaptureBox->GetEnabled() && m_InputMappingCaptureBox->GetVisible()) { @@ -86,7 +87,7 @@ namespace RTE { return (m_InputMappingSettingsBox->GetEnabled() && m_InputMappingSettingsBox->GetVisible()) ? m_InputMappingSettingsBox : nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingGUI::CloseActiveDialogBox() { if (m_InputConfigWizardMenu->IsEnabled()) { @@ -98,13 +99,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingGUI::IsConfiguringManually() const { return m_ConfiguringManually && m_InputMappingCaptureBox->GetVisible() && m_InputMappingCaptureBox->GetEnabled(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingGUI::ShowInputMappingCaptureBox(InputElements inputElement) { m_InputMappingSettingsBox->SetEnabled(false); @@ -117,7 +118,7 @@ namespace RTE { g_UInputMan.SetSkipHandlingSpecialInput(true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingGUI::HideInputMappingCaptureBox() { m_InputMappingSettingsBox->SetEnabled(true); @@ -128,13 +129,15 @@ namespace RTE { g_UInputMan.SetSkipHandlingSpecialInput(false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingGUI::UpdateMappingButtonLabels() { - const std::array *inputMappings = m_ConfiguringPlayerInputScheme->GetInputMappings(); + const std::array* inputMappings = m_ConfiguringPlayerInputScheme->GetInputMappings(); for (int i = 0; i < InputElements::INPUT_COUNT; ++i) { std::string inputDescription = inputMappings->at(i).GetPresetDescription(); - if (inputDescription.empty()) { inputDescription = m_ConfiguringPlayerInputScheme->GetMappingName(i); } + if (inputDescription.empty()) { + inputDescription = m_ConfiguringPlayerInputScheme->GetMappingName(i); + } m_InputMapButton[i]->SetText(!inputDescription.empty() ? "[" + inputDescription + "]" : "[Undefined]"); } // Adjust the scrolling box scroll range to hide mappings that are only relevant to gamepads. @@ -142,7 +145,7 @@ namespace RTE { m_InputMapScrollingBoxScrollbar->SetPageSize(m_InputMapScrollingBoxScrollbar->GetMaximum() / 2); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingGUI::UpdateScrollingInputBoxScrollPosition() { int scrollbarValue = m_InputMapScrollingBoxScrollbar->GetValue(); @@ -150,11 +153,13 @@ namespace RTE { m_LastInputMapScrollingBoxScrollbarValue = scrollbarValue; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsInputMappingGUI::HandleInputEvents(GUIEvent &guiEvent) { + void SettingsInputMappingGUI::HandleInputEvents(GUIEvent& guiEvent) { if (m_InputConfigWizardMenu->IsEnabled()) { - if (m_InputConfigWizardMenu->HandleInputEvents(guiEvent)) { UpdateMappingButtonLabels(); } + if (m_InputConfigWizardMenu->HandleInputEvents(guiEvent)) { + UpdateMappingButtonLabels(); + } return; } if (guiEvent.GetType() == GUIEvent::Command) { @@ -186,7 +191,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingGUI::HandleManualConfigSequence() { bool inputCaptured = false; @@ -209,4 +214,4 @@ namespace RTE { HideInputMappingCaptureBox(); } } -} +} // namespace RTE diff --git a/Source/Menus/SettingsInputMappingGUI.h b/Source/Menus/SettingsInputMappingGUI.h index 712b4c17a..4fe312157 100644 --- a/Source/Menus/SettingsInputMappingGUI.h +++ b/Source/Menus/SettingsInputMappingGUI.h @@ -19,13 +19,12 @@ namespace RTE { class SettingsInputMappingGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsInputMappingGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this SettingsInputMappingGUI. Ownership is NOT transferred! - explicit SettingsInputMappingGUI(GUIControlManager *parentControlManager); + explicit SettingsInputMappingGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Getters and Setters @@ -46,7 +45,7 @@ namespace RTE { /// Gets the currently active GUICollectionBox that acts as a dialog box and requires disabling navigation and drawing an overlay. /// /// Pointer to the GUICollectionBox that is the currently active dialog box, if any. Ownership is NOT transferred! - GUICollectionBox * GetActiveDialogBox() const; + GUICollectionBox* GetActiveDialogBox() const; /// /// Closes the currently active GUICollectionBox that acts as a dialog box by hiding it. If the active dialog box is a sub-menu, disables it. @@ -63,7 +62,7 @@ namespace RTE { /// Gets the SettingsInputMappingWizardGUI of this SettingsInputMappingGUI. /// /// Pointer to the SettingsInputMappingWizardGUI of this SettingsInputMappingGUI. Ownership is NOT transferred! - SettingsInputMappingWizardGUI * GetInputConfigWizardMenu() { return m_InputConfigWizardMenu.get(); } + SettingsInputMappingWizardGUI* GetInputConfigWizardMenu() { return m_InputConfigWizardMenu.get(); } #pragma endregion #pragma region Concrete Methods @@ -71,7 +70,7 @@ namespace RTE { /// Handles the player interaction with the SettingsInputMappingGUI GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandleInputEvents(GUIEvent &guiEvent); + void HandleInputEvents(GUIEvent& guiEvent); /// /// Handles capturing input and updating the manual input configuration sequence. @@ -80,13 +79,12 @@ namespace RTE { #pragma endregion private: - static std::array m_InputElementsUsedByMouse; //!< Array containing InputElements that are hard mapped to mouse controls when using mouse + keyboard. - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. Players m_ConfiguringPlayer; //!< The player this SettingsInputMappingGUI is configuring input mapping for. - InputScheme *m_ConfiguringPlayerInputScheme; //!< The InputScheme of the configuring player. + InputScheme* m_ConfiguringPlayerInputScheme; //!< The InputScheme of the configuring player. bool m_ConfiguringManually; //!< Indicates that the SettingsInputMappingGUI needs to capture input because the player is configuring manually. InputElements m_InputElementCapturingInput; //!< The InputElement in the configuring player's InputScheme that is currently being configured and is capturing input. @@ -98,16 +96,16 @@ namespace RTE { /// /// GUI elements that compose the input mapping settings menu screen. /// - GUICollectionBox *m_InputMappingSettingsBox; - GUILabel *m_InputMappingSettingsLabel; - GUIButton *m_CloseMappingBoxButton; - GUIButton *m_RunConfigWizardButton; - GUICollectionBox *m_InputMapScrollingBox; - GUIScrollbar *m_InputMapScrollingBoxScrollbar; - GUICollectionBox *m_InputMappingCaptureBox; - GUIButton *m_InputElementCapturingInputNameLabel; - std::array m_InputMapLabel; - std::array m_InputMapButton; + GUICollectionBox* m_InputMappingSettingsBox; + GUILabel* m_InputMappingSettingsLabel; + GUIButton* m_CloseMappingBoxButton; + GUIButton* m_RunConfigWizardButton; + GUICollectionBox* m_InputMapScrollingBox; + GUIScrollbar* m_InputMapScrollingBoxScrollbar; + GUICollectionBox* m_InputMappingCaptureBox; + GUIButton* m_InputElementCapturingInputNameLabel; + std::array m_InputMapLabel; + std::array m_InputMapButton; #pragma region Input Mapping Settings Handling /// @@ -133,8 +131,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - SettingsInputMappingGUI(const SettingsInputMappingGUI &reference) = delete; - SettingsInputMappingGUI & operator=(const SettingsInputMappingGUI &rhs) = delete; + SettingsInputMappingGUI(const SettingsInputMappingGUI& reference) = delete; + SettingsInputMappingGUI& operator=(const SettingsInputMappingGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SettingsInputMappingWizardGUI.cpp b/Source/Menus/SettingsInputMappingWizardGUI.cpp index 75fa50c76..c7d1762d1 100644 --- a/Source/Menus/SettingsInputMappingWizardGUI.cpp +++ b/Source/Menus/SettingsInputMappingWizardGUI.cpp @@ -9,7 +9,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::Clear() { m_ConfiguringPlayer = Players::NoPlayer; @@ -35,13 +35,14 @@ namespace RTE { m_DualAnalogXBDiagramBitmaps.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsInputMappingWizardGUI::SettingsInputMappingWizardGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { + SettingsInputMappingWizardGUI::SettingsInputMappingWizardGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { Clear(); - m_InputWizardScreenBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxInputMappingWizard")); - m_InputWizardTitleLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelPlayerInputMappingWizardTitle")); + m_InputWizardScreenBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxInputMappingWizard")); + m_InputWizardTitleLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelPlayerInputMappingWizardTitle")); int dpadDiagramBitampCount = 13; ContentFile("Base.rte/GUIs/Controllers/D-Pad.png").GetAsAnimation(m_DPadDiagramBitmaps, dpadDiagramBitampCount, COLORCONV_8_TO_32); @@ -54,56 +55,56 @@ namespace RTE { CreatePresetSelectionScreen(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::CreateManualConfigScreen() { - m_WizardManualConfigScreen.ManualConfigBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxWizardManualConfig")); - - m_WizardManualConfigScreen.ConfigDeviceTypeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelConfigDeviceType")); - m_WizardManualConfigScreen.ConfigStepDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelConfigInputDescription")); - m_WizardManualConfigScreen.ConfigStepRecommendedKeyLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelRecommendedKeyInput")); - m_WizardManualConfigScreen.GamepadConfigRecommendedBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxGamepadRecommendedInput")); - m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelRecommendedGamepadInput")); - m_WizardManualConfigScreen.GamepadConfigRecommendedDiagramBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxRecommendedGamepadInputDiagram")); - - m_WizardManualConfigScreen.ConfigStepLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelConfigStep")); - m_WizardManualConfigScreen.PrevConfigStepButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigPrevStep")); - m_WizardManualConfigScreen.NextConfigStepButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigNextStep")); - m_WizardManualConfigScreen.ResetConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigRestart")); - m_WizardManualConfigScreen.DiscardOrApplyConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonDiscardOrApply")); + m_WizardManualConfigScreen.ManualConfigBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxWizardManualConfig")); + + m_WizardManualConfigScreen.ConfigDeviceTypeLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelConfigDeviceType")); + m_WizardManualConfigScreen.ConfigStepDescriptionLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelConfigInputDescription")); + m_WizardManualConfigScreen.ConfigStepRecommendedKeyLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelRecommendedKeyInput")); + m_WizardManualConfigScreen.GamepadConfigRecommendedBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxGamepadRecommendedInput")); + m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelRecommendedGamepadInput")); + m_WizardManualConfigScreen.GamepadConfigRecommendedDiagramBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxRecommendedGamepadInputDiagram")); + + m_WizardManualConfigScreen.ConfigStepLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelConfigStep")); + m_WizardManualConfigScreen.PrevConfigStepButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigPrevStep")); + m_WizardManualConfigScreen.NextConfigStepButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigNextStep")); + m_WizardManualConfigScreen.ResetConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigRestart")); + m_WizardManualConfigScreen.DiscardOrApplyConfigButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonDiscardOrApply")); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::CreatePresetSelectionScreen() { - m_WizardPresetSelectScreen.PresetSelectBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxWizardPresets")); - m_WizardPresetSelectScreen.CloseWizardButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCloseWizardBox")); + m_WizardPresetSelectScreen.PresetSelectBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxWizardPresets")); + m_WizardPresetSelectScreen.CloseWizardButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCloseWizardBox")); - m_WizardPresetSelectScreen.PresetSelectSNESButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonPresetDPadSNES")); - m_WizardPresetSelectScreen.PresetSelectDS4Button = dynamic_cast(m_GUIControlManager->GetControl("ButtonPresetAnalogDS4")); - m_WizardPresetSelectScreen.PresetSelectXB360Button = dynamic_cast(m_GUIControlManager->GetControl("ButtonPresetAnalogXB360")); - m_WizardPresetSelectScreen.StartConfigDPadTypeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigDPadType")); - m_WizardPresetSelectScreen.StartConfigAnalogDSTypeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigAnalogTypeDS")); - m_WizardPresetSelectScreen.StartConfigAnalogXBTypeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigAnalogTypeXB")); + m_WizardPresetSelectScreen.PresetSelectSNESButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonPresetDPadSNES")); + m_WizardPresetSelectScreen.PresetSelectDS4Button = dynamic_cast(m_GUIControlManager->GetControl("ButtonPresetAnalogDS4")); + m_WizardPresetSelectScreen.PresetSelectXB360Button = dynamic_cast(m_GUIControlManager->GetControl("ButtonPresetAnalogXB360")); + m_WizardPresetSelectScreen.StartConfigDPadTypeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigDPadType")); + m_WizardPresetSelectScreen.StartConfigAnalogDSTypeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigAnalogTypeDS")); + m_WizardPresetSelectScreen.StartConfigAnalogXBTypeButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfigAnalogTypeXB")); // Ownership of the AllegroBitmaps is passed to the GUIControlManager. - dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxConfigDPadTypeDiagram"))->SetDrawImage(new AllegroBitmap(m_DPadDiagramBitmaps[0])); - dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPresetDPadSNESDiagram"))->SetDrawImage(new AllegroBitmap(m_DPadDiagramBitmaps[0])); - dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxConfigAnalogTypeDSDiagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogDSDiagramBitmaps[0])); - dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPresetAnalogDS4Diagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogDSDiagramBitmaps[0])); - dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxConfigAnalogTypeXBDiagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogXBDiagramBitmaps[0])); - dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPresetAnalogXB360Diagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogXBDiagramBitmaps[0])); + dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxConfigDPadTypeDiagram"))->SetDrawImage(new AllegroBitmap(m_DPadDiagramBitmaps[0])); + dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPresetDPadSNESDiagram"))->SetDrawImage(new AllegroBitmap(m_DPadDiagramBitmaps[0])); + dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxConfigAnalogTypeDSDiagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogDSDiagramBitmaps[0])); + dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPresetAnalogDS4Diagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogDSDiagramBitmaps[0])); + dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxConfigAnalogTypeXBDiagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogXBDiagramBitmaps[0])); + dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxPresetAnalogXB360Diagram"))->SetDrawImage(new AllegroBitmap(m_DualAnalogXBDiagramBitmaps[0])); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingWizardGUI::IsEnabled() const { return m_InputWizardScreenBox->GetVisible() && m_InputWizardScreenBox->GetEnabled(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsInputMappingWizardGUI::SetEnabled(bool enable, int player, InputScheme *playerScheme) { + void SettingsInputMappingWizardGUI::SetEnabled(bool enable, int player, InputScheme* playerScheme) { m_InputWizardScreenBox->SetVisible(enable); m_InputWizardScreenBox->SetEnabled(enable); @@ -133,19 +134,19 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUICollectionBox * SettingsInputMappingWizardGUI::GetActiveDialogBox() const { + GUICollectionBox* SettingsInputMappingWizardGUI::GetActiveDialogBox() const { return (m_InputWizardScreenBox->GetEnabled() && m_InputWizardScreenBox->GetVisible()) ? m_InputWizardScreenBox : nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingWizardGUI::IsConfiguringManually() const { return m_ConfiguringManually && m_WizardManualConfigScreen.ManualConfigBox->GetVisible() && m_WizardManualConfigScreen.ManualConfigBox->GetEnabled(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::ShowManualConfigScreen() { m_WizardPresetSelectScreen.PresetSelectBox->SetVisible(false); @@ -191,7 +192,7 @@ namespace RTE { m_ConfiguringManually = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::ShowPresetSelectionScreen() { m_WizardManualConfigScreen.ManualConfigBox->SetVisible(false); @@ -201,7 +202,7 @@ namespace RTE { m_WizardPresetSelectScreen.PresetSelectBox->SetEnabled(true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::ResetManualConfigSequence() { m_ConfigFinished = false; @@ -211,7 +212,7 @@ namespace RTE { m_NewInputScheme.SetDevice(m_ConfiguringDevice); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::ApplyGamepadInputPreset(GamepadType gamepadType) { switch (gamepadType) { @@ -232,7 +233,7 @@ namespace RTE { m_NewInputSchemeApplied = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::ApplyManuallyConfiguredScheme() { m_ConfiguringPlayerScheme->SetDevice(m_NewInputScheme.GetDevice()); @@ -254,9 +255,9 @@ namespace RTE { m_ConfiguringManually = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool SettingsInputMappingWizardGUI::HandleInputEvents(GUIEvent &guiEvent) { + bool SettingsInputMappingWizardGUI::HandleInputEvents(GUIEvent& guiEvent) { if (m_WizardManualConfigScreen.ManualConfigBox->GetVisible()) { HandleManualConfigScreenInputEvents(guiEvent); } else if (m_WizardPresetSelectScreen.PresetSelectBox->GetVisible()) { @@ -269,9 +270,9 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsInputMappingWizardGUI::HandleManualConfigScreenInputEvents(GUIEvent &guiEvent) { + void SettingsInputMappingWizardGUI::HandleManualConfigScreenInputEvents(GUIEvent& guiEvent) { if (guiEvent.GetType() == GUIEvent::Command) { if (guiEvent.GetControl() == m_WizardManualConfigScreen.PrevConfigStepButton) { g_GUISound.ButtonPressSound()->Play(); @@ -303,9 +304,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsInputMappingWizardGUI::HandlePresetSelectScreenInputEvents(GUIEvent &guiEvent) { + void SettingsInputMappingWizardGUI::HandlePresetSelectScreenInputEvents(GUIEvent& guiEvent) { if (guiEvent.GetType() == GUIEvent::Command) { if (guiEvent.GetControl() == m_WizardPresetSelectScreen.CloseWizardButton) { g_GUISound.ButtonPressSound()->Play(); @@ -332,10 +333,12 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::HandleManualConfigSequence() { - if (m_ConfigStepChange) { HandleManualConfigStepChange(); } + if (m_ConfigStepChange) { + HandleManualConfigStepChange(); + } if (m_ConfigFinished) { m_GUIControlManager->GetManager()->SetFocus(m_BlinkTimer.AlternateReal(500) ? m_WizardManualConfigScreen.DiscardOrApplyConfigButton : nullptr); @@ -364,14 +367,16 @@ namespace RTE { break; } if (inputCaptured) { - if (!m_ConfigFinished) { m_ConfigStep++; } + if (!m_ConfigFinished) { + m_ConfigStep++; + } g_GUISound.ExitMenuSound()->Play(); m_ConfigStepChange = true; } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsInputMappingWizardGUI::HandleManualConfigStepChange() { int configuringDeviceSteps = 0; @@ -408,13 +413,15 @@ namespace RTE { m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetVisible(false); m_WizardManualConfigScreen.ConfigStepRecommendedKeyLabel->SetVisible(false); m_WizardManualConfigScreen.GamepadConfigRecommendedBox->SetVisible(false); - if (m_ConfigStep < configuringDeviceSteps - 1) { m_ConfigFinished = false; } + if (m_ConfigStep < configuringDeviceSteps - 1) { + m_ConfigFinished = false; + } } m_WizardManualConfigScreen.PrevConfigStepButton->SetVisible(m_ConfigStep != 0); m_WizardManualConfigScreen.NextConfigStepButton->SetVisible(m_ConfigStep < configuringDeviceSteps - 1); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingWizardGUI::UpdateKeyboardConfigSequence() { switch (m_ConfigStep) { @@ -586,7 +593,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingWizardGUI::UpdateMouseAndKeyboardConfigSequence() { switch (m_ConfigStep) { @@ -710,7 +717,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingWizardGUI::UpdateGamepadDPadConfigSequence() { switch (m_ConfigStep) { @@ -844,7 +851,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsInputMappingWizardGUI::UpdateGamepadAnalogConfigSequence() { switch (m_ConfigStep) { @@ -1059,4 +1066,4 @@ namespace RTE { } return false; } -} +} // namespace RTE diff --git a/Source/Menus/SettingsInputMappingWizardGUI.h b/Source/Menus/SettingsInputMappingWizardGUI.h index c8cf0b531..e56295cda 100644 --- a/Source/Menus/SettingsInputMappingWizardGUI.h +++ b/Source/Menus/SettingsInputMappingWizardGUI.h @@ -21,13 +21,12 @@ namespace RTE { class SettingsInputMappingWizardGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsInputMappingWizardGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this SettingsInputMappingWizardGUI. Ownership is NOT transferred! - explicit SettingsInputMappingWizardGUI(GUIControlManager *parentControlManager); + explicit SettingsInputMappingWizardGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Getters and Setters @@ -42,13 +41,13 @@ namespace RTE { /// /// Show and enable or hide and disable the SettingsInputMappingWizardGUI. /// The player this SettingsInputMappingWizardGUI is mapping inputs for. - void SetEnabled(bool enable = true, int player = 0, InputScheme *playerScheme = nullptr); + void SetEnabled(bool enable = true, int player = 0, InputScheme* playerScheme = nullptr); /// /// Gets the currently active GUICollectionBox that acts as a dialog box and requires disabling navigation and drawing an overlay. /// /// Pointer to the GUICollectionBox that is the currently active dialog box, if any. Ownership is NOT transferred! - GUICollectionBox * GetActiveDialogBox() const; + GUICollectionBox* GetActiveDialogBox() const; /// /// Gets whether this SettingsInputMappingWizardGUI needs to capture input for manual configuration. @@ -63,7 +62,7 @@ namespace RTE { /// /// The GUIEvent containing information about the player interaction with an element. /// Whether this SettingsInputMappingGUI changed the input scheme of the configuring player. - bool HandleInputEvents(GUIEvent &guiEvent); + bool HandleInputEvents(GUIEvent& guiEvent); /// /// Handles updating and progressing the manual input configuration sequence. @@ -72,42 +71,45 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for the different types of gamepads that can be configured. /// - enum GamepadType { DPad, AnalogDualShock, AnalogXbox }; + enum GamepadType { + DPad, + AnalogDualShock, + AnalogXbox + }; /// /// Struct containing GUI elements that compose the input mapping wizard manual configuration menu screen. /// struct WizardManualConfigScreen { - GUICollectionBox *ManualConfigBox; - GUILabel *ConfigDeviceTypeLabel; - GUILabel *ConfigStepDescriptionLabel; - GUILabel *ConfigStepRecommendedKeyLabel; - GUICollectionBox *GamepadConfigRecommendedBox; - GUILabel *GamepadConfigStepRecommendedInputLabel; - GUICollectionBox *GamepadConfigRecommendedDiagramBox; - GUILabel *ConfigStepLabel; - GUIButton *PrevConfigStepButton; - GUIButton *NextConfigStepButton; - GUIButton *ResetConfigButton; - GUIButton *DiscardOrApplyConfigButton; + GUICollectionBox* ManualConfigBox; + GUILabel* ConfigDeviceTypeLabel; + GUILabel* ConfigStepDescriptionLabel; + GUILabel* ConfigStepRecommendedKeyLabel; + GUICollectionBox* GamepadConfigRecommendedBox; + GUILabel* GamepadConfigStepRecommendedInputLabel; + GUICollectionBox* GamepadConfigRecommendedDiagramBox; + GUILabel* ConfigStepLabel; + GUIButton* PrevConfigStepButton; + GUIButton* NextConfigStepButton; + GUIButton* ResetConfigButton; + GUIButton* DiscardOrApplyConfigButton; }; /// /// Struct containing GUI elements that compose the input mapping wizard preset selection menu screen. /// struct WizardPresetSelectScreen { - GUICollectionBox *PresetSelectBox; - GUIButton *CloseWizardButton; - GUIButton *PresetSelectSNESButton; - GUIButton *PresetSelectDS4Button; - GUIButton *PresetSelectXB360Button; - GUIButton *StartConfigDPadTypeButton; - GUIButton *StartConfigAnalogDSTypeButton; - GUIButton *StartConfigAnalogXBTypeButton; + GUICollectionBox* PresetSelectBox; + GUIButton* CloseWizardButton; + GUIButton* PresetSelectSNESButton; + GUIButton* PresetSelectDS4Button; + GUIButton* PresetSelectXB360Button; + GUIButton* StartConfigDPadTypeButton; + GUIButton* StartConfigAnalogDSTypeButton; + GUIButton* StartConfigAnalogXBTypeButton; }; static constexpr int m_KeyboardConfigSteps = 16; //!< The step count for keyboard only manual configuration. @@ -115,10 +117,10 @@ namespace RTE { static constexpr int m_DPadConfigSteps = 12; //!< The step count for DPad type gamepad manual configuration. static constexpr int m_DualAnalogConfigSteps = 20; //!< The step count for DualAnalog type gamepad manual configuration. - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. Players m_ConfiguringPlayer; //!< The player this SettingsInputMappingWizardGUI is configuring input mapping for. - InputScheme *m_ConfiguringPlayerScheme; //!< The InputScheme of the configuring player. + InputScheme* m_ConfiguringPlayerScheme; //!< The InputScheme of the configuring player. InputDevice m_ConfiguringDevice; //!< Which type of device we are currently configuring. bool m_ConfiguringDeviceIsGamepad; //!< Whether the device being configured is a gamepad of any type. @@ -135,9 +137,9 @@ namespace RTE { Timer m_BlinkTimer; //!< Timer for blinking the "Apply Changes" button and animating the recommended input diagram when configuring gamepads. - std::vector m_DPadDiagramBitmaps; //!< Vector containing all the D-Pad type gamepad recommended input diagram bitmaps. - std::vector m_DualAnalogDSDiagramBitmaps; //!< Vector containing all the DualShock type gamepad recommended input diagram bitmaps. - std::vector m_DualAnalogXBDiagramBitmaps; //!< Vector containing all the Xbox type gamepad recommended input diagram bitmaps. + std::vector m_DPadDiagramBitmaps; //!< Vector containing all the D-Pad type gamepad recommended input diagram bitmaps. + std::vector m_DualAnalogDSDiagramBitmaps; //!< Vector containing all the DualShock type gamepad recommended input diagram bitmaps. + std::vector m_DualAnalogXBDiagramBitmaps; //!< Vector containing all the Xbox type gamepad recommended input diagram bitmaps. WizardManualConfigScreen m_WizardManualConfigScreen; //!< The manual input configuration menu screen. WizardPresetSelectScreen m_WizardPresetSelectScreen; //!< The preset selection menu screen. @@ -145,8 +147,8 @@ namespace RTE { /// /// GUI elements that compose the input mapping wizard menu screen. /// - GUICollectionBox *m_InputWizardScreenBox; - GUILabel *m_InputWizardTitleLabel; + GUICollectionBox* m_InputWizardScreenBox; + GUILabel* m_InputWizardTitleLabel; #pragma region Create Breakdown /// @@ -192,13 +194,13 @@ namespace RTE { /// Handles the player interaction with the SettingsInputMappingWizardGUI's WizardManualConfigScreen GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandleManualConfigScreenInputEvents(GUIEvent &guiEvent); + void HandleManualConfigScreenInputEvents(GUIEvent& guiEvent); /// /// Handles the player interaction with the SettingsInputMappingWizardGUI's WizardPresetSelectScreen GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandlePresetSelectScreenInputEvents(GUIEvent &guiEvent); + void HandlePresetSelectScreenInputEvents(GUIEvent& guiEvent); #pragma endregion #pragma region Input Configuration Sequence Handling Breakdown @@ -238,8 +240,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - SettingsInputMappingWizardGUI(const SettingsInputMappingWizardGUI &reference) = delete; - SettingsInputMappingWizardGUI & operator=(const SettingsInputMappingWizardGUI &rhs) = delete; + SettingsInputMappingWizardGUI(const SettingsInputMappingWizardGUI& reference) = delete; + SettingsInputMappingWizardGUI& operator=(const SettingsInputMappingWizardGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SettingsMiscGUI.cpp b/Source/Menus/SettingsMiscGUI.cpp index 8b3e43cc3..74185b656 100644 --- a/Source/Menus/SettingsMiscGUI.cpp +++ b/Source/Menus/SettingsMiscGUI.cpp @@ -11,50 +11,51 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsMiscGUI::SettingsMiscGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { - m_MiscSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxMiscSettings")); + SettingsMiscGUI::SettingsMiscGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { + m_MiscSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxMiscSettings")); - m_SkipIntroCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxSkipIntro")); + m_SkipIntroCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxSkipIntro")); m_SkipIntroCheckbox->SetCheck(g_SettingsMan.SkipIntro()); - m_ShowToolTipsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowToolTips")); + m_ShowToolTipsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowToolTips")); m_ShowToolTipsCheckbox->SetCheck(g_SettingsMan.ShowToolTips()); - m_ShowLoadingScreenProgressReportCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowLoadingScreenProgressReport")); + m_ShowLoadingScreenProgressReportCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowLoadingScreenProgressReport")); m_ShowLoadingScreenProgressReportCheckbox->SetCheck(!g_SettingsMan.GetLoadingScreenProgressReportDisabled()); - m_ShowAdvancedPerfStatsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowAdvancedPerfStats")); + m_ShowAdvancedPerfStatsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxShowAdvancedPerfStats")); m_ShowAdvancedPerfStatsCheckbox->SetCheck(g_PerformanceMan.AdvancedPerformanceStatsEnabled()); - m_MeasureLoadTimeCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMeasureLoadingTime")); + m_MeasureLoadTimeCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxMeasureLoadingTime")); m_MeasureLoadTimeCheckbox->SetCheck(g_SettingsMan.IsMeasuringModuleLoadTime()); - m_UseMonospaceConsoleFontCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxUseMonospaceConsoleFont")); + m_UseMonospaceConsoleFontCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxUseMonospaceConsoleFont")); m_UseMonospaceConsoleFontCheckbox->SetCheck(g_ConsoleMan.GetConsoleUseMonospaceFont()); - m_DisableFactionBuyMenuThemesCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxDisableFactionBuyMenuThemes")); + m_DisableFactionBuyMenuThemesCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxDisableFactionBuyMenuThemes")); m_DisableFactionBuyMenuThemesCheckbox->SetCheck(g_SettingsMan.FactionBuyMenuThemesDisabled()); - m_DisableFactionBuyMenuThemeCursorsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxDisableFactionBuyMenuThemeCursors")); + m_DisableFactionBuyMenuThemeCursorsCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxDisableFactionBuyMenuThemeCursors")); m_DisableFactionBuyMenuThemeCursorsCheckbox->SetCheck(g_SettingsMan.FactionBuyMenuThemeCursorsDisabled()); - m_SceneBackgroundAutoScaleLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneBackgroundAutoScaleSetting")); + m_SceneBackgroundAutoScaleLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelSceneBackgroundAutoScaleSetting")); UpdateSceneBackgroundAutoScaleLabel(); - m_SceneBackgroundAutoScaleSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderSceneBackgroundAutoScale")); + m_SceneBackgroundAutoScaleSlider = dynamic_cast(m_GUIControlManager->GetControl("SliderSceneBackgroundAutoScale")); m_SceneBackgroundAutoScaleSlider->SetValue(g_SettingsMan.GetSceneBackgroundAutoScaleMode()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsMiscGUI::SetEnabled(bool enable) const { m_MiscSettingsBox->SetVisible(enable); m_MiscSettingsBox->SetEnabled(enable); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsMiscGUI::UpdateSceneBackgroundAutoScaleLabel() { switch (g_SettingsMan.GetSceneBackgroundAutoScaleMode()) { @@ -70,9 +71,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsMiscGUI::HandleInputEvents(GUIEvent &guiEvent) { + void SettingsMiscGUI::HandleInputEvents(GUIEvent& guiEvent) { if (guiEvent.GetType() == GUIEvent::Notification) { if (guiEvent.GetControl() == m_SkipIntroCheckbox) { g_SettingsMan.SetSkipIntro(m_SkipIntroCheckbox->GetCheck()); @@ -96,4 +97,4 @@ namespace RTE { } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/SettingsMiscGUI.h b/Source/Menus/SettingsMiscGUI.h index f396db5a8..804c646e5 100644 --- a/Source/Menus/SettingsMiscGUI.h +++ b/Source/Menus/SettingsMiscGUI.h @@ -16,13 +16,12 @@ namespace RTE { class SettingsMiscGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsMiscGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this SettingsMiscGUI. Ownership is NOT transferred! - explicit SettingsMiscGUI(GUIControlManager *parentControlManager); + explicit SettingsMiscGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Concrete Methods @@ -36,27 +35,26 @@ namespace RTE { /// Handles the player interaction with the SettingsMiscGUI GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandleInputEvents(GUIEvent &guiEvent); + void HandleInputEvents(GUIEvent& guiEvent); #pragma endregion private: - - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. /// /// GUI elements that compose the misc settings menu screen. /// - GUICollectionBox *m_MiscSettingsBox; - GUICheckbox *m_SkipIntroCheckbox; - GUICheckbox *m_ShowToolTipsCheckbox; - GUICheckbox *m_ShowLoadingScreenProgressReportCheckbox; - GUICheckbox *m_ShowAdvancedPerfStatsCheckbox; - GUICheckbox *m_MeasureLoadTimeCheckbox; - GUICheckbox *m_UseMonospaceConsoleFontCheckbox; - GUICheckbox *m_DisableFactionBuyMenuThemesCheckbox; - GUICheckbox *m_DisableFactionBuyMenuThemeCursorsCheckbox; - GUILabel *m_SceneBackgroundAutoScaleLabel; - GUISlider *m_SceneBackgroundAutoScaleSlider; + GUICollectionBox* m_MiscSettingsBox; + GUICheckbox* m_SkipIntroCheckbox; + GUICheckbox* m_ShowToolTipsCheckbox; + GUICheckbox* m_ShowLoadingScreenProgressReportCheckbox; + GUICheckbox* m_ShowAdvancedPerfStatsCheckbox; + GUICheckbox* m_MeasureLoadTimeCheckbox; + GUICheckbox* m_UseMonospaceConsoleFontCheckbox; + GUICheckbox* m_DisableFactionBuyMenuThemesCheckbox; + GUICheckbox* m_DisableFactionBuyMenuThemeCursorsCheckbox; + GUILabel* m_SceneBackgroundAutoScaleLabel; + GUISlider* m_SceneBackgroundAutoScaleSlider; #pragma region Misc Settings Handling /// @@ -66,8 +64,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - SettingsMiscGUI(const SettingsMiscGUI &reference) = delete; - SettingsMiscGUI & operator=(const SettingsMiscGUI &rhs) = delete; + SettingsMiscGUI(const SettingsMiscGUI& reference) = delete; + SettingsMiscGUI& operator=(const SettingsMiscGUI& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/Menus/SettingsVideoGUI.cpp b/Source/Menus/SettingsVideoGUI.cpp index 6b9391c8a..902a5ef8a 100644 --- a/Source/Menus/SettingsVideoGUI.cpp +++ b/Source/Menus/SettingsVideoGUI.cpp @@ -26,48 +26,49 @@ namespace RTE { #if __cpp_lib_format >= 201907L return std::format("{}x{} ({:.1g}x Fullscreen scale)", Width, Height, Scale); #else - return std::to_string(Width) + "x" + std::to_string(Height); + return std::to_string(Width) + "x" + std::to_string(Height); #endif } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SettingsVideoGUI::SettingsVideoGUI(GUIControlManager *parentControlManager) : m_GUIControlManager(parentControlManager) { + SettingsVideoGUI::SettingsVideoGUI(GUIControlManager* parentControlManager) : + m_GUIControlManager(parentControlManager) { m_NewResX = g_WindowMan.GetResX(); m_NewResY = g_WindowMan.GetResY(); m_NewResMultiplier = g_WindowMan.GetResMultiplier(); m_NewFullscreen = g_WindowMan.IsFullscreen(); - m_VideoSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxVideoSettings")); + m_VideoSettingsBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxVideoSettings")); - m_ResolutionQuickToggleButtons[ResolutionQuickChangeType::Windowed] = dynamic_cast(m_GUIControlManager->GetControl("ButtonQuickWindowed")); - m_ResolutionQuickToggleButtons[ResolutionQuickChangeType::Fullscreen] = dynamic_cast(m_GUIControlManager->GetControl("ButtonQuickBorderless")); + m_ResolutionQuickToggleButtons[ResolutionQuickChangeType::Windowed] = dynamic_cast(m_GUIControlManager->GetControl("ButtonQuickWindowed")); + m_ResolutionQuickToggleButtons[ResolutionQuickChangeType::Fullscreen] = dynamic_cast(m_GUIControlManager->GetControl("ButtonQuickBorderless")); - m_TwoPlayerSplitscreenHSplitRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioSplitscreenHoriz")); - m_TwoPlayerSplitscreenVSplitRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioSplitscreenVert")); + m_TwoPlayerSplitscreenHSplitRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioSplitscreenHoriz")); + m_TwoPlayerSplitscreenVSplitRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioSplitscreenVert")); m_TwoPlayerSplitscreenVSplitRadioButton->SetCheck(g_FrameMan.GetTwoPlayerVSplit()); - m_EnableVSyncCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxEnableVSync")); + m_EnableVSyncCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxEnableVSync")); m_EnableVSyncCheckbox->SetCheck(g_WindowMan.GetVSyncEnabled()); - m_FullscreenCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxFullscreen")); + m_FullscreenCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxFullscreen")); m_FullscreenCheckbox->SetCheck(m_NewFullscreen); - m_UseMultiDisplaysCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxUseMultiDisplays")); + m_UseMultiDisplaysCheckbox = dynamic_cast(m_GUIControlManager->GetControl("CheckboxUseMultiDisplays")); m_UseMultiDisplaysCheckbox->SetCheck(g_WindowMan.GetUseMultiDisplays()); m_UseMultiDisplaysCheckbox->SetVisible(m_UseMultiDisplaysCheckbox->GetVisible() && SDL_GetNumVideoDisplays() > 1); - m_PresetResolutionRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioPresetResolution")); - m_CustomResolutionRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioCustomResolution")); + m_PresetResolutionRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioPresetResolution")); + m_CustomResolutionRadioButton = dynamic_cast(m_GUIControlManager->GetControl("RadioCustomResolution")); - m_ResolutionChangeDialogBox = dynamic_cast(m_GUIControlManager->GetControl("ResolutionChangeDialog")); + m_ResolutionChangeDialogBox = dynamic_cast(m_GUIControlManager->GetControl("ResolutionChangeDialog")); m_ResolutionChangeDialogBox->SetVisible(false); - const GUICollectionBox *settingsRootBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSettingsBase")); + const GUICollectionBox* settingsRootBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxSettingsBase")); m_ResolutionChangeDialogBox->SetPositionAbs(settingsRootBox->GetXPos() + ((settingsRootBox->GetWidth() - m_ResolutionChangeDialogBox->GetWidth()) / 2), settingsRootBox->GetYPos() + ((settingsRootBox->GetHeight() - m_ResolutionChangeDialogBox->GetHeight()) / 2)); - m_ResolutionChangeConfirmButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfirmResolutionChange")); - m_ResolutionChangeCancelButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCancelResolutionChange")); + m_ResolutionChangeConfirmButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonConfirmResolutionChange")); + m_ResolutionChangeCancelButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonCancelResolutionChange")); CreatePresetResolutionBox(); CreateCustomResolutionBox(); @@ -82,37 +83,37 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::CreatePresetResolutionBox() { - m_PresetResolutionBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionPresetResolution")); - m_PresetResolutionComboBox = dynamic_cast(m_GUIControlManager->GetControl("ComboPresetResolution")); - m_PresetResolutionApplyButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonApplyPresetResolution")); - m_PresetResolutionMessageLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelPresetResolutonValidation")); + m_PresetResolutionBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionPresetResolution")); + m_PresetResolutionComboBox = dynamic_cast(m_GUIControlManager->GetControl("ComboPresetResolution")); + m_PresetResolutionApplyButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonApplyPresetResolution")); + m_PresetResolutionMessageLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelPresetResolutonValidation")); m_PresetResolutionMessageLabel->SetVisible(false); PopulateResolutionsComboBox(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::CreateCustomResolutionBox() { - m_CustomResolutionBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionCustomResolution")); + m_CustomResolutionBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionCustomResolution")); m_CustomResolutionBox->SetVisible(false); - m_CustomResolutionWidthTextBox = dynamic_cast(m_GUIControlManager->GetControl("TextboxCustomWidth")); + m_CustomResolutionWidthTextBox = dynamic_cast(m_GUIControlManager->GetControl("TextboxCustomWidth")); m_CustomResolutionWidthTextBox->SetNumericOnly(true); m_CustomResolutionWidthTextBox->SetMaxNumericValue(g_WindowMan.GetMaxResX()); m_CustomResolutionWidthTextBox->SetMaxTextLength(4); m_CustomResolutionWidthTextBox->SetText(std::to_string(static_cast(g_WindowMan.GetResX()))); - m_CustomResolutionHeightTextBox = dynamic_cast(m_GUIControlManager->GetControl("TextboxCustomHeight")); + m_CustomResolutionHeightTextBox = dynamic_cast(m_GUIControlManager->GetControl("TextboxCustomHeight")); m_CustomResolutionHeightTextBox->SetNumericOnly(true); m_CustomResolutionHeightTextBox->SetMaxNumericValue(g_WindowMan.GetMaxResY()); m_CustomResolutionHeightTextBox->SetMaxTextLength(4); m_CustomResolutionHeightTextBox->SetText(std::to_string(static_cast(g_WindowMan.GetResY()))); - m_CustomResolutionMultiplierComboBox = dynamic_cast(m_GUIControlManager->GetControl("ComboboxResolutionMultiplier")); + m_CustomResolutionMultiplierComboBox = dynamic_cast(m_GUIControlManager->GetControl("ComboboxResolutionMultiplier")); PopulateResMultplierComboBox(); #if __cpp_lib_format >= 201907L m_CustomResolutionMultiplierComboBox->SetText(std::format("{:.3g}x", m_NewResMultiplier)); @@ -120,12 +121,12 @@ namespace RTE { m_CustomResolutionMultiplierComboBox->SetText(std::to_string(m_NewResMultiplier)); #endif - m_CustomResolutionApplyButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonApplyCustomResolution")); - m_CustomResolutionMessageLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelCustomResolutionValidation")); + m_CustomResolutionApplyButton = dynamic_cast(m_GUIControlManager->GetControl("ButtonApplyCustomResolution")); + m_CustomResolutionMessageLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelCustomResolutionValidation")); m_CustomResolutionMessageLabel->SetVisible(false); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::SetEnabled(bool enable) const { m_VideoSettingsBox->SetVisible(enable); @@ -146,13 +147,13 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GUICollectionBox * SettingsVideoGUI::GetActiveDialogBox() const { + GUICollectionBox* SettingsVideoGUI::GetActiveDialogBox() const { return (m_ResolutionChangeDialogBox->GetEnabled() && m_ResolutionChangeDialogBox->GetVisible()) ? m_ResolutionChangeDialogBox : nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::CloseActiveDialogBox() const { if (m_ResolutionChangeDialogBox->GetEnabled() && m_ResolutionChangeDialogBox->GetVisible()) { @@ -161,7 +162,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SettingsVideoGUI::IsSupportedResolution(int width, int height) const { if ((width >= c_MinResX && height >= c_MinResY) && (width <= g_WindowMan.GetMaxResX() && height <= g_WindowMan.GetMaxResY())) { @@ -170,7 +171,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::PopulateResolutionsComboBox() { m_PresetResolutions.clear(); @@ -195,7 +196,7 @@ namespace RTE { float defaultScale = std::min(std::round(g_WindowMan.GetMaxResX() / static_cast(c_DefaultResX)), std::round(g_WindowMan.GetMaxResY() / static_cast(c_DefaultResY))); for (int i = 0; i < m_PresetResolutions.size(); ++i) { - const PresetResolutionRecord &resRecord = m_PresetResolutions[i]; + const PresetResolutionRecord& resRecord = m_PresetResolutions[i]; m_PresetResolutionComboBox->AddItem(resRecord.GetDisplayString()); if (m_PresetResolutionComboBox->GetSelectedIndex() < 0 && (glm::epsilonEqual(resRecord.Scale, defaultScale, 0.5f))) { m_PresetResolutionComboBox->SetSelectedIndex(i); @@ -220,7 +221,7 @@ namespace RTE { m_CustomResolutionMultiplierComboBox->SetSelectedIndex(0); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::UpdateCustomResolutionLimits() { g_WindowMan.MapDisplays(); @@ -238,7 +239,7 @@ namespace RTE { m_CustomResolutionHeightTextBox->SetText(std::to_string(newMaxResY)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::ApplyNewResolution(bool displaysWereMapped) { bool needWarning = (g_WindowMan.GetResX() != m_NewResX) && (g_WindowMan.GetResY() != m_NewResY); @@ -257,7 +258,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::ApplyQuickChangeResolution(ResolutionQuickChangeType resolutionChangeType) { g_WindowMan.MapDisplays(); @@ -297,7 +298,7 @@ namespace RTE { ApplyNewResolution(true); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::ApplyPresetResolution() { int presetResListEntryID = m_PresetResolutionComboBox->GetSelectedIndex(); @@ -317,7 +318,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SettingsVideoGUI::ApplyCustomResolution() { m_CustomResolutionMessageLabel->SetVisible(false); @@ -349,7 +350,6 @@ namespace RTE { m_CustomResolutionHeightTextBox->SetText(std::to_string(m_NewResY)); } - bool invalidResolution = false; if (m_NewResX < c_MinResX || m_NewResY < c_MinResY) { m_CustomResolutionMessageLabel->SetText("Resolution width or height lower than the minimum (" + std::to_string(c_MinResX) + "x" + std::to_string(c_MinResY) + ") is not supported."); @@ -366,9 +366,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SettingsVideoGUI::HandleInputEvents(GUIEvent &guiEvent) { + void SettingsVideoGUI::HandleInputEvents(GUIEvent& guiEvent) { if (guiEvent.GetType() == GUIEvent::Command) { if (guiEvent.GetMsg() == GUIButton::Pushed) { if (guiEvent.GetControl() == m_ResolutionQuickToggleButtons[ResolutionQuickChangeType::Windowed]) { @@ -447,4 +447,4 @@ namespace RTE { } } } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/SettingsVideoGUI.h b/Source/Menus/SettingsVideoGUI.h index fe2967d2b..599ebd55d 100644 --- a/Source/Menus/SettingsVideoGUI.h +++ b/Source/Menus/SettingsVideoGUI.h @@ -19,13 +19,12 @@ namespace RTE { class SettingsVideoGUI { public: - #pragma region Creation /// /// Constructor method used to instantiate a SettingsVideoGUI object in system memory and make it ready for use. /// /// Pointer to the parent GUIControlManager which owns all the GUIControls of this SettingsVideoGUI. Ownership is NOT transferred! - explicit SettingsVideoGUI(GUIControlManager *parentControlManager); + explicit SettingsVideoGUI(GUIControlManager* parentControlManager); #pragma endregion #pragma region Getters and Setters @@ -39,7 +38,7 @@ namespace RTE { /// Gets the currently active GUICollectionBox that acts as a dialog box and requires disabling navigation and drawing an overlay. /// /// Pointer to the GUICollectionBox that is the currently active dialog box, if any. Ownership is NOT transferred! - GUICollectionBox * GetActiveDialogBox() const; + GUICollectionBox* GetActiveDialogBox() const; /// /// Closes the currently active GUICollectionBox that acts as a dialog box by hiding it. If the active dialog box is a sub-menu, disables it. @@ -52,11 +51,10 @@ namespace RTE { /// Handles the player interaction with the SettingsVideoGUI GUI elements. /// /// The GUIEvent containing information about the player interaction with an element. - void HandleInputEvents(GUIEvent &guiEvent); + void HandleInputEvents(GUIEvent& guiEvent); #pragma endregion private: - /// /// Enumeration for the different types of quick resolution change options. /// @@ -81,7 +79,8 @@ namespace RTE { /// Resolution width. /// Resolution height. /// Whether resolution is upscaled. - PresetResolutionRecord(int width, int height, float scale) : Width(width), Height(height), Scale(scale) {} + PresetResolutionRecord(int width, int height, float scale) : + Width(width), Height(height), Scale(scale) {} /// /// Makes UI displayable string with resolution info. @@ -94,7 +93,7 @@ namespace RTE { /// /// The PresetResolutionRecord to compare with. /// Bool with the result of the comparison. - bool operator<(const PresetResolutionRecord &rhs) const { + bool operator<(const PresetResolutionRecord& rhs) const { if (Width == rhs.Width && Height == rhs.Height) { return Scale > rhs.Scale; } else if (Width == rhs.Width) { @@ -104,40 +103,40 @@ namespace RTE { } }; - GUIControlManager *m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. + GUIControlManager* m_GUIControlManager; //!< The GUIControlManager which holds all the GUIControls of this menu. Not owned by this. std::vector m_PresetResolutions; //!< Contains PresetResolutionRecords for all the supported preset resolutions. int m_NewResX; //!< The new resolution width to use when changing resolution. int m_NewResY; //!< The new resolution height to use when changing resolution. float m_NewResMultiplier; //!< How much the new resolution should be upscaled when changing resolution. - bool m_NewFullscreen; //!< Whether the game will be windowed or fullscreen. + bool m_NewFullscreen; //!< Whether the game will be windowed or fullscreen. /// /// GUI elements that compose the video settings menu screen. /// - GUICollectionBox *m_VideoSettingsBox; - GUIRadioButton *m_TwoPlayerSplitscreenHSplitRadioButton; - GUIRadioButton *m_TwoPlayerSplitscreenVSplitRadioButton; - GUICheckbox *m_EnableVSyncCheckbox; - GUICheckbox *m_FullscreenCheckbox; - GUICheckbox *m_UseMultiDisplaysCheckbox; - GUIRadioButton *m_PresetResolutionRadioButton; - GUIRadioButton *m_CustomResolutionRadioButton; - GUICollectionBox *m_PresetResolutionBox; - GUIComboBox *m_PresetResolutionComboBox; - GUIButton *m_PresetResolutionApplyButton; - GUILabel *m_PresetResolutionMessageLabel; - GUICollectionBox *m_CustomResolutionBox; - GUITextBox *m_CustomResolutionWidthTextBox; - GUITextBox *m_CustomResolutionHeightTextBox; - GUIComboBox *m_CustomResolutionMultiplierComboBox; - GUILabel *m_CustomResolutionMessageLabel; - GUIButton *m_CustomResolutionApplyButton; - GUICollectionBox *m_ResolutionChangeDialogBox; - GUIButton *m_ResolutionChangeConfirmButton; - GUIButton *m_ResolutionChangeCancelButton; - std::array m_ResolutionQuickToggleButtons; + GUICollectionBox* m_VideoSettingsBox; + GUIRadioButton* m_TwoPlayerSplitscreenHSplitRadioButton; + GUIRadioButton* m_TwoPlayerSplitscreenVSplitRadioButton; + GUICheckbox* m_EnableVSyncCheckbox; + GUICheckbox* m_FullscreenCheckbox; + GUICheckbox* m_UseMultiDisplaysCheckbox; + GUIRadioButton* m_PresetResolutionRadioButton; + GUIRadioButton* m_CustomResolutionRadioButton; + GUICollectionBox* m_PresetResolutionBox; + GUIComboBox* m_PresetResolutionComboBox; + GUIButton* m_PresetResolutionApplyButton; + GUILabel* m_PresetResolutionMessageLabel; + GUICollectionBox* m_CustomResolutionBox; + GUITextBox* m_CustomResolutionWidthTextBox; + GUITextBox* m_CustomResolutionHeightTextBox; + GUIComboBox* m_CustomResolutionMultiplierComboBox; + GUILabel* m_CustomResolutionMessageLabel; + GUIButton* m_CustomResolutionApplyButton; + GUICollectionBox* m_ResolutionChangeDialogBox; + GUIButton* m_ResolutionChangeConfirmButton; + GUIButton* m_ResolutionChangeCancelButton; + std::array m_ResolutionQuickToggleButtons; #pragma region Create Breakdown /// @@ -199,8 +198,8 @@ namespace RTE { #pragma endregion // Disallow the use of some implicit methods. - SettingsVideoGUI(const SettingsVideoGUI &reference) = delete; - SettingsVideoGUI & operator=(const SettingsVideoGUI &rhs) = delete; + SettingsVideoGUI(const SettingsVideoGUI& reference) = delete; + SettingsVideoGUI& operator=(const SettingsVideoGUI& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/Menus/TitleScreen.cpp b/Source/Menus/TitleScreen.cpp index c9145b503..aabb0042a 100644 --- a/Source/Menus/TitleScreen.cpp +++ b/Source/Menus/TitleScreen.cpp @@ -12,7 +12,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::Clear() { m_FadeAmount = 0; @@ -68,9 +68,9 @@ namespace RTE { m_IntroSlides.fill(nullptr); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TitleScreen::Create(AllegroScreen *guiScreen) { + void TitleScreen::Create(AllegroScreen* guiScreen) { m_TitleScreenMaxWidth = g_WindowMan.FullyCoversAllDisplays() ? g_WindowMan.GetPrimaryWindowDisplayWidth() / g_WindowMan.GetResMultiplier() : g_WindowMan.GetResX(); CreateTitleElements(); @@ -94,7 +94,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::CreateTitleElements() { m_DataRealmsLogo = ContentFile("Base.rte/GUIs/Title/Intro/DRLogo5x.png").GetAsBitmap(); @@ -115,13 +115,13 @@ namespace RTE { m_Nebula.SetScrollRatio(Vector(-1.0F, 1.0F / 3.0F)); int starSmallBitmapCount = 4; - std::vector starSmallBitmaps = ContentFile("Base.rte/GUIs/Title/Stars/StarSmall.png").GetAsAnimation(starSmallBitmapCount); + std::vector starSmallBitmaps = ContentFile("Base.rte/GUIs/Title/Stars/StarSmall.png").GetAsAnimation(starSmallBitmapCount); int starLargeBitmapCount = 1; - std::vector starLargeBitmaps = ContentFile("Base.rte/GUIs/Title/Stars/StarLarge.png").GetAsAnimation(starLargeBitmapCount); + std::vector starLargeBitmaps = ContentFile("Base.rte/GUIs/Title/Stars/StarLarge.png").GetAsAnimation(starLargeBitmapCount); int starHugeBitmapCount = 2; - std::vector starHugeBitmaps = ContentFile("Base.rte/GUIs/Title/Stars/StarHuge.png").GetAsAnimation(starHugeBitmapCount); + std::vector starHugeBitmaps = ContentFile("Base.rte/GUIs/Title/Stars/StarHuge.png").GetAsAnimation(starHugeBitmapCount); int starCount = (g_WindowMan.GetResX() * m_Nebula.GetBitmap()->h) / 1000; for (int i = 0; i < starCount; ++i) { @@ -145,7 +145,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::CreateIntroSequenceSlides() { std::string highRes = (g_WindowMan.GetResY() >= 680) ? "HD" : ""; @@ -154,15 +154,19 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::Update() { - if (m_SectionSwitch) { m_SectionTimer.Reset(); } + if (m_SectionSwitch) { + m_SectionTimer.Reset(); + } m_SectionElapsedTime = static_cast(m_SectionTimer.GetElapsedRealTimeS()); m_SectionProgress = std::min((m_SectionDuration > 0) ? m_SectionElapsedTime / m_SectionDuration : 0, 0.9999F); // Checking for 0.999 instead of 0.9999 or 1.0 here otherwise there is a hiccup between ending and starting a new orbit cycle. - if (m_StationOrbitProgress >= 0.999F) { m_StationOrbitTimer.Reset(); } + if (m_StationOrbitProgress >= 0.999F) { + m_StationOrbitTimer.Reset(); + } m_StationOrbitProgress = std::clamp(static_cast(m_StationOrbitTimer.GetElapsedRealTimeS()) / 60.0F, 0.0F, 0.9999F); m_StationOrbitRotation = LERP(0, 1.0F, c_PI, -c_PI, m_StationOrbitProgress); @@ -181,7 +185,9 @@ namespace RTE { m_ScrollOffset.SetY(LERP(0, 1.0F, m_IntroScrollStartOffsetY, m_GameLogoAppearScrollOffsetY, introScrollProgress)); UpdateIntroSlideshowSequence(g_UInputMan.AnyStartPress()); } else if (m_IntroSequenceState >= IntroSequence::GameLogoAppear && m_IntroSequenceState <= IntroSequence::MainMenuAppear) { - if (m_IntroSequenceState < IntroSequence::PreMainMenu) { m_ScrollOffset.SetY(EaseOut(m_GameLogoAppearScrollOffsetY, m_PreMainMenuScrollOffsetY, introScrollProgress)); } + if (m_IntroSequenceState < IntroSequence::PreMainMenu) { + m_ScrollOffset.SetY(EaseOut(m_GameLogoAppearScrollOffsetY, m_PreMainMenuScrollOffsetY, introScrollProgress)); + } UpdateIntroPreMainMenuSequence(); } if (m_SectionElapsedTime >= m_SectionDuration) { @@ -194,7 +200,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::UpdateIntroLogoSequence(bool skipSection) { if (skipSection && m_IntroSequenceState != IntroSequence::FmodLogoFadeOut) { @@ -218,21 +224,31 @@ namespace RTE { m_FadeAmount = static_cast(LERP(0, 1.0F, 255.0F, 0, m_SectionProgress)); break; case IntroSequence::DataRealmsLogoDisplay: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(2.0F); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(2.0F); + } break; case IntroSequence::DataRealmsLogoFadeOut: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(0.25F); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(0.25F); + } m_FadeAmount = static_cast(LERP(0, 1.0F, 0, 255.0F, m_SectionProgress)); break; case IntroSequence::FmodLogoFadeIn: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(0.25F); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(0.25F); + } m_FadeAmount = static_cast(LERP(0, 1.0F, 255.0F, 0, m_SectionProgress)); break; case IntroSequence::FmodLogoDisplay: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(2.0F); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(2.0F); + } break; case IntroSequence::FmodLogoFadeOut: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(0.5F); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(0.5F); + } m_FadeAmount = static_cast(LERP(0, 1.0F, 0, 255.0F, m_SectionProgress)); break; default: @@ -240,7 +256,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::UpdateIntroSlideshowSequence(bool skipSlideshow) { if (skipSlideshow && (m_IntroSequenceState > IntroSequence::SlideshowFadeIn && m_IntroSequenceState != IntroSequence::MainMenuAppear)) { @@ -267,7 +283,9 @@ namespace RTE { m_FadeAmount = static_cast(LERP(0, 1.0F, 255.0F, 0, m_SectionProgress)); break; case IntroSequence::PreSlideshowPause: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(3.2F - static_cast(m_IntroSongTimer.GetElapsedRealTimeS())); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(3.2F - static_cast(m_IntroSongTimer.GetElapsedRealTimeS())); + } break; case IntroSequence::ShowSlide1: if (m_SectionSwitch) { @@ -275,7 +293,9 @@ namespace RTE { m_SlideFadeInDuration = 2.0F; m_SlideFadeOutDuration = 0.5F; } - if (m_SectionElapsedTime > 1.25F) { m_SlideshowSlideText = "At the end of humanity's darkest century..."; } + if (m_SectionElapsedTime > 1.25F) { + m_SlideshowSlideText = "At the end of humanity's darkest century..."; + } break; case IntroSequence::ShowSlide2: if (m_SectionSwitch) { @@ -283,7 +303,9 @@ namespace RTE { m_SlideFadeInDuration = 0.5F; m_SlideFadeOutDuration = 2.5F; } - if (m_SectionElapsedTime < m_SectionDuration - 1.75F) { m_SlideshowSlideText = "...a curious symbiosis between man and machine emerged."; } + if (m_SectionElapsedTime < m_SectionDuration - 1.75F) { + m_SlideshowSlideText = "...a curious symbiosis between man and machine emerged."; + } break; case IntroSequence::ShowSlide3: if (m_SectionSwitch) { @@ -354,7 +376,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::UpdateIntroPreMainMenuSequence() { switch (m_IntroSequenceState) { @@ -373,7 +395,9 @@ namespace RTE { SetSectionDurationAndResetSwitch(92.4F - static_cast(m_IntroSongTimer.GetElapsedRealTimeS())); clear_to_color(g_FrameMan.GetOverlayBitmap32(), 0); } - if (m_SectionProgress > 0.5F) { m_GameLogo.SetPos(Vector(static_cast(m_TitleScreenMaxWidth / 2), EaseIn((static_cast(g_WindowMan.GetResY() / 2)) - 20, 120, (m_SectionProgress - 0.5F) / 0.5F))); } + if (m_SectionProgress > 0.5F) { + m_GameLogo.SetPos(Vector(static_cast(m_TitleScreenMaxWidth / 2), EaseIn((static_cast(g_WindowMan.GetResY() / 2)) - 20, 120, (m_SectionProgress - 0.5F) / 0.5F))); + } break; case IntroSequence::PreMainMenu: if (m_SectionSwitch) { @@ -399,7 +423,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::UpdateTitleTransitions() { static const float endDelay = 0.2F * g_SettingsMan.GetMenuTransitionDurationMultiplier(); @@ -428,7 +452,9 @@ namespace RTE { } m_ScrollOffset.SetY(EaseOut(0, m_PlanetViewScrollOffsetY, m_SectionProgress)); m_GameLogo.SetPos(Vector(static_cast(m_TitleScreenMaxWidth / 2), EaseOut(m_GameLogoMainMenuOffsetY, m_GameLogoPlanetViewOffsetY, m_SectionProgress))); - if (m_SectionElapsedTime >= m_SectionDuration) { SetTitleTransitionState((m_TitleTransitionState == TitleTransition::MainMenuToScenario) ? TitleTransition::ScenarioMenu : TitleTransition::MetaGameMenu); } + if (m_SectionElapsedTime >= m_SectionDuration) { + SetTitleTransitionState((m_TitleTransitionState == TitleTransition::MainMenuToScenario) ? TitleTransition::ScenarioMenu : TitleTransition::MetaGameMenu); + } break; case TitleTransition::PlanetToMainMenu: if (m_SectionSwitch) { @@ -437,18 +463,26 @@ namespace RTE { } m_ScrollOffset.SetY(EaseOut(m_PlanetViewScrollOffsetY, 0, m_SectionProgress)); m_GameLogo.SetPos(Vector(static_cast(m_TitleScreenMaxWidth / 2), EaseOut(m_GameLogoPlanetViewOffsetY, m_GameLogoMainMenuOffsetY, m_SectionProgress))); - if (m_SectionElapsedTime >= m_SectionDuration) { SetTitleTransitionState(TitleTransition::MainMenu); } + if (m_SectionElapsedTime >= m_SectionDuration) { + SetTitleTransitionState(TitleTransition::MainMenu); + } break; case TitleTransition::MainMenuToCredits: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(1.0F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(1.0F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); + } m_ScrollOffset.SetY(EaseOut(0, m_PlanetViewScrollOffsetY, m_SectionProgress)); m_FadeAmount = static_cast(EaseOut(0, 128.0F, m_SectionProgress)); break; case TitleTransition::CreditsToMainMenu: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(1.0F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(1.0F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); + } m_ScrollOffset.SetY(EaseOut(m_PlanetViewScrollOffsetY, 0, m_SectionProgress)); m_FadeAmount = static_cast(EaseOut(128.0F, 0, m_SectionProgress)); - if (m_SectionElapsedTime >= m_SectionDuration) { SetTitleTransitionState(TitleTransition::MainMenu); } + if (m_SectionElapsedTime >= m_SectionDuration) { + SetTitleTransitionState(TitleTransition::MainMenu); + } break; case TitleTransition::ScenarioFadeIn: case TitleTransition::MetaGameFadeIn: @@ -461,13 +495,19 @@ namespace RTE { } g_AudioMan.SetTempMusicVolume(EaseOut(0, 1.0F, m_SectionProgress)); m_FadeAmount = static_cast(LERP(0, 1.0F, 255.0F, 0, m_SectionProgress)); - if (m_SectionElapsedTime >= m_SectionDuration) { SetTitleTransitionState((m_TitleTransitionState == TitleTransition::ScenarioFadeIn) ? TitleTransition::ScenarioMenu : TitleTransition::MetaGameMenu); } + if (m_SectionElapsedTime >= m_SectionDuration) { + SetTitleTransitionState((m_TitleTransitionState == TitleTransition::ScenarioFadeIn) ? TitleTransition::ScenarioMenu : TitleTransition::MetaGameMenu); + } break; case TitleTransition::FadeOut: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(0.75F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(0.75F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); + } g_AudioMan.SetTempMusicVolume(EaseIn(1.0F, 0, m_SectionProgress)); m_FadeAmount = static_cast(EaseIn(0, 255, m_SectionProgress)); - if (m_SectionElapsedTime >= (m_SectionDuration + endDelay)) { SetTitleTransitionState(TitleTransition::TransitionEnd); } + if (m_SectionElapsedTime >= (m_SectionDuration + endDelay)) { + SetTitleTransitionState(TitleTransition::TransitionEnd); + } break; case TitleTransition::ScrollingFadeIn: if (m_SectionSwitch) { @@ -479,16 +519,22 @@ namespace RTE { m_ScrollOffset.SetY(EaseOut(250, 0, m_SectionProgress)); m_GameLogo.SetPos(Vector(static_cast(m_TitleScreenMaxWidth / 2), EaseOut(m_GameLogoPlanetViewOffsetY, m_GameLogoMainMenuOffsetY, m_SectionProgress))); m_FadeAmount = static_cast(EaseOut(255, 0, m_SectionProgress)); - if (m_SectionElapsedTime >= m_SectionDuration) { SetTitleTransitionState(TitleTransition::MainMenu); } + if (m_SectionElapsedTime >= m_SectionDuration) { + SetTitleTransitionState(TitleTransition::MainMenu); + } break; case TitleTransition::ScrollingFadeOut: case TitleTransition::ScrollingFadeOutQuit: - if (m_SectionSwitch) { SetSectionDurationAndResetSwitch(0.75F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); } + if (m_SectionSwitch) { + SetSectionDurationAndResetSwitch(0.75F * g_SettingsMan.GetMenuTransitionDurationMultiplier()); + } g_AudioMan.SetTempMusicVolume(EaseIn(1.0F, 0, m_SectionProgress)); m_ScrollOffset.SetY(EaseIn(0, 250, m_SectionProgress)); m_GameLogo.SetPos(Vector(static_cast(m_TitleScreenMaxWidth / 2), EaseIn(m_GameLogoMainMenuOffsetY, m_GameLogoPlanetViewOffsetY, m_SectionProgress))); m_FadeAmount = static_cast(EaseIn(0, 255, m_SectionProgress)); - if (m_SectionElapsedTime >= (m_SectionDuration + endDelay)) { SetTitleTransitionState((m_TitleTransitionState == TitleTransition::ScrollingFadeOutQuit) ? TitleTransition::TransitionEndQuit : TitleTransition::TransitionEnd); } + if (m_SectionElapsedTime >= (m_SectionDuration + endDelay)) { + SetTitleTransitionState((m_TitleTransitionState == TitleTransition::ScrollingFadeOutQuit) ? TitleTransition::TransitionEndQuit : TitleTransition::TransitionEnd); + } break; case TitleTransition::TransitionEnd: if (m_SectionSwitch) { @@ -501,12 +547,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::Draw() { if (!m_FinishedPlayingIntro) { - if (m_IntroSequenceState >= IntroSequence::SlideshowFadeIn) { DrawTitleScreenScene(); } - if (m_IntroSequenceState >= IntroSequence::GameLogoAppear) { DrawGameLogo(); } + if (m_IntroSequenceState >= IntroSequence::SlideshowFadeIn) { + DrawTitleScreenScene(); + } + if (m_IntroSequenceState >= IntroSequence::GameLogoAppear) { + DrawGameLogo(); + } if (m_IntroSequenceState >= IntroSequence::DataRealmsLogoFadeIn && m_IntroSequenceState <= IntroSequence::DataRealmsLogoFadeOut) { draw_sprite(g_FrameMan.GetBackBuffer32(), m_DataRealmsLogo, (m_TitleScreenMaxWidth - m_DataRealmsLogo->w) / 2, (g_WindowMan.GetResY() - m_DataRealmsLogo->h) / 2); @@ -531,28 +581,32 @@ namespace RTE { // In credits have to draw the overlay before the game logo otherwise drawing the game logo again on top of an existing one causes the glow effect to look wonky. if (m_TitleTransitionState == TitleTransition::MainMenuToCredits || m_TitleTransitionState == TitleTransition::CreditsToMainMenu) { - if (m_FadeAmount > 0) { DrawOverlayEffectBitmap(); } + if (m_FadeAmount > 0) { + DrawOverlayEffectBitmap(); + } DrawGameLogo(); return; } DrawGameLogo(); } - if (m_FadeAmount > 0) { DrawOverlayEffectBitmap(); } + if (m_FadeAmount > 0) { + DrawOverlayEffectBitmap(); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::DrawTitleScreenScene() { // This only needs to be done once, but bitmaps can be reloaded which effectively undoes this, so just do it all the time to not deal with flags and checks. set_write_alpha_blender(); draw_trans_sprite(m_Planet.GetSpriteFrame(0), ContentFile("Base.rte/GUIs/Title/PlanetAlpha.png").GetAsBitmap(), 0, 0); draw_trans_sprite(m_Moon.GetSpriteFrame(0), ContentFile("Base.rte/GUIs/Title/MoonAlpha.png").GetAsBitmap(), 0, 0); - + Box nebulaTargetBox; m_Nebula.SetOffset(Vector(static_cast((m_TitleScreenMaxWidth - m_Nebula.GetBitmap()->w) / 2), m_ScrollOffset.GetY())); m_Nebula.Draw(g_FrameMan.GetBackBuffer32(), nebulaTargetBox, true); - for (const Star &star : m_BackdropStars) { + for (const Star& star: m_BackdropStars) { int intensity = star.Intensity + RandomNum(0, (star.Size == Star::StarSize::StarSmall) ? 35 : 70); set_screen_blender(intensity, intensity, intensity, intensity); int starPosY = static_cast(star.Position.GetY() - (m_ScrollOffset.GetY() * (m_Nebula.GetScrollRatio().GetY() * ((star.Size == Star::StarSize::StarSmall) ? 0.8F : 1.0F)))); @@ -572,7 +626,7 @@ namespace RTE { m_Station.Draw(g_FrameMan.GetBackBuffer32()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::DrawGameLogo() { m_GameLogo.Draw(g_FrameMan.GetBackBuffer32()); @@ -582,7 +636,7 @@ namespace RTE { m_GameLogoGlow.Draw(g_FrameMan.GetBackBuffer32(), Vector(), DrawMode::g_DrawTrans); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::DrawSlideshowSlide() { int slide = static_cast(m_IntroSequenceState) - static_cast(IntroSequence::ShowSlide1); @@ -614,10 +668,10 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TitleScreen::DrawOverlayEffectBitmap() const { set_trans_blender(m_FadeAmount, m_FadeAmount, m_FadeAmount, m_FadeAmount); draw_trans_sprite(g_FrameMan.GetBackBuffer32(), g_FrameMan.GetOverlayBitmap32(), 0, 0); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/Menus/TitleScreen.h b/Source/Menus/TitleScreen.h index caca20ca7..a56501805 100644 --- a/Source/Menus/TitleScreen.h +++ b/Source/Menus/TitleScreen.h @@ -18,7 +18,6 @@ namespace RTE { class TitleScreen { public: - /// /// Enumeration for the different transition (scrolling) states of the title screen. /// @@ -48,13 +47,16 @@ namespace RTE { /// Constructor method used to instantiate a TitleScreen object in system memory and make it ready for use. /// /// Pointer to a GUIScreen interface that will be used to create this TitleScreen's GUIFont. Ownership is NOT transferred! - explicit TitleScreen(AllegroScreen *guiScreen) { Clear(); Create(guiScreen); } + explicit TitleScreen(AllegroScreen* guiScreen) { + Clear(); + Create(guiScreen); + } /// /// Makes the TitleScreen object ready for use. /// /// Pointer to a GUIScreen interface that will be used to create this TitleScreen's GUIFont. Ownership is NOT transferred! - void Create(AllegroScreen *guiScreen); + void Create(AllegroScreen* guiScreen); #pragma endregion #pragma region Getters and Setters @@ -68,13 +70,22 @@ namespace RTE { /// Sets the target title transition state and, if different from the current, sets the section switch to trigger the transition. /// /// The target title transition state. - void SetTitleTransitionState(TitleTransition newTransitionState) { if (newTransitionState != m_TitleTransitionState) { m_TitleTransitionState = newTransitionState; m_SectionSwitch = true; } } + void SetTitleTransitionState(TitleTransition newTransitionState) { + if (newTransitionState != m_TitleTransitionState) { + m_TitleTransitionState = newTransitionState; + m_SectionSwitch = true; + } + } /// /// Sets the title transition to a pending state, stores the orbit timer elapsed time and resets the fade screen blend value. /// This is used to correctly restart transition states after breaking out of the game loop back to the menu loop. /// - void SetTitlePendingTransition() { m_TitleTransitionState = TitleTransition::TransitionPending; m_StationOrbitTimerElapsedTime = static_cast(m_StationOrbitTimer.GetElapsedRealTimeS()); m_FadeAmount = 0; } + void SetTitlePendingTransition() { + m_TitleTransitionState = TitleTransition::TransitionPending; + m_StationOrbitTimerElapsedTime = static_cast(m_StationOrbitTimer.GetElapsedRealTimeS()); + m_FadeAmount = 0; + } /// /// Gets the position of the planet on the title screen scene. @@ -108,7 +119,6 @@ namespace RTE { #pragma endregion private: - /// /// Enumeration for the different states of the intro sequence. /// @@ -143,10 +153,14 @@ namespace RTE { /// /// Enumeration for the different Star sizes. /// - enum class StarSize { StarSmall, StarLarge, StarHuge }; + enum class StarSize { + StarSmall, + StarLarge, + StarHuge + }; StarSize Size; //!< The size of the Star. Used for the appropriate Bitmap selection and Intensity randomization when drawing. - BITMAP *Bitmap; //!< The bitmap to draw, not owned by this. Not Owned. + BITMAP* Bitmap; //!< The bitmap to draw, not owned by this. Not Owned. int Intensity; //!< Intensity value on a scale from 0 to 255. Vector Position; //!< The position of the Star on the title screen scene backdrop. }; @@ -196,11 +210,11 @@ namespace RTE { float m_SlideFadeOutDuration; //!< How many seconds the duration of a slideshow slide fade out is supposed to elapse. std::unique_ptr m_IntroTextFont; //!< The GUIFont used for drawing text during the logo splash screens and slideshow. std::string m_SlideshowSlideText; //!< String containing the slide text during each section of the slideshow. - BITMAP *m_DataRealmsLogo; //!< The DataRealms logo bitmap used in the logo splash screen. Not Owned. - BITMAP *m_FmodLogo; //!< The Fmod logo bitmap used in the logo splash screen. Not Owned. + BITMAP* m_DataRealmsLogo; //!< The DataRealms logo bitmap used in the logo splash screen. Not Owned. + BITMAP* m_FmodLogo; //!< The Fmod logo bitmap used in the logo splash screen. Not Owned. MOSParticle m_PreGameLogoText; //!< The pre-game logo text that appears at the end of the slideshow. MOSParticle m_PreGameLogoTextGlow; //!< The pre-game logo text glow. - std::array m_IntroSlides; //!< Array that contains all the slideshow slide bitmaps. Not Owned. + std::array m_IntroSlides; //!< Array that contains all the slideshow slide bitmaps. Not Owned. #pragma region Create Breakdown /// @@ -219,7 +233,10 @@ namespace RTE { /// Sets the duration of a new section and resets the switch. /// /// The duration of the new section, in seconds. - void SetSectionDurationAndResetSwitch(float newDuration) { m_SectionDuration = newDuration; m_SectionSwitch = false; } + void SetSectionDurationAndResetSwitch(float newDuration) { + m_SectionDuration = newDuration; + m_SectionSwitch = false; + } /// /// Updates the title screen transition states and scrolls the title screen scene accordingly. @@ -272,8 +289,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - TitleScreen(const TitleScreen &reference) = delete; - TitleScreen & operator=(const TitleScreen &rhs) = delete; + TitleScreen(const TitleScreen& reference) = delete; + TitleScreen& operator=(const TitleScreen& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/AllegroTools.cpp b/Source/System/AllegroTools.cpp index 1a429df5d..166914fcf 100644 --- a/Source/System/AllegroTools.cpp +++ b/Source/System/AllegroTools.cpp @@ -12,7 +12,9 @@ namespace RTE { n = geta32(x); - if (n){ n++; } + if (n) { + n++; + } res = ((x & 0xFF00FF) - (y & 0xFF00FF)) * n / 256 + y; y &= 0xFF00; @@ -31,4 +33,4 @@ namespace RTE { void SetTrueAlphaBlender() { set_blender_mode_ex(_blender_black, _blender_black, _blender_black, TrueAlphaBlender, _blender_black, _blender_black, _blender_black, 0, 0, 0, 0); } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/System/AllegroTools.h b/Source/System/AllegroTools.h index a714c44cd..b41b7a571 100644 --- a/Source/System/AllegroTools.h +++ b/Source/System/AllegroTools.h @@ -6,18 +6,18 @@ /// Note: Prefer fixing in allegro itself over adding hacks here. /// namespace RTE { - #pragma region True Alpha Blending +#pragma region True Alpha Blending - /// - /// Workaround for allegro's missing true alpha blender, use instead of set_alpha_blender when alpha values are desired or necessary after draw: - /// ``` set_blender_mode_ex(_blender_black, _blender_black, _blender_black, TrueAlphaBlender, _blender_black, _blender_black, _blender_black, 0, 0, 0, 0);``` - /// - unsigned long TrueAlphaBlender(unsigned long x, unsigned long y, unsigned long n); - /// - /// Sets the 32bit allegro blender mode to TrueAlphaBlender - /// - void SetTrueAlphaBlender(); - #pragma endregion -} + /// + /// Workaround for allegro's missing true alpha blender, use instead of set_alpha_blender when alpha values are desired or necessary after draw: + /// ``` set_blender_mode_ex(_blender_black, _blender_black, _blender_black, TrueAlphaBlender, _blender_black, _blender_black, _blender_black, 0, 0, 0, 0);``` + /// + unsigned long TrueAlphaBlender(unsigned long x, unsigned long y, unsigned long n); + /// + /// Sets the 32bit allegro blender mode to TrueAlphaBlender + /// + void SetTrueAlphaBlender(); +#pragma endregion +} // namespace RTE -#endif \ No newline at end of file +#endif diff --git a/Source/System/Atom.cpp b/Source/System/Atom.cpp index 0d567f816..e5266f898 100644 --- a/Source/System/Atom.cpp +++ b/Source/System/Atom.cpp @@ -14,14 +14,14 @@ namespace RTE { const std::string Atom::c_ClassName = "Atom"; std::mutex Atom::s_MemoryPoolMutex; - std::vector Atom::s_AllocatedPool; + std::vector Atom::s_AllocatedPool; int Atom::s_PoolAllocBlockCount = 200; int Atom::s_InstancesInUse = 0; // This forms a circle around the Atom's offset center, to check for mask color pixels in order to determine the normal at the Atom's position. - const int Atom::s_NormalChecks[c_NormalCheckCount][2] = { {0, -3}, {1, -3}, {2, -2}, {3, -1}, {3, 0}, {3, 1}, {2, 2}, {1, 3}, {0, 3}, {-1, 3}, {-2, 2}, {-3, 1}, {-3, 0}, {-3, -1}, {-2, -2}, {-1, -3} }; + const int Atom::s_NormalChecks[c_NormalCheckCount][2] = {{0, -3}, {1, -3}, {2, -2}, {3, -1}, {3, 0}, {3, 1}, {2, 2}, {1, 3}, {0, 3}, {-1, 3}, {-2, 2}, {-3, 1}, {-3, 0}, {-3, -1}, {-2, -2}, {-1, -3}}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Atom::Clear() { m_Offset.Reset(); @@ -58,13 +58,13 @@ namespace RTE { // While an AtomGroup is travelling, the OnCollideWithTerrain Lua function can run, which will in turn force Create to run if it hasn't already. // If this Create function adds to an AtomGroup (e.g. adds an Attachable to it), there will be problems. // Setting these values in Clear doesn't help if Atoms are removed at this point, but helps if Atoms are added, since these values mean the added Atoms won't try to step forwards. - //m_Dom = 0; - //m_Delta[m_Dom] = 0; + // m_Dom = 0; + // m_Delta[m_Dom] = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Atom::Create(const Vector &offset, Material const *material, MovableObject *owner, Color trailColor, int trailLength) { + int Atom::Create(const Vector& offset, Material const* material, MovableObject* owner, Color trailColor, int trailLength) { m_Offset = m_OriginalOffset = offset; // Use the offset as normal for now m_Normal = m_Offset; @@ -77,9 +77,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Atom::Create(const Atom &reference) { + int Atom::Create(const Atom& reference) { m_Offset = reference.m_Offset; m_OriginalOffset = reference.m_OriginalOffset; m_Normal = reference.m_Normal; @@ -96,11 +96,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Atom::ReadProperty(const std::string_view &propName, Reader &reader) { + int Atom::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("Offset", { reader >> m_Offset; }); MatchProperty("OriginalOffset", { reader >> m_OriginalOffset; }); MatchProperty("Material", { @@ -108,19 +108,20 @@ namespace RTE { mat.Reset(); reader >> mat; m_Material = g_SceneMan.AddMaterialCopy(&mat); - if (!m_Material) { RTEAbort("Failed to store material \"" + mat.GetPresetName() + "\". Aborting!"); } + if (!m_Material) { + RTEAbort("Failed to store material \"" + mat.GetPresetName() + "\". Aborting!"); + } }); MatchProperty("TrailColor", { reader >> m_TrailColor; }); MatchProperty("TrailLength", { reader >> m_TrailLength; }); MatchProperty("TrailLengthVariation", { reader >> m_TrailLengthVariation; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Atom::Save(Writer &writer) const { + int Atom::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("Offset", m_Offset); @@ -133,16 +134,18 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void * Atom::GetPoolMemory() { + void* Atom::GetPoolMemory() { std::lock_guard guard(s_MemoryPoolMutex); // If the pool is empty, then fill it up again with as many instances as we are set to - if (s_AllocatedPool.empty()) { FillPool((s_PoolAllocBlockCount > 0) ? s_PoolAllocBlockCount : 10); } + if (s_AllocatedPool.empty()) { + FillPool((s_PoolAllocBlockCount > 0) ? s_PoolAllocBlockCount : 10); + } // Get the instance in the top of the pool and pop it off - void *foundMemory = s_AllocatedPool.back(); + void* foundMemory = s_AllocatedPool.back(); s_AllocatedPool.pop_back(); RTEAssert(foundMemory, "Could not find an available instance in the pool, even after increasing its size!"); @@ -153,11 +156,13 @@ namespace RTE { return foundMemory; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Atom::FillPool(int fillAmount) { // Default to the set block allocation size if fillAmount is 0 - if (fillAmount <= 0) { fillAmount = s_PoolAllocBlockCount; } + if (fillAmount <= 0) { + fillAmount = s_PoolAllocBlockCount; + } // If concrete class, fill up the pool with pre-allocated memory blocks the size of the type if (fillAmount > 0) { @@ -168,9 +173,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Atom::ReturnPoolMemory(void *returnedMemory) { + int Atom::ReturnPoolMemory(void* returnedMemory) { if (!returnedMemory) { return false; } @@ -184,9 +189,9 @@ namespace RTE { return s_InstancesInUse; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Atom::CalculateNormal(BITMAP *sprite, Vector spriteCenter) { + bool Atom::CalculateNormal(BITMAP* sprite, Vector spriteCenter) { RTEAssert(sprite, "Trying to set up Atom normal without passing in bitmap"); // Can't set up a normal on an atom that doesn't have an offset from its parent's center @@ -217,22 +222,22 @@ namespace RTE { // Check whether the normal vector makes sense at all. It can't point against the offset, for example if (m_Normal.Dot(m_Offset) < 0) { - // Abort and revert to offset-based normal - m_Normal = m_Offset; - m_Normal.Normalize(); - return false; + // Abort and revert to offset-based normal + m_Normal = m_Offset; + m_Normal.Normalize(); + return false; } */ return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Atom::IsIgnoringMOID(MOID whichMOID) { if (whichMOID == m_IgnoreMOID) { return true; } - const MovableObject *hitMO = g_MovableMan.GetMOFromID(whichMOID); + const MovableObject* hitMO = g_MovableMan.GetMOFromID(whichMOID); hitMO = hitMO ? hitMO->GetRootParent() : 0; // First check if we are ignoring the team of the MO we hit, or if it's an AtomGroup and we're ignoring all those @@ -240,7 +245,7 @@ namespace RTE { if (m_OwnerMO->IgnoresTeamHits() && hitMO->IgnoresTeamHits() && m_OwnerMO->GetTeam() == hitMO->GetTeam()) { return true; } - if ((m_OwnerMO->IgnoresAtomGroupHits() && dynamic_cast(hitMO)) || (hitMO->IgnoresAtomGroupHits() && dynamic_cast(m_OwnerMO))) { + if ((m_OwnerMO->IgnoresAtomGroupHits() && dynamic_cast(hitMO)) || (hitMO->IgnoresAtomGroupHits() && dynamic_cast(m_OwnerMO))) { return true; } if ((m_OwnerMO->GetIgnoresActorHits() && dynamic_cast(hitMO)) || (hitMO->GetIgnoresActorHits() && dynamic_cast(m_OwnerMO))) { @@ -249,7 +254,7 @@ namespace RTE { } // Now check for explicit ignore bool ignored = false; - for (const MOID &moid : m_IgnoreMOIDs) { + for (const MOID& moid: m_IgnoreMOIDs) { if (moid == whichMOID) { ignored = true; break; @@ -257,7 +262,7 @@ namespace RTE { } // Check in AtomGroup-owned list if it's assigned to this atom if (!ignored && m_IgnoreMOIDsByGroup) { - for (const MOID &moid : *m_IgnoreMOIDsByGroup) { + for (const MOID& moid: *m_IgnoreMOIDsByGroup) { if (moid == whichMOID) { ignored = true; break; @@ -267,7 +272,7 @@ namespace RTE { return ignored; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Atom::MOHitResponse() { RTEAssert(m_OwnerMO, "Stepping an Atom without a parent MO!"); @@ -306,7 +311,9 @@ namespace RTE { } m_LastHit.BitmapNormal.Normalize(); - if (!m_Normal.IsZero()) { m_LastHit.BitmapNormal = -m_OwnerMO->RotateOffset(m_Normal); } + if (!m_Normal.IsZero()) { + m_LastHit.BitmapNormal = -m_OwnerMO->RotateOffset(m_Normal); + } // Cancel collision response for this if it appears the collision is happening in the 'wrong' direction, meaning away from the center. // This happens when things are sunk into each other, and thus getting 'hooked' on each other @@ -324,8 +331,12 @@ namespace RTE { #endif // Get the roots for both bodies - if (m_LastHit.Body[HITOR]) { m_LastHit.RootBody[HITOR] = m_LastHit.Body[HITOR]->GetRootParent(); } - if (m_LastHit.Body[HITEE]) { m_LastHit.RootBody[HITEE] = m_LastHit.Body[HITEE]->GetRootParent(); } + if (m_LastHit.Body[HITOR]) { + m_LastHit.RootBody[HITOR] = m_LastHit.Body[HITOR]->GetRootParent(); + } + if (m_LastHit.Body[HITEE]) { + m_LastHit.RootBody[HITEE] = m_LastHit.Body[HITEE]->GetRootParent(); + } validHit = validHit && m_LastHit.Body[HITEE]->CollideAtPoint(m_LastHit); @@ -335,9 +346,9 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - HitData & Atom::TerrHitResponse() { + HitData& Atom::TerrHitResponse() { RTEAssert(m_OwnerMO, "Stepping an Atom without a parent MO!"); if (m_TerrainMatHit) { @@ -345,9 +356,9 @@ namespace RTE { MID domMaterialID = g_MaterialAir; MID subMaterialID = g_MaterialAir; m_LastHit.HitMaterial[HITOR] = m_Material; - Material const *hitMaterial = m_LastHit.HitMaterial[HITEE] = g_SceneMan.GetMaterialFromID(hitMaterialID); - Material const *domMaterial = g_SceneMan.GetMaterialFromID(g_MaterialAir); - Material const *subMaterial = g_SceneMan.GetMaterialFromID(g_MaterialAir); + Material const* hitMaterial = m_LastHit.HitMaterial[HITEE] = g_SceneMan.GetMaterialFromID(hitMaterialID); + Material const* domMaterial = g_SceneMan.GetMaterialFromID(g_MaterialAir); + Material const* subMaterial = g_SceneMan.GetMaterialFromID(g_MaterialAir); bool hit[2]; hit[X] = hit[Y] = false; m_LastHit.BitmapNormal.Reset(); @@ -411,7 +422,7 @@ namespace RTE { return m_LastHit; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Atom::SetupPos(Vector startPos) { RTEAssert(m_OwnerMO, "Stepping an Atom without a parent MO!"); @@ -429,7 +440,9 @@ namespace RTE { if ((m_TerrainMatHit = g_SceneMan.GetTerrMatter(m_IntPos[X], m_IntPos[Y])) != g_MaterialAir) { m_OwnerMO->SetHitWhatTerrMaterial(m_TerrainMatHit); - if (m_OwnerMO->IntersectionWarning()) { m_TerrainHitsDisabled = true; } + if (m_OwnerMO->IntersectionWarning()) { + m_TerrainHitsDisabled = true; + } } else { m_TerrainHitsDisabled = false; } @@ -437,7 +450,7 @@ namespace RTE { return m_MOIDHit != g_NoMOID || m_TerrainMatHit != g_MaterialAir; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Atom::SetupSeg(Vector startPos, Vector trajectory, float stepRatio) { RTEAssert(m_OwnerMO, "Stepping an Atom without a parent MO!"); @@ -492,7 +505,7 @@ namespace RTE { return m_Delta[m_Dom] - m_DomSteps; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Atom::StepForward(int numSteps) { RTEAssert(m_OwnerMO, "Stepping an Atom without a parent MO!"); @@ -507,7 +520,9 @@ namespace RTE { if (m_DomSteps < m_Delta[m_Dom]) { ++m_DomSteps; - if (m_SubStepped) { ++m_SubSteps; } + if (m_SubStepped) { + ++m_SubSteps; + } m_SubStepped = false; m_IntPos[m_Dom] += m_Increment[m_Dom]; @@ -516,13 +531,13 @@ namespace RTE { m_SubStepped = true; m_Error -= m_Delta2[m_Dom]; } - //if (m_ChangedDir){ - m_Error += m_Delta2[m_Sub]; + // if (m_ChangedDir){ + m_Error += m_Delta2[m_Sub]; //} else { - //m_Error = m_PrevError; + // m_Error = m_PrevError; //} - // Scene wrapping, if necessary + // Scene wrapping, if necessary g_SceneMan.WrapPosition(m_IntPos[X], m_IntPos[Y]); // Detect terrain hits, if not disabled. @@ -544,7 +559,9 @@ namespace RTE { // Detect hits with non-ignored MO's, if enabled. if (m_OwnerMO->m_HitsMOs) { m_MOIDHit = g_SceneMan.GetMOIDPixel(m_IntPos[X], m_IntPos[Y], m_OwnerMO->GetTeam()); - if (IsIgnoringMOID(m_MOIDHit)) { m_MOIDHit = g_NoMOID; } + if (IsIgnoringMOID(m_MOIDHit)) { + m_MOIDHit = g_NoMOID; + } if (m_MOIDHit != g_NoMOID) { if (!m_MOHitsDisabled) { @@ -564,7 +581,7 @@ namespace RTE { if (m_OwnerMO) { abortString += "\nRoot owner is " + m_OwnerMO->GetPresetName() + "."; if (m_SubgroupID != 0) { - const MovableObject *realOwner = g_MovableMan.FindObjectByUniqueID(m_SubgroupID); + const MovableObject* realOwner = g_MovableMan.FindObjectByUniqueID(m_SubgroupID); abortString += " Owner is " + realOwner->GetPresetName() + "."; } } @@ -576,7 +593,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Atom::StepBack() { RTEAssert(m_OwnerMO, "Stepping an Atom without a parent MO!"); @@ -601,7 +618,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Atom::Travel(float travelTime, bool autoTravel, bool scenePreLocked) { ZoneScoped; @@ -610,14 +627,14 @@ namespace RTE { RTEAbort("Traveling an Atom without a parent MO!"); return travelTime; } - Vector &position = m_OwnerMO->m_Pos; - Vector &velocity = m_OwnerMO->m_Vel; + Vector& position = m_OwnerMO->m_Pos; + Vector& velocity = m_OwnerMO->m_Vel; float mass = m_OwnerMO->GetMass(); float sharpness = m_OwnerMO->GetSharpness(); - bool &didWrap = m_OwnerMO->m_DidWrap; + bool& didWrap = m_OwnerMO->m_DidWrap; m_LastHit.Reset(); - BITMAP *trailBitmap = 0; + BITMAP* trailBitmap = 0; int hitCount = 0; int error = 0; @@ -639,15 +656,15 @@ namespace RTE { bool hit[2]; bool sinkHit; bool subStepped; - //bool endOfTraj = false; + // bool endOfTraj = false; - const Material *hitMaterial = 0; //g_SceneMan.GetMaterialFromID(g_MaterialAir); + const Material* hitMaterial = 0; // g_SceneMan.GetMaterialFromID(g_MaterialAir); unsigned char hitMaterialID = 0; - const Material *domMaterial = 0; //g_SceneMan.GetMaterialFromID(g_MaterialAir); + const Material* domMaterial = 0; // g_SceneMan.GetMaterialFromID(g_MaterialAir); unsigned char domMaterialID = 0; - const Material *subMaterial = 0; //g_SceneMan.GetMaterialFromID(g_MaterialAir); + const Material* subMaterial = 0; // g_SceneMan.GetMaterialFromID(g_MaterialAir); unsigned char subMaterialID = 0; Vector segTraj; @@ -667,7 +684,9 @@ namespace RTE { position += m_Offset; // Lock all bitmaps involved outside the loop. - if (!scenePreLocked) { g_SceneMan.LockScene(); } + if (!scenePreLocked) { + g_SceneMan.LockScene(); + } // Loop for all the different straight segments (between bounces etc) that have to be traveled during the timeLeft. do { @@ -677,7 +696,7 @@ namespace RTE { // Get trail bitmap and put first pixel. if (m_TrailLength) { trailBitmap = g_SceneMan.GetMOColorBitmap(); - trailPoints.push_back({ intPos[X], intPos[Y] }); + trailPoints.push_back({intPos[X], intPos[Y]}); } // Compute and scale the actual on-screen travel trajectory for this segment, based on the velocity, the travel time and the pixels-per-meter constant. segTraj = velocity * timeLeft * c_PPM; @@ -686,14 +705,14 @@ namespace RTE { delta[Y] = std::floor(position.m_Y + segTraj.m_Y) - intPos[Y]; RTEAssert(std::abs(delta[X]) < 2500 && std::abs(delta[Y] < 2500), "Extremely long difference trajectory found during Atom::Travel. Owner is " + m_OwnerMO->GetPresetName() + ", with Vel (" + std::to_string(velocity.GetX()) + ", " + std::to_string(velocity.GetY()) + ")."); - //segProgress = 0.0F; - //delta2[X] = 0; - //delta2[Y] = 0; - //increment[X] = 0; - //increment[Y] = 0; + // segProgress = 0.0F; + // delta2[X] = 0; + // delta2[Y] = 0; + // increment[X] = 0; + // increment[Y] = 0; hit[X] = false; hit[Y] = false; - //domSteps = 0; + // domSteps = 0; subSteps = 0; subStepped = false; sinkHit = false; @@ -703,9 +722,9 @@ namespace RTE { break; } - //HitMaterial->Reset(); - //domMaterial->Reset(); - //subMaterial->Reset(); + // HitMaterial->Reset(); + // domMaterial->Reset(); + // subMaterial->Reset(); // Bresenham's line drawing algorithm preparation if (delta[X] < 0) { @@ -742,18 +761,20 @@ namespace RTE { ++hitCount; hit[X] = hit[Y] = true; if (g_SceneMan.TryPenetrate(intPos[X], intPos[Y], velocity * mass * sharpness, velocity, retardation, 0.5F, m_NumPenetrations, removeOrphansRadius, removeOrphansMaxArea, removeOrphansRate)) { - //segProgress = 0.0F; + // segProgress = 0.0F; velocity += velocity * retardation; continue; } else { - //segProgress = 1.0F; + // segProgress = 1.0F; velocity.SetXY(0, 0); timeLeft = 0.0F; break; } } - if (subStepped) { ++subSteps; } + if (subStepped) { + ++subSteps; + } subStepped = false; intPos[dom] += increment[dom]; @@ -780,7 +801,9 @@ namespace RTE { // Back up so the Atom is not inside the MO. intPos[dom] -= increment[dom]; - if (subStepped) { intPos[sub] -= increment[sub]; } + if (subStepped) { + intPos[sub] -= increment[sub]; + } m_LastHit.Reset(); m_LastHit.TotalMass[HITOR] = mass; @@ -788,12 +811,14 @@ namespace RTE { m_LastHit.MomInertia[HITOR] = 1.0F; m_LastHit.ImpulseFactor[HITOR] = 1.0F; m_LastHit.ImpulseFactor[HITEE] = 1.0F; - //m_LastHit.HitPoint = Vector(hitPos[X], hitPos[Y]); + // m_LastHit.HitPoint = Vector(hitPos[X], hitPos[Y]); m_LastHit.HitVel[HITOR] = velocity; - MovableObject *MO = g_MovableMan.GetMOFromID(m_MOIDHit); + MovableObject* MO = g_MovableMan.GetMOFromID(m_MOIDHit); - if (MO) { MO->SetHitWhatParticleUniqueID(m_OwnerMO->GetUniqueID()); } + if (MO) { + MO->SetHitWhatParticleUniqueID(m_OwnerMO->GetUniqueID()); + } m_LastHit.Body[HITOR] = m_OwnerMO; m_LastHit.Body[HITEE] = MO; @@ -805,13 +830,13 @@ namespace RTE { // Don't do this normal approximation based on object centers, it causes particles to 'slide into' sprite objects when they should be resting on them. // Orthogonal normals only, as the pixel boundaries themselves! See further down for the setting of this. - //m_LastHit.BitmapNormal = m_LastHit.Body[HITOR]->GetPos() - m_LastHit.Body[HITEE]->GetPos(); - //m_LastHit.BitmapNormal.Normalize(); + // m_LastHit.BitmapNormal = m_LastHit.Body[HITOR]->GetPos() - m_LastHit.Body[HITEE]->GetPos(); + // m_LastHit.BitmapNormal.Normalize(); // Gold special collection case! // TODO: Make material IDs more robust!") if (m_Material->GetIndex() == c_GoldMaterialID && g_MovableMan.IsOfActor(m_MOIDHit)) { - if (Actor *actor = dynamic_cast(g_MovableMan.GetMOFromID(m_LastHit.Body[HITEE]->GetRootID())); actor && !actor->IsDead()) { + if (Actor* actor = dynamic_cast(g_MovableMan.GetMOFromID(m_LastHit.Body[HITEE]->GetRootID())); actor && !actor->IsDead()) { actor->AddGold(m_OwnerMO->GetMass() * g_SceneMan.GetOzPerKg() * removeOrphansRadius ? 1.25F : 1.0F); m_OwnerMO->SetToDelete(true); // This is to break out of the do-while and the function properly. @@ -869,7 +894,9 @@ namespace RTE { // If there was no MO collision detected, then check for terrain hits. else if ((hitMaterialID = g_SceneMan.GetTerrMatter(intPos[X], intPos[Y])) && !m_OwnerMO->m_IgnoreTerrain) { - if (hitMaterialID != g_MaterialAir) { m_OwnerMO->SetHitWhatTerrMaterial(hitMaterialID); } + if (hitMaterialID != g_MaterialAir) { + m_OwnerMO->SetHitWhatTerrMaterial(hitMaterialID); + } hitMaterial = g_SceneMan.GetMaterialFromID(hitMaterialID); hitPos[X] = intPos[X]; @@ -877,7 +904,9 @@ namespace RTE { ++hitCount; #ifdef DEBUG_BUILD - if (m_TrailLength) { putpixel(trailBitmap, intPos[X], intPos[Y], 199); } + if (m_TrailLength) { + putpixel(trailBitmap, intPos[X], intPos[Y], 199); + } #endif // Try penetration of the terrain. if (hitMaterial->GetIndex() != g_MaterialOutOfBounds && g_SceneMan.TryPenetrate(intPos[X], intPos[Y], velocity * mass * sharpness, velocity, retardation, 0.65F, m_NumPenetrations, removeOrphansRadius, removeOrphansMaxArea, removeOrphansRate)) { @@ -896,14 +925,16 @@ namespace RTE { // Back up so the Atom is not inside the terrain. intPos[dom] -= increment[dom]; - if (subStepped) { intPos[sub] -= increment[sub]; } + if (subStepped) { + intPos[sub] -= increment[sub]; + } // Undo scene wrapping, if necessary g_SceneMan.WrapPosition(intPos[X], intPos[Y]); // Check if particle is sticky and should adhere to where it collided if (!m_OwnerMO->IsMissionCritical() && velocity.MagnitudeIsGreaterThan(1.0F)) { - MOPixel *ownerMOAsPixel = dynamic_cast(m_OwnerMO); + MOPixel* ownerMOAsPixel = dynamic_cast(m_OwnerMO); if (RandomNum() < std::max(m_Material->GetStickiness(), ownerMOAsPixel ? ownerMOAsPixel->GetStaininess() : 0.0f)) { // Weighted random select between stickiness or staininess const float randomChoice = RandomNum(0.0f, m_Material->GetStickiness() + (ownerMOAsPixel ? ownerMOAsPixel->GetStaininess() : 0.0f)); @@ -913,7 +944,7 @@ namespace RTE { m_OwnerMO->SetToDelete(true); m_LastHit.Terminate[HITOR] = hit[dom] = hit[sub] = true; break; - } else if (MOPixel *ownerMOAsPixel = dynamic_cast(m_OwnerMO); ownerMOAsPixel && randomChoice <= m_Material->GetStickiness() + ownerMOAsPixel->GetStaininess()) { + } else if (MOPixel* ownerMOAsPixel = dynamic_cast(m_OwnerMO); ownerMOAsPixel && randomChoice <= m_Material->GetStickiness() + ownerMOAsPixel->GetStaininess()) { Vector stickPos(intPos[X], intPos[Y]); stickPos += velocity * (c_PPM * g_TimerMan.GetDeltaTimeSecs()) * RandomNum(); int terrainMaterialID = g_SceneMan.GetTerrain()->GetMaterialPixel(stickPos.GetFloorIntX(), stickPos.GetFloorIntY()); @@ -953,7 +984,7 @@ namespace RTE { // If hit right on the corner of a pixel, bounce straight back with no friction. if (!hit[dom] && !hit[sub]) { hit[dom] = true; - hitAccel[dom] = -velocity[dom] - velocity[dom] * m_Material->GetRestitution() * hitMaterial->GetRestitution(); + hitAccel[dom] = -velocity[dom] - velocity[dom] * m_Material->GetRestitution() * hitMaterial->GetRestitution(); hit[sub] = true; hitAccel[sub] = -velocity[sub] - velocity[sub] * m_Material->GetRestitution() * hitMaterial->GetRestitution(); } else if (hit[dom] && !hit[sub]) { @@ -964,7 +995,7 @@ namespace RTE { } } } else if (m_TrailLength) { - trailPoints.push_back({ intPos[X], intPos[Y] }); + trailPoints.push_back({intPos[X], intPos[Y]}); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -974,14 +1005,14 @@ namespace RTE { if ((hit[X] || hit[Y]) && !m_LastHit.Terminate[HITOR]) { // Calculate the progress made on this segment before hitting something. // We count the hitting step made if it resulted in a terrain sink, because the Atoms weren't stepped back out of intersection. - //segProgress = static_cast(domSteps + sinkHit) / static_cast(delta[dom]); + // segProgress = static_cast(domSteps + sinkHit) / static_cast(delta[dom]); segProgress = (static_cast(domSteps + static_cast(sinkHit)) < delta[dom]) ? (static_cast(domSteps + static_cast(sinkHit)) / std::fabs(static_cast(segTraj[dom]))) : 1.0F; // Now calculate the total time left to travel, according to the progress made. timeLeft -= timeLeft * segProgress; // Move position forward to the hit position. - //position += segTraj * segProgress; + // position += segTraj * segProgress; // Only move the dom forward by int domSteps, so we don't cross into a pixel too far position[dom] += (domSteps + static_cast(sinkHit)) * increment[dom]; @@ -1002,7 +1033,7 @@ namespace RTE { } } while ((hit[X] || hit[Y]) && /* !segTraj.GetFloored().IsZero() && */ hitCount < 100 && !m_LastHit.Terminate[HITOR]); - //RTEAssert(hitCount < 100, "Atom travel resulted in more than 100 segments!!"); + // RTEAssert(hitCount < 100, "Atom travel resulted in more than 100 segments!!"); // Draw the trail if (g_TimerMan.DrawnSimUpdate() && m_TrailLength && trailPoints.size() > 0) { @@ -1023,14 +1054,18 @@ namespace RTE { } // Unlock all bitmaps involved. - //if (m_TrailLength) { trailBitmap->UnLock(); } - if (!scenePreLocked) { g_SceneMan.UnlockScene(); } + // if (m_TrailLength) { trailBitmap->UnLock(); } + if (!scenePreLocked) { + g_SceneMan.UnlockScene(); + } // Extract Atom offset. position -= m_Offset; // Travel along the remaining segTraj. - if (!(hit[X] || hit[Y]) && autoTravel) { position += segTraj; } + if (!(hit[X] || hit[Y]) && autoTravel) { + position += segTraj; + } didWrap = g_SceneMan.WrapPosition(position) || didWrap; @@ -1039,7 +1074,7 @@ namespace RTE { return hitCount; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void HitData::Clear() { HitPoint.Reset(); @@ -1063,9 +1098,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - HitData & HitData::operator=(const HitData &rhs) { + HitData& HitData::operator=(const HitData& rhs) { if (this == &rhs) { return *this; } @@ -1092,4 +1127,4 @@ namespace RTE { } return *this; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Atom.h b/Source/System/Atom.h index 66bb976fe..d9d25e7ea 100644 --- a/Source/System/Atom.h +++ b/Source/System/Atom.h @@ -10,7 +10,10 @@ namespace RTE { class SLTerrain; class MovableObject; - enum { HITOR = 0, HITEE = 1 }; + enum { + HITOR = 0, + HITEE = 1 + }; #pragma region HitData /// @@ -18,12 +21,12 @@ namespace RTE { /// struct HitData { - MovableObject *Body[2]; //!< Pointers to the two hitting bodies. If hitee is 0, that means collision with terrain. The HitData struct doesn't own these. - MovableObject *RootBody[2]; //!< Pointers to root parents of the two hitting bodies. If hitee is 0, that means collision with terrain. The HitData struct doesn't own these. + MovableObject* Body[2]; //!< Pointers to the two hitting bodies. If hitee is 0, that means collision with terrain. The HitData struct doesn't own these. + MovableObject* RootBody[2]; //!< Pointers to root parents of the two hitting bodies. If hitee is 0, that means collision with terrain. The HitData struct doesn't own these. Vector BitmapNormal; //!< The approximated normal vector of the bitmap that the hitee is presenting to the hittor at the collision point. The inverse of this is the one representing the hittor bitmap. - const Material *HitMaterial[2]; //!< The material of the respective bodies at the hit point. + const Material* HitMaterial[2]; //!< The material of the respective bodies at the hit point. float TotalMass[2]; //!< Total mass of each body. float MomInertia[2]; //!< Moment of inertia. If 0, assume to be a point mass. @@ -56,7 +59,7 @@ namespace RTE { /// /// A HitData reference. /// A reference to the changed HitData. - HitData & operator=(const HitData &rhs); + HitData& operator=(const HitData& rhs); /// /// Clears all the member variables of this HitData, effectively resetting the members of this abstraction level only. @@ -71,7 +74,6 @@ namespace RTE { class Atom : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -85,7 +87,12 @@ namespace RTE { /// Copy constructor method used to instantiate an Atom object identical to an already existing one. /// /// An Atom object which is passed in by reference. - Atom(const Atom &reference) { if (this != &reference) { Clear(); Create(reference); } } + Atom(const Atom& reference) { + if (this != &reference) { + Clear(); + Create(reference); + } + } /// /// Convenience constructor to both instantiate an Atom in memory and Create it at the same time. @@ -95,7 +102,10 @@ namespace RTE { /// The owner MovableObject of this Atom. Ownership is NOT transferred! /// The trail color. /// The trail length. If 0, no trail will be drawn. - Atom(const Vector &offset, Material const *material, MovableObject *owner, Color trailColor = Color(), int trailLength = 0) { Clear(); Create(offset, material, owner, trailColor, trailLength); } + Atom(const Vector& offset, Material const* material, MovableObject* owner, Color trailColor = Color(), int trailLength = 0) { + Clear(); + Create(offset, material, owner, trailColor, trailLength); + } /// /// Convenience constructor to both instantiate an Atom in memory and Create it at the same time. @@ -105,14 +115,17 @@ namespace RTE { /// The owner MovableObject of this Atom. Ownership is NOT transferred! /// The trail color. /// The trail length. If 0, no trail will be drawn. - Atom(const Vector &offset, unsigned char materialID, MovableObject *owner, Color trailColor = Color(), int trailLength = 0) { Clear(); Create(offset, g_SceneMan.GetMaterialFromID(materialID), owner, trailColor, trailLength); } + Atom(const Vector& offset, unsigned char materialID, MovableObject* owner, Color trailColor = Color(), int trailLength = 0) { + Clear(); + Create(offset, g_SceneMan.GetMaterialFromID(materialID), owner, trailColor, trailLength); + } /// /// Creates an Atom to be identical to another, by deep copy. /// /// A reference to the Atom to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Atom &reference); + int Create(const Atom& reference); /// /// Makes the Atom object ready for use. @@ -123,7 +136,7 @@ namespace RTE { /// The trail color. /// The trail length. If 0, no trail will be drawn. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Vector &offset, Material const *material, MovableObject *owner, Color trailColor = Color(), int trailLength = 0); + int Create(const Vector& offset, Material const* material, MovableObject* owner, Color trailColor = Color(), int trailLength = 0); #pragma endregion #pragma region Destruction @@ -143,7 +156,7 @@ namespace RTE { /// Grabs from the pre-allocated pool, an available chunk of memory the exact size of an Atom. OWNERSHIP IS TRANSFERRED! /// /// A pointer to the pre-allocated pool memory. OWNERSHIP IS TRANSFERRED! - static void * GetPoolMemory(); + static void* GetPoolMemory(); /// /// Adds a certain number of newly allocated instances to this' pool. @@ -156,7 +169,7 @@ namespace RTE { /// /// The raw chunk of memory that is being returned. Needs to be the same size as an Atom. OWNERSHIP IS TRANSFERRED! /// The count of outstanding memory chunks after this was returned. - static int ReturnPoolMemory(void *returnedMemory); + static int ReturnPoolMemory(void* returnedMemory); #pragma endregion #pragma region Getters and Setters @@ -164,13 +177,13 @@ namespace RTE { /// Gets the current owner MovableObject of this AtomGroup. /// /// A const pointer to the owner. - const MovableObject * GetOwner() const { return m_OwnerMO; } + const MovableObject* GetOwner() const { return m_OwnerMO; } /// /// Sets the current owner MovableObject of this AtomGroup. /// /// A pointer to the new owner. Ownership is NOT transferred! - void SetOwner(MovableObject *newOwner) { m_OwnerMO = newOwner; } + void SetOwner(MovableObject* newOwner) { m_OwnerMO = newOwner; } /// /// Gets the group ID of this Atom. @@ -188,13 +201,13 @@ namespace RTE { /// Gets the material of this Atom. /// /// The material of this Atom. - Material const * GetMaterial() const { return m_Material ? m_Material : g_SceneMan.GetMaterialFromID(g_MaterialAir); } + Material const* GetMaterial() const { return m_Material ? m_Material : g_SceneMan.GetMaterialFromID(g_MaterialAir); } /// /// Sets the material of this Atom. /// /// The new material of this Atom. - void SetMaterial(const Material *newMat) { m_Material = newMat; } + void SetMaterial(const Material* newMat) { m_Material = newMat; } /// /// Gets the Color of this Atom's trail. @@ -236,25 +249,25 @@ namespace RTE { /// Gets the offset vector that was first set for this Atom. The GetOffset may have additional offsets baked into it if this is part of an group. /// /// The original offset Vector. - const Vector & GetOriginalOffset() const { return m_OriginalOffset; } + const Vector& GetOriginalOffset() const { return m_OriginalOffset; } /// /// Gets the offset vector. /// /// The current offset Vector. - const Vector & GetOffset() const { return m_Offset; } + const Vector& GetOffset() const { return m_Offset; } /// /// Sets a new offset vector for the collision calculations. /// /// A const reference to a Vector that will be used as offset. - void SetOffset(const Vector &newOffset) { m_Offset = newOffset; } + void SetOffset(const Vector& newOffset) { m_Offset = newOffset; } /// /// Gets the surface normal of this vector, if it has been successfully calculated. If not, it'll be a 0 vector. /// /// The current normalized surface normal Vector of this. - const Vector & GetNormal() const { return m_Normal; } + const Vector& GetNormal() const { return m_Normal; } #pragma endregion #pragma region Concrete Methods @@ -265,7 +278,7 @@ namespace RTE { /// The bitmap to check against. Ownership IS NOT transferred! /// Where on the bitmap the center of the object is. This atom's offset will be applied automatically before checking for its normal. /// Whether normal was successfully derived from the bitmap. If not, then a provisional one is derived from the offset. - bool CalculateNormal(BITMAP *sprite, Vector spriteCenter); + bool CalculateNormal(BITMAP* sprite, Vector spriteCenter); #pragma endregion #pragma region Collision @@ -273,13 +286,13 @@ namespace RTE { /// Gets the stored data struct on the last collision experienced by this Atom. /// /// The Vector describing the velocity of this Atom at the last time it hit something. - HitData & GetHitData() { return m_LastHit; } + HitData& GetHitData() { return m_LastHit; } /// /// Sets the HitData struct this Atom uses to represent the last hit it experienced. /// /// A reference to a HitData struct that will be copied to the Atom's. - void SetHitData(const HitData &newHitData) { m_LastHit = newHitData; } + void SetHitData(const HitData& newHitData) { m_LastHit = newHitData; } /// /// Checks whether this Atom is set to ignore collisions with the terrain. @@ -310,7 +323,7 @@ namespace RTE { /// AtomGroup may set this shared list of ignored MOIDs to avoid setting and removing ignored MOIDs for every atom one by one. The list is maintained only by AtomGroup, Atom never owns it. /// /// New MOIDs list to ignore. - void SetIgnoreMOIDsByGroup(std::vector const * ignoreMOIDsByGroup) { m_IgnoreMOIDsByGroup = ignoreMOIDsByGroup; }; + void SetIgnoreMOIDsByGroup(std::vector const* ignoreMOIDsByGroup) { m_IgnoreMOIDsByGroup = ignoreMOIDsByGroup; }; /// /// Clear the list of MOIDs that this Atom is set to ignore collisions with during its next travel sequence. @@ -352,7 +365,7 @@ namespace RTE { /// /// Collision data should already be set by SetHitData(). /// The resulting HitData of this Atom with all the information about the collision filled out. - HitData & TerrHitResponse(); + HitData& TerrHitResponse(); #pragma endregion #pragma region Travel @@ -447,28 +460,33 @@ namespace RTE { /// /// /// - static void *operator new (size_t size) { return Atom::GetPoolMemory(); } + static void* operator new(size_t size) { return Atom::GetPoolMemory(); } /// /// Delete operator overload for the pool deallocation of Atoms. /// /// - static void operator delete (void *instance) { Atom::ReturnPoolMemory(instance); } + static void operator delete(void* instance) { Atom::ReturnPoolMemory(instance); } /// /// An assignment operator for setting one Atom equal to another. /// /// An Atom reference. /// A reference to the changed Atom. - Atom & operator=(const Atom &rhs) { if (this != &rhs) { Destroy(); Create(rhs); } return *this; } + Atom& operator=(const Atom& rhs) { + if (this != &rhs) { + Destroy(); + Create(rhs); + } + return *this; + } #pragma endregion protected: - static constexpr int c_NormalCheckCount = 16; //!< Array size for offsets to form circle in s_NormalChecks. static std::mutex s_MemoryPoolMutex; - static std::vector s_AllocatedPool; //!< Pool of pre-allocated Atoms. + static std::vector s_AllocatedPool; //!< Pool of pre-allocated Atoms. static int s_PoolAllocBlockCount; //!< The number of instances to fill up the pool of Atoms with each time it runs dry. static int s_InstancesInUse; //!< The number of allocated instances passed out from the pool. static const int s_NormalChecks[c_NormalCheckCount][2]; //!< This forms a circle around the Atom's offset center, to check for key color pixels in order to determine the normal at the Atom's position. @@ -476,7 +494,7 @@ namespace RTE { Vector m_Offset; //!< The offset of this Atom for collision calculations. Vector m_OriginalOffset; //!< This offset is before altering the m_Offset for use in composite groups. Vector m_Normal; //!< The current normalized surface normal Vector of this Atom. - Material const * m_Material; //!< The material this Atom is made of. + Material const* m_Material; //!< The material this Atom is made of. int m_SubgroupID; //!< Identifying ID for adding and removing atoms from AtomGroups. bool m_StepWasTaken; //!< Whether the last call to StepForward actually resulted in a step or not. @@ -491,10 +509,10 @@ namespace RTE { bool m_MOHitsDisabled; //!< Temporary disabling of MO collisions for this. bool m_TerrainHitsDisabled; //!< Temporary disabling of terrain collisions for this. Will be re-enabled once out of terrain again. - MovableObject *m_OwnerMO; //!< The owner of this Atom. The owner is obviously not owned by this Atom. + MovableObject* m_OwnerMO; //!< The owner of this Atom. The owner is obviously not owned by this Atom. MOID m_IgnoreMOID; //!< Special ignored MOID. std::vector m_IgnoreMOIDs; //!< ignore hits with MOs of these IDs. - std::vector const * m_IgnoreMOIDsByGroup; //!< Also ignore hits with MOs of these IDs. This one may be set externally by atom group. + std::vector const* m_IgnoreMOIDsByGroup; //!< Also ignore hits with MOs of these IDs. This one may be set externally by atom group. HitData m_LastHit; //!< Data containing information on the last collision experienced by this Atom. MOID m_MOIDHit; //!< The MO, if any, this Atom hit on the last step. @@ -528,7 +546,6 @@ namespace RTE { bool m_SubStepped; private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this. /// @@ -536,5 +553,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Box.cpp b/Source/System/Box.cpp index ca340a345..ce06304ed 100644 --- a/Source/System/Box.cpp +++ b/Source/System/Box.cpp @@ -4,9 +4,9 @@ namespace RTE { const std::string Box::c_ClassName = "Box"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool IntRect::IntersectionCut(const IntRect &rhs) { + bool IntRect::IntersectionCut(const IntRect& rhs) { if (Intersects(rhs)) { m_Left = std::max(m_Left, rhs.m_Left); m_Right = std::min(m_Right, rhs.m_Right); @@ -17,9 +17,9 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Box::Create(const Vector &corner1, const Vector &corner2) { + int Box::Create(const Vector& corner1, const Vector& corner2) { m_Corner = corner1; m_Width = corner2.m_X - corner1.m_X; m_Height = corner2.m_Y - corner1.m_Y; @@ -27,7 +27,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Box::Create(float x1, float y1, float x2, float y2) { m_Corner.SetXY(x1, y1); @@ -37,9 +37,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Box::Create(const Vector &corner, float width, float height) { + int Box::Create(const Vector& corner, float width, float height) { m_Corner = corner; m_Width = width; m_Height = height; @@ -47,9 +47,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Box::Create(const Box &reference) { + int Box::Create(const Box& reference) { m_Corner = reference.m_Corner; m_Width = reference.m_Width; m_Height = reference.m_Height; @@ -57,22 +57,21 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Box::ReadProperty(const std::string_view &propName, Reader &reader) { + int Box::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("Corner", { reader >> m_Corner; }); MatchProperty("Width", { reader >> m_Width; }); MatchProperty("Height", { reader >> m_Height; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Box::Save(Writer &writer) const { + int Box::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("Corner", m_Corner); @@ -82,7 +81,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Box::Unflip() { if (m_Width < 0) { @@ -95,30 +94,30 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Box::IsWithinBox(const Vector &point) const { + bool Box::IsWithinBox(const Vector& point) const { return !IsEmpty() && (((m_Width > 0 && point.m_X >= m_Corner.m_X && point.m_X < (m_Corner.m_X + m_Width)) || - (m_Width < 0 && point.m_X < m_Corner.m_X && point.m_X >= (m_Corner.m_X + m_Width))) && - (m_Height > 0 && point.m_Y >= m_Corner.m_Y && point.m_Y < (m_Corner.m_Y + m_Height)) || - (m_Height < 0 && point.m_Y < m_Corner.m_Y && point.m_Y <= (m_Corner.m_Y + m_Height))); + (m_Width < 0 && point.m_X < m_Corner.m_X && point.m_X >= (m_Corner.m_X + m_Width))) && + (m_Height > 0 && point.m_Y >= m_Corner.m_Y && point.m_Y < (m_Corner.m_Y + m_Height)) || + (m_Height < 0 && point.m_Y < m_Corner.m_Y && point.m_Y <= (m_Corner.m_Y + m_Height))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Box::IsWithinBoxX(float pointX) const { return !IsEmpty() && ((m_Width > 0 && pointX >= m_Corner.m_X && pointX < (m_Corner.m_X + m_Width)) || - (m_Width < 0 && pointX < m_Corner.m_X && pointX >= (m_Corner.m_X + m_Width))); + (m_Width < 0 && pointX < m_Corner.m_X && pointX >= (m_Corner.m_X + m_Width))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Box::IsWithinBoxY(float pointY) const { return !IsEmpty() && ((m_Height > 0 && pointY >= m_Corner.m_Y && pointY < (m_Corner.m_Y + m_Height)) || - (m_Height < 0 && pointY < m_Corner.m_Y && pointY <= (m_Corner.m_Y + m_Height))); + (m_Height < 0 && pointY < m_Corner.m_Y && pointY <= (m_Corner.m_Y + m_Height))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Box::GetWithinBoxX(float pointX) const { if (m_Width > 0) { @@ -129,7 +128,7 @@ namespace RTE { return m_Corner.m_X; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Box::GetWithinBoxY(float pointY) const { if (m_Height > 0) { @@ -140,9 +139,9 @@ namespace RTE { return m_Corner.m_Y; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Box::IntersectsBox(const Box &rhs) { + bool Box::IntersectsBox(const Box& rhs) { if (IsEmpty() || rhs.IsEmpty()) { return false; } @@ -151,6 +150,6 @@ namespace RTE { box1.Unflip(); box2.Unflip(); return (box1.m_Corner.m_X < box2.m_Corner.m_X + box2.m_Width) && (box1.m_Corner.m_X + box1.m_Width > box2.m_Corner.m_X) && - (box1.m_Corner.m_Y < box2.m_Corner.m_Y + box2.m_Height) && (box1.m_Corner.m_Y + box1.m_Height > box2.m_Corner.m_Y); + (box1.m_Corner.m_Y < box2.m_Corner.m_Y + box2.m_Height) && (box1.m_Corner.m_Y + box1.m_Height > box2.m_Corner.m_Y); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Box.h b/Source/System/Box.h index fe6495a84..56d0e82e1 100644 --- a/Source/System/Box.h +++ b/Source/System/Box.h @@ -23,14 +23,15 @@ namespace RTE { /// Y position of the IntRect top left corner. /// X position of the IntRect bottom right corner. /// Y position of the IntRect bottom right corner. - IntRect(int left, int top, int right, int bottom) : m_Left(left), m_Top(top), m_Right(right), m_Bottom(bottom) {} + IntRect(int left, int top, int right, int bottom) : + m_Left(left), m_Top(top), m_Right(right), m_Bottom(bottom) {} /// /// Checks whether this IntRect is intersecting another one. /// /// The other IntRect to check for intersection with. /// Whether this IntRect is intersecting another one. - bool Intersects(const IntRect &rhs) const { return m_Left < rhs.m_Right && m_Right > rhs.m_Left && m_Top < rhs.m_Bottom && m_Bottom > rhs.m_Top; } + bool Intersects(const IntRect& rhs) const { return m_Left < rhs.m_Right && m_Right > rhs.m_Left && m_Top < rhs.m_Bottom && m_Bottom > rhs.m_Top; } /// /// If this and the passed in IntRect intersect, this will be modified to represent the boolean AND of the two. @@ -38,7 +39,7 @@ namespace RTE { /// /// THe other IntRect to cut against. /// Whether an intersection was detected and this was cut down to the AND of the two IntRects. - bool IntersectionCut(const IntRect &rhs); + bool IntersectionCut(const IntRect& rhs); }; /// @@ -47,7 +48,6 @@ namespace RTE { class Box : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -66,7 +66,7 @@ namespace RTE { /// /// Vector position of the upper left corner of this box. /// Vector position of the lower right corner of this box. - Box(const Vector &corner1, const Vector &corner2) { Create(corner1, corner2); } + Box(const Vector& corner1, const Vector& corner2) { Create(corner1, corner2); } /// /// Constructor method used to instantiate a Box object from four float values defining the initial corners of this Box. @@ -84,13 +84,13 @@ namespace RTE { /// Vector position of the upper left corner of this box. /// Width of this box. /// Height of this box. - Box(const Vector &corner, float width, float height) { Create(corner, width, height); } + Box(const Vector& corner, float width, float height) { Create(corner, width, height); } /// /// Copy constructor method used to instantiate a Box object identical to an already existing one. /// /// A Box object which is passed in by reference. - Box(const Box &reference) { Create(reference); } + Box(const Box& reference) { Create(reference); } /// /// Makes the Box object ready for use. @@ -98,7 +98,7 @@ namespace RTE { /// Vector position of the upper left corner of this box. /// Vector position of the lower right corner of this box. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Vector &corner1, const Vector &corner2); + int Create(const Vector& corner1, const Vector& corner2); /// /// Makes the Box object ready for use. @@ -117,14 +117,14 @@ namespace RTE { /// Width of this box. /// Height of this box. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Vector &corner, float width, float height); + int Create(const Vector& corner, float width, float height); /// /// Creates a Box to be identical to another, by deep copy. /// /// A reference to the Box to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Box &reference); + int Create(const Box& reference); #pragma endregion #pragma region Destruction @@ -158,7 +158,7 @@ namespace RTE { /// Sets the primary corner of this box. /// /// A Vector with the new primary corner. - void SetCorner(const Vector &newCorner) { m_Corner = newCorner; } + void SetCorner(const Vector& newCorner) { m_Corner = newCorner; } /// /// Gets the center point of this Box' area, in absolute Scene coordinates. @@ -170,7 +170,7 @@ namespace RTE { /// Sets the primary corner of this box, by specifying where the center ought to be. /// /// A Vector with the new center point. - void SetCenter(const Vector &newCenter) { m_Corner.SetXY(newCenter.m_X - (m_Width / 2), newCenter.m_Y - (m_Height / 2)); } + void SetCenter(const Vector& newCenter) { m_Corner.SetXY(newCenter.m_X - (m_Width / 2), newCenter.m_Y - (m_Height / 2)); } /// /// Gets the width of this box. Note that this can be negative if the box hasn't been righted with Unflip(). @@ -215,14 +215,14 @@ namespace RTE { /// /// The other Box to check for intersection with. /// Intersecting the other box or not. - bool IntersectsBox(const Box &rhs); + bool IntersectsBox(const Box& rhs); /// /// Tells whether a point is within the Box or not, taking potential flipping into account. /// /// The Vector describing the point to test for within box bounds. /// Inside the box or not. False if the box IsEmpty() - bool IsWithinBox(const Vector &point) const; + bool IsWithinBox(const Vector& point) const; /// /// Tells whether an X coordinate is within the Box's X-range or not, taking potential flipping into account. @@ -243,7 +243,7 @@ namespace RTE { /// /// The Vector describing the point to constrain inside the box. /// The resulting point inside the box. - Vector GetWithinBox(const Vector &point) const { return Vector(GetWithinBoxX(point.m_X), GetWithinBoxY(point.m_Y)); } + Vector GetWithinBox(const Vector& point) const { return Vector(GetWithinBoxX(point.m_X), GetWithinBoxY(point.m_Y)); } /// /// Returns an X value constrained inside the Box and returns it. @@ -266,7 +266,12 @@ namespace RTE { /// /// A Box reference. /// A reference to the changed Box. - Box & operator=(const Box &rhs) { if (*this != rhs) { Create(rhs); } return *this; } + Box& operator=(const Box& rhs) { + if (*this != rhs) { + Create(rhs); + } + return *this; + } /// /// An equality operator for testing if any two Boxes are equal. @@ -274,7 +279,7 @@ namespace RTE { /// A Box reference as the left hand side operand. /// A Box reference as the right hand side operand. /// A boolean indicating whether the two operands are equal or not. - friend bool operator==(const Box &lhs, const Box &rhs) { return lhs.m_Corner == rhs.m_Corner && lhs.m_Width == rhs.m_Width && lhs.m_Height == rhs.m_Height; } + friend bool operator==(const Box& lhs, const Box& rhs) { return lhs.m_Corner == rhs.m_Corner && lhs.m_Width == rhs.m_Width && lhs.m_Height == rhs.m_Height; } /// /// An inequality operator for testing if any two Boxes are unequal. @@ -282,17 +287,19 @@ namespace RTE { /// A Box reference as the left hand side operand. /// A Box reference as the right hand side operand. /// A boolean indicating whether the two operands are unequal or not. - friend bool operator!=(const Box &lhs, const Box &rhs) { return lhs.m_Corner != rhs.m_Corner || lhs.m_Width != rhs.m_Width || lhs.m_Height != rhs.m_Height; } + friend bool operator!=(const Box& lhs, const Box& rhs) { return lhs.m_Corner != rhs.m_Corner || lhs.m_Width != rhs.m_Width || lhs.m_Height != rhs.m_Height; } #pragma endregion private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this. /// /// Clears all the member variables of this Box, effectively resetting the members of this abstraction level only. /// - void Clear() { m_Corner.Reset(); m_Width = m_Height = 0; } + void Clear() { + m_Corner.Reset(); + m_Width = m_Height = 0; + } }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Color.cpp b/Source/System/Color.cpp index e9f763f70..bbc334b52 100644 --- a/Source/System/Color.cpp +++ b/Source/System/Color.cpp @@ -5,7 +5,7 @@ namespace RTE { const std::string Color::c_ClassName = "Color"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Color::Create() { if (Serializable::Create()) { @@ -15,7 +15,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Color::Create(int inputR, int inputG, int inputB) { SetR(inputR); @@ -25,11 +25,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Color::ReadProperty(const std::string_view &propName, Reader &reader) { + int Color::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("Index", { SetRGBWithIndex(std::stoi(reader.ReadPropValue())); }); MatchProperty("R", { SetR(std::stoi(reader.ReadPropValue())); }); MatchProperty("G", { SetG(std::stoi(reader.ReadPropValue())); }); @@ -38,9 +38,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Color::Save(Writer &writer) const { + int Color::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("R", m_R); @@ -50,7 +50,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Color::SetRGBWithIndex(int index) { m_Index = std::clamp(index, 0, 255); @@ -64,9 +64,9 @@ namespace RTE { m_B = rgbColor.b * 4; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Color::RecalculateIndex() { return m_Index = makecol8(m_R, m_G, m_B); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Color.h b/Source/System/Color.h index 2a1692fa6..c1e8bd7e4 100644 --- a/Source/System/Color.h +++ b/Source/System/Color.h @@ -11,7 +11,6 @@ namespace RTE { class Color : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -27,19 +26,28 @@ namespace RTE { /// Initial Red value of this color. /// Initial Green value of this color. /// Initial Blue value of this color. - Color(int R, int G, int B) { Clear(); Create(R, G, B); } + Color(int R, int G, int B) { + Clear(); + Create(R, G, B); + } /// /// Constructor method used to instantiate a Color object from an entry in the current color palette. /// /// Palette index entry to create this color from. - Color(int index) { Clear(); SetRGBWithIndex(index); } + Color(int index) { + Clear(); + SetRGBWithIndex(index); + } /// /// Copy constructor method used to instantiate a Color object identical to an already existing one. /// /// A Color object which is passed in by reference. - Color(const Color &reference) { Clear(); Create(reference.m_R, reference.m_G, reference.m_B); } + Color(const Color& reference) { + Clear(); + Create(reference.m_R, reference.m_G, reference.m_B); + } /// /// Makes the Color object ready for use. @@ -87,7 +95,10 @@ namespace RTE { /// Sets the red value of this Color. /// /// An integer value that the R value will be set to, between 0 and 255. - void SetR(int newR) { m_R = std::clamp(newR, 0, 255); m_Index = 0; } + void SetR(int newR) { + m_R = std::clamp(newR, 0, 255); + m_Index = 0; + } /// /// Gets the green value of this Color. @@ -99,7 +110,10 @@ namespace RTE { /// Sets the green value of this Color. /// /// An integer value that the green value will be set to, between 0 and 255. - void SetG(int newG) { m_G = std::clamp(newG, 0, 255); m_Index = 0; } + void SetG(int newG) { + m_G = std::clamp(newG, 0, 255); + m_Index = 0; + } /// /// Gets the blue value of this Color. @@ -111,7 +125,10 @@ namespace RTE { /// Sets the blue value of this Color. /// /// An integer value that the blue value will be set to, between 0 and 255. - void SetB(int newB) { m_B = std::clamp(newB, 0, 255); m_Index = 0; } + void SetB(int newB) { + m_B = std::clamp(newB, 0, 255); + m_Index = 0; + } /// /// Sets all three RGB values of this Color. @@ -119,7 +136,12 @@ namespace RTE { /// Integer value that the Red value will be set to, between 0 and 255. /// Integer value that the Green value will be set to, between 0 and 255. /// Integer value that the Blue value will be set to, between 0 and 255. - void SetRGB(int newR, int newG, int newB) { SetR(newR); SetG(newG); SetB(newB); m_Index = 0; } + void SetRGB(int newR, int newG, int newB) { + SetR(newR); + SetG(newG); + SetB(newB); + m_Index = 0; + } #pragma endregion #pragma region Concrete Methods @@ -131,14 +153,12 @@ namespace RTE { #pragma endregion protected: - int m_R; //!< Red value of this color. int m_G; //!< Green value of this color. int m_B; //!< Blue value of this color. int m_Index; //!< The closest matching index in the current color palette. If 0, this needs to be recalculated and updated. private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this. /// @@ -146,5 +166,5 @@ namespace RTE { /// void Clear() { m_R = m_G = m_B = m_Index = 0; } }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Constants.h b/Source/System/Constants.h index a2416f4c6..0df67bb3a 100644 --- a/Source/System/Constants.h +++ b/Source/System/Constants.h @@ -30,7 +30,7 @@ namespace RTE { #pragma endregion #pragma region AI Constants - static constexpr float c_PathFindingDefaultDigStrength = 35.0F; //!< A default pathfinder penetration value that'll allow pathing through corpses, debris, and such stuff. + static constexpr float c_PathFindingDefaultDigStrength = 35.0F; //!< A default pathfinder penetration value that'll allow pathing through corpses, debris, and such stuff. #pragma endregion #pragma region Graphics Constants @@ -53,9 +53,9 @@ namespace RTE { enum ColorKeys { g_InvalidColor = -1, g_MaskColor = 0, //!< Mask color for all 8bpp bitmaps (palette index 0 (255,0,255)). This color is fully transparent. - //g_MOIDMaskColor = 0, //!< Mask color for 8bpp MOID layer bitmaps (palette index 0 (255,0,255)). This color is fully transparent. + // g_MOIDMaskColor = 0, //!< Mask color for 8bpp MOID layer bitmaps (palette index 0 (255,0,255)). This color is fully transparent. g_MOIDMaskColor = 0xF81F, //!< Mask color for 16bpp MOID layer bitmaps (255,0,255). This color is fully transparent. - //g_MOIDMaskColor = 0xFF00FF, //!< Mask color for 32bpp MOID layer bitmaps (255,0,255). This color is fully transparent. + // g_MOIDMaskColor = 0xFF00FF, //!< Mask color for 32bpp MOID layer bitmaps (255,0,255). This color is fully transparent. g_BlackColor = 245, g_WhiteColor = 254, g_RedColor = 13, @@ -75,7 +75,12 @@ namespace RTE { g_MaterialDoor = 181 }; - enum DotGlowColor { NoDot, YellowDot, RedDot, BlueDot }; + enum DotGlowColor { + NoDot, + YellowDot, + RedDot, + BlueDot + }; enum DrawBlendMode { NoBlend, @@ -93,9 +98,16 @@ namespace RTE { BlendModeCount }; - enum BlendAmountLimits { MinBlend = 0, MaxBlend = 100 }; + enum BlendAmountLimits { + MinBlend = 0, + MaxBlend = 100 + }; - enum TransparencyPreset { LessTrans = 25, HalfTrans = 50, MoreTrans = 75 }; + enum TransparencyPreset { + LessTrans = 25, + HalfTrans = 50, + MoreTrans = 75 + }; enum SpriteAnimMode { NOANIM, @@ -110,25 +122,25 @@ namespace RTE { SpriteAnimModeCount }; - // GUI colors - #define c_GUIColorWhite makecol(255, 255, 255) - #define c_GUIColorYellow makecol(255, 255, 128) - #define c_GUIColorRed makecol(255, 100, 100) - #define c_GUIColorGreen makecol(128, 255, 128) - #define c_GUIColorCyan makecol(127, 255, 255) - #define c_GUIColorLightBlue makecol(109, 117, 170) - #define c_GUIColorBlue makecol(59, 65, 83) - #define c_GUIColorDarkBlue makecol(12, 20, 39) - #define c_GUIColorGray makecol(232, 232, 248) - - #define c_PlayerSlotColorDefault makecol(161, 109, 20) - #define c_PlayerSlotColorHovered makecol(203, 130, 56) - #define c_PlayerSlotColorDisabled makecol(104, 67, 15) - static constexpr std::array c_Quad { - 1.0f, 1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 1.0f, 1.0f, - -1.0f, 1.0f, 0.0f, 0.0f, - -1.0f, -1.0f, 0.0f, 1.0f}; +// GUI colors +#define c_GUIColorWhite makecol(255, 255, 255) +#define c_GUIColorYellow makecol(255, 255, 128) +#define c_GUIColorRed makecol(255, 100, 100) +#define c_GUIColorGreen makecol(128, 255, 128) +#define c_GUIColorCyan makecol(127, 255, 255) +#define c_GUIColorLightBlue makecol(109, 117, 170) +#define c_GUIColorBlue makecol(59, 65, 83) +#define c_GUIColorDarkBlue makecol(12, 20, 39) +#define c_GUIColorGray makecol(232, 232, 248) + +#define c_PlayerSlotColorDefault makecol(161, 109, 20) +#define c_PlayerSlotColorHovered makecol(203, 130, 56) +#define c_PlayerSlotColorDisabled makecol(104, 67, 15) + static constexpr std::array c_Quad{ + 1.0f, 1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 0.0f, + -1.0f, -1.0f, 0.0f, 1.0f}; #pragma endregion #pragma region Math Constants @@ -142,7 +154,7 @@ namespace RTE { #pragma endregion #pragma region Audio Constants - static constexpr std::array c_SupportedAudioFormats = { ".wav", ".ogg", ".flac" }; + static constexpr std::array c_SupportedAudioFormats = {".wav", ".ogg", ".flac"}; static constexpr unsigned short c_MaxSoftwareChannels = 128; static constexpr unsigned short c_MaxVirtualChannels = 1024; @@ -217,33 +229,33 @@ namespace RTE { }; static const std::array c_InputElementNames = { - "Move Up", // INPUT_L_UP - "Move Down", // INPUT_L_DOWN - "Move Left", // INPUT_L_LEFT - "Move Right", // INPUT_L_RIGHT - "Aim Up", // INPUT_AIM_UP - "Aim Down", // INPUT_AIM_DOWN - "Aim Left", // INPUT_AIM_LEFT - "Aim Right", // INPUT_AIM_RIGHT - "Fire/Activate", // INPUT_FIRE - "Sharp Aim", // INPUT_AIM - "Pie Menu Analog", // INPUT_PIEMENU_ANALOG - "Pie Menu Digital", // INPUT_PIEMENU_DIGITAL - "Jump", // INPUT_JUMP - "Crouch", // INPUT_CROUCH - "Next Body", // INPUT_NEXT - "Prev. Body", // INPUT_PREV - "Next Device", // INPUT_WEAPON_CHANGE_NEXT - "Prev. Device", // INPUT_WEAPON_CHANGE_PREV - "Pick Up Device", // INPUT_WEAPON_PICKUP - "Drop Device", // INPUT_WEAPON_DROP - "Reload Weapon", // INPUT_WEAPON_RELOAD - "Start", // INPUT_START - "Back", // INPUT_BACK - "Analog Aim Up", // INPUT_R_UP - "Analog Aim Down", // INPUT_R_DOWN - "Analog Aim Left", // INPUT_R_LEFT - "Analog Aim Right" // INPUT_R_RIGHT + "Move Up", // INPUT_L_UP + "Move Down", // INPUT_L_DOWN + "Move Left", // INPUT_L_LEFT + "Move Right", // INPUT_L_RIGHT + "Aim Up", // INPUT_AIM_UP + "Aim Down", // INPUT_AIM_DOWN + "Aim Left", // INPUT_AIM_LEFT + "Aim Right", // INPUT_AIM_RIGHT + "Fire/Activate", // INPUT_FIRE + "Sharp Aim", // INPUT_AIM + "Pie Menu Analog", // INPUT_PIEMENU_ANALOG + "Pie Menu Digital", // INPUT_PIEMENU_DIGITAL + "Jump", // INPUT_JUMP + "Crouch", // INPUT_CROUCH + "Next Body", // INPUT_NEXT + "Prev. Body", // INPUT_PREV + "Next Device", // INPUT_WEAPON_CHANGE_NEXT + "Prev. Device", // INPUT_WEAPON_CHANGE_PREV + "Pick Up Device", // INPUT_WEAPON_PICKUP + "Drop Device", // INPUT_WEAPON_DROP + "Reload Weapon", // INPUT_WEAPON_RELOAD + "Start", // INPUT_START + "Back", // INPUT_BACK + "Analog Aim Up", // INPUT_R_UP + "Analog Aim Down", // INPUT_R_DOWN + "Analog Aim Left", // INPUT_R_LEFT + "Analog Aim Right" // INPUT_R_RIGHT }; /// @@ -289,14 +301,20 @@ namespace RTE { /// /// Enumeration for joystick direction types. /// - enum JoyDirections { JOYDIR_ONE = 0, JOYDIR_TWO }; + enum JoyDirections { + JOYDIR_ONE = 0, + JOYDIR_TWO + }; /// /// Enumeration for joystick dead zone types. /// Square deadzone cuts-off any input from every axis separately. For example if x-axis has less than 20% input and y-axis has more, x-axis input is ignored. /// Circle uses a round zone to capture stick position on both axis then cut-off if this position is inside the round dead zone. /// - enum DeadZoneType { CIRCLE = 0, SQUARE = 1 }; + enum DeadZoneType { + CIRCLE = 0, + SQUARE = 1 + }; #pragma endregion #pragma region Global Enumerations @@ -315,38 +333,43 @@ namespace RTE { /// /// Enumeration and supporting maps for cardinal directions, as well as None and Any. /// - enum Directions { None = -1, Up, Down, Left, Right, Any }; + enum Directions { + None = -1, + Up, + Down, + Left, + Right, + Any + }; static const std::unordered_map c_DirectionNameToDirectionsMap = { - {"None", Directions::None}, - {"Up", Directions::Up}, - {"Down", Directions::Down}, - {"Left", Directions::Left}, - {"Right", Directions::Right}, - {"Any", Directions::Any} - }; + {"None", Directions::None}, + {"Up", Directions::Up}, + {"Down", Directions::Down}, + {"Left", Directions::Left}, + {"Right", Directions::Right}, + {"Any", Directions::Any}}; static const std::unordered_map c_DirectionsToRadiansMap = { - {Directions::Up, c_HalfPI}, - {Directions::Down, c_OneAndAHalfPI}, - {Directions::Left, c_PI}, - {Directions::Right, 0.0F} - }; + {Directions::Up, c_HalfPI}, + {Directions::Down, c_OneAndAHalfPI}, + {Directions::Left, c_PI}, + {Directions::Right, 0.0F}}; #pragma endregion -#pragma region Un-Definitions - // Allegro defines these via define in astdint.h and Boost with stdlib go crazy so we need to undefine them manually. - #undef int8_t - #undef uint8_t - #undef int16_t - #undef uint16_t - #undef int32_t - #undef uint32_t - #undef intptr_t - #undef uintptr_t - #undef LONG_LONG - #undef int64_t - #undef uint64_t +#pragma region Un - Definitions +// Allegro defines these via define in astdint.h and Boost with stdlib go crazy so we need to undefine them manually. +#undef int8_t +#undef uint8_t +#undef int16_t +#undef uint16_t +#undef int32_t +#undef uint32_t +#undef intptr_t +#undef uintptr_t +#undef LONG_LONG +#undef int64_t +#undef uint64_t #pragma endregion -} +} // namespace RTE #endif diff --git a/Source/System/ContentFile.cpp b/Source/System/ContentFile.cpp index f4552e20e..24de53ba5 100644 --- a/Source/System/ContentFile.cpp +++ b/Source/System/ContentFile.cpp @@ -13,11 +13,11 @@ namespace RTE { const std::string ContentFile::c_ClassName = "ContentFile"; - std::array, ContentFile::BitDepths::BitDepthCount> ContentFile::s_LoadedBitmaps; - std::unordered_map ContentFile::s_LoadedSamples; + std::array, ContentFile::BitDepths::BitDepthCount> ContentFile::s_LoadedBitmaps; + std::unordered_map ContentFile::s_LoadedSamples; std::unordered_map ContentFile::s_PathHashes; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ContentFile::Clear() { m_DataPath.clear(); @@ -31,17 +31,17 @@ namespace RTE { m_ImageFileInfo.fill(-1); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ContentFile::Create(const char *filePath) { + int ContentFile::Create(const char* filePath) { SetDataPath(filePath); return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ContentFile::Create(const ContentFile &reference) { + int ContentFile::Create(const ContentFile& reference) { m_DataPath = reference.m_DataPath; m_DataPathExtension = reference.m_DataPathExtension; m_DataPathWithoutExtension = reference.m_DataPathWithoutExtension; @@ -50,46 +50,47 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ContentFile::FreeAllLoaded() { for (int depth = BitDepths::Eight; depth < BitDepths::BitDepthCount; ++depth) { - for (const auto &[bitmapPath, bitmapPtr] : s_LoadedBitmaps[depth]) { + for (const auto& [bitmapPath, bitmapPtr]: s_LoadedBitmaps[depth]) { destroy_bitmap(bitmapPtr); } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ContentFile::ReadProperty(const std::string_view &propName, Reader &reader) { + int ContentFile::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchForwards("FilePath") MatchProperty("Path", { SetDataPath(reader.ReadPropValue()); }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int ContentFile::Save(Writer &writer) const { + int ContentFile::Save(Writer& writer) const { Serializable::Save(writer); - if (!m_DataPath.empty()) { writer.NewPropertyWithValue("FilePath", m_DataPath); } + if (!m_DataPath.empty()) { + writer.NewPropertyWithValue("FilePath", m_DataPath); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int ContentFile::GetDataModuleID() const { return (m_DataModuleID < 0) ? g_PresetMan.GetModuleIDFromPath(m_DataPath) : m_DataModuleID; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ContentFile::SetDataPath(const std::string &newDataPath) { + void ContentFile::SetDataPath(const std::string& newDataPath) { m_DataPath = g_PresetMan.GetFullModulePath(newDataPath); m_DataPathExtension = std::filesystem::path(m_DataPath).extension().string(); @@ -102,31 +103,31 @@ namespace RTE { m_DataModuleID = g_PresetMan.GetModuleIDFromPath(m_DataPath); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// size_t ContentFile::GetHash() const { return Hash(m_DataPath); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ContentFile::SetFormattedReaderPosition(const std::string &newPosition) { + void ContentFile::SetFormattedReaderPosition(const std::string& newPosition) { m_FormattedReaderPosition = newPosition; m_DataPathAndReaderPosition = m_DataPath + "\n" + newPosition; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int ContentFile::GetImageFileInfo(ImageFileInfoType infoTypeToGet) { bool fetchFileInfo = false; - for (const int &fileInfoEntry : m_ImageFileInfo) { + for (const int& fileInfoEntry: m_ImageFileInfo) { if (fileInfoEntry == -1) { fetchFileInfo = true; break; } } if (fetchFileInfo) { - FILE *imageFile = fopen(m_DataPath.c_str(), "rb"); + FILE* imageFile = fopen(m_DataPath.c_str(), "rb"); RTEAssert(imageFile, "Failed to open file prior to reading info of image file with following path and name:\n\n" + m_DataPath + "\n\nThe file may not exist or be corrupt."); if (m_DataPathExtension == ".png") { @@ -141,9 +142,9 @@ namespace RTE { return m_ImageFileInfo[infoTypeToGet]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ContentFile::ReadAndStorePNGFileInfo(FILE *imageFile) { + void ContentFile::ReadAndStorePNGFileInfo(FILE* imageFile) { std::array fileSignature = {}; // Read the first 8 bytes to then verify they match the PNG file signature which is { 137, 80, 78, 71, 13, 10, 26, 10 } or { '\211', 'P', 'N', 'G', '\r', '\n', '\032', '\n' }. @@ -167,10 +168,10 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ContentFile::ReadAndStoreBMPFileInfo(FILE *imageFile) { - std::array bmpSignature = { 0x42, 0x4D }; // { 'B', 'M' }. + void ContentFile::ReadAndStoreBMPFileInfo(FILE* imageFile) { + std::array bmpSignature = {0x42, 0x4D}; // { 'B', 'M' }. std::array fileSignature = {}; // Read the first 2 bytes to then verify they match the BMP file signature. @@ -202,24 +203,24 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ContentFile::ReloadAllBitmaps() { - for (const std::unordered_map &bitmapCache : s_LoadedBitmaps) { - for (const auto &[filePath, oldBitmap] : bitmapCache) { + for (const std::unordered_map& bitmapCache: s_LoadedBitmaps) { + for (const auto& [filePath, oldBitmap]: bitmapCache) { ReloadBitmap(filePath); } } g_ConsoleMan.PrintString("SYSTEM: Sprites reloaded"); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BITMAP * ContentFile::GetAsBitmap(int conversionMode, bool storeBitmap, const std::string &dataPathToSpecificFrame) { + BITMAP* ContentFile::GetAsBitmap(int conversionMode, bool storeBitmap, const std::string& dataPathToSpecificFrame) { if (m_DataPath.empty()) { return nullptr; } - BITMAP *returnBitmap = nullptr; + BITMAP* returnBitmap = nullptr; const int bitDepth = conversionMode == COLORCONV_8_TO_32 ? BitDepths::ThirtyTwo : BitDepths::Eight; std::string dataPathToLoad = dataPathToSpecificFrame.empty() ? m_DataPath : dataPathToSpecificFrame; @@ -228,7 +229,7 @@ namespace RTE { } // Check if the file has already been read and loaded from the disk and, if so, use that data. - std::unordered_map::iterator foundBitmap = s_LoadedBitmaps[bitDepth].find(dataPathToLoad); + std::unordered_map::iterator foundBitmap = s_LoadedBitmaps[bitDepth].find(dataPathToLoad); if (storeBitmap && foundBitmap != s_LoadedBitmaps[bitDepth].end()) { returnBitmap = (*foundBitmap).second; } else { @@ -247,14 +248,16 @@ namespace RTE { returnBitmap = LoadAndReleaseBitmap(conversionMode, dataPathToLoad); // NOTE: This takes ownership of the bitmap file // Insert the bitmap into the map, PASSING OVER OWNERSHIP OF THE LOADED DATAFILE - if (storeBitmap) { s_LoadedBitmaps[bitDepth].try_emplace(dataPathToLoad, returnBitmap); } + if (storeBitmap) { + s_LoadedBitmaps[bitDepth].try_emplace(dataPathToLoad, returnBitmap); + } } return returnBitmap; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ContentFile::GetAsAnimation(std::vector &vectorToFill, int frameCount, int conversionMode) { + void ContentFile::GetAsAnimation(std::vector& vectorToFill, int frameCount, int conversionMode) { if (m_DataPath.empty() || frameCount < 1) { return; } @@ -282,15 +285,15 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BITMAP * ContentFile::LoadAndReleaseBitmap(int conversionMode, const std::string &dataPathToSpecificFrame) { + BITMAP* ContentFile::LoadAndReleaseBitmap(int conversionMode, const std::string& dataPathToSpecificFrame) { if (m_DataPath.empty()) { return nullptr; } const std::string dataPathToLoad = dataPathToSpecificFrame.empty() ? m_DataPath : dataPathToSpecificFrame; - BITMAP *returnBitmap = nullptr; + BITMAP* returnBitmap = nullptr; PALETTE currentPalette; get_palette(currentPalette); @@ -303,19 +306,19 @@ namespace RTE { return returnBitmap; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - FMOD::Sound * ContentFile::GetAsSound(bool abortGameForInvalidSound, bool asyncLoading) { + FMOD::Sound* ContentFile::GetAsSound(bool abortGameForInvalidSound, bool asyncLoading) { if (m_DataPath.empty() || !g_AudioMan.IsAudioEnabled()) { return nullptr; } - FMOD::Sound *returnSample = nullptr; + FMOD::Sound* returnSample = nullptr; - std::unordered_map::iterator foundSound = s_LoadedSamples.find(m_DataPath); + std::unordered_map::iterator foundSound = s_LoadedSamples.find(m_DataPath); if (foundSound != s_LoadedSamples.end()) { returnSample = (*foundSound).second; } else { - returnSample = LoadAndReleaseSound(abortGameForInvalidSound, asyncLoading); //NOTE: This takes ownership of the sample file + returnSample = LoadAndReleaseSound(abortGameForInvalidSound, asyncLoading); // NOTE: This takes ownership of the sample file // Insert the Sound object into the map, PASSING OVER OWNERSHIP OF THE LOADED FILE s_LoadedSamples.try_emplace(m_DataPath, returnSample); @@ -323,15 +326,15 @@ namespace RTE { return returnSample; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - FMOD::Sound * ContentFile::LoadAndReleaseSound(bool abortGameForInvalidSound, bool asyncLoading) { + FMOD::Sound* ContentFile::LoadAndReleaseSound(bool abortGameForInvalidSound, bool asyncLoading) { if (m_DataPath.empty() || !g_AudioMan.IsAudioEnabled()) { return nullptr; } if (!System::PathExistsCaseSensitive(m_DataPath)) { bool foundAltExtension = false; - for (const std::string &altFileExtension : c_SupportedAudioFormats) { + for (const std::string& altFileExtension: c_SupportedAudioFormats) { const std::string altDataPathToLoad = m_DataPathWithoutExtension + altFileExtension; if (System::PathExistsCaseSensitive(altDataPathToLoad)) { g_ConsoleMan.AddLoadWarningLogExtensionMismatchEntry(m_DataPath, m_FormattedReaderPosition, altFileExtension); @@ -353,7 +356,7 @@ namespace RTE { g_ConsoleMan.PrintString("ERROR: " + errorMessage + m_DataPath); return nullptr; } - FMOD::Sound *returnSample = nullptr; + FMOD::Sound* returnSample = nullptr; FMOD_MODE fmodFlags = FMOD_CREATESAMPLE | FMOD_3D | (asyncLoading ? FMOD_NONBLOCKING : FMOD_DEFAULT); FMOD_RESULT result = g_AudioMan.GetAudioSystem()->createSound(m_DataPath.c_str(), fmodFlags, nullptr, &returnSample); @@ -367,9 +370,9 @@ namespace RTE { return returnSample; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ContentFile::ReloadBitmap(const std::string &filePath, int conversionMode) { + void ContentFile::ReloadBitmap(const std::string& filePath, int conversionMode) { const int bitDepth = (conversionMode == COLORCONV_8_TO_32) ? BitDepths::ThirtyTwo : BitDepths::Eight; auto bmpItr = s_LoadedBitmaps[bitDepth].find(filePath); @@ -381,8 +384,8 @@ namespace RTE { get_palette(currentPalette); set_color_conversion((conversionMode == COLORCONV_NONE) ? COLORCONV_MOST : conversionMode); - BITMAP *loadedBitmap = (*bmpItr).second; - BITMAP *newBitmap = load_bitmap(filePath.c_str(), currentPalette); + BITMAP* loadedBitmap = (*bmpItr).second; + BITMAP* newBitmap = load_bitmap(filePath.c_str(), currentPalette); AddAlphaChannel(newBitmap); BITMAP swap; @@ -393,7 +396,7 @@ namespace RTE { destroy_bitmap(newBitmap); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ContentFile::AddAlphaChannel(BITMAP* bitmap) { if (!bitmap) { @@ -406,9 +409,9 @@ namespace RTE { for (int x = 0; x < bitmap->w; ++x) { unsigned long color = _getpixel32(bitmap, x, y); if (color != MASK_COLOR_32) { - _putpixel32(bitmap, x, y, color|(0xFF << 24)); + _putpixel32(bitmap, x, y, color | (0xFF << 24)); } } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/ContentFile.h b/Source/System/ContentFile.h index a0503ea47..89331690d 100644 --- a/Source/System/ContentFile.h +++ b/Source/System/ContentFile.h @@ -3,7 +3,9 @@ #include "Serializable.h" -namespace FMOD { class Sound; } +namespace FMOD { + class Sound; +} struct BITMAP; namespace RTE { @@ -14,7 +16,6 @@ namespace RTE { class ContentFile : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -28,27 +29,33 @@ namespace RTE { /// Constructor method used to instantiate a ContentFile object in system memory, and also do a Create() in the same line. /// /// A string defining the path to where the content file itself is located. - explicit ContentFile(const char *filePath) { Clear(); Create(filePath); } + explicit ContentFile(const char* filePath) { + Clear(); + Create(filePath); + } /// /// Constructor method used to instantiate a ContentFile object in system memory from a hash value of the file path, and also do a Create() in the same line. /// /// A hash value containing the path to where the content file itself is located. - explicit ContentFile(size_t hash) { Clear(); Create(GetPathFromHash(hash).c_str()); } + explicit ContentFile(size_t hash) { + Clear(); + Create(GetPathFromHash(hash).c_str()); + } /// /// Makes the ContentFile object ready for use. /// /// A string defining the path to where the content file itself is located. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const char *filePath); + int Create(const char* filePath); /// /// Creates a ContentFile to be identical to another, by deep copy. /// /// A reference to the ContentFile to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const ContentFile &reference); + int Create(const ContentFile& reference); #pragma endregion #pragma region Destruction @@ -79,13 +86,13 @@ namespace RTE { /// Gets the file path of the content file represented by this ContentFile object. /// /// A string with the file name path. - const std::string & GetDataPath() const { return m_DataPath; } + const std::string& GetDataPath() const { return m_DataPath; } /// /// Sets the file path of the content file represented by this ContentFile object. /// /// A string with the new file name path. - void SetDataPath(const std::string &newDataPath); + void SetDataPath(const std::string& newDataPath); /// /// Creates a hash value out of a path to a ContentFile. @@ -106,13 +113,13 @@ namespace RTE { /// Gets the file and line that are currently being read. Formatted to be used for logging warnings and errors. /// /// A string containing the currently read file path and the line being read. - const std::string & GetFormattedReaderPosition() const { return m_FormattedReaderPosition; } + const std::string& GetFormattedReaderPosition() const { return m_FormattedReaderPosition; } /// /// Sets the file and line that are currently being read. Formatted to be used for logging warnings and errors. /// /// A string containing the currently read file path and the line being read. - void SetFormattedReaderPosition(const std::string &newPosition) override; + void SetFormattedReaderPosition(const std::string& newPosition) override; #pragma endregion #pragma region Image Info Getters @@ -154,7 +161,7 @@ namespace RTE { /// Whether to store the BITMAP in the relevant static map after loading it or not. If this is false, ownership of the BITMAP IS transferred! /// Path to a specific frame when loading an animation to avoid overwriting the original preset DataPath when loading each frame. /// Pointer to the BITMAP loaded from disk. - BITMAP * GetAsBitmap(int conversionMode = 0, bool storeBitmap = true, const std::string &dataPathToSpecificFrame = ""); + BITMAP* GetAsBitmap(int conversionMode = 0, bool storeBitmap = true, const std::string& dataPathToSpecificFrame = ""); /// /// Fills an existing vector of Allegro BITMAPs representing each frame in the animation with the data represented by this ContentFile object. @@ -163,7 +170,7 @@ namespace RTE { /// The existing vector of Allegro BITMAPs to fill. /// The number of frames to attempt to load, more than 1 frame will mean 00# is appended to DataPath to handle naming conventions. /// The Allegro color conversion mode to use when loading this bitmap. - void GetAsAnimation(std::vector &vectorToFill, int frameCount = 1, int conversionMode = 0); + void GetAsAnimation(std::vector& vectorToFill, int frameCount = 1, int conversionMode = 0); /// /// Gets the data represented by this ContentFile object as a vector of Allegro BITMAPs, each representing a frame in the animation. @@ -172,7 +179,11 @@ namespace RTE { /// The number of frames to attempt to load, more than 1 frame will mean 00# is appended to DataPath to handle naming conventions. /// The Allegro color conversion mode to use when loading this bitmap. /// A vector of BITMAP pointers loaded from the disk. - std::vector GetAsAnimation(int frameCount = 1, int conversionMode = 0) { std::vector returnBitmaps; GetAsAnimation(returnBitmaps, frameCount, conversionMode); return returnBitmaps; } + std::vector GetAsAnimation(int frameCount = 1, int conversionMode = 0) { + std::vector returnBitmaps; + GetAsAnimation(returnBitmaps, frameCount, conversionMode); + return returnBitmaps; + } /// /// Gets the data represented by this ContentFile object as an FMOD FSOUND_SAMPLE, loading it into the static maps if it's not already loaded. Ownership of the FSOUND_SAMPLE is NOT transferred! @@ -180,26 +191,34 @@ namespace RTE { /// Whether to abort the game if the sound couldn't be added, or just show a console error. Default true. /// Whether to enable FMOD asynchronous loading or not. Should be disabled for loading audio files with Lua AddSound. /// Pointer to the FSOUND_SAMPLE loaded from disk. - FMOD::Sound * GetAsSound(bool abortGameForInvalidSound = true, bool asyncLoading = true); + FMOD::Sound* GetAsSound(bool abortGameForInvalidSound = true, bool asyncLoading = true); #pragma endregion private: - /// /// Enumeration for loading BITMAPs by bit depth. NOTE: This can't be lower down because s_LoadedBitmaps relies on this definition. /// - enum BitDepths { Eight = 0, ThirtyTwo, BitDepthCount }; + enum BitDepths { + Eight = 0, + ThirtyTwo, + BitDepthCount + }; /// /// Enumeration for the image file information types that can be stored. /// - enum ImageFileInfoType { ImageBitDepth, ImageWidth, ImageHeight, ImageInfoTypeCount }; + enum ImageFileInfoType { + ImageBitDepth, + ImageWidth, + ImageHeight, + ImageInfoTypeCount + }; static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. static std::unordered_map s_PathHashes; //!< Static map containing the hash values of paths of all loaded data files. - static std::array, BitDepths::BitDepthCount> s_LoadedBitmaps; //!< Static map containing all the already loaded BITMAPs and their paths for each bit depth. - static std::unordered_map s_LoadedSamples; //!< Static map containing all the already loaded FSOUND_SAMPLEs and their paths. + static std::array, BitDepths::BitDepthCount> s_LoadedBitmaps; //!< Static map containing all the already loaded BITMAPs and their paths for each bit depth. + static std::unordered_map s_LoadedSamples; //!< Static map containing all the already loaded FSOUND_SAMPLEs and their paths. std::string m_DataPath; //!< The path to this ContentFile's data file. In the case of an animation, this filename/name will be appended with 000, 001, 002 etc. std::string m_DataPathExtension; //!< The extension of the data file of this ContentFile's path. @@ -225,13 +244,13 @@ namespace RTE { /// Reads a PNG file from disk and stores the relevant information without actually loading the whole file into memory. /// /// Pointer to the file stream to read. - void ReadAndStorePNGFileInfo(FILE *imageFile); + void ReadAndStorePNGFileInfo(FILE* imageFile); /// /// Reads a BMP file from disk and stores the relevant information without actually loading the whole file into memory. /// /// Pointer to the file stream to read. - void ReadAndStoreBMPFileInfo(FILE *imageFile); + void ReadAndStoreBMPFileInfo(FILE* imageFile); #pragma endregion #pragma region Data Handling @@ -242,7 +261,7 @@ namespace RTE { /// The Allegro color conversion mode to use when loading this bitmap. Only applies the first time a bitmap is loaded from the disk. /// Path to a specific frame when loading an animation to avoid overwriting the original preset DataPath when loading each frame. /// Pointer to the BITMAP loaded from disk. - BITMAP * LoadAndReleaseBitmap(int conversionMode = 0, const std::string &dataPathToSpecificFrame = ""); + BITMAP* LoadAndReleaseBitmap(int conversionMode = 0, const std::string& dataPathToSpecificFrame = ""); /// /// Loads and transfers the data represented by this ContentFile object as an FMOD FSOUND_SAMPLE. Ownership of the FSOUND_SAMPLE is NOT transferred! @@ -250,14 +269,14 @@ namespace RTE { /// Whether to abort the game if the sound couldn't be added, or just show a console error. Default true. /// Whether to enable FMOD asynchronous loading or not. Should be disabled for loading audio files with Lua AddSound. /// Pointer to the FSOUND_SAMPLE loaded from disk. - FMOD::Sound * LoadAndReleaseSound(bool abortGameForInvalidSound = true, bool asyncLoading = true); + FMOD::Sound* LoadAndReleaseSound(bool abortGameForInvalidSound = true, bool asyncLoading = true); /// /// Reloads a specific BITMAP in the cache from disk, allowing any changes to be reflected at runtime. /// /// The filepath to the bitmap we want to reload. /// The Allegro color conversion mode to use when reloading this bitmap. - static void ReloadBitmap(const std::string &filePath, int conversionMode = 0); + static void ReloadBitmap(const std::string& filePath, int conversionMode = 0); /// /// Set alpha value of non mask color pixels to 255 for 32-bit bitmaps. (WARN: would override existing alpha values!) @@ -270,5 +289,5 @@ namespace RTE { /// void Clear(); }; -} +} // namespace RTE #endif diff --git a/Source/System/Controller.cpp b/Source/System/Controller.cpp index fad7b95f3..fad67c450 100644 --- a/Source/System/Controller.cpp +++ b/Source/System/Controller.cpp @@ -7,7 +7,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Controller::Clear() { m_ControlStates.fill(false); @@ -28,25 +28,27 @@ namespace RTE { m_WeaponDropIgnore = false; m_WeaponReloadIgnore = false; m_MouseMovement.Reset(); - m_AnalogCursorAngleLimits = { {0, 0}, false }; + m_AnalogCursorAngleLimits = {{0, 0}, false}; m_ReleaseTimer.Reset(); m_JoyAccelTimer.Reset(); m_KeyAccelTimer.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Controller::Create(InputMode mode, Actor *controlledActor) { + int Controller::Create(InputMode mode, Actor* controlledActor) { m_InputMode = mode; m_ControlledActor = controlledActor; - if (m_ControlledActor) { m_Team = m_ControlledActor->GetTeam(); } + if (m_ControlledActor) { + m_Team = m_ControlledActor->GetTeam(); + } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Controller::Create(const Controller &reference) { + int Controller::Create(const Controller& reference) { for (int i = 0; i < ControlState::CONTROLSTATECOUNT; ++i) { m_ControlStates[i] = reference.m_ControlStates[i]; } @@ -70,9 +72,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Controller::RelativeCursorMovement(Vector &cursorPos, float moveScale) const { + bool Controller::RelativeCursorMovement(Vector& cursorPos, float moveScale) const { bool altered = false; // Try the mouse first for analog input @@ -80,14 +82,14 @@ namespace RTE { cursorPos += GetMouseMovement() * moveScale; altered = true; - // See if there's other analog input, only if the mouse isn't active (or the cursor will float if mouse is used!) + // See if there's other analog input, only if the mouse isn't active (or the cursor will float if mouse is used!) } else if (GetAnalogCursor().GetLargest() > 0.1F && !IsMouseControlled()) { // See how much to accelerate the joystick input based on how long the stick has been pushed around float acceleration = static_cast(0.5 + std::min(m_JoyAccelTimer.GetElapsedRealTimeS(), 0.5) * 6); cursorPos += GetAnalogCursor() * 10 * moveScale * acceleration; altered = true; - // Digital movement + // Digital movement } else { // See how much to accelerate the keyboard input based on how long any key has been pressed float acceleration = static_cast(0.25 + std::min(m_KeyAccelTimer.GetElapsedRealTimeS(), 0.75) * 6); @@ -112,25 +114,25 @@ namespace RTE { return altered; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Controller::GetDigitalAimSpeed() const { return m_Player != Players::NoPlayer ? g_UInputMan.GetControlScheme(m_Player)->GetDigitalAimSpeed() : 1.0F; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Controller::IsMouseControlled() const { return m_Player != Players::NoPlayer && g_UInputMan.GetControlScheme(m_Player)->GetDevice() == InputDevice::DEVICE_MOUSE_KEYB; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Controller::IsKeyboardOnlyControlled() const { return m_Player != Players::NoPlayer && g_UInputMan.GetControlScheme(m_Player)->GetDevice() == InputDevice::DEVICE_KEYB_ONLY; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Controller::IsGamepadControlled() const { bool isGamepadControlled = false; @@ -143,27 +145,29 @@ namespace RTE { return isGamepadControlled; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Controller::GetTeam() const { return m_ControlledActor ? m_ControlledActor->GetTeam() : m_Team; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Controller::SetTeam(short team) { - if (m_ControlledActor) { m_ControlledActor->SetTeam(team); } + if (m_ControlledActor) { + m_ControlledActor->SetTeam(team); + } m_Team = team; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Controller::Update() { if (IsDisabled()) { return; } - if (m_ControlledActor) { + if (m_ControlledActor) { m_Team = m_ControlledActor->GetTeam(); if (m_ControlledActor->GetHealth() == 0.0f || m_ControlledActor->GetStatus() == Actor::DYING || m_ControlledActor->GetStatus() == Actor::DEAD) { @@ -187,7 +191,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Controller::ResetCommandState() { // Reset all command states. @@ -198,7 +202,7 @@ namespace RTE { m_MouseMovement.Reset(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Controller::GetInputFromPlayer() { ResetCommandState(); @@ -210,10 +214,9 @@ namespace RTE { UpdatePlayerInput(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Controller::ShouldUpdateAIThisFrame() const - { + bool Controller::ShouldUpdateAIThisFrame() const { if (IsDisabled() || m_InputMode != InputMode::CIM_AI) { return false; } @@ -228,9 +231,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Controller & Controller::operator=(const Controller &rhs) { + Controller& Controller::operator=(const Controller& rhs) { if (this == &rhs) { return *this; } @@ -239,15 +242,14 @@ namespace RTE { return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Controller::Override(const Controller &otherController) - { + void Controller::Override(const Controller& otherController) { RTEAssert(otherController.m_ControlledActor == m_ControlledActor, "Overriding a controller with a mismatched controlled actor!"); *this = otherController; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Controller::UpdatePlayerInput() { UpdatePlayerPieMenuInput(); @@ -255,17 +257,21 @@ namespace RTE { // Only actually switch when the change button(s) are released // BRAIN ACTOR if ((g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_NEXT) && g_UInputMan.ElementPressed(m_Player, InputElements::INPUT_PREV)) || - (g_UInputMan.ElementPressed(m_Player, InputElements::INPUT_NEXT) && g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_PREV))) { + (g_UInputMan.ElementPressed(m_Player, InputElements::INPUT_NEXT) && g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_PREV))) { m_ControlStates[ControlState::ACTOR_BRAIN] = true; // Ignore the next releases of next and previous buttons so that the brain isn't switched away form immediate after using the brain shortcut m_NextIgnore = m_PrevIgnore = true; - // NEXT ACTOR + // NEXT ACTOR } else if (g_UInputMan.ElementReleased(m_Player, InputElements::INPUT_NEXT)) { - if (!m_NextIgnore) { m_ControlStates[ControlState::ACTOR_NEXT] = true; } + if (!m_NextIgnore) { + m_ControlStates[ControlState::ACTOR_NEXT] = true; + } m_NextIgnore = false; - // PREV ACTOR + // PREV ACTOR } else if (g_UInputMan.ElementReleased(m_Player, InputElements::INPUT_PREV)) { - if (!m_PrevIgnore) { m_ControlStates[ControlState::ACTOR_PREV] = true; } + if (!m_PrevIgnore) { + m_ControlStates[ControlState::ACTOR_PREV] = true; + } m_PrevIgnore = false; } else if (g_UInputMan.ElementReleased(m_Player, InputElements::INPUT_WEAPON_CHANGE_NEXT)) { m_WeaponChangeNextIgnore = false; @@ -298,9 +304,9 @@ namespace RTE { UpdatePlayerAnalogInput(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Controller::UpdatePlayerPieMenuInput() { + void Controller::UpdatePlayerPieMenuInput() { // Holding of the switch buttons disables aiming later if (g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_NEXT)) { m_ControlStates[ControlState::ACTOR_NEXT_PREP] = true; @@ -308,7 +314,7 @@ namespace RTE { } else if (g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_PREV)) { m_ControlStates[ControlState::ACTOR_PREV_PREP] = true; m_ReleaseTimer.Reset(); - // No actions can be performed while switching actors, and short time thereafter + // No actions can be performed while switching actors, and short time thereafter } else if (m_ReleaseTimer.IsPastRealMS(m_ReleaseDelay)) { m_ControlStates[ControlState::WEAPON_FIRE] = g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_FIRE); m_ControlStates[ControlState::AIM_SHARP] = g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_AIM); @@ -384,7 +390,7 @@ namespace RTE { m_ControlStates[ControlState::WEAPON_FIRE] = false; m_ControlStates[ControlState::AIM_UP] = false; m_ControlStates[ControlState::AIM_DOWN] = false; - + if (m_ControlStates[ControlState::PIE_MENU_ACTIVE_DIGITAL]) { m_ControlStates[ControlState::MOVE_RIGHT] = false; m_ControlStates[ControlState::MOVE_LEFT] = false; @@ -397,7 +403,7 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Controller::UpdatePlayerAnalogInput() { // ANALOG joystick values @@ -409,8 +415,8 @@ namespace RTE { // Only change aim and move if not holding actor switch buttons - don't want to mess up AI's aim if (!m_ControlStates[ControlState::ACTOR_PREV_PREP] && !m_ControlStates[ControlState::ACTOR_NEXT_PREP] && m_ReleaseTimer.IsPastRealMS(m_ReleaseDelay)) { m_AnalogMove = move; - } - + } + if (!pieMenuActive || m_ControlStates[ControlState::PIE_MENU_ACTIVE_DIGITAL]) { m_AnalogAim = aim; } else { @@ -421,18 +427,18 @@ namespace RTE { } // If the joystick-controlled analog cursor is less than at the edge of input range, don't accelerate - if (GetAnalogCursor().MagnitudeIsLessThan(0.85F)) { - m_JoyAccelTimer.Reset(); + if (GetAnalogCursor().MagnitudeIsLessThan(0.85F)) { + m_JoyAccelTimer.Reset(); } - + // If the keyboard inputs for cursor movements is initially pressed, reset the acceleration timer if (IsState(ControlState::ACTOR_NEXT) || IsState(ControlState::ACTOR_PREV) || (IsState(ControlState::PRESS_LEFT) || IsState(ControlState::PRESS_RIGHT) || IsState(ControlState::PRESS_UP) || IsState(ControlState::PRESS_DOWN))) { m_KeyAccelTimer.Reset(); } // Translate analog aim input into sharp aim control state - if (m_AnalogAim.MagnitudeIsGreaterThan(0.1F) && !pieMenuActive) { - m_ControlStates[ControlState::AIM_SHARP] = true; + if (m_AnalogAim.MagnitudeIsGreaterThan(0.1F) && !pieMenuActive) { + m_ControlStates[ControlState::AIM_SHARP] = true; } // Disable sharp aim while moving - this also helps with keyboard vs mouse fighting when moving and aiming in opposite directions @@ -462,4 +468,4 @@ namespace RTE { m_ControlStates[ControlState::RELEASE_SECONDARY] = g_UInputMan.MouseButtonReleased(activeSecondary, m_Player); } } -} +} // namespace RTE diff --git a/Source/System/Controller.h b/Source/System/Controller.h index 18c510b9e..3de2fcab7 100644 --- a/Source/System/Controller.h +++ b/Source/System/Controller.h @@ -71,7 +71,6 @@ namespace RTE { class Controller { public: - Vector m_AnalogMove; //!< Analog values for movement. Vector m_AnalogAim; //!< Analog values for aiming. Vector m_AnalogCursor; //!< Analog values for Pie Menu operation. @@ -96,20 +95,30 @@ namespace RTE { /// /// The controller input mode, like AI, player etc. /// The Actor this is supposed to control. Ownership is NOT transferred! - Controller(InputMode mode, Actor *controlledActor) { Clear(); Create(mode, controlledActor); } + Controller(InputMode mode, Actor* controlledActor) { + Clear(); + Create(mode, controlledActor); + } /// /// Constructor method used to instantiate a Controller object in system memory. Create() should be called before using the object. /// /// The controller input mode, like AI, player etc. /// Which human player is controlling this. - Controller(InputMode mode, int player = Players::PlayerOne) { Clear(); Create(mode, player); } + Controller(InputMode mode, int player = Players::PlayerOne) { + Clear(); + Create(mode, player); + } /// /// Copy constructor method used to instantiate a Controller object identical to an already existing one. /// /// A Controller object which is passed in by reference. - Controller(const Controller &reference) { if (this != &reference) { Create(reference); } } + Controller(const Controller& reference) { + if (this != &reference) { + Create(reference); + } + } /// /// Makes the Controller object ready for use. @@ -117,7 +126,7 @@ namespace RTE { /// The controller input mode, like AI, player etc. /// The Actor this is supposed to control. Ownership is NOT transferred! /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(InputMode mode, Actor *controlledActor); + int Create(InputMode mode, Actor* controlledActor); /// /// Makes the Controller object ready for use. @@ -125,14 +134,18 @@ namespace RTE { /// The controller input mode, like AI, player etc. /// Which player is controlling this. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(InputMode mode, int player) { m_InputMode = mode; m_Player = player; return 0; } + int Create(InputMode mode, int player) { + m_InputMode = mode; + m_Player = player; + return 0; + } /// /// Creates a Controller to be identical to another, by deep copy. /// /// A reference to the Controller to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Controller &reference); + int Create(const Controller& reference); #pragma endregion #pragma region Destruction @@ -160,7 +173,13 @@ namespace RTE { /// Sets whether this is a disabled controller that doesn't give any new output. /// /// Disabled or not. - void SetDisabled(bool disabled = true) { if (m_Disabled != disabled) { m_ReleaseTimer.Reset(); ResetCommandState(); } m_Disabled = disabled; } + void SetDisabled(bool disabled = true) { + if (m_Disabled != disabled) { + m_ReleaseTimer.Reset(); + ResetCommandState(); + } + m_Disabled = disabled; + } /// /// Shows whether the current controller is in a specific state. @@ -174,7 +193,10 @@ namespace RTE { /// /// Value of the state being set. - void SetState(ControlState controlState, bool setting = true) { RTEAssert(controlState >= 0 && controlState < ControlState::CONTROLSTATECOUNT, "Control state out of whack"); m_ControlStates[controlState] = setting; }; + void SetState(ControlState controlState, bool setting = true) { + RTEAssert(controlState >= 0 && controlState < ControlState::CONTROLSTATECOUNT, "Control state out of whack"); + m_ControlStates[controlState] = setting; + }; /// /// Gets the current mode of input for this Controller. @@ -186,7 +208,12 @@ namespace RTE { /// Sets the mode of input for this Controller. /// /// The new InputMode for this controller to use. - void SetInputMode(InputMode newMode) { if (m_InputMode != newMode) { m_ReleaseTimer.Reset(); } m_InputMode = newMode; } + void SetInputMode(InputMode newMode) { + if (m_InputMode != newMode) { + m_ReleaseTimer.Reset(); + } + m_InputMode = newMode; + } /// /// Gets the analog movement input data. @@ -198,7 +225,7 @@ namespace RTE { /// Sets the analog movement vector state of this. /// /// The new analog movement vector. - void SetAnalogMove(const Vector &newMove) { m_AnalogMove = newMove; } + void SetAnalogMove(const Vector& newMove) { m_AnalogMove = newMove; } /// /// Gets the analog aiming input data. @@ -210,7 +237,7 @@ namespace RTE { /// Sets the analog aiming vector state of this. /// /// The new analog aiming vector. - void SetAnalogAim(const Vector &newAim) { m_AnalogAim = newAim; } + void SetAnalogAim(const Vector& newAim) { m_AnalogAim = newAim; } /// /// Gets the analog menu input data. @@ -222,14 +249,14 @@ namespace RTE { /// Sets the analog cursor to the specified position. /// /// The position the analog cursor should be set to. - void SetAnalogCursor(const Vector &newAnalogCursor) { m_AnalogCursor = newAnalogCursor; } + void SetAnalogCursor(const Vector& newAnalogCursor) { m_AnalogCursor = newAnalogCursor; } /// /// Sets the analog cursor angle limits for the given player (does nothing for player -1). The limit end is always CCW from the limit start. /// /// The starting angle limit for the analog cursor. /// The ending angle limit for the analog cursor. - void SetAnalogCursorAngleLimits(float angleLimitStart, float angleLimitEnd) { m_AnalogCursorAngleLimits = { {angleLimitStart, angleLimitEnd}, true }; } + void SetAnalogCursorAngleLimits(float angleLimitStart, float angleLimitEnd) { m_AnalogCursorAngleLimits = {{angleLimitStart, angleLimitEnd}, true}; } /// /// Clears the analog cursor aim limits for the given player (does nothing for player -1). @@ -242,7 +269,7 @@ namespace RTE { /// The vector to alter. /// The scale of the input. 1.0 is 'normal'. /// Whether the vector was altered or not. - bool RelativeCursorMovement(Vector &cursorPos, float moveScale = 1.0F) const; + bool RelativeCursorMovement(Vector& cursorPos, float moveScale = 1.0F) const; /// /// Indicates whether this is listening to mouse input at all. @@ -266,7 +293,7 @@ namespace RTE { /// Gets the relative movement of the mouse since last update. /// /// The relative mouse movements, in both axes. - const Vector & GetMouseMovement() const { return m_MouseMovement; } + const Vector& GetMouseMovement() const { return m_MouseMovement; } /// /// Get the digital aim speed multiplier of the scheme associated with this Controller. @@ -290,7 +317,12 @@ namespace RTE { /// Sets which player's input this is listening to, and will enable player input mode. /// /// The player number. - void SetPlayer(int player) { m_Player = player; if (m_Player >= Players::PlayerOne) { m_InputMode = InputMode::CIM_PLAYER; } } + void SetPlayer(int player) { + m_Player = player; + if (m_Player >= Players::PlayerOne) { + m_InputMode = InputMode::CIM_PLAYER; + } + } /// /// Gets the Team number using this controller. @@ -308,13 +340,13 @@ namespace RTE { /// Gets which Actor is being controlled by this. 0 if none. /// /// A pointer to the Actor which is being controlled by this. Ownership is NOT transferred! - Actor * GetControlledActor() const { return m_ControlledActor; } + Actor* GetControlledActor() const { return m_ControlledActor; } /// /// Sets which Actor is supposed to be controlled by this. /// /// A pointer to a an Actor which is being controlled by this. Ownership is NOT transferred! - void SetControlledActor(Actor *controlledActor = nullptr) { m_ControlledActor = controlledActor; } + void SetControlledActor(Actor* controlledActor = nullptr) { m_ControlledActor = controlledActor; } /// /// Returns whether the AI should be updated this frame. @@ -336,7 +368,7 @@ namespace RTE { /// /// A Controller reference. /// A reference to the changed Controller. - Controller & operator=(const Controller &rhs); + Controller& operator=(const Controller& rhs); #pragma endregion #pragma region Misc @@ -349,7 +381,6 @@ namespace RTE { #pragma endregion protected: - static constexpr int m_ReleaseDelay = 250; //!< The delay between releasing a menu button and activating the regular controls, to avoid accidental input. std::array m_ControlStates; //!< Control states. @@ -357,7 +388,7 @@ namespace RTE { InputMode m_InputMode; //!< The current controller input mode, like AI, player etc. - Actor *m_ControlledActor; //!< The actor controlled by this. + Actor* m_ControlledActor; //!< The actor controlled by this. /// /// The last player this controlled. This is necessary so we still have some control after controlled's death. @@ -390,7 +421,6 @@ namespace RTE { std::pair, bool> m_AnalogCursorAngleLimits; //!< Analog aim value limits, as well as whether or not the limit is actually enabled. private: - #pragma region Update Breakdown /// /// Updates the player's inputs portion of this Controller. For breaking down Update into more comprehensible chunks. @@ -424,5 +454,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/DataModule.cpp b/Source/System/DataModule.cpp index 1f8b5e5ca..3079cb988 100644 --- a/Source/System/DataModule.cpp +++ b/Source/System/DataModule.cpp @@ -10,7 +10,7 @@ namespace RTE { const std::string DataModule::c_ClassName = "DataModule"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void DataModule::Clear() { m_IsUserdata = false; @@ -35,22 +35,26 @@ namespace RTE { m_IsMerchant = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int DataModule::Create(const std::string &moduleName, const ProgressCallback &progressCallback) { + int DataModule::Create(const std::string& moduleName, const ProgressCallback& progressCallback) { m_FileName = std::filesystem::path(moduleName).generic_string(); m_ModuleID = g_PresetMan.GetModuleID(moduleName); m_CrabToHumanSpawnRatio = 0; // Report that we're starting to read a new DataModule - if (progressCallback) { progressCallback(m_FileName + " " + static_cast(-43) + " loading:", true); } + if (progressCallback) { + progressCallback(m_FileName + " " + static_cast(-43) + " loading:", true); + } Reader reader; std::string indexPath = g_PresetMan.GetFullModulePath(m_FileName + "/Index.ini"); std::string mergedIndexPath = g_PresetMan.GetFullModulePath(m_FileName + "/MergedIndex.ini"); // NOTE: This looks for the MergedIndex.ini generated by the index merger tool. The tool is mostly superseded by disabling loading visuals, but still provides some benefit. - if (std::filesystem::exists(mergedIndexPath)) { indexPath = mergedIndexPath; } + if (std::filesystem::exists(mergedIndexPath)) { + indexPath = mergedIndexPath; + } // If the module is a mod, read only its `index.ini` to validate its SupportedGameVersion. if (m_ModuleID >= g_PresetMan.GetOfficialModuleCount() && !m_IsUserdata && ReadModuleProperties(moduleName, progressCallback) >= 0) { @@ -61,18 +65,22 @@ namespace RTE { int result = Serializable::Create(reader); // Print an empty line to separate the end of a module from the beginning of the next one in the loading progress log. - if (progressCallback) { progressCallback(" ", true); } + if (progressCallback) { + progressCallback(" ", true); + } - if (m_ScanFolderContents) { result = FindAndRead(progressCallback); } + if (m_ScanFolderContents) { + result = FindAndRead(progressCallback); + } return result; } return -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool DataModule::CreateOnDiskAsUserdata(const std::string &moduleName, const std::string_view &friendlyName, bool ignoreMissingItems, bool scanFolderContents) { + bool DataModule::CreateOnDiskAsUserdata(const std::string& moduleName, const std::string_view& friendlyName, bool ignoreMissingItems, bool scanFolderContents) { std::string moduleNameWithPackageExtension = System::GetUserdataDirectory() + moduleName + (moduleName.ends_with(System::GetModulePackageExtension()) ? "" : System::GetModulePackageExtension()); if (Writer writer(moduleNameWithPackageExtension + "/Index.ini", false, true); writer.WriterOK()) { DataModule newModule; @@ -88,25 +96,27 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void DataModule::Destroy() { - for (const PresetEntry &preset : m_PresetList){ + for (const PresetEntry& preset: m_PresetList) { delete preset.m_EntityPreset; } delete m_SupportedGameVersion; Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int DataModule::ReadModuleProperties(const std::string &moduleName, const ProgressCallback &progressCallback) { + int DataModule::ReadModuleProperties(const std::string& moduleName, const ProgressCallback& progressCallback) { m_FileName = moduleName; m_ModuleID = g_PresetMan.GetModuleID(moduleName); m_CrabToHumanSpawnRatio = 0; // Report that we're starting to read a new DataModule - if (progressCallback) { progressCallback(m_FileName + " " + static_cast(-43) + " reading properties:", true); } + if (progressCallback) { + progressCallback(m_FileName + " " + static_cast(-43) + " reading properties:", true); + } Reader reader; std::string indexPath(m_FileName + "/Index.ini"); @@ -118,12 +128,12 @@ namespace RTE { return -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int DataModule::ReadProperty(const std::string_view &propName, Reader &reader) { + int DataModule::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(if (!g_PresetMan.GetEntityPreset(reader)) { reader.ReportError("Could not understand Preset type!"); }) - - MatchProperty("ModuleName", { reader >> m_FriendlyName; }); + + MatchProperty("ModuleName", { reader >> m_FriendlyName; }); MatchProperty("Author", { reader >> m_Author; }); MatchProperty("Description", { std::string descriptionValue = reader.ReadPropValue(); @@ -141,11 +151,15 @@ namespace RTE { }); MatchProperty("IsFaction", { reader >> m_IsFaction; - if (m_IsMerchant) { m_IsFaction = false; } + if (m_IsMerchant) { + m_IsFaction = false; + } }); MatchProperty("IsMerchant", { reader >> m_IsMerchant; - if (m_IsMerchant) { m_IsFaction = false; } + if (m_IsMerchant) { + m_IsFaction = false; + } }); MatchProperty("SupportedGameVersion", { std::string versionText; @@ -154,7 +168,7 @@ namespace RTE { if (!m_SupportedGameVersion) { try { m_SupportedGameVersion = new version::Semver200_version(versionText); - } catch (version::Parse_error &) { + } catch (version::Parse_error&) { reader.ReportError("Couldn't parse the supported game version from the value provided: \"" + versionText + "\"!\nThe supported game version must be a valid semantic version number.\n"); } } @@ -202,9 +216,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int DataModule::Save(Writer &writer) const { + int DataModule::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("ModuleName", m_FriendlyName); @@ -228,16 +242,16 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string DataModule::GetEntityDataLocation(const std::string &exactType, const std::string &instance) { - const Entity *foundEntity = GetEntityPreset(exactType, instance); + std::string DataModule::GetEntityDataLocation(const std::string& exactType, const std::string& instance) { + const Entity* foundEntity = GetEntityPreset(exactType, instance); if (foundEntity == nullptr) { return ""; } // Search for entity in instanceList - for (const PresetEntry &presetListEntry : m_PresetList) { + for (const PresetEntry& presetListEntry: m_PresetList) { if (presetListEntry.m_EntityPreset == foundEntity) { return presetListEntry.m_FileReadFrom; } @@ -247,15 +261,15 @@ namespace RTE { return ""; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Entity * DataModule::GetEntityPreset(const std::string &exactType, const std::string &instance) { + const Entity* DataModule::GetEntityPreset(const std::string& exactType, const std::string& instance) { if (exactType.empty() || instance == "None" || instance.empty()) { return nullptr; } if (auto classItr = m_TypeMap.find(exactType); classItr != m_TypeMap.end()) { // Find an instance of that EXACT type and name; derived types are not matched - for (const auto &[instanceName, entity] : classItr->second) { + for (const auto& [instanceName, entity]: classItr->second) { if (instanceName == instance && entity->GetClassName() == exactType) { return entity; } @@ -264,21 +278,21 @@ namespace RTE { return nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool DataModule::AddEntityPreset(Entity *entityToAdd, bool overwriteSame, const std::string &readFromFile) { + bool DataModule::AddEntityPreset(Entity* entityToAdd, bool overwriteSame, const std::string& readFromFile) { // Fail if the entity is unnamed or it's not the original preset. - //TODO If we're overwriting, we may not want to fail if it's not the original preset, this needs to be investigated + // TODO If we're overwriting, we may not want to fail if it's not the original preset, this needs to be investigated if (entityToAdd->GetPresetName() == "None" || entityToAdd->GetPresetName().empty() || !entityToAdd->IsOriginalPreset()) { return false; } bool entityAdded = false; - if (Entity *existingEntity = GetEntityIfExactType(entityToAdd->GetClassName(), entityToAdd->GetPresetName())) { + if (Entity* existingEntity = GetEntityIfExactType(entityToAdd->GetClassName(), entityToAdd->GetPresetName())) { // If we're commanded to overwrite any collisions, then do so by cloning over the existing instance in the list // This way we're not invalidating any instance references that would have been taken out and held by clients if (overwriteSame) { - entityToAdd->SetModuleID(m_ModuleID); //TODO this is probably overwritten by Entity::Create(other), making it useless. Double-check this and remove this line if certain + entityToAdd->SetModuleID(m_ModuleID); // TODO this is probably overwritten by Entity::Create(other), making it useless. Double-check this and remove this line if certain entityToAdd->Clone(existingEntity); // Make sure the existing one is still marked as the Original Preset existingEntity->m_IsOriginalPreset = true; @@ -300,7 +314,7 @@ namespace RTE { } } else { entityToAdd->SetModuleID(m_ModuleID); - Entity *entityClone = entityToAdd->Clone(); + Entity* entityClone = entityToAdd->Clone(); // Mark the one we are about to add to the list as the Original now - this is now the actual Original Preset instance entityClone->m_IsOriginalPreset = true; @@ -316,25 +330,25 @@ namespace RTE { return entityAdded; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool DataModule::GetGroupsWithType(std::list &groupList, const std::string &withType) { + bool DataModule::GetGroupsWithType(std::list& groupList, const std::string& withType) { bool foundAny = false; if (withType == "All" || withType.empty()) { - for (const std::string &groupRegisterEntry : m_GroupRegister) { + for (const std::string& groupRegisterEntry: m_GroupRegister) { groupList.push_back(groupRegisterEntry); // TODO: it seems weird that foundAny isn't set to true here, given that the list gets filled. // But I suppose no actual finding is done. Investigate this and see where it's called, maybe this should be changed } } else { if (auto classItr = m_TypeMap.find(withType); classItr != m_TypeMap.end()) { - const std::unordered_set *groupListPtr = nullptr; + const std::unordered_set* groupListPtr = nullptr; // Go through all the entities of that type, adding the groups they belong to - for (const auto &[instanceName, entity] : classItr->second) { + for (const auto& [instanceName, entity]: classItr->second) { groupListPtr = entity->GetGroups(); - for (const std::string &groupListEntry : *groupListPtr) { + for (const std::string& groupListEntry: *groupListPtr) { groupList.push_back(groupListEntry); // Get the grouped entities, without transferring ownership foundAny = true; } @@ -348,10 +362,9 @@ namespace RTE { return foundAny; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool DataModule::GetAllOfOrNotOfGroups(std::list &entityList, const std::string &type, const std::vector &groups, bool excludeGroups) { + bool DataModule::GetAllOfOrNotOfGroups(std::list& entityList, const std::string& type, const std::vector& groups, bool excludeGroups) { if (groups.empty()) { return false; } @@ -361,10 +374,10 @@ namespace RTE { if (auto classItr = m_TypeMap.find((type.empty() || type == "All") ? "Entity" : type); classItr != m_TypeMap.end()) { RTEAssert(!classItr->second.empty(), "DataModule has class entry without instances in its map!?"); - for (const auto &[instanceName, entity] : classItr->second) { + for (const auto& [instanceName, entity]: classItr->second) { if (excludeGroups) { bool excludeEntity = false; - for (const std::string &group : groups) { + for (const std::string& group: groups) { if (entity->IsInGroup(group)) { excludeEntity = true; break; @@ -375,7 +388,7 @@ namespace RTE { foundAny = true; } } else { - for (const std::string &group : groups) { + for (const std::string& group: groups) { if (entity->IsInGroup(group)) { entityList.emplace_back(entity); foundAny = true; @@ -388,17 +401,17 @@ namespace RTE { return foundAny; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool DataModule::GetAllOfType(std::list &entityList, const std::string &type) { + bool DataModule::GetAllOfType(std::list& entityList, const std::string& type) { if (type.empty()) { return false; } - if (auto classItr = m_TypeMap.find(type); classItr != m_TypeMap.end()) { + if (auto classItr = m_TypeMap.find(type); classItr != m_TypeMap.end()) { RTEAssert(!classItr->second.empty(), "DataModule has class entry without instances in its map!?"); - for (const auto &[instanceName, entity] : classItr->second) { + for (const auto& [instanceName, entity]: classItr->second) { entityList.push_back(entity); // Get the entities, without transferring ownership } return true; @@ -406,7 +419,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool DataModule::AddMaterialMapping(unsigned char fromID, unsigned char toID) { RTEAssert(fromID > 0 && fromID < c_PaletteEntriesNumber && toID > 0 && toID < c_PaletteEntriesNumber, "Tried to make an out-of-bounds Material mapping"); @@ -417,59 +430,61 @@ namespace RTE { return clear; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int DataModule::LoadScripts() const { if (m_ScriptPath.empty()) { return 0; } - + g_LuaMan.GetMasterScriptState().RunScriptFile(m_ScriptPath); - for (LuaStateWrapper &luaState : g_LuaMan.GetThreadedScriptStates()) { + for (LuaStateWrapper& luaState: g_LuaMan.GetThreadedScriptStates()) { luaState.RunScriptFile(m_ScriptPath); } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void DataModule::ReloadAllScripts() const { - for (const PresetEntry &presetListEntry : m_PresetList) { + for (const PresetEntry& presetListEntry: m_PresetList) { presetListEntry.m_EntityPreset->ReloadScripts(); } LoadScripts(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int DataModule::FindAndRead(const ProgressCallback &progressCallback) { + int DataModule::FindAndRead(const ProgressCallback& progressCallback) { int result = 0; const std::string directoryToScan = g_PresetMan.GetFullModulePath(m_FileName); - for (const std::filesystem::directory_entry &directoryEntry : std::filesystem::directory_iterator(System::GetWorkingDirectory() + directoryToScan)) { + for (const std::filesystem::directory_entry& directoryEntry: std::filesystem::directory_iterator(System::GetWorkingDirectory() + directoryToScan)) { if (directoryEntry.path().extension() == ".ini" && directoryEntry.path().filename() != "Index.ini") { Reader iniReader; if (iniReader.Create(directoryToScan + "/" + directoryEntry.path().filename().generic_string(), false, progressCallback) >= 0) { result = Serializable::CreateSerializable(iniReader, false, true, true); - if (progressCallback) { progressCallback(" ", true); } + if (progressCallback) { + progressCallback(" ", true); + } } } } return result; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: This method is almost identical to GetEntityPreset, except it doesn't return a const Entity *. // Investigate if the latter needs to return const (based on what's using it) and if not, get rid of this and replace its uses. At the very least, consider renaming this // See https://github.com/cortex-command-community/Cortex-Command-Community-Project-Source/issues/87 - Entity * DataModule::GetEntityIfExactType(const std::string &exactType, const std::string &presetName) { + Entity* DataModule::GetEntityIfExactType(const std::string& exactType, const std::string& presetName) { if (exactType.empty() || presetName == "None" || presetName.empty()) { return nullptr; } if (auto classItr = m_TypeMap.find(exactType); classItr != m_TypeMap.end()) { // Find an instance of that EXACT type and name; derived types are not matched - for (const auto &[instanceName, entity] : classItr->second) { + for (const auto& [instanceName, entity]: classItr->second) { if (instanceName == presetName && entity->GetClassName() == exactType) { return entity; } @@ -478,29 +493,29 @@ namespace RTE { return nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool DataModule::AddToTypeMap(Entity *entityToAdd) { + bool DataModule::AddToTypeMap(Entity* entityToAdd) { if (!entityToAdd || entityToAdd->GetPresetName() == "None" || entityToAdd->GetPresetName().empty()) { return false; } // Walk up the class hierarchy till we reach the top, adding an entry of the passed in entity into each typelist as we go along - for (const Entity::ClassInfo *pClass = &(entityToAdd->GetClass()); pClass != nullptr; pClass = pClass->GetParent()) { + for (const Entity::ClassInfo* pClass = &(entityToAdd->GetClass()); pClass != nullptr; pClass = pClass->GetParent()) { auto classItr = m_TypeMap.find(pClass->GetName()); // No instances of this entity have been added yet so add a class category for it if (classItr == m_TypeMap.end()) { - classItr = (m_TypeMap.insert(std::pair>>(pClass->GetName(), std::list>()))).first; + classItr = (m_TypeMap.insert(std::pair>>(pClass->GetName(), std::list>()))).first; } // NOTE We're adding the entity to the class category list but not transferring ownership. Also, we're not checking for collisions as they're assumed to have been checked for already - (*classItr).second.push_back(std::pair(entityToAdd->GetPresetName(), entityToAdd)); + (*classItr).second.push_back(std::pair(entityToAdd->GetPresetName(), entityToAdd)); } return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void DataModule::CheckSupportedGameVersion() const { if (*m_SupportedGameVersion == c_GameVersion) { @@ -526,4 +541,4 @@ namespace RTE { RTEAssert(majorVersionMatch && minorVersionInRange, m_FileName + " was developed for Cortex Command v" + m_SupportedGameVersion->str() + ", so this version of Cortex Command (v" + c_GameVersion.str() + ") may not support it.\n" + contactAuthor); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/DataModule.h b/Source/System/DataModule.h index 79a4a99bd..39bd88413 100644 --- a/Source/System/DataModule.h +++ b/Source/System/DataModule.h @@ -4,7 +4,7 @@ #include "ContentFile.h" #include "Constants.h" -//struct DATAFILE; // DataFile loading not implemented. +// struct DATAFILE; // DataFile loading not implemented. struct BITMAP; namespace version { @@ -22,7 +22,6 @@ namespace RTE { friend struct SystemLuaBindings; public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -49,7 +48,10 @@ namespace RTE { /// /// A string defining the path to where the content file itself is located, either within the package file, or directly on the disk. /// A function pointer to a function that will be called and sent a string with information about the progress of this DataModule's creation. - DataModule(const std::string &moduleName, const ProgressCallback &progressCallback = nullptr) { Clear(); Create(moduleName, progressCallback); } + DataModule(const std::string& moduleName, const ProgressCallback& progressCallback = nullptr) { + Clear(); + Create(moduleName, progressCallback); + } /// /// Makes the DataModule object ready for use. This needs to be called after PresetMan is created. @@ -58,7 +60,7 @@ namespace RTE { /// A string defining the name of this DataModule, e.g. "MyModule.rte". /// A function pointer to a function that will be called and sent a string with information about the progress of this DataModule's creation. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const std::string &moduleName, const ProgressCallback &progressCallback = nullptr); + int Create(const std::string& moduleName, const ProgressCallback& progressCallback = nullptr); /// /// Creates a new DataModule directory with "Index.ini" on disk to be used for userdata. Does NOT instantiate the newly created DataModule. @@ -68,7 +70,7 @@ namespace RTE { /// Whether module loader should scan for any .ini's inside module folder instead of loading files defined in IncludeFile only. /// Whether module loader should ignore missing items in this module. /// Whether the DataModule was successfully created on disk. - static bool CreateOnDiskAsUserdata(const std::string &moduleName, const std::string_view &friendlyName, bool scanFolderContents = false, bool ignoreMissingItems = false); + static bool CreateOnDiskAsUserdata(const std::string& moduleName, const std::string_view& friendlyName, bool scanFolderContents = false, bool ignoreMissingItems = false); #pragma endregion #pragma region Destruction @@ -95,7 +97,7 @@ namespace RTE { /// A string defining the name of this DataModule, e.g. "MyModule.rte". /// A function pointer to a function that will be called and sent a string with information about the progress of this DataModule's creation. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int ReadModuleProperties(const std::string &moduleName, const ProgressCallback &progressCallback = nullptr); + int ReadModuleProperties(const std::string& moduleName, const ProgressCallback& progressCallback = nullptr); /// /// Returns true if loader should ignore missing items in this module. @@ -120,25 +122,25 @@ namespace RTE { /// Gets the file name of this DataModule, e.g. "MyMod.rte". /// /// A string with the data module file name. - const std::string & GetFileName() const { return m_FileName; } + const std::string& GetFileName() const { return m_FileName; } /// /// Gets the friendly name of this DataModule, e.g. "My Great Mod". /// /// A string with the data module's friendly name. - const std::string & GetFriendlyName() const { return m_FriendlyName; } + const std::string& GetFriendlyName() const { return m_FriendlyName; } /// /// Gets the author name of this DataModule, e.g. "Data Realms, LLC". /// /// A string with the author's name. - const std::string & GetAuthor() const { return m_Author; } + const std::string& GetAuthor() const { return m_Author; } /// /// Gets the description of this DataModule's contents. /// /// A string with the description. - const std::string & GetDescription() const { return m_Description; } + const std::string& GetDescription() const { return m_Description; } /// /// Gets whether this DataModule is considered a faction. @@ -162,7 +164,7 @@ namespace RTE { /// Gets the BITMAP that visually represents this DataModule, for use in menus. /// /// BITMAP pointer that might have the icon. 0 is very possible. - BITMAP * GetIcon() const { return m_Icon; } + BITMAP* GetIcon() const { return m_Icon; } /// /// Returns crab-to-human spawn ration for this tech. @@ -174,7 +176,7 @@ namespace RTE { /// Gets the faction BuyMenu theme data of this DataModule. /// /// The faction BuyMenu theme information of this DataModule - const BuyMenuTheme & GetFactionBuyMenuTheme() const { return m_BuyMenuTheme; } + const BuyMenuTheme& GetFactionBuyMenuTheme() const { return m_BuyMenuTheme; } #pragma endregion #pragma region Entity Mapping @@ -184,7 +186,7 @@ namespace RTE { /// The type name of the derived Entity. Ownership is NOT transferred! /// The instance name of the derived Entity instance. /// The file path of the data file that the specified Entity was read from. If no Entity of that description was found, "" is returned. - std::string GetEntityDataLocation(const std::string &exactType, const std::string &instance); + std::string GetEntityDataLocation(const std::string& exactType, const std::string& instance); /// /// Gets a previously read in (defined) Entity, by exact type and instance name. Ownership is NOT transferred! @@ -192,7 +194,7 @@ namespace RTE { /// The exact type name of the derived Entity instance to get. /// The instance name of the derived Entity instance. /// A pointer to the requested Entity instance. 0 if no Entity with that derived type or instance name was found. Ownership is NOT transferred! - const Entity * GetEntityPreset(const std::string &exactType, const std::string &instance); + const Entity* GetEntityPreset(const std::string& exactType, const std::string& instance); /// /// Adds an Entity instance's pointer and name associations to the internal list of already read in Entities. Ownership is NOT transferred! @@ -211,19 +213,23 @@ namespace RTE { /// Whether or not a copy of the passed-in instance was successfully inserted into the module. /// False will be returned if there already was an instance of that class and instance name inserted previously, unless overwritten. /// - bool AddEntityPreset(Entity *entityToAdd, bool overwriteSame = false, const std::string &readFromFile = "Same"); + bool AddEntityPreset(Entity* entityToAdd, bool overwriteSame = false, const std::string& readFromFile = "Same"); /// /// Gets the list of all registered Entity groups of this. /// /// The list of all groups. Ownership is not transferred. - const std::list * GetGroupRegister() const { return &m_GroupRegister; } + const std::list* GetGroupRegister() const { return &m_GroupRegister; } /// /// Registers the existence of an Entity group in this module. /// /// The group to register. - void RegisterGroup(const std::string &newGroup) { m_GroupRegister.push_back(newGroup); m_GroupRegister.sort(); m_GroupRegister.unique(); } + void RegisterGroup(const std::string& newGroup) { + m_GroupRegister.push_back(newGroup); + m_GroupRegister.sort(); + m_GroupRegister.unique(); + } /// /// Fills out a list with all groups registered with this that contain any objects of a specific type and it derivatives. @@ -231,7 +237,7 @@ namespace RTE { /// The list that all found groups will be ADDED to. OWNERSHIP IS NOT TRANSFERRED! /// The name of the type to only get groups of. /// Whether any groups with the specified type were found. - bool GetGroupsWithType(std::list &groupList, const std::string &withType); + bool GetGroupsWithType(std::list& groupList, const std::string& withType); /// /// Adds to a list all previously read in (defined) Entities which are associated with several specific groups. @@ -240,7 +246,7 @@ namespace RTE { /// A list of groups to look for. /// The name of the least common denominator type of the Entities you want. "All" will look at all types. /// Whether any Entities were found and added to the list. - bool GetAllOfGroups(std::list &entityList, const std::vector &groups, const std::string &type) { return GetAllOfOrNotOfGroups(entityList, type, groups, false); } + bool GetAllOfGroups(std::list& entityList, const std::vector& groups, const std::string& type) { return GetAllOfOrNotOfGroups(entityList, type, groups, false); } /// /// Adds to a list all previously read in (defined) Entities which are not associated with several specific groups. @@ -249,7 +255,7 @@ namespace RTE { /// A list of groups to exclude. /// The name of the least common denominator type of the Entities you want. "All" will look at all types. /// Whether any Entities were found and added to the list. - bool GetAllNotOfGroups(std::list &entityList, const std::vector &groups, const std::string &type) { return GetAllOfOrNotOfGroups(entityList, type, groups, true); } + bool GetAllNotOfGroups(std::list& entityList, const std::vector& groups, const std::string& type) { return GetAllOfOrNotOfGroups(entityList, type, groups, true); } /// /// Adds to a list all previously read in (defined) Entities, by inexact type. @@ -257,7 +263,7 @@ namespace RTE { /// Reference to a list which will get all matching Entities added to it. Ownership of the list or the Entities placed in it are NOT transferred! /// The name of the least common denominator type of the Entities you want. "All" will look at all types. /// Whether any Entities were found and added to the list. - bool GetAllOfType(std::list &objectList, const std::string &type); + bool GetAllOfType(std::list& objectList, const std::string& type); #pragma endregion #pragma region Material Mapping @@ -273,7 +279,7 @@ namespace RTE { /// Gets the entire Material mapping array local to this DataModule. /// /// A const reference to the entire local mapping array, 256 unsigned chars. Ownership is NOT transferred! - const std::array & GetAllMaterialMappings() const { return m_MaterialMappings; } + const std::array& GetAllMaterialMappings() const { return m_MaterialMappings; } /// /// Adds a Material mapping local to a DataModule. @@ -299,7 +305,6 @@ namespace RTE { #pragma endregion protected: - /// /// Holds and owns the actual object instance pointer, and the location of the data file it was read from, as well as where in that file. /// @@ -307,9 +312,10 @@ namespace RTE { /// /// Constructor method used to instantiate a PresetEntry object in system memory. /// - PresetEntry(Entity *preset, const std::string &file) : m_EntityPreset(preset), m_FileReadFrom(file) {} + PresetEntry(Entity* preset, const std::string& file) : + m_EntityPreset(preset), m_FileReadFrom(file) {} - Entity *m_EntityPreset; //!< Owned by this. + Entity* m_EntityPreset; //!< Owned by this. std::string m_FileReadFrom; //!< Where the instance was read from. }; @@ -324,18 +330,18 @@ namespace RTE { std::string m_ScriptPath; //!< Path to script to execute when this module is loaded. bool m_IsFaction; //!< Whether this data module is considered a faction. bool m_IsMerchant; //!< Whether this data module is considered a merchant. - version::Semver200_version *m_SupportedGameVersion; //!< Game version this DataModule supports. Needs to satisfy Caret Version Range for this DataModule to be allowed. Base DataModules don't need this. + version::Semver200_version* m_SupportedGameVersion; //!< Game version this DataModule supports. Needs to satisfy Caret Version Range for this DataModule to be allowed. Base DataModules don't need this. int m_Version; //!< Version number, starting with 1. int m_ModuleID; //!< ID number assigned to this upon loading, for internal use only, don't reflect in ini's. ContentFile m_IconFile; //!< File to the icon/symbol bitmap. - BITMAP *m_Icon; //!< Bitmap with the icon loaded from above file. + BITMAP* m_Icon; //!< Bitmap with the icon loaded from above file. BuyMenuTheme m_BuyMenuTheme; //!< Faction BuyMenu theme data. float m_CrabToHumanSpawnRatio; //!< Crab-to-human Spawn ratio to replace value from Constants.lua. - std::list m_EntityList; //!< A list of loaded entities solely for the purpose of enumeration presets from Lua. + std::list m_EntityList; //!< A list of loaded entities solely for the purpose of enumeration presets from Lua. std::list m_GroupRegister; //!< List of all Entity groups ever registered in this, all uniques. std::array m_MaterialMappings; //!< Material mappings local to this DataModule. @@ -352,10 +358,9 @@ namespace RTE { /// There can be multiple entries of the same instance name in any of the type sub-maps, but only ONE whose exact class is that of the type-list! /// The Entity instances are NOT owned by this map. /// - std::unordered_map>> m_TypeMap; + std::unordered_map>> m_TypeMap; private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. #pragma region INI Handling @@ -369,7 +374,7 @@ namespace RTE { /// /// A function pointer to a function that will be called and sent a string with information about the progress of this DataModule's creation. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int FindAndRead(const ProgressCallback &progressCallback = nullptr); + int FindAndRead(const ProgressCallback& progressCallback = nullptr); #pragma endregion #pragma region Entity Mapping @@ -381,7 +386,7 @@ namespace RTE { /// The groups to look for. /// Whether Entities belonging to the specified group or groups should be excluded. /// Whether any Entities were found and added to the list. - bool GetAllOfOrNotOfGroups(std::list &entityList, const std::string &type, const std::vector &groups, bool excludeGroups); + bool GetAllOfOrNotOfGroups(std::list& entityList, const std::string& type, const std::vector& groups, bool excludeGroups); /// /// Checks if the type map has an instance added of a specific name and exact type. @@ -390,7 +395,7 @@ namespace RTE { /// The exact type name to look for. /// The exact PresetName to look for. /// The found Entity Preset of the exact type and name, if found. - Entity * GetEntityIfExactType(const std::string &exactType, const std::string &presetName); + Entity* GetEntityIfExactType(const std::string& exactType, const std::string& presetName); /// /// Adds a newly added preset instance to the type map, where it will end up in every type-list of every class it derived from as well. @@ -400,7 +405,7 @@ namespace RTE { /// /// The new object instance to add. OWNERSHIP IS NOT TRANSFERRED! /// Whether the Entity was added successfully or not. - bool AddToTypeMap(Entity *entityToAdd); + bool AddToTypeMap(Entity* entityToAdd); #pragma endregion /// @@ -409,8 +414,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - DataModule(const DataModule &reference) = delete; - DataModule & operator=(const DataModule &rhs) = delete; + DataModule(const DataModule& reference) = delete; + DataModule& operator=(const DataModule& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Entity.cpp b/Source/System/Entity.cpp index be6982a4b..b9cb6fa70 100644 --- a/Source/System/Entity.cpp +++ b/Source/System/Entity.cpp @@ -7,9 +7,9 @@ namespace RTE { Entity::ClassInfo Entity::m_sClass("Entity"); - Entity::ClassInfo * Entity::ClassInfo::s_ClassHead = 0; + Entity::ClassInfo* Entity::ClassInfo::s_ClassHead = 0; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Entity::Clear() { m_PresetName = "None"; @@ -20,36 +20,35 @@ namespace RTE { m_RandomWeight = 100; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Entity::Create() { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Entity::Create(const Entity &reference) { + int Entity::Create(const Entity& reference) { m_PresetName = reference.m_PresetName; // Note how m_IsOriginalPreset is NOT assigned, automatically indicating that the copy is not an original Preset! m_DefinedInModule = reference.m_DefinedInModule; m_PresetDescription = reference.m_PresetDescription; - for (const std::string &group : reference.m_Groups) { + for (const std::string& group: reference.m_Groups) { m_Groups.emplace(group); } m_RandomWeight = reference.m_RandomWeight; return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Entity::ReadProperty(const std::string_view &propName, Reader &reader) { + int Entity::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList( - // Search for a property name match failed! - // TODO: write this out to some log file - return Serializable::ReadProperty(propName, reader); - ); - + // Search for a property name match failed! + // TODO: write this out to some log file + return Serializable::ReadProperty(propName, reader);); + MatchProperty("CopyOf", { std::string refName = reader.ReadPropValue(); if (refName != "None") { @@ -66,7 +65,9 @@ namespace RTE { SetPresetName(reader.ReadPropValue()); // Preset name might have "[ModuleName]/" preceding it, detect it here and select proper module! int slashPos = m_PresetName.find_first_of('/'); - if (slashPos != std::string::npos) { m_PresetName = m_PresetName.substr(slashPos + 1); } + if (slashPos != std::string::npos) { + m_PresetName = m_PresetName.substr(slashPos + 1); + } // Mark this so that the derived class knows it should be added to the PresetMan when it's done reading all properties. m_IsOriginalPreset = true; // Indicate where this was read from @@ -101,9 +102,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Entity::Save(Writer &writer) const { + int Entity::Save(Writer& writer) const { Serializable::Save(writer); // Is an original preset definition @@ -113,7 +114,7 @@ namespace RTE { if (!m_PresetDescription.empty()) { writer.NewPropertyWithValue("Description", m_PresetDescription); } - // Only write out a copy reference if there is one + // Only write out a copy reference if there is one } else if (!m_PresetName.empty() && m_PresetName != "None") { writer.NewPropertyWithValue("CopyOf", GetModuleAndPresetName()); } @@ -121,15 +122,15 @@ namespace RTE { // TODO: Make proper save system that knows not to save redundant data! /* for (auto itr = m_Groups.begin(); itr != m_Groups.end(); ++itr) { - writer.NewPropertyWithValue("AddToGroup", *itr); + writer.NewPropertyWithValue("AddToGroup", *itr); } */ return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Entity::SavePresetCopy(Writer &writer) const { + int Entity::SavePresetCopy(Writer& writer) const { // Can only save out copies with this if (m_IsOriginalPreset) { RTEAbort("Tried to save out a pure Preset Copy Reference from an original Preset!"); @@ -142,19 +143,19 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Entity * Entity::GetPreset() const { - return g_PresetMan.GetEntityPreset(GetClassName(), GetPresetName(), m_DefinedInModule); - } + const Entity* Entity::GetPreset() const { + return g_PresetMan.GetEntityPreset(GetClassName(), GetPresetName(), m_DefinedInModule); + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Entity::GetModuleAndPresetName() const { if (m_DefinedInModule < 0) { return GetPresetName(); } - const DataModule *dataModule = g_PresetMan.GetDataModule(m_DefinedInModule); + const DataModule* dataModule = g_PresetMan.GetDataModule(m_DefinedInModule); if (!dataModule) { return GetPresetName(); @@ -162,18 +163,18 @@ namespace RTE { return dataModule->GetFileName() + "/" + GetPresetName(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Entity::GetModuleName() const { if (m_DefinedInModule >= 0) { - if (const DataModule *dataModule = g_PresetMan.GetDataModule(m_DefinedInModule)) { + if (const DataModule* dataModule = g_PresetMan.GetDataModule(m_DefinedInModule)) { return dataModule->GetFileName(); } } return ""; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Entity::MigrateToModule(int whichModule) { if (m_DefinedInModule == whichModule) { @@ -184,9 +185,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Reader & operator>>(Reader &reader, Entity &operand) { + Reader& operator>>(Reader& reader, Entity& operand) { // Get this before reading Entity, since if it's the last one in its datafile, the stream will show the parent file instead std::string objectFilePath = reader.GetCurrentFilePath(); // Read the Entity from the file and try to add it to PresetMan @@ -196,9 +197,9 @@ namespace RTE { return reader; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Reader & operator>>(Reader &reader, Entity *operand) { + Reader& operator>>(Reader& reader, Entity* operand) { if (operand) { // Get this before reading Entity, since if it's the last one in its datafile, the stream will show the parent file instead std::string objectFilePath = reader.GetCurrentFilePath(); @@ -211,38 +212,38 @@ namespace RTE { return reader; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Entity::ClassInfo::ClassInfo(const std::string &name, ClassInfo *parentInfo, MemoryAllocate allocFunc, MemoryDeallocate deallocFunc, Entity * (*newFunc)(), int allocBlockCount) : - m_Name(name), - m_ParentInfo(parentInfo), - m_Allocate(allocFunc), - m_Deallocate(deallocFunc), - m_NewInstance(newFunc), - m_NextClass(s_ClassHead) { - s_ClassHead = this; + Entity::ClassInfo::ClassInfo(const std::string& name, ClassInfo* parentInfo, MemoryAllocate allocFunc, MemoryDeallocate deallocFunc, Entity* (*newFunc)(), int allocBlockCount) : + m_Name(name), + m_ParentInfo(parentInfo), + m_Allocate(allocFunc), + m_Deallocate(deallocFunc), + m_NewInstance(newFunc), + m_NextClass(s_ClassHead) { + s_ClassHead = this; - m_AllocatedPool.clear(); - m_PoolAllocBlockCount = (allocBlockCount > 0) ? allocBlockCount : 10; - } + m_AllocatedPool.clear(); + m_PoolAllocBlockCount = (allocBlockCount > 0) ? allocBlockCount : 10; + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::list Entity::ClassInfo::GetClassNames() { std::list retList; - for (const ClassInfo *itr = s_ClassHead; itr != 0; itr = itr->m_NextClass) { + for (const ClassInfo* itr = s_ClassHead; itr != 0; itr = itr->m_NextClass) { retList.push_back(itr->GetName()); } return retList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Entity::ClassInfo * Entity::ClassInfo::GetClass(const std::string &name) { + const Entity::ClassInfo* Entity::ClassInfo::GetClass(const std::string& name) { if (name.empty() || name == "None") { return 0; } - for (const ClassInfo *itr = s_ClassHead; itr != 0; itr = itr->m_NextClass) { + for (const ClassInfo* itr = s_ClassHead; itr != 0; itr = itr->m_NextClass) { if (itr->GetName() == name) { return itr; } @@ -250,19 +251,23 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Entity::ClassInfo::FillAllPools(int fillAmount) { - for (ClassInfo *itr = s_ClassHead; itr != 0; itr = itr->m_NextClass) { - if (itr->IsConcrete()) { itr->FillPool(fillAmount); } + for (ClassInfo* itr = s_ClassHead; itr != 0; itr = itr->m_NextClass) { + if (itr->IsConcrete()) { + itr->FillPool(fillAmount); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Entity::ClassInfo::FillPool(int fillAmount) { // Default to the set block allocation size if fillAmount is 0 - if (fillAmount <= 0) { fillAmount = m_PoolAllocBlockCount; } + if (fillAmount <= 0) { + fillAmount = m_PoolAllocBlockCount; + } // If concrete class, fill up the pool with pre-allocated memory blocks the size of the type if (m_Allocate && fillAmount > 0) { @@ -272,9 +277,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Entity::ClassInfo::IsClassOrChildClassOf(const ClassInfo *classInfoToCheck) const { + bool Entity::ClassInfo::IsClassOrChildClassOf(const ClassInfo* classInfoToCheck) const { if (GetName() == classInfoToCheck->GetName()) { return true; } else if (m_ParentInfo) { @@ -283,18 +288,20 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void * Entity::ClassInfo::GetPoolMemory() { + void* Entity::ClassInfo::GetPoolMemory() { std::lock_guard guard(m_Mutex); RTEAssert(IsConcrete(), "Trying to get pool memory of an abstract Entity class!"); // If the pool is empty, then fill it up again with as many instances as we are set to - if (m_AllocatedPool.empty()) { FillPool((m_PoolAllocBlockCount > 0) ? m_PoolAllocBlockCount : 10); } + if (m_AllocatedPool.empty()) { + FillPool((m_PoolAllocBlockCount > 0) ? m_PoolAllocBlockCount : 10); + } // Get the instance in the top of the pool and pop it off - void *foundMemory = m_AllocatedPool.back(); + void* foundMemory = m_AllocatedPool.back(); m_AllocatedPool.pop_back(); RTEAssert(foundMemory, "Could not find an available instance in the pool, even after increasing its size!"); @@ -305,9 +312,9 @@ namespace RTE { return foundMemory; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Entity::ClassInfo::ReturnPoolMemory(void *returnedMemory) { + int Entity::ClassInfo::ReturnPoolMemory(void* returnedMemory) { if (!returnedMemory) { return 0; } @@ -320,11 +327,13 @@ namespace RTE { return m_InstancesInUse; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Entity::ClassInfo::DumpPoolMemoryInfo(const Writer &fileWriter) { - for (const ClassInfo *itr = s_ClassHead; itr != nullptr; itr = itr->m_NextClass) { - if (itr->IsConcrete()) { fileWriter.NewLineString(itr->GetName() + ": " + std::to_string(itr->m_InstancesInUse), false); } + void Entity::ClassInfo::DumpPoolMemoryInfo(const Writer& fileWriter) { + for (const ClassInfo* itr = s_ClassHead; itr != nullptr; itr = itr->m_NextClass) { + if (itr->IsConcrete()) { + fileWriter.NewLineString(itr->GetName() + ": " + std::to_string(itr->m_InstancesInUse), false); + } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Entity.h b/Source/System/Entity.h index 258b81346..e4ff20bfe 100644 --- a/Source/System/Entity.h +++ b/Source/System/Entity.h @@ -10,42 +10,44 @@ namespace RTE { typedef std::function MemoryDeallocate; //!< Convenient name definition for the memory deallocation callback function. #pragma region Global Macro Definitions - #define AbstractClassInfo(TYPE, PARENT) \ - Entity::ClassInfo TYPE::m_sClass(#TYPE, &PARENT::m_sClass); - - #define ConcreteClassInfo(TYPE, PARENT, BLOCKCOUNT) \ - Entity::ClassInfo TYPE::m_sClass(#TYPE, &PARENT::m_sClass, TYPE::Allocate, TYPE::Deallocate, TYPE::NewInstance, BLOCKCOUNT); - - #define ConcreteSubClassInfo(TYPE, SUPER, PARENT, BLOCKCOUNT) \ - Entity::ClassInfo SUPER::TYPE::m_sClass(#TYPE, &PARENT::m_sClass, SUPER::TYPE::Allocate, SUPER::TYPE::Deallocate, SUPER::TYPE::NewInstance, BLOCKCOUNT); - - /// - /// Convenience macro to cut down on duplicate ClassInfo methods in classes that extend Entity. - /// - #define ClassInfoGetters \ - const Entity::ClassInfo & GetClass() const override { return m_sClass; } \ - const std::string & GetClassName() const override { return m_sClass.GetName(); } - - /// - /// Static method used in conjunction with ClassInfo to allocate an Entity. - /// This function is passed into the constructor of this Entity's static ClassInfo's constructor, so that it can instantiate MovableObjects. - /// - /// A pointer to the newly dynamically allocated Entity. Ownership is transferred as well. - #define EntityAllocation(TYPE) \ - static void * operator new (size_t size) { return TYPE::m_sClass.GetPoolMemory(); } \ - static void operator delete (void *instance) { TYPE::m_sClass.ReturnPoolMemory(instance); } \ - static void * operator new (size_t size, void *p) throw() { return p; } \ - static void operator delete (void *, void *) throw() { } \ - static void * Allocate() { return malloc(sizeof(TYPE)); } \ - static void Deallocate(void *instance) { free(instance); } \ - static Entity * NewInstance() { return new TYPE; } \ - Entity * Clone(Entity *cloneTo = nullptr) const override { \ - TYPE *ent = cloneTo ? dynamic_cast(cloneTo) : new TYPE(); \ - RTEAssert(ent, "Tried to clone to an incompatible instance!"); \ - if (cloneTo) { ent->Destroy(); } \ - ent->Create(*this); \ - return ent; \ - } +#define AbstractClassInfo(TYPE, PARENT) \ + Entity::ClassInfo TYPE::m_sClass(#TYPE, &PARENT::m_sClass); + +#define ConcreteClassInfo(TYPE, PARENT, BLOCKCOUNT) \ + Entity::ClassInfo TYPE::m_sClass(#TYPE, &PARENT::m_sClass, TYPE::Allocate, TYPE::Deallocate, TYPE::NewInstance, BLOCKCOUNT); + +#define ConcreteSubClassInfo(TYPE, SUPER, PARENT, BLOCKCOUNT) \ + Entity::ClassInfo SUPER::TYPE::m_sClass(#TYPE, &PARENT::m_sClass, SUPER::TYPE::Allocate, SUPER::TYPE::Deallocate, SUPER::TYPE::NewInstance, BLOCKCOUNT); + +/// +/// Convenience macro to cut down on duplicate ClassInfo methods in classes that extend Entity. +/// +#define ClassInfoGetters \ + const Entity::ClassInfo& GetClass() const override { return m_sClass; } \ + const std::string& GetClassName() const override { return m_sClass.GetName(); } + +/// +/// Static method used in conjunction with ClassInfo to allocate an Entity. +/// This function is passed into the constructor of this Entity's static ClassInfo's constructor, so that it can instantiate MovableObjects. +/// +/// A pointer to the newly dynamically allocated Entity. Ownership is transferred as well. +#define EntityAllocation(TYPE) \ + static void* operator new(size_t size) { return TYPE::m_sClass.GetPoolMemory(); } \ + static void operator delete(void* instance) { TYPE::m_sClass.ReturnPoolMemory(instance); } \ + static void* operator new(size_t size, void* p) throw() { return p; } \ + static void operator delete(void*, void*) throw() {} \ + static void* Allocate() { return malloc(sizeof(TYPE)); } \ + static void Deallocate(void* instance) { free(instance); } \ + static Entity* NewInstance() { return new TYPE; } \ + Entity* Clone(Entity* cloneTo = nullptr) const override { \ + TYPE* ent = cloneTo ? dynamic_cast(cloneTo) : new TYPE(); \ + RTEAssert(ent, "Tried to clone to an incompatible instance!"); \ + if (cloneTo) { \ + ent->Destroy(); \ + } \ + ent->Create(*this); \ + return ent; \ + } #pragma endregion /// @@ -69,7 +71,6 @@ namespace RTE { friend class DataModule; public: - SerializableOverrideMethods; #pragma region ClassInfo @@ -80,7 +81,6 @@ namespace RTE { friend class Entity; public: - #pragma region Creation /// /// Constructor method used to instantiate a ClassInfo Entity. @@ -91,7 +91,7 @@ namespace RTE { /// Function pointer to the raw deallocation function of memory. If the represented Entity subclass isn't concrete, pass in 0. /// Function pointer to the new instance factory. If the represented Entity subclass isn't concrete, pass in 0. /// The number of new instances to fill the pre-allocated pool with when it runs out. - ClassInfo(const std::string &name, ClassInfo *parentInfo = 0, MemoryAllocate allocFunc = 0, MemoryDeallocate deallocFunc = 0, Entity * (*newFunc)() = 0, int allocBlockCount = 10); + ClassInfo(const std::string& name, ClassInfo* parentInfo = 0, MemoryAllocate allocFunc = 0, MemoryDeallocate deallocFunc = 0, Entity* (*newFunc)() = 0, int allocBlockCount = 10); #pragma endregion #pragma region Getters @@ -99,7 +99,7 @@ namespace RTE { /// Gets the name of this ClassInfo. /// /// A string with the friendly-formatted name of this ClassInfo. - const std::string & GetName() const { return m_Name; } + const std::string& GetName() const { return m_Name; } /// /// Gets the names of all ClassInfos in existence. @@ -112,41 +112,41 @@ namespace RTE { /// /// The friendly name of the desired ClassInfo. /// A pointer to the requested ClassInfo, or 0 if none that matched the name was found. Ownership is NOT transferred! - static const ClassInfo * GetClass(const std::string &name); + static const ClassInfo* GetClass(const std::string& name); /// /// Gets the ClassInfo which describes the parent of this. /// /// A pointer to the parent ClassInfo. 0 if this is a root class. - const ClassInfo * GetParent() const { return m_ParentInfo; } + const ClassInfo* GetParent() const { return m_ParentInfo; } /// /// Gets whether or not this ClassInfo is the same as, or a parent of the ClassInfo corresponding to the given class name. /// /// The name of the class to check for. /// Whether or not this ClassInfo is the same as, or a parent of corresponding ClassInfo for the given class. - bool IsClassOrParentClassOf(const std::string &classNameToCheck) const { return GetClass(classNameToCheck)->IsClassOrChildClassOf(this); } + bool IsClassOrParentClassOf(const std::string& classNameToCheck) const { return GetClass(classNameToCheck)->IsClassOrChildClassOf(this); } /// /// Gets whether or not this ClassInfo is the same as, or a parent of the given ClassInfo. /// /// The name of the class to check for. /// Whether or not this ClassInfo is the same as, or a parent of the given ClassInfo. - bool IsClassOrParentClassOf(const ClassInfo *classInfoToCheck) const { return classInfoToCheck->IsClassOrChildClassOf(this); } + bool IsClassOrParentClassOf(const ClassInfo* classInfoToCheck) const { return classInfoToCheck->IsClassOrChildClassOf(this); } /// /// Gets whether or not this ClassInfo is the same as, or a child of the ClassInfo corresponding to the given class name. /// /// The name of the class to check for. /// Whether or not this ClassInfo is the same as, or a child of corresponding ClassInfo for the given class. - bool IsClassOrChildClassOf(const std::string &classNameToCheck) const { return IsClassOrChildClassOf(GetClass(classNameToCheck)); } + bool IsClassOrChildClassOf(const std::string& classNameToCheck) const { return IsClassOrChildClassOf(GetClass(classNameToCheck)); } /// /// Gets whether or not this ClassInfo is the same as, or a child of the given ClassInfo. /// /// The name of the class to check for. /// Whether or not this ClassInfo is the same as, or a child of the given ClassInfo. - bool IsClassOrChildClassOf(const ClassInfo *classInfoToCheck) const; + bool IsClassOrChildClassOf(const ClassInfo* classInfoToCheck) const; #pragma endregion #pragma region Memory Management @@ -154,20 +154,20 @@ namespace RTE { /// Grabs from the pre-allocated pool, an available chunk of memory the exact size of the Entity this ClassInfo represents. OWNERSHIP IS TRANSFERRED! /// /// A pointer to the pre-allocated pool memory. OWNERSHIP IS TRANSFERRED! - void * GetPoolMemory(); + void* GetPoolMemory(); /// /// Returns a raw chunk of memory back to the pre-allocated available pool. /// /// The raw chunk of memory that is being returned. Needs to be the same size as the type this ClassInfo describes. OWNERSHIP IS TRANSFERRED! /// The count of outstanding memory chunks after this was returned. - int ReturnPoolMemory(void *returnedMemory); + int ReturnPoolMemory(void* returnedMemory); /// /// Writes a bunch of useful debug info about the memory pools to a file. /// /// The writer to write info to. - static void DumpPoolMemoryInfo(const Writer &fileWriter); + static void DumpPoolMemoryInfo(const Writer& fileWriter); /// /// Adds a certain number of newly allocated instances to this' pool. @@ -193,32 +193,31 @@ namespace RTE { /// Dynamically allocates an instance of the Entity subclass that this ClassInfo represents. If the Entity isn't concrete, 0 will be returned. /// /// A pointer to the dynamically allocated Entity. Ownership is transferred. If the represented Entity subclass isn't concrete, 0 will be returned. - virtual Entity * NewInstance() const { return IsConcrete() ? m_NewInstance() : 0; } + virtual Entity* NewInstance() const { return IsConcrete() ? m_NewInstance() : 0; } #pragma endregion protected: - - static ClassInfo *s_ClassHead; //!< Head of unordered linked list of ClassInfos in existence. + static ClassInfo* s_ClassHead; //!< Head of unordered linked list of ClassInfos in existence. const std::string m_Name; //!< A string with the friendly - formatted name of this ClassInfo. - const ClassInfo *m_ParentInfo; //!< A pointer to the parent ClassInfo. + const ClassInfo* m_ParentInfo; //!< A pointer to the parent ClassInfo. MemoryAllocate m_Allocate; //!< Raw memory allocation for the size of the type this ClassInfo describes. MemoryDeallocate m_Deallocate; //!< Raw memory deallocation for the size of the type this ClassInfo describes. // TODO: figure out why this doesn't want to work when defined as std::function. - Entity *(*m_NewInstance)(); //!< Returns an actual new instance of the type that this describes. + Entity* (*m_NewInstance)(); //!< Returns an actual new instance of the type that this describes. - ClassInfo *m_NextClass; //!< Next ClassInfo after this one on aforementioned unordered linked list. + ClassInfo* m_NextClass; //!< Next ClassInfo after this one on aforementioned unordered linked list. - std::vector m_AllocatedPool; //!< Pool of pre-allocated objects of the type described by this ClassInfo. + std::vector m_AllocatedPool; //!< Pool of pre-allocated objects of the type described by this ClassInfo. int m_PoolAllocBlockCount; //!< The number of instances to fill up the pool of this type with each time it runs dry. int m_InstancesInUse; //!< The number of allocated instances passed out from the pool. std::mutex m_Mutex; //!< Mutex to ensure multiple things aren't grabbing/deallocating memory at the same time // Forbidding copying - ClassInfo(const ClassInfo &reference) = delete; - ClassInfo & operator=(const ClassInfo &rhs) = delete; + ClassInfo(const ClassInfo& reference) = delete; + ClassInfo& operator=(const ClassInfo& rhs) = delete; }; #pragma endregion @@ -239,7 +238,7 @@ namespace RTE { /// /// A reference to the Entity to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - virtual int Create(const Entity &reference); + virtual int Create(const Entity& reference); /// /// Makes the Serializable ready for use. @@ -248,14 +247,17 @@ namespace RTE { /// Whether there is a class name in the stream to check against to make sure the correct type is being read from the stream. /// Whether to do any additional initialization of the object after reading in all the properties from the Reader. This is done by calling Create(). /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(Reader &reader, bool checkType = true, bool doCreate = true) override { return Serializable::Create(reader, checkType, doCreate); } + int Create(Reader& reader, bool checkType = true, bool doCreate = true) override { return Serializable::Create(reader, checkType, doCreate); } /// /// Uses a passed-in instance, or creates a new one, and makes it identical to this. /// /// A pointer to an instance to make identical to this. If 0 is passed in, a new instance is made inside here, and ownership of it IS returned! /// An Entity pointer to the newly cloned-to instance. Ownership IS transferred! - virtual Entity * Clone(Entity *cloneTo = nullptr) const { RTEAbort("Attempt to clone an abstract or unclonable type!"); return nullptr; } + virtual Entity* Clone(Entity* cloneTo = nullptr) const { + RTEAbort("Attempt to clone an abstract or unclonable type!"); + return nullptr; + } #pragma endregion #pragma region Destruction @@ -283,7 +285,7 @@ namespace RTE { /// /// A Writer that the Entity will save itself to. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int SavePresetCopy(Writer &writer) const; + int SavePresetCopy(Writer& writer) const; #pragma endregion #pragma region Getters and Setters @@ -303,13 +305,13 @@ namespace RTE { /// Gets this Entity's data preset. /// /// This Entity's data preset. - const Entity * GetPreset() const; + const Entity* GetPreset() const; /// /// Gets the name of this Entity's data Preset. /// /// A string reference with the instance name of this Entity. - const std::string & GetPresetName() const { return m_PresetName; } + const std::string& GetPresetName() const { return m_PresetName; } /// /// Sets the name of this Entity's data Preset. @@ -318,19 +320,22 @@ namespace RTE { /// Whether this method was called from Lua, in which case this change is cosmetic only and shouldn't affect scripts. // TODO: Replace the calledFromLua flag with some DisplayName property // TODO: Figure out how to handle if same name was set, still make it wasgivenname = true? - virtual void SetPresetName(const std::string &newName, bool calledFromLua = false) { /*if (m_PresetName != newName) { m_IsOriginalPreset = true; }*/ m_IsOriginalPreset = calledFromLua ? m_IsOriginalPreset : true; m_PresetName = newName; } + virtual void SetPresetName(const std::string& newName, bool calledFromLua = false) { /*if (m_PresetName != newName) { m_IsOriginalPreset = true; }*/ + m_IsOriginalPreset = calledFromLua ? m_IsOriginalPreset : true; + m_PresetName = newName; + } /// /// Gets the plain text description of this Entity's data Preset. /// /// A string reference with the plain text description name of this Preset. - const std::string & GetDescription() const { return m_PresetDescription; } + const std::string& GetDescription() const { return m_PresetDescription; } /// /// Sets the plain text description of this Entity's data Preset. Shouldn't be more than a couple of sentences. /// /// A string reference with the preset description. - void SetDescription(const std::string &newDesc) { m_PresetDescription = newDesc; } + void SetDescription(const std::string& newDesc) { m_PresetDescription = newDesc; } /// /// Gets the name of this Entity's data Preset, preceded by the name of the Data Module it was defined in, separated with a '/'. @@ -361,13 +366,13 @@ namespace RTE { /// Gets the file and line that are currently being read. Formatted to be used for logging warnings and errors. /// /// A string containing the currently read file path and the line being read. - const std::string & GetFormattedReaderPosition() const { return m_FormattedReaderPosition; } + const std::string& GetFormattedReaderPosition() const { return m_FormattedReaderPosition; } /// /// Sets the file and line that are currently being read. Formatted to be used for logging warnings and errors. /// /// A string containing the currently read file path and the line being read. - void SetFormattedReaderPosition(const std::string &newPosition) override { m_FormattedReaderPosition = newPosition; } + void SetFormattedReaderPosition(const std::string& newPosition) override { m_FormattedReaderPosition = newPosition; } #pragma endregion #pragma region Virtual Override Methods @@ -384,26 +389,26 @@ namespace RTE { /// Gets the set of groups this is member of. /// /// A pointer to a list of strings which describes the groups this is added to. Ownership is NOT transferred! - const std::unordered_set * GetGroups() const { return &m_Groups; } + const std::unordered_set* GetGroups() const { return &m_Groups; } /// /// Gets whether this is part of a specific group or not. /// /// A string which describes the group to check for. /// Whether this Entity is in the specified group or not. - bool IsInGroup(const std::string &whichGroup) const { return whichGroup == "None" ? false : (whichGroup == "All" || whichGroup == "Any" || m_Groups.contains(whichGroup)); } + bool IsInGroup(const std::string& whichGroup) const { return whichGroup == "None" ? false : (whichGroup == "All" || whichGroup == "Any" || m_Groups.contains(whichGroup)); } /// /// Adds this Entity to a new grouping. /// /// A string which describes the group to add this to. Duplicates will be ignored. - void AddToGroup(const std::string &newGroup) { m_Groups.emplace(newGroup); } + void AddToGroup(const std::string& newGroup) { m_Groups.emplace(newGroup); } /// /// Removes this Entity from the specified grouping. /// /// A string which describes the group to remove this from. - void RemoveFromGroup(const std::string &groupToRemoveFrom) { m_Groups.erase(groupToRemoveFrom); } + void RemoveFromGroup(const std::string& groupToRemoveFrom) { m_Groups.erase(groupToRemoveFrom); } /// /// Returns random weight used in PresetMan::GetRandomBuyableOfGroupFromTech. @@ -428,7 +433,10 @@ namespace RTE { /// An ostream reference as the left hand side operand. /// A Entity reference as the right hand side operand. /// An ostream reference for further use in an expression. - friend std::ostream & operator<<(std::ostream &stream, const Entity &operand) { stream << operand.GetPresetName() << ", " << operand.GetClassName(); return stream; } + friend std::ostream& operator<<(std::ostream& stream, const Entity& operand) { + stream << operand.GetPresetName() << ", " << operand.GetClassName(); + return stream; + } /// /// A Reader extraction operator for filling an Entity from a Reader. @@ -436,7 +444,7 @@ namespace RTE { /// A Reader reference as the left hand side operand. /// An Entity reference as the right hand side operand. /// A Reader reference for further use in an expression. - friend Reader & operator>>(Reader &reader, Entity &operand); + friend Reader& operator>>(Reader& reader, Entity& operand); /// /// A Reader extraction operator for filling an Entity from a Reader. @@ -444,7 +452,7 @@ namespace RTE { /// A Reader reference as the left hand side operand. /// An Entity pointer as the right hand side operand. /// A Reader reference for further use in an expression. - friend Reader & operator>>(Reader &reader, Entity *operand); + friend Reader& operator>>(Reader& reader, Entity* operand); #pragma endregion #pragma region Class Info @@ -452,17 +460,16 @@ namespace RTE { /// Gets the ClassInfo instance of this Entity. /// /// A reference to the ClassInfo of this' class. - virtual const Entity::ClassInfo & GetClass() const { return m_sClass; } + virtual const Entity::ClassInfo& GetClass() const { return m_sClass; } /// /// Gets the class name of this Entity. /// /// A string with the friendly-formatted type name of this Entity. - virtual const std::string & GetClassName() const { return m_sClass.GetName(); } + virtual const std::string& GetClassName() const { return m_sClass.GetName(); } #pragma endregion protected: - static Entity::ClassInfo m_sClass; //!< Type description of this Entity. std::string m_PresetName; //!< The name of the Preset data this was cloned from, if any. @@ -477,15 +484,14 @@ namespace RTE { int m_RandomWeight; //!< Random weight used when picking item using PresetMan::GetRandomBuyableOfGroupFromTech. From 0 to 100. 0 means item won't be ever picked. // Forbidding copying - Entity(const Entity &reference) {} - Entity & operator=(const Entity &rhs) { return *this; } + Entity(const Entity& reference) {} + Entity& operator=(const Entity& rhs) { return *this; } private: - /// /// Clears all the member variables of this Entity, effectively resetting the members of this abstraction level only. /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/GLCheck.cpp b/Source/System/GLCheck.cpp index 17f7e7166..a715eee0c 100644 --- a/Source/System/GLCheck.cpp +++ b/Source/System/GLCheck.cpp @@ -1,6 +1,6 @@ #include "GLCheck.h" #include "glad/gl.h" -void CheckOpenGLError(const char *stmt, const char *fname, int line) { +void CheckOpenGLError(const char* stmt, const char* fname, int line) { GLenum err = glGetError(); if (err != GL_NO_ERROR) { printf("OpenGL error %08x, at %s:%i - for %s\n", err, fname, line, stmt); diff --git a/Source/System/GLCheck.h b/Source/System/GLCheck.h index ca3bf9239..4e2038c7d 100644 --- a/Source/System/GLCheck.h +++ b/Source/System/GLCheck.h @@ -5,7 +5,7 @@ /// Debug function to print GL errors to the console from: /// https : // stackoverflow.com/questions/11256470/define-a-macro-to-facilitate-opengl-command-debugging /// -void CheckOpenGLError(const char *stmt, const char *fname, int line); +void CheckOpenGLError(const char* stmt, const char* fname, int line); ///< summary> /// Debug macro to be used for all GL calls. diff --git a/Source/System/GameVersion.h b/Source/System/GameVersion.h index 4ca1327c1..1f5b1704c 100644 --- a/Source/System/GameVersion.h +++ b/Source/System/GameVersion.h @@ -6,8 +6,8 @@ namespace RTE { #pragma region Game Version - static constexpr const char *c_VersionString = "5.1.0"; + static constexpr const char* c_VersionString = "5.1.0"; static const version::Semver200_version c_GameVersion = version::Semver200_version(c_VersionString); #pragma endregion -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Gamepad.h b/Source/System/Gamepad.h index 2b4a7336c..2fdb24959 100644 --- a/Source/System/Gamepad.h +++ b/Source/System/Gamepad.h @@ -29,7 +29,8 @@ namespace RTE { /// The joystick ID for event handling. /// Number of analog axis. /// Number of buttons. - Gamepad(int deviceIndex, SDL_JoystickID id, int numAxis, int numButtons) : m_DeviceIndex(deviceIndex), m_JoystickID(id), m_Axis(numAxis), m_DigitalAxis(numAxis), m_Buttons(numButtons) {} + Gamepad(int deviceIndex, SDL_JoystickID id, int numAxis, int numButtons) : + m_DeviceIndex(deviceIndex), m_JoystickID(id), m_Axis(numAxis), m_DigitalAxis(numAxis), m_Buttons(numButtons) {} #pragma endregion #pragma region Operator Overloads @@ -45,14 +46,14 @@ namespace RTE { /// /// A Gamepad reference as the right hand side operand. /// A boolean indicating whether the two operands are equal or not. - bool operator==(const Gamepad &rhs) const { return m_JoystickID == rhs.m_JoystickID; } + bool operator==(const Gamepad& rhs) const { return m_JoystickID == rhs.m_JoystickID; } /// /// Comparison operator for sorting Gamepads by ID. /// /// A Gamepad reference as the right hand side operand. /// A boolean indicating the comparison result. - bool operator<(const Gamepad &rhs) const { return m_JoystickID < rhs.m_JoystickID; } + bool operator<(const Gamepad& rhs) const { return m_JoystickID < rhs.m_JoystickID; } }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/GenericSavedData.cpp b/Source/System/GenericSavedData.cpp index e9b22abff..539b42062 100644 --- a/Source/System/GenericSavedData.cpp +++ b/Source/System/GenericSavedData.cpp @@ -9,11 +9,11 @@ namespace RTE { const std::string GenericSavedData::GenericSavedStrings::c_ClassName = "GenericSavedStrings"; const std::string GenericSavedData::GenericSavedNumbers::c_ClassName = "GenericSavedNumbers"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::ReadProperty(const std::string_view &propName, Reader &reader) { + int GenericSavedData::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("StringValues", { reader >> m_SavedStrings; }); MatchProperty("EncodedStringValues", { reader >> m_SavedEncodedStrings; }); MatchProperty("NumberValues", { reader >> m_SavedNumbers; }); @@ -21,9 +21,9 @@ namespace RTE { EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::Save(Writer &writer) const { + int GenericSavedData::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("EncodedStringValues", m_SavedEncodedStrings); @@ -33,9 +33,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void GenericSavedData::SaveString(const std::string &key, const std::string &value) { + void GenericSavedData::SaveString(const std::string& key, const std::string& value) { if (value.length() == 0) { m_SavedEncodedStrings.m_Data[key] = value; m_SavedStrings.m_Data[key] = value; @@ -67,74 +67,78 @@ namespace RTE { m_SavedEncodedStrings.m_Data[key] = ""; m_SavedStrings.m_Data[key] = value; } - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::string &GenericSavedData::LoadString(const std::string &key) { - const std::string *loadString = &m_SavedStrings.m_Data[key]; + const std::string& GenericSavedData::LoadString(const std::string& key) { + const std::string* loadString = &m_SavedStrings.m_Data[key]; if (*loadString == "") { loadString = &m_SavedEncodedStrings.m_Data[key]; } return *loadString; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::GenericSavedEncodedStrings::ReadProperty(const std::string_view &propName, Reader &reader) { + int GenericSavedData::GenericSavedEncodedStrings::ReadProperty(const std::string_view& propName, Reader& reader) { std::string value = reader.ReadPropValue(); m_Data[std::string(propName)] = base64_decode(value); // until we get P0919R2. return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::GenericSavedEncodedStrings::Save(Writer &writer) const { + int GenericSavedData::GenericSavedEncodedStrings::Save(Writer& writer) const { Serializable::Save(writer); - for (const auto &[propName, value] : m_Data) { + for (const auto& [propName, value]: m_Data) { // Need to encode as URL, so it avoids = character - if (!value.empty()) { writer.NewPropertyWithValue(propName, base64_encode(value, true)); } + if (!value.empty()) { + writer.NewPropertyWithValue(propName, base64_encode(value, true)); + } } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::GenericSavedStrings::ReadProperty(const std::string_view &propName, Reader &reader) { + int GenericSavedData::GenericSavedStrings::ReadProperty(const std::string_view& propName, Reader& reader) { m_Data[std::string(propName)] = reader.ReadPropValue(); // until we get P0919R2. return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::GenericSavedStrings::Save(Writer &writer) const { + int GenericSavedData::GenericSavedStrings::Save(Writer& writer) const { Serializable::Save(writer); - for (const auto &[propName, value] : m_Data) { - if (!value.empty()) { writer.NewPropertyWithValue(propName, value); } + for (const auto& [propName, value]: m_Data) { + if (!value.empty()) { + writer.NewPropertyWithValue(propName, value); + } } return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::GenericSavedNumbers::ReadProperty(const std::string_view &propName, Reader &reader) { + int GenericSavedData::GenericSavedNumbers::ReadProperty(const std::string_view& propName, Reader& reader) { float value; reader >> value; m_Data[std::string(propName)] = value; // until we get P0919R2. return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int GenericSavedData::GenericSavedNumbers::Save(Writer &writer) const { + int GenericSavedData::GenericSavedNumbers::Save(Writer& writer) const { Serializable::Save(writer); - for (const auto &[propName, value] : m_Data) { + for (const auto& [propName, value]: m_Data) { writer.NewPropertyWithValue(propName, value); } return 0; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/GenericSavedData.h b/Source/System/GenericSavedData.h index c664dae44..29a6022d3 100644 --- a/Source/System/GenericSavedData.h +++ b/Source/System/GenericSavedData.h @@ -16,7 +16,6 @@ namespace RTE { class GenericSavedEncodedStrings : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -29,12 +28,11 @@ namespace RTE { /// Constructor method used to instantiate a GenericSavedEncodedStrings object to be identical to another, by deep copy, and make it ready for use. /// /// A reference to the GenericSavedEncodedStrings to deep copy. - GenericSavedEncodedStrings(const GenericSavedEncodedStrings &reference) = default; + GenericSavedEncodedStrings(const GenericSavedEncodedStrings& reference) = default; std::unordered_map m_Data; //!< Stored string data. private: - static const std::string c_ClassName; //!< A string with the friendly formatted type name of this object. }; @@ -44,7 +42,6 @@ namespace RTE { class GenericSavedStrings : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -57,12 +54,11 @@ namespace RTE { /// Constructor method used to instantiate a GenericSavedStrings object to be identical to another, by deep copy, and make it ready for use. /// /// A reference to the GenericSavedStrings to deep copy. - GenericSavedStrings(const GenericSavedStrings &reference) = default; + GenericSavedStrings(const GenericSavedStrings& reference) = default; std::unordered_map m_Data; //!< Stored string data. private: - static const std::string c_ClassName; //!< A string with the friendly formatted type name of this object. }; @@ -72,7 +68,6 @@ namespace RTE { class GenericSavedNumbers : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -85,17 +80,15 @@ namespace RTE { /// Constructor method used to instantiate a GenericSavedNumbers object to be identical to another, by deep copy, and make it ready for use. /// /// A reference to the GenericSavedNumbers to deep copy. - GenericSavedNumbers(const GenericSavedNumbers &reference) = default; + GenericSavedNumbers(const GenericSavedNumbers& reference) = default; std::unordered_map m_Data; //!< Stored number data. private: - static const std::string c_ClassName; //!< A string with the friendly formatted type name of this object. }; public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -108,21 +101,20 @@ namespace RTE { /// Constructor method used to instantiate a GenericSavedData object to be identical to another, by deep copy, and make it ready for use. /// /// A reference to the GenericSavedData to deep copy. - GenericSavedData(const GenericSavedData &reference) = default; + GenericSavedData(const GenericSavedData& reference) = default; - void SaveString(const std::string &key, const std::string &value); - const std::string& LoadString(const std::string &key); + void SaveString(const std::string& key, const std::string& value); + const std::string& LoadString(const std::string& key); - void SaveNumber(const std::string &key, float value) { m_SavedNumbers.m_Data[key] = value; }; - float LoadNumber(const std::string &key) { return m_SavedNumbers.m_Data[key]; }; + void SaveNumber(const std::string& key, float value) { m_SavedNumbers.m_Data[key] = value; }; + float LoadNumber(const std::string& key) { return m_SavedNumbers.m_Data[key]; }; - GenericSavedEncodedStrings m_SavedEncodedStrings; //!< Stored encoded string data. - GenericSavedStrings m_SavedStrings; //!< Stored string data. - GenericSavedNumbers m_SavedNumbers; //!< Stored number data. + GenericSavedEncodedStrings m_SavedEncodedStrings; //!< Stored encoded string data. + GenericSavedStrings m_SavedStrings; //!< Stored string data. + GenericSavedNumbers m_SavedNumbers; //!< Stored number data. private: - static const std::string c_ClassName; //!< A string with the friendly formatted type name of this object. }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/GraphicalPrimitive.cpp b/Source/System/GraphicalPrimitive.cpp index 59c229ef0..f677d62c0 100644 --- a/Source/System/GraphicalPrimitive.cpp +++ b/Source/System/GraphicalPrimitive.cpp @@ -27,15 +27,17 @@ namespace RTE { const GraphicalPrimitive::PrimitiveType TextPrimitive::c_PrimitiveType = PrimitiveType::Text; const GraphicalPrimitive::PrimitiveType BitmapPrimitive::c_PrimitiveType = PrimitiveType::Bitmap; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void GraphicalPrimitive::TranslateCoordinates(Vector targetPos, const Vector &scenePos, Vector &drawLeftPos, Vector &drawRightPos) const { + void GraphicalPrimitive::TranslateCoordinates(Vector targetPos, const Vector& scenePos, Vector& drawLeftPos, Vector& drawRightPos) const { drawLeftPos = scenePos; drawRightPos = scenePos; if (g_SceneMan.SceneWrapsX()) { float sceneWidth = static_cast(g_SceneMan.GetSceneWidth()); - if (targetPos.m_X <= sceneWidth && targetPos.m_X > sceneWidth / 2) { targetPos.m_X -= sceneWidth; } + if (targetPos.m_X <= sceneWidth && targetPos.m_X > sceneWidth / 2) { + targetPos.m_X -= sceneWidth; + } drawLeftPos.m_X = (drawLeftPos.m_X > 0) ? (drawLeftPos.m_X -= sceneWidth) : (drawLeftPos.m_X -= sceneWidth + targetPos.m_X); } drawLeftPos.m_X -= targetPos.m_X; @@ -43,16 +45,18 @@ namespace RTE { if (g_SceneMan.SceneWrapsY()) { float sceneHeight = static_cast(g_SceneMan.GetSceneHeight()); - if (targetPos.m_Y <= sceneHeight && targetPos.m_Y > sceneHeight / 2) { targetPos.m_Y -= sceneHeight; } + if (targetPos.m_Y <= sceneHeight && targetPos.m_Y > sceneHeight / 2) { + targetPos.m_Y -= sceneHeight; + } drawLeftPos.m_Y = (drawLeftPos.m_Y > 0) ? (drawLeftPos.m_Y -= sceneHeight) : (drawLeftPos.m_Y -= sceneHeight + targetPos.m_Y); } drawLeftPos.m_Y -= targetPos.m_Y; drawRightPos.m_Y -= targetPos.m_Y; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void LinePrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void LinePrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; Vector drawEnd = m_EndPos - targetPos; @@ -71,9 +75,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ArcPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void ArcPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; if (m_Thickness > 1) { @@ -90,7 +94,7 @@ namespace RTE { TranslateCoordinates(targetPos, m_StartPos, drawStartLeft, drawStartRight); if (m_Thickness > 1) { - for (int i = 0; i < m_Thickness; i++){ + for (int i = 0; i < m_Thickness; i++) { arc(drawScreen, drawStartLeft.GetFloorIntX(), drawStartLeft.GetFloorIntY(), ftofix(GetAllegroAngle(m_StartAngle)), ftofix(GetAllegroAngle(m_EndAngle)), (m_Radius - (m_Thickness / 2)) + i, m_Color); arc(drawScreen, drawStartRight.GetFloorIntX(), drawStartRight.GetFloorIntY(), ftofix(GetAllegroAngle(m_StartAngle)), ftofix(GetAllegroAngle(m_EndAngle)), (m_Radius - (m_Thickness / 2)) + i, m_Color); } @@ -101,16 +105,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SplinePrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void SplinePrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; Vector drawGuideA = m_GuidePointAPos - targetPos; Vector drawGuideB = m_GuidePointBPos - targetPos; Vector drawEnd = m_EndPos - targetPos; - std::array guidePoints = { drawStart.GetFloorIntX(), drawStart.GetFloorIntY(), drawGuideA.GetFloorIntX(), drawGuideA.GetFloorIntY(), drawGuideB.GetFloorIntX(), drawGuideB.GetFloorIntY(), drawEnd.GetFloorIntX(), drawEnd.GetFloorIntY() }; + std::array guidePoints = {drawStart.GetFloorIntX(), drawStart.GetFloorIntY(), drawGuideA.GetFloorIntX(), drawGuideA.GetFloorIntY(), drawGuideB.GetFloorIntX(), drawGuideB.GetFloorIntY(), drawEnd.GetFloorIntX(), drawEnd.GetFloorIntY()}; spline(drawScreen, guidePoints.data(), m_Color); } else { Vector drawStartLeft; @@ -127,16 +131,16 @@ namespace RTE { TranslateCoordinates(targetPos, m_GuidePointBPos, drawGuideBLeft, drawGuideBRight); TranslateCoordinates(targetPos, m_EndPos, drawEndLeft, drawEndRight); - std::array guidePointsLeft = { drawStartLeft.GetFloorIntX(), drawStartLeft.GetFloorIntY(), drawGuideALeft.GetFloorIntX(), drawGuideALeft.GetFloorIntY(), drawGuideBLeft.GetFloorIntX(), drawGuideBLeft.GetFloorIntY(), drawEndLeft.GetFloorIntX(), drawEndLeft.GetFloorIntY() }; - std::array guidePointsRight = { drawStartRight.GetFloorIntX(), drawStartRight.GetFloorIntY(), drawGuideARight.GetFloorIntX(), drawGuideARight.GetFloorIntY(), drawGuideBRight.GetFloorIntX(), drawGuideBRight.GetFloorIntY(), drawEndRight.GetFloorIntX(), drawEndRight.GetFloorIntY() }; + std::array guidePointsLeft = {drawStartLeft.GetFloorIntX(), drawStartLeft.GetFloorIntY(), drawGuideALeft.GetFloorIntX(), drawGuideALeft.GetFloorIntY(), drawGuideBLeft.GetFloorIntX(), drawGuideBLeft.GetFloorIntY(), drawEndLeft.GetFloorIntX(), drawEndLeft.GetFloorIntY()}; + std::array guidePointsRight = {drawStartRight.GetFloorIntX(), drawStartRight.GetFloorIntY(), drawGuideARight.GetFloorIntX(), drawGuideARight.GetFloorIntY(), drawGuideBRight.GetFloorIntX(), drawGuideBRight.GetFloorIntY(), drawEndRight.GetFloorIntX(), drawEndRight.GetFloorIntY()}; spline(drawScreen, guidePointsLeft.data(), m_Color); spline(drawScreen, guidePointsRight.data(), m_Color); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void BoxPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void BoxPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; Vector drawEnd = m_EndPos - targetPos; @@ -155,9 +159,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void BoxFillPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void BoxFillPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; Vector drawEnd = m_EndPos - targetPos; @@ -176,11 +180,15 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void RoundedBoxPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { - if (m_StartPos.m_X > m_EndPos.m_X) { std::swap(m_StartPos.m_X, m_EndPos.m_X); } - if (m_StartPos.m_Y > m_EndPos.m_Y) { std::swap(m_StartPos.m_Y, m_EndPos.m_Y); } + void RoundedBoxPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { + if (m_StartPos.m_X > m_EndPos.m_X) { + std::swap(m_StartPos.m_X, m_EndPos.m_X); + } + if (m_StartPos.m_Y > m_EndPos.m_Y) { + std::swap(m_StartPos.m_Y, m_EndPos.m_Y); + } if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; @@ -224,11 +232,15 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void RoundedBoxFillPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { - if (m_StartPos.m_X > m_EndPos.m_X) { std::swap(m_StartPos.m_X, m_EndPos.m_X); } - if (m_StartPos.m_Y > m_EndPos.m_Y) { std::swap(m_StartPos.m_Y, m_EndPos.m_Y); } + void RoundedBoxFillPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { + if (m_StartPos.m_X > m_EndPos.m_X) { + std::swap(m_StartPos.m_X, m_EndPos.m_X); + } + if (m_StartPos.m_Y > m_EndPos.m_Y) { + std::swap(m_StartPos.m_Y, m_EndPos.m_Y); + } if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; @@ -266,9 +278,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void CirclePrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void CirclePrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; circle(drawScreen, drawStart.GetFloorIntX(), drawStart.GetFloorIntY(), m_Radius, m_Color); @@ -283,9 +295,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void CircleFillPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void CircleFillPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; circlefill(drawScreen, drawStart.GetFloorIntX(), drawStart.GetFloorIntY(), m_Radius, m_Color); @@ -300,9 +312,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void EllipsePrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void EllipsePrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; ellipse(drawScreen, drawStart.GetFloorIntX(), drawStart.GetFloorIntY(), m_HorizRadius, m_VertRadius, m_Color); @@ -317,9 +329,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void EllipseFillPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void EllipseFillPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart = m_StartPos - targetPos; ellipsefill(drawScreen, drawStart.GetFloorIntX(), drawStart.GetFloorIntY(), m_HorizRadius, m_VertRadius, m_Color); @@ -334,9 +346,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TrianglePrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void TrianglePrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawPointA = m_PointAPos - targetPos; Vector drawPointB = m_PointBPos - targetPos; @@ -365,9 +377,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TriangleFillPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void TriangleFillPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawPointA = m_PointAPos - targetPos; Vector drawPointB = m_PointBPos - targetPos; @@ -390,9 +402,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PolygonPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void PolygonPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { Vector drawStart; Vector drawEnd; @@ -416,9 +428,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PolygonFillPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void PolygonFillPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { size_t drawPointsSize = m_Vertices.size() * 2; if (!g_SceneMan.SceneWrapsX() && !g_SceneMan.SceneWrapsY()) { @@ -427,8 +439,8 @@ namespace RTE { std::vector drawPoints = {}; drawPoints.reserve(drawPointsSize); - for (const Vector *vertice : m_Vertices) { - drawPoints.insert(drawPoints.end(), { drawStart.GetFloorIntX() + vertice->GetFloorIntX(), drawStart.GetFloorIntY() + vertice->GetFloorIntY() }); + for (const Vector* vertice: m_Vertices) { + drawPoints.insert(drawPoints.end(), {drawStart.GetFloorIntX() + vertice->GetFloorIntX(), drawStart.GetFloorIntY() + vertice->GetFloorIntY()}); } polygon(drawScreen, m_Vertices.size(), drawPoints.data(), m_Color); } else { @@ -440,30 +452,30 @@ namespace RTE { Vector drawPointLeft; Vector drawPointRight; - for (const Vector *vertice : m_Vertices) { + for (const Vector* vertice: m_Vertices) { TranslateCoordinates(targetPos, m_StartPos + (*vertice), drawPointLeft, drawPointRight); - drawPointsLeft.insert(drawPointsLeft.end(), { drawPointLeft.GetFloorIntX(), drawPointLeft.GetFloorIntY() }); - drawPointsRight.insert(drawPointsRight.end(), { drawPointRight.GetFloorIntX(), drawPointRight.GetFloorIntY() }); + drawPointsLeft.insert(drawPointsLeft.end(), {drawPointLeft.GetFloorIntX(), drawPointLeft.GetFloorIntY()}); + drawPointsRight.insert(drawPointsRight.end(), {drawPointRight.GetFloorIntX(), drawPointRight.GetFloorIntY()}); } polygon(drawScreen, m_Vertices.size(), drawPointsLeft.data(), m_Color); polygon(drawScreen, m_Vertices.size(), drawPointsRight.data(), m_Color); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void TextPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void TextPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (m_Text.empty()) { return; } AllegroBitmap playerGUIBitmap(drawScreen); - GUIFont *font = m_IsSmall ? g_FrameMan.GetSmallFont() : g_FrameMan.GetLargeFont(); + GUIFont* font = m_IsSmall ? g_FrameMan.GetSmallFont() : g_FrameMan.GetLargeFont(); Matrix rotation = Matrix(m_RotAngle); Vector targetPosAdjustment = Vector(); - BITMAP *tempDrawBitmap = nullptr; + BITMAP* tempDrawBitmap = nullptr; if (m_BlendMode > DrawBlendMode::NoBlend || m_RotAngle != 0) { int textWidth = font->CalculateWidth(m_Text); int textHeight = font->CalculateHeight(m_Text); @@ -516,22 +528,24 @@ namespace RTE { } } } - if (tempDrawBitmap) { destroy_bitmap(tempDrawBitmap); } + if (tempDrawBitmap) { + destroy_bitmap(tempDrawBitmap); + } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void BitmapPrimitive::Draw(BITMAP *drawScreen, const Vector &targetPos) { + void BitmapPrimitive::Draw(BITMAP* drawScreen, const Vector& targetPos) { if (!m_Bitmap) { return; } - BITMAP *bitmapToDraw = create_bitmap_ex(8, m_Bitmap->w, m_Bitmap->h); + BITMAP* bitmapToDraw = create_bitmap_ex(8, m_Bitmap->w, m_Bitmap->h); clear_to_color(bitmapToDraw, ColorKeys::g_MaskColor); draw_sprite(bitmapToDraw, m_Bitmap, 0, 0); if (m_HFlipped || m_VFlipped) { - BITMAP *flipBitmap = create_bitmap_ex(8, bitmapToDraw->w, bitmapToDraw->h); + BITMAP* flipBitmap = create_bitmap_ex(8, bitmapToDraw->w, bitmapToDraw->h); clear_to_color(flipBitmap, ColorKeys::g_MaskColor); if (m_HFlipped && !m_VFlipped) { @@ -572,4 +586,4 @@ namespace RTE { } destroy_bitmap(bitmapToDraw); } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/GraphicalPrimitive.h b/Source/System/GraphicalPrimitive.h index 5d53cb82b..0307abc5a 100644 --- a/Source/System/GraphicalPrimitive.h +++ b/Source/System/GraphicalPrimitive.h @@ -13,13 +13,12 @@ namespace RTE { class GraphicalPrimitive { public: - - /// - /// Convenience macro to cut down on duplicate methods in classes that extend GraphicalPrimitive. - /// - #define GraphicalPrimitiveOverrideMethods \ - const PrimitiveType GetPrimitiveType() const override { return c_PrimitiveType; } \ - void Draw(BITMAP *drawScreen, const Vector &targetPos) override; +/// +/// Convenience macro to cut down on duplicate methods in classes that extend GraphicalPrimitive. +/// +#define GraphicalPrimitiveOverrideMethods \ + const PrimitiveType GetPrimitiveType() const override { return c_PrimitiveType; } \ + void Draw(BITMAP* drawScreen, const Vector& targetPos) override; /// /// Enumeration of the different primitive types derived from GraphicalPrimitive. @@ -50,7 +49,7 @@ namespace RTE { unsigned char m_Color = 0; //!< Color to draw this primitive with. int m_Player = -1; //!< Player screen to draw this primitive on. DrawBlendMode m_BlendMode = DrawBlendMode::NoBlend; //!< The blending mode that will be used when drawing this primitive. - std::array m_ColorChannelBlendAmounts = { BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend }; //!< The blending amount for each color channel when drawing in blended mode. + std::array m_ColorChannelBlendAmounts = {BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend, BlendAmountLimits::MinBlend}; //!< The blending amount for each color channel when drawing in blended mode. /// /// Destructor method used to clean up a GraphicalPrimitive object before deletion from system memory. @@ -72,14 +71,14 @@ namespace RTE { /// I really don't know how to make it simpler, because it has so many special cases and simply wrapping all out-of-the scene coordinates don't work because this way nothing will be ever draw across the seam. /// You're welcome to rewrite this nightmare if you can, I wasted a whole week on this (I can admit that I'm just too dumb for this) ))) /// - void TranslateCoordinates(Vector targetPos, const Vector &scenePos, Vector &drawLeftPos, Vector &drawRightPos) const; + void TranslateCoordinates(Vector targetPos, const Vector& scenePos, Vector& drawLeftPos, Vector& drawRightPos) const; /// /// Draws this primitive on provided bitmap. /// /// Bitmap to draw on. /// Position of graphical primitive. - virtual void Draw(BITMAP *drawScreen, const Vector &targetPos) = 0; + virtual void Draw(BITMAP* drawScreen, const Vector& targetPos) = 0; /// /// Gets the type identifier of this primitive. @@ -88,7 +87,6 @@ namespace RTE { virtual const PrimitiveType GetPrimitiveType() const = 0; private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -100,7 +98,6 @@ namespace RTE { class LinePrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; /// @@ -110,7 +107,7 @@ namespace RTE { /// Start position of the primitive. /// End position of the primitive. /// Color to draw this primitive with. - LinePrimitive(int player, const Vector &startPos, const Vector &endPos, unsigned char color) { + LinePrimitive(int player, const Vector& startPos, const Vector& endPos, unsigned char color) { m_StartPos = startPos; m_EndPos = endPos; m_Color = color; @@ -118,7 +115,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -130,7 +126,6 @@ namespace RTE { class ArcPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; float m_StartAngle = 0; //!< The angle from which the arc begins. @@ -147,8 +142,8 @@ namespace RTE { /// The angle at which the arc drawing ends. /// Radius of the arc primitive. /// Color to draw this primitive with. - ArcPrimitive(int player, const Vector ¢erPos, float startAngle, float endAngle, int radius, int thickness, unsigned char color) : - m_StartAngle(startAngle), m_EndAngle(endAngle), m_Radius(radius), m_Thickness(thickness) { + ArcPrimitive(int player, const Vector& centerPos, float startAngle, float endAngle, int radius, int thickness, unsigned char color) : + m_StartAngle(startAngle), m_EndAngle(endAngle), m_Radius(radius), m_Thickness(thickness) { m_StartPos = centerPos; m_Color = color; @@ -156,7 +151,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -168,7 +162,6 @@ namespace RTE { class SplinePrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; Vector m_GuidePointAPos; //!< A guide point that controls the curve of the spline. @@ -183,8 +176,8 @@ namespace RTE { /// The second guide point that controls the curve of the spline. The spline won't necessarily pass through this point, but it will affect it's shape. /// End position of the primitive. /// Color to draw this primitive with. - SplinePrimitive(int player, const Vector &startPos, const Vector &guideA, const Vector &guideB, const Vector &endPos, unsigned char color) : - m_GuidePointAPos(guideA), m_GuidePointBPos(guideB) { + SplinePrimitive(int player, const Vector& startPos, const Vector& guideA, const Vector& guideB, const Vector& endPos, unsigned char color) : + m_GuidePointAPos(guideA), m_GuidePointBPos(guideB) { m_StartPos = startPos; m_EndPos = endPos; @@ -193,7 +186,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -205,7 +197,6 @@ namespace RTE { class BoxPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; /// @@ -215,7 +206,7 @@ namespace RTE { /// Start position of the primitive. Top left corner. /// End position of the primitive. Bottom right corner. /// Color to draw this primitive with. - BoxPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color) { + BoxPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color) { m_StartPos = topLeftPos; m_EndPos = bottomRightPos; m_Color = color; @@ -223,7 +214,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -235,7 +225,6 @@ namespace RTE { class BoxFillPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; /// @@ -245,7 +234,7 @@ namespace RTE { /// Start position of the primitive. Top left corner. /// End position of the primitive. Bottom right corner. /// Color to draw this primitive with. - BoxFillPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, unsigned char color) { + BoxFillPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, unsigned char color) { m_StartPos = topLeftPos; m_EndPos = bottomRightPos; m_Color = color; @@ -253,7 +242,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -265,7 +253,6 @@ namespace RTE { class RoundedBoxPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; int m_CornerRadius = 0; //!< The radius of the corners of the box. @@ -278,8 +265,8 @@ namespace RTE { /// End position of the primitive. Bottom right corner. /// The radius of the corners of the box. Smaller radius equals sharper corners. /// Color to draw this primitive with. - RoundedBoxPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color) : - m_CornerRadius(cornerRadius) { + RoundedBoxPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color) : + m_CornerRadius(cornerRadius) { m_StartPos = topLeftPos; m_EndPos = bottomRightPos; @@ -288,7 +275,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -300,7 +286,6 @@ namespace RTE { class RoundedBoxFillPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; int m_CornerRadius = 0; //!< The radius of the corners of the box. @@ -313,8 +298,8 @@ namespace RTE { /// End position of the primitive. Bottom right corner. /// The radius of the corners of the box. Smaller radius equals sharper corners. /// Color to draw this primitive with. - RoundedBoxFillPrimitive(int player, const Vector &topLeftPos, const Vector &bottomRightPos, int cornerRadius, unsigned char color) : - m_CornerRadius(cornerRadius) { + RoundedBoxFillPrimitive(int player, const Vector& topLeftPos, const Vector& bottomRightPos, int cornerRadius, unsigned char color) : + m_CornerRadius(cornerRadius) { m_StartPos = topLeftPos; m_EndPos = bottomRightPos; @@ -323,7 +308,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -335,7 +319,6 @@ namespace RTE { class CirclePrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; int m_Radius = 0; //!< Radius of the circle primitive. @@ -347,8 +330,8 @@ namespace RTE { /// Position of this primitive's center. /// Radius of the circle primitive. /// Color to draw this primitive with. - CirclePrimitive(int player, const Vector ¢erPos, int radius, unsigned char color) : - m_Radius(radius) { + CirclePrimitive(int player, const Vector& centerPos, int radius, unsigned char color) : + m_Radius(radius) { m_StartPos = centerPos; m_Color = color; @@ -356,7 +339,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -368,7 +350,6 @@ namespace RTE { class CircleFillPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; int m_Radius = 0; //!< Radius of the circle primitive. @@ -380,8 +361,8 @@ namespace RTE { /// Position of this primitive's center. /// Radius of the circle primitive. /// Color to draw this primitive with. - CircleFillPrimitive(int player, const Vector ¢erPos, int radius, unsigned char color) : - m_Radius(radius) { + CircleFillPrimitive(int player, const Vector& centerPos, int radius, unsigned char color) : + m_Radius(radius) { m_StartPos = centerPos; m_Color = color; @@ -389,7 +370,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -401,7 +381,6 @@ namespace RTE { class EllipsePrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; int m_HorizRadius = 0; //!< The horizontal radius of the ellipse primitive. @@ -415,8 +394,8 @@ namespace RTE { /// Horizontal radius of the ellipse primitive. /// Vertical radius of the ellipse primitive. /// Color to draw this primitive with. - EllipsePrimitive(int player, const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color) : - m_HorizRadius(horizRadius), m_VertRadius(vertRadius) { + EllipsePrimitive(int player, const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color) : + m_HorizRadius(horizRadius), m_VertRadius(vertRadius) { m_StartPos = centerPos; m_Color = color; @@ -424,7 +403,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -436,7 +414,6 @@ namespace RTE { class EllipseFillPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; int m_HorizRadius = 0; //!< The horizontal radius of the ellipse primitive. @@ -449,8 +426,8 @@ namespace RTE { /// Position of this primitive's center. /// Radius of the circle primitive. /// Color to draw this primitive with. - EllipseFillPrimitive(int player, const Vector ¢erPos, int horizRadius, int vertRadius, unsigned char color) : - m_HorizRadius(horizRadius), m_VertRadius(vertRadius) { + EllipseFillPrimitive(int player, const Vector& centerPos, int horizRadius, int vertRadius, unsigned char color) : + m_HorizRadius(horizRadius), m_VertRadius(vertRadius) { m_StartPos = centerPos; m_Color = color; @@ -458,7 +435,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -470,7 +446,6 @@ namespace RTE { class TrianglePrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; Vector m_PointAPos; //!< First point of the triangle. @@ -485,15 +460,14 @@ namespace RTE { /// Position of the second point of the triangle /// Position of the third point of the triangle /// Color to draw this primitive with. - TrianglePrimitive(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color) : - m_PointAPos(pointA), m_PointBPos(pointB), m_PointCPos(pointC) { + TrianglePrimitive(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color) : + m_PointAPos(pointA), m_PointBPos(pointB), m_PointCPos(pointC) { m_Color = color; m_Player = player; } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -505,7 +479,6 @@ namespace RTE { class TriangleFillPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; Vector m_PointAPos; //!< First point of the triangle. @@ -520,15 +493,14 @@ namespace RTE { /// Position of the second point of the triangle /// Position of the third point of the triangle /// Color to draw this primitive with. - TriangleFillPrimitive(int player, const Vector &pointA, const Vector &pointB, const Vector &pointC, unsigned char color) : - m_PointAPos(pointA), m_PointBPos(pointB), m_PointCPos(pointC) { + TriangleFillPrimitive(int player, const Vector& pointA, const Vector& pointB, const Vector& pointC, unsigned char color) : + m_PointAPos(pointA), m_PointBPos(pointB), m_PointCPos(pointC) { m_Color = color; m_Player = player; } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -540,10 +512,9 @@ namespace RTE { class PolygonPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; - std::vector m_Vertices = {}; //!< Positions of the vertices of the polygon, relative to the center position. + std::vector m_Vertices = {}; //!< Positions of the vertices of the polygon, relative to the center position. /// /// Constructor method for PolygonPrimitive object. @@ -552,8 +523,8 @@ namespace RTE { /// Start position of the primitive. /// A vector containing the positions of the vertices of the polygon, relative to the center position. /// Color to draw this primitive with. - PolygonPrimitive(int player, const Vector &startPos, unsigned char color, const std::vector &vertices) : - m_Vertices(vertices) { + PolygonPrimitive(int player, const Vector& startPos, unsigned char color, const std::vector& vertices) : + m_Vertices(vertices) { m_StartPos = startPos; m_Color = color; @@ -561,7 +532,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -573,10 +543,9 @@ namespace RTE { class PolygonFillPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; - std::vector m_Vertices = {}; //!< Positions of the vertices of the polygon, relative to the center position. + std::vector m_Vertices = {}; //!< Positions of the vertices of the polygon, relative to the center position. /// /// Constructor method for PolygonFillPrimitive object. @@ -585,8 +554,8 @@ namespace RTE { /// Start position of the primitive. /// A vector containing the positions of the vertices of the polygon, relative to the center position. /// Color to draw this primitive with. - PolygonFillPrimitive(int player, const Vector &startPos, unsigned char color, const std::vector &vertices) : - m_Vertices(vertices) { + PolygonFillPrimitive(int player, const Vector& startPos, unsigned char color, const std::vector& vertices) : + m_Vertices(vertices) { m_StartPos = startPos; m_Color = color; @@ -594,7 +563,6 @@ namespace RTE { } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -606,7 +574,6 @@ namespace RTE { class TextPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; std::string m_Text = ""; //!< String containing text to draw. @@ -623,15 +590,14 @@ namespace RTE { /// Use small or large font. True for small font. /// Alignment of text. /// Angle to rotate text in radians. - TextPrimitive(int player, const Vector &pos, const std::string &text, bool isSmall, int alignment, float rotAngle) : - m_Text(text), m_IsSmall(isSmall), m_Alignment(alignment), m_RotAngle(rotAngle) { + TextPrimitive(int player, const Vector& pos, const std::string& text, bool isSmall, int alignment, float rotAngle) : + m_Text(text), m_IsSmall(isSmall), m_Alignment(alignment), m_RotAngle(rotAngle) { m_StartPos = pos; m_Player = player; } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion @@ -643,10 +609,9 @@ namespace RTE { class BitmapPrimitive : public GraphicalPrimitive { public: - GraphicalPrimitiveOverrideMethods; - BITMAP *m_Bitmap = nullptr; //!< Bitmap to draw. + BITMAP* m_Bitmap = nullptr; //!< Bitmap to draw. float m_RotAngle = 0; //!< Angle to rotate bitmap in radians. bool m_HFlipped = false; //!< Whether the Bitmap to draw should be horizontally flipped. bool m_VFlipped = false; //!< Whether the Bitmap to draw should be vertically flipped. @@ -660,8 +625,8 @@ namespace RTE { /// Angle to rotate BITMAP in radians. /// Whether the BITMAP to draw should be horizontally flipped. /// Whether the BITMAP to draw should be vertically flipped. - BitmapPrimitive(int player, const Vector ¢erPos, BITMAP *bitmap, float rotAngle, bool hFlipped, bool vFlipped) : - m_Bitmap(bitmap), m_RotAngle(rotAngle), m_HFlipped(hFlipped), m_VFlipped(vFlipped) { + BitmapPrimitive(int player, const Vector& centerPos, BITMAP* bitmap, float rotAngle, bool hFlipped, bool vFlipped) : + m_Bitmap(bitmap), m_RotAngle(rotAngle), m_HFlipped(hFlipped), m_VFlipped(vFlipped) { m_StartPos = centerPos; m_Player = player; @@ -677,8 +642,8 @@ namespace RTE { /// Frame number of the MOSprite that will be drawn. /// Whether the BITMAP to draw should be horizontally flipped. /// Whether the BITMAP to draw should be vertically flipped. - BitmapPrimitive(int player, const Vector ¢erPos, const MOSprite *moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped) : - m_Bitmap(moSprite->GetSpriteFrame(frame)), m_RotAngle(rotAngle), m_HFlipped(hFlipped), m_VFlipped(vFlipped) { + BitmapPrimitive(int player, const Vector& centerPos, const MOSprite* moSprite, float rotAngle, int frame, bool hFlipped, bool vFlipped) : + m_Bitmap(moSprite->GetSpriteFrame(frame)), m_RotAngle(rotAngle), m_HFlipped(hFlipped), m_VFlipped(vFlipped) { m_StartPos = centerPos; m_Player = player; @@ -693,17 +658,16 @@ namespace RTE { /// Angle to rotate BITMAP in radians. /// Whether the BITMAP to draw should be horizontally flipped. /// Whether the BITMAP to draw should be vertically flipped. - BitmapPrimitive(int player, const Vector ¢erPos, const std::string &filePath, float rotAngle, bool hFlipped, bool vFlipped) : - m_Bitmap(ContentFile(filePath.c_str()).GetAsBitmap()), m_RotAngle(rotAngle), m_HFlipped(hFlipped), m_VFlipped(vFlipped) { + BitmapPrimitive(int player, const Vector& centerPos, const std::string& filePath, float rotAngle, bool hFlipped, bool vFlipped) : + m_Bitmap(ContentFile(filePath.c_str()).GetAsBitmap()), m_RotAngle(rotAngle), m_HFlipped(hFlipped), m_VFlipped(vFlipped) { m_StartPos = centerPos; m_Player = player; } private: - static const PrimitiveType c_PrimitiveType; //!< Type identifier of this primitive. }; #pragma endregion -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/InputMapping.cpp b/Source/System/InputMapping.cpp index bbe22cc2f..cb2578c0c 100644 --- a/Source/System/InputMapping.cpp +++ b/Source/System/InputMapping.cpp @@ -4,7 +4,7 @@ namespace RTE { const std::string InputMapping::c_ClassName = "InputMapping"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InputMapping::Clear() { m_PresetDescription.clear(); @@ -16,9 +16,9 @@ namespace RTE { m_DirectionMap = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int InputMapping::Create(const InputMapping &reference) { + int InputMapping::Create(const InputMapping& reference) { m_KeyMap = reference.m_KeyMap; m_MouseButtonMap = reference.m_MouseButtonMap; m_DirectionMapped = reference.m_DirectionMapped; @@ -29,11 +29,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int InputMapping::ReadProperty(const std::string_view &propName, Reader &reader) { + int InputMapping::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("KeyMap", { reader >> m_KeyMap; }); MatchProperty("MouseButtonMap", { reader >> m_MouseButtonMap; }); MatchProperty("JoyButtonMap", { reader >> m_JoyButtonMap; }); @@ -45,19 +45,25 @@ namespace RTE { reader >> m_DirectionMap; m_DirectionMapped = true; }); - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int InputMapping::Save(Writer &writer) const { + int InputMapping::Save(Writer& writer) const { Serializable::Save(writer); - if (m_JoyButtonMap < 0 || !m_DirectionMapped) { writer.NewPropertyWithValue("KeyMap", m_KeyMap); } + if (m_JoyButtonMap < 0 || !m_DirectionMapped) { + writer.NewPropertyWithValue("KeyMap", m_KeyMap); + } - if (m_MouseButtonMap >= 0) { writer.NewPropertyWithValue("MouseButtonMap", m_MouseButtonMap); } - if (m_JoyButtonMap >= 0) { writer.NewPropertyWithValue("JoyButtonMap", m_JoyButtonMap); } + if (m_MouseButtonMap >= 0) { + writer.NewPropertyWithValue("MouseButtonMap", m_MouseButtonMap); + } + if (m_JoyButtonMap >= 0) { + writer.NewPropertyWithValue("JoyButtonMap", m_JoyButtonMap); + } if (m_DirectionMapped) { writer.NewPropertyWithValue("AxisMap", m_AxisMap); @@ -66,4 +72,4 @@ namespace RTE { return 0; } -} +} // namespace RTE diff --git a/Source/System/InputMapping.h b/Source/System/InputMapping.h index 332095dd8..40bc2229d 100644 --- a/Source/System/InputMapping.h +++ b/Source/System/InputMapping.h @@ -11,7 +11,6 @@ namespace RTE { class InputMapping : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -26,7 +25,7 @@ namespace RTE { /// /// A reference to the InputMapping to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const InputMapping &reference); + int Create(const InputMapping& reference); #pragma endregion #pragma region Destruction @@ -47,7 +46,7 @@ namespace RTE { /// Sets the description of the input scheme preset that this element is part of, if any preset has been set for this element's scheme. /// /// The description associated with this element by the scheme preset, if any has been set. This string should be empty otherwise. - void SetPresetDescription(const std::string &presetDescription) { m_PresetDescription = presetDescription; } + void SetPresetDescription(const std::string& presetDescription) { m_PresetDescription = presetDescription; } #pragma endregion #pragma region Keyboard Getters and Setters @@ -96,7 +95,11 @@ namespace RTE { /// /// The number of the axis this should be mapped to. /// The number of the direction this should be mapped to. - void SetDirection(int newAxis, int newDirection) { m_DirectionMapped = true; m_AxisMap = newAxis; m_DirectionMap = newDirection; } + void SetDirection(int newAxis, int newDirection) { + m_DirectionMapped = true; + m_AxisMap = newAxis; + m_DirectionMap = newDirection; + } /// /// Gets the joystick button mapping. @@ -118,7 +121,6 @@ namespace RTE { #pragma endregion protected: - std::string m_PresetDescription; //!< The friendly description that is associated with the scheme preset element, if any is set. int m_KeyMap; //!< The keyboard key mapping. @@ -131,7 +133,6 @@ namespace RTE { int m_DirectionMap; //!< The joystick direction mapping. private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. /// @@ -139,5 +140,5 @@ namespace RTE { /// void Clear(); }; -} +} // namespace RTE #endif diff --git a/Source/System/InputScheme.cpp b/Source/System/InputScheme.cpp index 9d378d8d2..3c8d4b19a 100644 --- a/Source/System/InputScheme.cpp +++ b/Source/System/InputScheme.cpp @@ -5,7 +5,7 @@ namespace RTE { const std::string InputScheme::c_ClassName = "InputScheme"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InputScheme::Clear() { m_ActiveDevice = InputDevice::DEVICE_KEYB_ONLY; @@ -14,14 +14,14 @@ namespace RTE { m_JoystickDeadzone = 0.01F; m_DigitalAimSpeed = 1.0F; - for (InputMapping &inputMapping : m_InputMappings) { + for (InputMapping& inputMapping: m_InputMappings) { inputMapping.Reset(); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int InputScheme::Create(const InputScheme &reference) { + int InputScheme::Create(const InputScheme& reference) { m_ActiveDevice = reference.m_ActiveDevice; m_SchemePreset = reference.m_SchemePreset; m_JoystickDeadzoneType = reference.m_JoystickDeadzoneType; @@ -34,11 +34,11 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int InputScheme::ReadProperty(const std::string_view &propName, Reader &reader) { + int InputScheme::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("Device", { SetDevice(static_cast(std::stoi(reader.ReadPropValue()))); }); MatchProperty("Preset", { SetPreset(static_cast(std::stoi(reader.ReadPropValue()))); }); MatchProperty("LeftUp", { reader >> m_InputMappings[InputElements::INPUT_L_UP]; }); @@ -71,14 +71,13 @@ namespace RTE { MatchProperty("JoystickDeadzoneType", { SetJoystickDeadzoneType(static_cast(std::stoi(reader.ReadPropValue()))); }); MatchProperty("JoystickDeadzone", { reader >> m_JoystickDeadzone; }); MatchProperty("DigitalAimSpeed", { reader >> m_DigitalAimSpeed; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int InputScheme::Save(Writer &writer) const { + int InputScheme::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("Device", m_ActiveDevice); @@ -121,7 +120,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InputScheme::ResetToPlayerDefaults(Players player) { switch (player) { @@ -150,7 +149,7 @@ namespace RTE { m_DigitalAimSpeed = 1.0F; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void InputScheme::SetPreset(InputPreset schemePreset) { m_SchemePreset = schemePreset; @@ -158,7 +157,7 @@ namespace RTE { if (schemePreset == InputPreset::NoPreset || schemePreset == InputPreset::InputPresetCount) { return; } - for (InputMapping &inputMapping : m_InputMappings) { + for (InputMapping& inputMapping: m_InputMappings) { inputMapping.Reset(); } switch (m_SchemePreset) { @@ -240,11 +239,11 @@ namespace RTE { m_InputMappings[InputElements::INPUT_PREV].SetJoyButton(SDL_CONTROLLER_BUTTON_LEFTSHOULDER); m_InputMappings[InputElements::INPUT_START].SetJoyButton(SDL_CONTROLLER_BUTTON_START); m_InputMappings[InputElements::INPUT_BACK].SetJoyButton(SDL_CONTROLLER_BUTTON_BACK); - //m_InputMappings[InputElements::INPUT_WEAPON_RELOAD].SetKey(); - //m_InputMappings[InputElements::INPUT_WEAPON_PICKUP].SetKey(); - //m_InputMappings[InputElements::INPUT_WEAPON_DROP].SetKey(); - //m_InputMappings[InputElements::INPUT_WEAPON_CHANGE_PREV].SetKey(); - //m_InputMappings[InputElements::INPUT_WEAPON_CHANGE_NEXT].SetKey(); + // m_InputMappings[InputElements::INPUT_WEAPON_RELOAD].SetKey(); + // m_InputMappings[InputElements::INPUT_WEAPON_PICKUP].SetKey(); + // m_InputMappings[InputElements::INPUT_WEAPON_DROP].SetKey(); + // m_InputMappings[InputElements::INPUT_WEAPON_CHANGE_PREV].SetKey(); + // m_InputMappings[InputElements::INPUT_WEAPON_CHANGE_NEXT].SetKey(); break; case InputPreset::PresetGenericDualAnalog: SetPreset(InputPreset::PresetGamepadXbox360); @@ -366,10 +365,10 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string InputScheme::GetMappingName(int whichElement) const { - const InputMapping *inputElement = &(m_InputMappings.at(whichElement)); + const InputMapping* inputElement = &(m_InputMappings.at(whichElement)); if (m_SchemePreset != InputScheme::InputPreset::NoPreset && !inputElement->GetPresetDescription().empty()) { return inputElement->GetPresetDescription(); } @@ -405,7 +404,7 @@ namespace RTE { return ""; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool InputScheme::CaptureKeyMapping(int whichInput) { for (int whichKey = SDL_SCANCODE_A; whichKey < SDL_NUM_SCANCODES; ++whichKey) { @@ -422,7 +421,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool InputScheme::CaptureJoystickMapping(int whichJoy, int whichInput) { if (whichJoy < 0) { @@ -447,4 +446,4 @@ namespace RTE { } return false; } -} +} // namespace RTE diff --git a/Source/System/InputScheme.h b/Source/System/InputScheme.h index 052f0a4ba..8eef7b10d 100644 --- a/Source/System/InputScheme.h +++ b/Source/System/InputScheme.h @@ -12,7 +12,6 @@ namespace RTE { class InputScheme : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -43,7 +42,7 @@ namespace RTE { /// /// A reference to the InputScheme to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const InputScheme &reference); + int Create(const InputScheme& reference); #pragma endregion #pragma region Destruction @@ -88,7 +87,7 @@ namespace RTE { /// Gets the InputMappings for this. /// /// The input mappings array, which is INPUT_COUNT large. - std::array * GetInputMappings() { return &m_InputMappings; } + std::array* GetInputMappings() { return &m_InputMappings; } #pragma endregion #pragma region Input Mapping Getters and Setters @@ -182,7 +181,6 @@ namespace RTE { #pragma endregion protected: - InputDevice m_ActiveDevice; //!< The currently active device for this scheme. InputPreset m_SchemePreset; //!< The preset this scheme was last set to, if any. @@ -193,7 +191,6 @@ namespace RTE { std::array m_InputMappings; //!< The input element mappings of this InputScheme. private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this object. /// @@ -201,5 +198,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Matrix.cpp b/Source/System/Matrix.cpp index 96838b732..a85df72ca 100644 --- a/Source/System/Matrix.cpp +++ b/Source/System/Matrix.cpp @@ -4,7 +4,7 @@ namespace RTE { const std::string Matrix::c_ClassName = "Matrix"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Matrix::Clear() { m_Rotation = 0; @@ -17,7 +17,7 @@ namespace RTE { m_Elements[1][1] = 1.0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Matrix::Create() { // Read all the properties @@ -29,7 +29,7 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Matrix::Create(float angle) { m_Rotation = angle; @@ -46,9 +46,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Matrix::Create(const Matrix &reference) { + int Matrix::Create(const Matrix& reference) { m_Rotation = reference.m_Rotation; m_Flipped[X] = reference.m_Flipped[X]; m_Flipped[Y] = reference.m_Flipped[Y]; @@ -57,25 +57,24 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Matrix::ReadProperty(const std::string_view &propName, Reader &reader) { + int Matrix::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("AngleDegrees", { float degAngle; reader >> degAngle; SetDegAngle(degAngle); }); MatchProperty("AngleRadians", { reader >> m_Rotation; }); - - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Matrix::Save(Writer &writer) const { + int Matrix::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("AngleRadians", m_Rotation); @@ -83,37 +82,45 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Matrix::GetRadAngleTo(float otherAngle) const { // Rotate this' angle with the other angle so that the sought after difference angle is between the resulting angle and the x-axis float difference = otherAngle - GetRadAngle(); // "Normalize" difference to range [-PI,PI) - while (difference < -c_PI) { difference += c_TwoPI; } - while (difference >= c_PI) { difference -= c_TwoPI; } + while (difference < -c_PI) { + difference += c_TwoPI; + } + while (difference >= c_PI) { + difference -= c_TwoPI; + } // difference has the signed answer return difference; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Matrix::GetDegAngleTo(float otherAngle) const { // Rotate this' angle with the other angle so that the sought after difference angle is between the resulting angle and the x-axis float difference = otherAngle - GetDegAngle(); // "Normalize" difference to range [-180,180) - while (difference < -180) { difference += 360; } - while (difference >= 180) { difference -= 360; } + while (difference < -180) { + difference += 360; + } + while (difference >= 180) { + difference -= 360; + } // difference has the signed answer return difference; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Matrix & Matrix::operator=(const Matrix &rhs) { + Matrix& Matrix::operator=(const Matrix& rhs) { if (*this == rhs) { return *this; } @@ -125,10 +132,12 @@ namespace RTE { return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Vector Matrix::operator*(const Vector &rhs) { - if (!m_ElementsUpdated) { UpdateElements(); } + Vector Matrix::operator*(const Vector& rhs) { + if (!m_ElementsUpdated) { + UpdateElements(); + } Vector retVec = rhs; // Apply flipping as set. @@ -141,10 +150,12 @@ namespace RTE { return retVec; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Vector Matrix::operator/(const Vector &rhs) { - if (!m_ElementsUpdated) { UpdateElements(); } + Vector Matrix::operator/(const Vector& rhs) { + if (!m_ElementsUpdated) { + UpdateElements(); + } Vector retVec = rhs; // Apply flipping as set. @@ -157,7 +168,7 @@ namespace RTE { return retVec; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Matrix Matrix::operator-() { m_Rotation = -m_Rotation; @@ -171,7 +182,7 @@ namespace RTE { return *this; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Matrix::UpdateElements() { // Negative angle to Account for upside-down coordinate system. @@ -184,4 +195,4 @@ namespace RTE { m_ElementsUpdated = true; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Matrix.h b/Source/System/Matrix.h index 35e7d55bd..d9a45f019 100644 --- a/Source/System/Matrix.h +++ b/Source/System/Matrix.h @@ -12,7 +12,6 @@ namespace RTE { class Matrix : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -31,13 +30,19 @@ namespace RTE { /// Constructor method used to instantiate a Matrix object from an angle. /// /// A float of an angle in radians that this Matrix should be set to represent. - Matrix(float radAng) { Clear(); Create(radAng); } + Matrix(float radAng) { + Clear(); + Create(radAng); + } /// /// Copy constructor method used to instantiate a Matrix object identical to an already existing one. /// /// A Matrix object which is passed in by reference. - Matrix(const Matrix &reference) { Clear(); Create(reference); } + Matrix(const Matrix& reference) { + Clear(); + Create(reference); + } /// /// Makes the Matrix object ready for use. @@ -57,7 +62,7 @@ namespace RTE { /// /// A reference to the Matrix to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Matrix &reference); + int Create(const Matrix& reference); #pragma endregion #pragma region Destruction @@ -102,7 +107,10 @@ namespace RTE { /// Sets the angle that this rotational Matrix should represent. /// /// A float with the new angle, in radians. - void SetRadAngle(float newAngle) { m_Rotation = newAngle; m_ElementsUpdated = false; } + void SetRadAngle(float newAngle) { + m_Rotation = newAngle; + m_ElementsUpdated = false; + } /// /// Returns the angle this rotational Matrix is currently representing. @@ -114,7 +122,10 @@ namespace RTE { /// Sets the angle that this rotational Matrix should represent. /// /// A float with the new angle, in degrees. - void SetDegAngle(float newAngle) { m_Rotation = (newAngle / 180.0F) * c_PI; m_ElementsUpdated = false; } + void SetDegAngle(float newAngle) { + m_Rotation = (newAngle / 180.0F) * c_PI; + m_ElementsUpdated = false; + } /// /// Returns the angle difference between what this is currently representing, to another angle in radians. @@ -145,14 +156,18 @@ namespace RTE { /// /// A Matrix reference. /// A reference to the changed Matrix. - Matrix & operator=(const Matrix &rhs); + Matrix& operator=(const Matrix& rhs); /// /// An assignment operator for setting one Matrix to represent an angle. /// /// A float in radians to set this rotational Matrix to. /// A reference to the changed Matrix. - Matrix & operator=(const float &rhs) { m_Rotation = rhs; m_ElementsUpdated = false; return *this; } + Matrix& operator=(const float& rhs) { + m_Rotation = rhs; + m_ElementsUpdated = false; + return *this; + } /// /// Unary negation overload for single Matrices. @@ -166,7 +181,7 @@ namespace RTE { /// A Matrix reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A boolean indicating whether the two operands are equal or not. - friend bool operator==(const Matrix &lhs, const Matrix &rhs) { return lhs.m_Rotation == rhs.m_Rotation; } + friend bool operator==(const Matrix& lhs, const Matrix& rhs) { return lhs.m_Rotation == rhs.m_Rotation; } /// /// An inequality operator for testing if any two Matrices are unequal. @@ -174,14 +189,18 @@ namespace RTE { /// A Matrix reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A boolean indicating whether the two operands are unequal or not. - friend bool operator!=(const Matrix &lhs, const Matrix &rhs) { return !operator==(lhs, rhs); } + friend bool operator!=(const Matrix& lhs, const Matrix& rhs) { return !operator==(lhs, rhs); } /// /// Self-addition operator overload for a Matrix and a float. /// /// A float reference as the right hand side operand. /// A reference to the resulting Matrix. - Matrix & operator+=(const float &rhs) { m_Rotation += rhs; m_ElementsUpdated = false; return *this; } + Matrix& operator+=(const float& rhs) { + m_Rotation += rhs; + m_ElementsUpdated = false; + return *this; + } /// /// Self-addition operator overload for Matrices. @@ -189,14 +208,22 @@ namespace RTE { /// A Matrix reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Matrix (the left one). - friend Matrix & operator+=(Matrix &lhs, const Matrix &rhs) { lhs.m_Rotation += rhs.m_Rotation; lhs.m_ElementsUpdated = false; return lhs; } + friend Matrix& operator+=(Matrix& lhs, const Matrix& rhs) { + lhs.m_Rotation += rhs.m_Rotation; + lhs.m_ElementsUpdated = false; + return lhs; + } /// /// Self-subtraction operator overload for a Matrix and a float. /// /// A float reference as the right hand side operand. /// A reference to the resulting Matrix. - Matrix & operator-=(const float &rhs) { m_Rotation -= rhs; m_ElementsUpdated = false; return *this; } + Matrix& operator-=(const float& rhs) { + m_Rotation -= rhs; + m_ElementsUpdated = false; + return *this; + } /// /// Self-subtraction operator overload for Matrices. @@ -204,14 +231,22 @@ namespace RTE { /// A Matrix reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Matrix (the left one). - friend Matrix & operator-=(Matrix &lhs, const Matrix &rhs) { lhs.m_Rotation -= rhs.m_Rotation; lhs.m_ElementsUpdated = false; return lhs; } + friend Matrix& operator-=(Matrix& lhs, const Matrix& rhs) { + lhs.m_Rotation -= rhs.m_Rotation; + lhs.m_ElementsUpdated = false; + return lhs; + } /// /// Self-multiplication operator overload for a Matrix and a float. /// /// A float reference as the right hand side operand. /// A reference to the resulting Matrix. - Matrix & operator*=(const float &rhs) { m_Rotation *= rhs; m_ElementsUpdated = false; return *this; } + Matrix& operator*=(const float& rhs) { + m_Rotation *= rhs; + m_ElementsUpdated = false; + return *this; + } /// /// Self-multiplication operator overload for Matrices. @@ -219,14 +254,18 @@ namespace RTE { /// A Matrix reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Matrix (the left one). - friend Matrix & operator*=(Matrix &lhs, const Matrix &rhs) { lhs.m_Rotation *= rhs.m_Rotation; lhs.m_ElementsUpdated = false; return lhs; } + friend Matrix& operator*=(Matrix& lhs, const Matrix& rhs) { + lhs.m_Rotation *= rhs.m_Rotation; + lhs.m_ElementsUpdated = false; + return lhs; + } /// /// self-division operator overload for a Matrix and a float. /// /// A float reference as the right hand side operand. /// A reference to the resulting Matrix. - Matrix & operator/=(const float &rhs) { + Matrix& operator/=(const float& rhs) { if (rhs) { m_Rotation /= rhs; m_ElementsUpdated = false; @@ -240,8 +279,11 @@ namespace RTE { /// A Matrix reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Matrix (the left one). - friend Matrix & operator/=(Matrix &lhs, const Matrix &rhs) { - if (rhs.m_Rotation) { lhs.m_Rotation /= rhs.m_Rotation; lhs.m_ElementsUpdated = false; } + friend Matrix& operator/=(Matrix& lhs, const Matrix& rhs) { + if (rhs.m_Rotation) { + lhs.m_Rotation /= rhs.m_Rotation; + lhs.m_ElementsUpdated = false; + } return lhs; } @@ -251,7 +293,7 @@ namespace RTE { /// /// A Vector reference as the right hand side operand. /// The resulting transformed Vector. - Vector operator*(const Vector &rhs); + Vector operator*(const Vector& rhs); /// /// Multiplication operator overload for Vectors with Matrices. @@ -259,14 +301,17 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Vector. - friend Vector operator*(const Vector &lhs, const Matrix &rhs) { Matrix m(rhs); return m * lhs; } + friend Vector operator*(const Vector& lhs, const Matrix& rhs) { + Matrix m(rhs); + return m * lhs; + } /// /// Division operator overload for a Matrix and a Vector. The vector will be transformed according to the Matrix's elements. /// /// A Vector reference as the right hand side operand. /// The resulting transformed Vector. - Vector operator/(const Vector &rhs); + Vector operator/(const Vector& rhs); /// /// Division operator overload for Vector:s with Matrices. @@ -274,7 +319,7 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Vector. - friend Vector operator/(const Vector &lhs, Matrix &rhs) { return rhs / lhs; } + friend Vector operator/(const Vector& lhs, Matrix& rhs) { return rhs / lhs; } /// /// Self-multiplication operator overload for Vector with a Matrix. @@ -282,7 +327,7 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Vector (the left one) - friend Vector & operator*=(Vector &lhs, Matrix &rhs) { return lhs = rhs * lhs; } + friend Vector& operator*=(Vector& lhs, Matrix& rhs) { return lhs = rhs * lhs; } /// /// Self-division operator overload for Vector with a Matrix. @@ -290,11 +335,10 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Matrix reference as the right hand side operand. /// A reference to the resulting Vector (the left one). - friend Vector & operator/=(Vector &lhs, Matrix &rhs) { return lhs = rhs / lhs; } + friend Vector& operator/=(Vector& lhs, Matrix& rhs) { return lhs = rhs / lhs; } #pragma endregion private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this. /// @@ -307,5 +351,5 @@ namespace RTE { /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/NetworkMessages.h b/Source/System/NetworkMessages.h index b303904d2..dd9d61c50 100644 --- a/Source/System/NetworkMessages.h +++ b/Source/System/NetworkMessages.h @@ -296,7 +296,6 @@ namespace RTE { bool ResetActivityVote; bool RestartActivityVote; - int MouseWheelMoved; unsigned int padElement3; @@ -306,5 +305,5 @@ namespace RTE { // Disables the previously set pack pragma. #pragma pack(pop) -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/PathFinder.cpp b/Source/System/PathFinder.cpp index 0eaf990f4..fc8e8c6d5 100644 --- a/Source/System/PathFinder.cpp +++ b/Source/System/PathFinder.cpp @@ -19,7 +19,7 @@ namespace RTE { delete m_Instance; } - MicroPather *m_Instance; + MicroPather* m_Instance; }; thread_local MicroPatherWrapper s_Pather; @@ -29,24 +29,25 @@ namespace RTE { // TODO: Enhance MicroPather to add that capability (or write our own pather)! thread_local float s_DigStrength = 0.0F; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PathNode::PathNode(const Vector &pos) : Pos(pos) { - const Material *outOfBounds = g_SceneMan.GetMaterialFromID(MaterialColorKeys::g_MaterialOutOfBounds); + PathNode::PathNode(const Vector& pos) : + Pos(pos) { + const Material* outOfBounds = g_SceneMan.GetMaterialFromID(MaterialColorKeys::g_MaterialOutOfBounds); for (int i = 0; i < c_MaxAdjacentNodeCount; i++) { AdjacentNodes[i] = nullptr; AdjacentNodeBlockingMaterials[i] = outOfBounds; // Costs are infinite unless recalculated as otherwise. } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PathFinder::Clear() { m_NodeGrid.clear(); m_NodeDimension = SCENEGRIDSIZE; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int PathFinder::Create(int nodeDimension) { RTEAssert(g_SceneMan.GetScene(), "Scene doesn't exist or isn't loaded when creating PathFinder!"); @@ -80,7 +81,7 @@ namespace RTE { nodePos.m_X = sceneWidth - 1.0F; } - // Add the newly created node to the column. + // Add the newly created node to the column. // Warning! Emplace back must be used to ensure this is constructed in-place, as otherwise the Up/Right/Down etc references will be incorrect. m_NodeGrid.emplace_back(nodePos); @@ -93,7 +94,7 @@ namespace RTE { // Assign all the adjacent nodes on each node. GetPathNodeAtGridCoords handles Scene wrapping. for (int x = 0; x < m_GridWidth; ++x) { for (int y = 0; y < m_GridHeight; ++y) { - PathNode &node = *GetPathNodeAtGridCoords(x, y); + PathNode& node = *GetPathNodeAtGridCoords(x, y); node.Up = GetPathNodeAtGridCoords(x, y - 1); node.Right = GetPathNodeAtGridCoords(x + 1, y); @@ -111,23 +112,23 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PathFinder::Destroy() { Clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - MicroPather * PathFinder::GetPather() { + MicroPather* PathFinder::GetPather() { // TODO: cache a collection of pathers. For async pathfinding right now we create a new pather for every thread! if (!s_Pather.m_Instance || s_Pather.m_Instance->GetGraph() != this) { // First time this thread has asked for a pather, let's initialize it delete s_Pather.m_Instance; // Might be reinitialized and Graph ptrs mismatch, in that case delete the old one - + // TODO: test dynamically setting this. The code below sets it based on map area and block size, with a hefty upper limit. - //int sceneArea = m_GridWidth * m_GridHeight; - //unsigned int numberOfBlocksToAllocate = std::min(128000, sceneArea / (m_NodeDimension * m_NodeDimension)); + // int sceneArea = m_GridWidth * m_GridHeight; + // unsigned int numberOfBlocksToAllocate = std::min(128000, sceneArea / (m_NodeDimension * m_NodeDimension)); unsigned int numberOfBlocksToAllocate = 4000; s_Pather.m_Instance = new MicroPather(this, numberOfBlocksToAllocate, PathNode::c_MaxAdjacentNodeCount, false); } @@ -135,13 +136,13 @@ namespace RTE { return s_Pather.m_Instance; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int PathFinder::CalculatePath(Vector start, Vector end, std::list &pathResult, float &totalCostResult, float digStrength) { + int PathFinder::CalculatePath(Vector start, Vector end, std::list& pathResult, float& totalCostResult, float digStrength) { ZoneScoped; - + ++m_CurrentPathingRequests; - + // Make sure start and end are within scene bounds. g_SceneMan.ForceBounds(start); g_SceneMan.ForceBounds(end); @@ -163,7 +164,7 @@ namespace RTE { // Do the actual pathfinding, fetch out the list of states that comprise the best path. int result = MicroPather::NO_SOLUTION; - std::vector statePath; + std::vector statePath; // If end node is invalid, there's no path PathNode* endNode = GetPathNodeAtGridCoords(endNodeX, endNodeY); @@ -179,12 +180,12 @@ namespace RTE { if (!statePath.empty()) { // Replace the approximate first point from the pathfound path with the exact starting point. pathResult.push_back(start); - std::vector::iterator itr = statePath.begin(); + std::vector::iterator itr = statePath.begin(); itr++; // Convert from a list of state void pointers to a list of scene position vectors. for (; itr != statePath.end(); ++itr) { - pathResult.push_back((static_cast(*itr))->Pos); + pathResult.push_back((static_cast(*itr))->Pos); } // Adjust the last point to be exactly where the end is supposed to be (really?). @@ -204,20 +205,20 @@ namespace RTE { return result; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::shared_ptr PathFinder::CalculatePathAsync(Vector start, Vector end, float digStrength, PathCompleteCallback callback) { std::shared_ptr pathRequest = std::make_shared(); - const_cast(pathRequest->startPos) = start; - const_cast(pathRequest->targetPos) = end; + const_cast(pathRequest->startPos) = start; + const_cast(pathRequest->targetPos) = end; g_ThreadMan.GetBackgroundThreadPool().push_task([this, start, end, digStrength, callback](std::shared_ptr volRequest) { // Cast away the volatile-ness - only matters outside (and complicates the API otherwise) - PathRequest &request = const_cast(*volRequest); + PathRequest& request = const_cast(*volRequest); int status = this->CalculatePath(start, end, request.path, request.totalCost, digStrength); - + request.status = status; request.pathLength = request.path.size(); @@ -228,18 +229,19 @@ namespace RTE { // Have to set to complete after the callback, so anything that blocks on it knows that the callback will have been called by now // This has the awkward side-effect that the complete flag is actually false during the callback - but that's fine, if it's called we know it's complete anyways request.complete = true; - }, pathRequest); + }, + pathRequest); return pathRequest; - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PathFinder::RecalculateAllCosts() { - RTEAssert(g_SceneMan.GetScene(), "Scene doesn't exist or isn't loaded when recalculating PathFinder!"); + void PathFinder::RecalculateAllCosts() { + RTEAssert(g_SceneMan.GetScene(), "Scene doesn't exist or isn't loaded when recalculating PathFinder!"); // Deadlock until all path requests are complete - while (m_CurrentPathingRequests.load() != 0) { }; + while (m_CurrentPathingRequests.load() != 0) {}; // I hate this copy, but fuck it. std::vector pathNodesIdsVec; @@ -249,18 +251,18 @@ namespace RTE { } UpdateNodeList(pathNodesIdsVec); - } + } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector PathFinder::RecalculateAreaCosts(std::deque &boxList, int nodeUpdateLimit) { + std::vector PathFinder::RecalculateAreaCosts(std::deque& boxList, int nodeUpdateLimit) { ZoneScoped; - + std::unordered_set nodeIDsToUpdate; while (!boxList.empty()) { std::vector nodesInside = GetNodeIdsInBox(boxList.front()); - for (int nodeId : nodesInside) { + for (int nodeId: nodesInside) { nodeIDsToUpdate.insert(nodeId); } @@ -283,16 +285,16 @@ namespace RTE { return nodeVec; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - float PathFinder::LeastCostEstimate(void *startState, void *endState) { - return g_SceneMan.ShortestDistance((static_cast(startState))->Pos, (static_cast(endState))->Pos).GetMagnitude() / m_NodeDimension; + float PathFinder::LeastCostEstimate(void* startState, void* endState) { + return g_SceneMan.ShortestDistance((static_cast(startState))->Pos, (static_cast(endState))->Pos).GetMagnitude() / m_NodeDimension; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PathFinder::AdjacentCost(void *state, std::vector *adjacentList) { - const PathNode *node = static_cast(state); + void PathFinder::AdjacentCost(void* state, std::vector* adjacentList) { + const PathNode* node = static_cast(state); micropather::StateCost adjCost; // We do a little trick here, where we radiate out a little percentage of our average cost in all directions. @@ -306,49 +308,49 @@ namespace RTE { // Add cost for digging upwards. if (node->Up && node->Up->m_Navigatable) { adjCost.cost = 1.0F + extraUpCost + (GetMaterialTransitionCost(*node->UpMaterial) * 4.0F) + radiatedCost; // Four times more expensive when digging. - adjCost.state = static_cast(node->Up); + adjCost.state = static_cast(node->Up); adjacentList->push_back(adjCost); } if (node->Right && node->Right->m_Navigatable) { adjCost.cost = 1.0F + GetMaterialTransitionCost(*node->RightMaterial) + radiatedCost; - adjCost.state = static_cast(node->Right); + adjCost.state = static_cast(node->Right); adjacentList->push_back(adjCost); } if (node->Down && node->Down->m_Navigatable) { adjCost.cost = 1.0F + GetMaterialTransitionCost(*node->DownMaterial) + radiatedCost; - adjCost.state = static_cast(node->Down); + adjCost.state = static_cast(node->Down); adjacentList->push_back(adjCost); } if (node->Left && node->Left->m_Navigatable) { adjCost.cost = 1.0F + GetMaterialTransitionCost(*node->LeftMaterial) + radiatedCost; - adjCost.state = static_cast(node->Left); + adjCost.state = static_cast(node->Left); adjacentList->push_back(adjCost); } // Add cost for digging at 45 degrees and for digging upwards. if (node->UpRight && node->UpRight->m_Navigatable) { - adjCost.cost = 1.4F + extraUpCost + (GetMaterialTransitionCost(*node->UpRightMaterial) * 1.4F * 3.0F) + radiatedCost; // Three times more expensive when digging. - adjCost.state = static_cast(node->UpRight); + adjCost.cost = 1.4F + extraUpCost + (GetMaterialTransitionCost(*node->UpRightMaterial) * 1.4F * 3.0F) + radiatedCost; // Three times more expensive when digging. + adjCost.state = static_cast(node->UpRight); adjacentList->push_back(adjCost); } if (node->RightDown && node->RightDown->m_Navigatable) { adjCost.cost = 1.4F + (GetMaterialTransitionCost(*node->RightDownMaterial) * 1.4F) + radiatedCost; - adjCost.state = static_cast(node->RightDown); + adjCost.state = static_cast(node->RightDown); adjacentList->push_back(adjCost); } if (node->DownLeft && node->DownLeft->m_Navigatable) { adjCost.cost = 1.4F + (GetMaterialTransitionCost(*node->DownLeftMaterial) * 1.4F) + radiatedCost; - adjCost.state = static_cast(node->DownLeft); + adjCost.state = static_cast(node->DownLeft); adjacentList->push_back(adjCost); } if (node->LeftUp && node->LeftUp->m_Navigatable) { - adjCost.cost = 1.4F + extraUpCost + (GetMaterialTransitionCost(*node->LeftUpMaterial) * 1.4F * 3.0F) + radiatedCost; // Three times more expensive when digging. - adjCost.state = static_cast(node->LeftUp); + adjCost.cost = 1.4F + extraUpCost + (GetMaterialTransitionCost(*node->LeftUpMaterial) * 1.4F * 3.0F) + radiatedCost; // Three times more expensive when digging. + adjCost.state = static_cast(node->LeftUp); adjacentList->push_back(adjCost); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool PathFinder::PositionsAreTheSamePathNode(const Vector& pos1, const Vector& pos2) const { int startNodeX = std::floor(pos1.m_X / static_cast(m_NodeDimension)); @@ -358,9 +360,9 @@ namespace RTE { return startNodeX == endNodeX && startNodeY == endNodeY; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - float PathFinder::GetMaterialTransitionCost(const Material &material) const { + float PathFinder::GetMaterialTransitionCost(const Material& material) const { float strength = material.GetIntegrity(); // Always treat doors as diggable. if (strength > s_DigStrength && material.GetIndex() != MaterialColorKeys::g_MaterialDoor) { @@ -369,22 +371,22 @@ namespace RTE { return strength; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Material * PathFinder::StrongestMaterialAlongLine(const Vector &start, const Vector &end) const { + const Material* PathFinder::StrongestMaterialAlongLine(const Vector& start, const Vector& end) const { return g_SceneMan.CastMaxStrengthRayMaterial(start, end, 0, MaterialColorKeys::g_MaterialAir); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PathFinder::UpdateNodeCosts(PathNode *node) const { + bool PathFinder::UpdateNodeCosts(PathNode* node) const { if (!node) { return false; } - std::array oldMaterials = node->AdjacentNodeBlockingMaterials; + std::array oldMaterials = node->AdjacentNodeBlockingMaterials; - auto getStrongerMaterial = [](const Material *first, const Material *second) { + auto getStrongerMaterial = [](const Material* first, const Material* second) { return first->GetIntegrity() > second->GetIntegrity() ? first : second; }; @@ -408,8 +410,8 @@ namespace RTE { } for (int i = 0; i < PathNode::c_MaxAdjacentNodeCount; ++i) { - const Material *oldMat = oldMaterials[i]; - const Material *newMat = node->AdjacentNodeBlockingMaterials[i]; + const Material* oldMat = oldMaterials[i]; + const Material* newMat = node->AdjacentNodeBlockingMaterials[i]; // Check if the material strength is more than our delta, or if a door has appeared/disappeared (since we handle their costs in a special manner). float delta = std::abs(oldMat->GetIntegrity() - newMat->GetIntegrity()); @@ -424,7 +426,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::vector PathFinder::GetNodeIdsInBox(Box box) { std::vector result; @@ -450,12 +452,12 @@ namespace RTE { return result; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - float PathFinder::GetNodeAverageTransitionCost(const PathNode &node) const { + float PathFinder::GetNodeAverageTransitionCost(const PathNode& node) const { float totalCostOfAdjacentNodes = 0.0F; int count = 0; - for (const Material *material : node.AdjacentNodeBlockingMaterials) { + for (const Material* material: node.AdjacentNodeBlockingMaterials) { // Don't use node transition cost, because we don't care about digging. float cost = material->GetIntegrity(); if (cost < std::numeric_limits::max()) { @@ -466,61 +468,66 @@ namespace RTE { return totalCostOfAdjacentNodes / std::max(static_cast(count), 1.0F); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PathFinder::UpdateNodeList(const std::vector &nodeVec) { + bool PathFinder::UpdateNodeList(const std::vector& nodeVec) { ZoneScoped; - + std::atomic anyChange = false; // Update all the costs going out from each node. std::for_each( - std::execution::par_unseq, - nodeVec.begin(), - nodeVec.end(), - [this, &anyChange](int nodeId) { - if (UpdateNodeCosts(&m_NodeGrid[nodeId])) { - anyChange = true; - } - } - ); + std::execution::par_unseq, + nodeVec.begin(), + nodeVec.end(), + [this, &anyChange](int nodeId) { + if (UpdateNodeCosts(&m_NodeGrid[nodeId])) { + anyChange = true; + } + }); if (anyChange) { // UpdateNodeCosts only calculates Materials for Right and Down directions, so each PathNode's Up and Left direction Materials need to be matched to the respective neighbor's opposite direction Materials. // For example, this PathNode's Left Material is its Left neighbor's Right Material. std::for_each( - std::execution::par_unseq, - nodeVec.begin(), - nodeVec.end(), - [this](int nodeId) { - PathNode *node = &m_NodeGrid[nodeId]; - if (node->Right) { node->Right->LeftMaterial = node->RightMaterial; } - if (node->Down) { node->Down->UpMaterial = node->DownMaterial; } - if (node->UpRight) { node->UpRight->DownLeftMaterial = node->UpRightMaterial; } - if (node->RightDown) { node->RightDown->LeftUpMaterial = node->RightDownMaterial; } - } - ); + std::execution::par_unseq, + nodeVec.begin(), + nodeVec.end(), + [this](int nodeId) { + PathNode* node = &m_NodeGrid[nodeId]; + if (node->Right) { + node->Right->LeftMaterial = node->RightMaterial; + } + if (node->Down) { + node->Down->UpMaterial = node->DownMaterial; + } + if (node->UpRight) { + node->UpRight->DownLeftMaterial = node->UpRightMaterial; + } + if (node->RightDown) { + node->RightDown->LeftUpMaterial = node->RightDownMaterial; + } + }); } return anyChange; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PathFinder::MarkBoxNavigatable(Box box, bool navigatable) { std::vector pathNodesInBox = GetNodeIdsInBox(box); std::for_each( - std::execution::par_unseq, - pathNodesInBox.begin(), - pathNodesInBox.end(), - [this, navigatable](int nodeId) { - PathNode* node = &m_NodeGrid[nodeId]; - node->m_Navigatable = navigatable; - } - ); + std::execution::par_unseq, + pathNodesInBox.begin(), + pathNodesInBox.end(), + [this, navigatable](int nodeId) { + PathNode* node = &m_NodeGrid[nodeId]; + node->m_Navigatable = navigatable; + }); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PathFinder::MarkAllNodesNavigatable(bool navigatable) { std::vector pathNodesIdsVec; @@ -530,24 +537,23 @@ namespace RTE { } std::for_each( - std::execution::par_unseq, - pathNodesIdsVec.begin(), - pathNodesIdsVec.end(), - [this, navigatable](int nodeId) { - PathNode* node = &m_NodeGrid[nodeId]; - node->m_Navigatable = navigatable; - } - ); + std::execution::par_unseq, + pathNodesIdsVec.begin(), + pathNodesIdsVec.end(), + [this, navigatable](int nodeId) { + PathNode* node = &m_NodeGrid[nodeId]; + node->m_Navigatable = navigatable; + }); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PathNode * PathFinder::GetPathNodeAtGridCoords(int x, int y) { + PathNode* PathFinder::GetPathNodeAtGridCoords(int x, int y) { int nodeId = ConvertCoordsToNodeId(x, y); return nodeId != -1 ? &m_NodeGrid[nodeId] : nullptr; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int PathFinder::ConvertCoordsToNodeId(int x, int y) { if (m_WrapsX) { @@ -566,4 +572,4 @@ namespace RTE { return (y * m_GridWidth) + x; } -} +} // namespace RTE diff --git a/Source/System/PathFinder.h b/Source/System/PathFinder.h index 664e46ba2..284d13113 100644 --- a/Source/System/PathFinder.h +++ b/Source/System/PathFinder.h @@ -24,7 +24,7 @@ namespace RTE { Vector targetPos; }; - using PathCompleteCallback = std::function)>; + using PathCompleteCallback = std::function)>; /// /// Contains everything related to a PathNode on the path grid used by PathFinder. @@ -40,34 +40,34 @@ namespace RTE { /// /// Pointers to all adjacent PathNodes, in clockwise order with top first. These are not owned, and may be 0 if adjacent to non-wrapping scene border. /// - std::array AdjacentNodes; - PathNode *&Up = AdjacentNodes[0]; - PathNode *&UpRight = AdjacentNodes[1]; - PathNode *&Right = AdjacentNodes[2]; - PathNode *&RightDown = AdjacentNodes[3]; - PathNode *&Down = AdjacentNodes[4]; - PathNode *&DownLeft = AdjacentNodes[5]; - PathNode *&Left = AdjacentNodes[6]; - PathNode *&LeftUp = AdjacentNodes[7]; + std::array AdjacentNodes; + PathNode*& Up = AdjacentNodes[0]; + PathNode*& UpRight = AdjacentNodes[1]; + PathNode*& Right = AdjacentNodes[2]; + PathNode*& RightDown = AdjacentNodes[3]; + PathNode*& Down = AdjacentNodes[4]; + PathNode*& DownLeft = AdjacentNodes[5]; + PathNode*& Left = AdjacentNodes[6]; + PathNode*& LeftUp = AdjacentNodes[7]; /// /// The strongest material between us and our adjacent PathNodes, in clockwise order with top first. /// - std::array AdjacentNodeBlockingMaterials; - const Material *&UpMaterial = AdjacentNodeBlockingMaterials[0]; - const Material *&UpRightMaterial = AdjacentNodeBlockingMaterials[1]; - const Material *&RightMaterial = AdjacentNodeBlockingMaterials[2]; - const Material *&RightDownMaterial = AdjacentNodeBlockingMaterials[3]; - const Material *&DownMaterial = AdjacentNodeBlockingMaterials[4]; - const Material *&DownLeftMaterial = AdjacentNodeBlockingMaterials[5]; - const Material *&LeftMaterial = AdjacentNodeBlockingMaterials[6]; - const Material *&LeftUpMaterial = AdjacentNodeBlockingMaterials[7]; + std::array AdjacentNodeBlockingMaterials; + const Material*& UpMaterial = AdjacentNodeBlockingMaterials[0]; + const Material*& UpRightMaterial = AdjacentNodeBlockingMaterials[1]; + const Material*& RightMaterial = AdjacentNodeBlockingMaterials[2]; + const Material*& RightDownMaterial = AdjacentNodeBlockingMaterials[3]; + const Material*& DownMaterial = AdjacentNodeBlockingMaterials[4]; + const Material*& DownLeftMaterial = AdjacentNodeBlockingMaterials[5]; + const Material*& LeftMaterial = AdjacentNodeBlockingMaterials[6]; + const Material*& LeftUpMaterial = AdjacentNodeBlockingMaterials[7]; /// /// Constructor method used to instantiate a PathNode object in system memory and make it ready for use. /// /// Absolute position of the center of the PathNode in the scene. - explicit PathNode(const Vector &pos); + explicit PathNode(const Vector& pos); }; /// @@ -76,14 +76,16 @@ namespace RTE { class PathFinder : public Graph { public: - #pragma region Creation /// /// Constructor method used to instantiate a PathFinder object. /// /// The width and height in scene pixels that of each PathNode should represent. /// The block size that the PathNode cache is allocated from. Should be about a fourth of the total number of PathNodes. - PathFinder(int nodeDimension) { Clear(); Create(nodeDimension); } + PathFinder(int nodeDimension) { + Clear(); + Create(nodeDimension); + } /// /// Makes the PathFinder object ready for use. @@ -121,7 +123,7 @@ namespace RTE { /// The total minimum difficulty cost calculated between the two points on the scene. /// What material strength the search is capable of digging through. /// Success or failure, expressed as SOLVED, NO_SOLUTION, or START_END_SAME. - int CalculatePath(Vector start, Vector end, std::list &pathResult, float &totalCostResult, float digStrength); + int CalculatePath(Vector start, Vector end, std::list& pathResult, float& totalCostResult, float digStrength); /// /// Calculates and returns the least difficult path between two points on the current scene. @@ -151,7 +153,7 @@ namespace RTE { /// The deque of Boxes representing the updated areas. /// The maximum number of PathNodes we'll try to update this frame. True PathNode update count can be higher if we received a big box, as we always do at least 1 box. /// The set of PathNode ids that were updated. - std::vector RecalculateAreaCosts(std::deque &boxList, int nodeUpdateLimit); + std::vector RecalculateAreaCosts(std::deque& boxList, int nodeUpdateLimit); /// /// Updates a set of PathNodes, adjusting their transitions. @@ -159,7 +161,7 @@ namespace RTE { /// /// The set of PathNode IDs to update. /// Whether any PathNode costs changed. - bool UpdateNodeList(const std::vector &nodeVec); + bool UpdateNodeList(const std::vector& nodeVec); /// /// Implementation of the abstract interface of Graph. @@ -168,7 +170,7 @@ namespace RTE { /// Pointer to PathNode to start from. OWNERSHIP IS NOT TRANSFERRED! /// PathNode to end up at. OWNERSHIP IS NOT TRANSFERRED! /// The cost of the absolutely fastest possible way between the two points, as if traveled through air all the way. - float LeastCostEstimate(void *startState, void *endState) override; + float LeastCostEstimate(void* startState, void* endState) override; /// /// Implementation of the abstract interface of Graph. @@ -176,7 +178,7 @@ namespace RTE { /// /// Pointer to PathNode to get to cost of all adjacents for. OWNERSHIP IS NOT TRANSFERRED! /// An empty vector which will be filled out with all the valid PathNodes adjacent to the one passed in. If at non-wrapping edge of seam, those non existent PathNodes won't be added. - void AdjacentCost(void *state, std::vector *adjacentList) override; + void AdjacentCost(void* state, std::vector* adjacentList) override; /// /// Returns whether two position represent the same path nodes. @@ -207,15 +209,14 @@ namespace RTE { /// Since void* aren't really human readable, this will print out some concise info without an ending newline. /// /// The state to print out info about. - void PrintStateInfo(void *state) override {} + void PrintStateInfo(void* state) override {} #pragma endregion private: - static constexpr float c_NodeCostChangeEpsilon = 5.0F; //!< The minimum change in a PathNodes's cost for the pathfinder to recognize a change and reset itself. This is so minor changes (e.g. blood particles) don't force constant pathfinder resets. - MicroPather *m_Pather; //!< The actual pathing object that does the pathfinding work. Owned. - std::vector m_NodeGrid; //!< The array of PathNodes representing the grid on the scene. + MicroPather* m_Pather; //!< The actual pathing object that does the pathfinding work. Owned. + std::vector m_NodeGrid; //!< The array of PathNodes representing the grid on the scene. unsigned int m_NodeDimension; //!< The width and height of each PathNode, in pixels on the scene. int m_GridWidth; //!< The width of the pathing grid, in PathNodes. int m_GridHeight; //!< The height of the pathing grid, in PathNodes. @@ -227,7 +228,7 @@ namespace RTE { /// Gets the pather for this thread. Lazily-initialized for each new thread that needs a pather. /// /// The pather for this thread. - MicroPather * GetPather(); + MicroPather* GetPather(); #pragma region Path Cost Updates /// @@ -236,7 +237,7 @@ namespace RTE { /// Origin point. /// Destination point. /// The strongest material. - const Material * StrongestMaterialAlongLine(const Vector &start, const Vector &end) const; + const Material* StrongestMaterialAlongLine(const Vector& start, const Vector& end) const; /// /// Helper function for updating all the values of cost edges going out from a specific PathNodes. @@ -244,7 +245,7 @@ namespace RTE { /// /// The PathNode to update all costs of. It's safe to pass nullptr here. OWNERSHIP IS NOT TRANSFERRED! /// Whether the PathNodes costs changed. - bool UpdateNodeCosts(PathNode *node) const; + bool UpdateNodeCosts(PathNode* node) const; /// /// Helper function for getting the PathNode ids in a Box. @@ -258,14 +259,14 @@ namespace RTE { /// /// The Material to get the transition cost for. /// The transition cost for the Material. - float GetMaterialTransitionCost(const Material &material) const; + float GetMaterialTransitionCost(const Material& material) const; /// /// Gets the average cost for all transitions out of this PathNode, ignoring infinities/unpathable transitions. /// /// The PathNode to get the average transition cost for. /// The average transition cost. - float GetNodeAverageTransitionCost(const PathNode &node) const; + float GetNodeAverageTransitionCost(const PathNode& node) const; #pragma endregion /// @@ -274,7 +275,7 @@ namespace RTE { /// The X coordinate, in PathNodes. /// The Y coordinate, in PathNodes. /// The PathNode at the given coordinates. - PathNode * GetPathNodeAtGridCoords(int x, int y); + PathNode* GetPathNodeAtGridCoords(int x, int y); /// /// Gets the PathNode id at the given coordinates. @@ -290,8 +291,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - PathFinder(const PathFinder &reference) = delete; - PathFinder & operator=(const PathFinder &rhs) = delete; + PathFinder(const PathFinder& reference) = delete; + PathFinder& operator=(const PathFinder& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/PieQuadrant.cpp b/Source/System/PieQuadrant.cpp index 674fb30f3..1c6b610d3 100644 --- a/Source/System/PieQuadrant.cpp +++ b/Source/System/PieQuadrant.cpp @@ -4,28 +4,28 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieQuadrant::Clear() { m_Enabled = true; m_Direction = Directions::None; m_MiddlePieSlice.reset(); - for (std::unique_ptr &pieSlice : m_LeftPieSlices) { + for (std::unique_ptr& pieSlice: m_LeftPieSlices) { pieSlice.reset(); } - for (std::unique_ptr &pieSlice : m_RightPieSlices) { + for (std::unique_ptr& pieSlice: m_RightPieSlices) { pieSlice.reset(); } m_SlotsForPieSlices.fill(nullptr); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void PieQuadrant::Create(const PieQuadrant &reference, const Entity *oldOriginalPieSliceSourceToCheck, const Entity *newOriginalPieSliceSourceToSet) { + void PieQuadrant::Create(const PieQuadrant& reference, const Entity* oldOriginalPieSliceSourceToCheck, const Entity* newOriginalPieSliceSourceToSet) { m_Enabled = reference.m_Enabled; m_Direction = reference.m_Direction; - for (const PieSlice *referencePieSlice : reference.GetFlattenedPieSlices()) { - PieSlice *pieSliceToAdd = dynamic_cast(referencePieSlice->Clone()); + for (const PieSlice* referencePieSlice: reference.GetFlattenedPieSlices()) { + PieSlice* pieSliceToAdd = dynamic_cast(referencePieSlice->Clone()); if (referencePieSlice->GetOriginalSource() == oldOriginalPieSliceSourceToCheck) { pieSliceToAdd->SetOriginalSource(newOriginalPieSliceSourceToSet); } @@ -33,48 +33,62 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector PieQuadrant::GetFlattenedPieSlices(bool inCCWOrder) const { - std::vector pieSlices; + std::vector PieQuadrant::GetFlattenedPieSlices(bool inCCWOrder) const { + std::vector pieSlices; if (inCCWOrder) { for (auto pieSliceReverseIterator = m_RightPieSlices.crbegin(); pieSliceReverseIterator < m_RightPieSlices.crend(); pieSliceReverseIterator++) { - if (*pieSliceReverseIterator) { pieSlices.emplace_back((*pieSliceReverseIterator).get()); } + if (*pieSliceReverseIterator) { + pieSlices.emplace_back((*pieSliceReverseIterator).get()); + } } - if (m_MiddlePieSlice) { pieSlices.emplace_back(m_MiddlePieSlice.get()); } - for (const std::unique_ptr &pieSlice : m_LeftPieSlices) { - if (pieSlice) { pieSlices.emplace_back(pieSlice.get()); } + if (m_MiddlePieSlice) { + pieSlices.emplace_back(m_MiddlePieSlice.get()); + } + for (const std::unique_ptr& pieSlice: m_LeftPieSlices) { + if (pieSlice) { + pieSlices.emplace_back(pieSlice.get()); + } } } else { - if (m_MiddlePieSlice) { pieSlices.emplace_back(m_MiddlePieSlice.get()); } - const std::array, 2> &firstSliceArray = (m_Direction == Directions::Left) ? m_RightPieSlices : m_LeftPieSlices; - const std::array, 2> &secondSliceArray = (m_Direction == Directions::Left) ? m_LeftPieSlices : m_RightPieSlices; + if (m_MiddlePieSlice) { + pieSlices.emplace_back(m_MiddlePieSlice.get()); + } + const std::array, 2>& firstSliceArray = (m_Direction == Directions::Left) ? m_RightPieSlices : m_LeftPieSlices; + const std::array, 2>& secondSliceArray = (m_Direction == Directions::Left) ? m_LeftPieSlices : m_RightPieSlices; for (int i = 0; i < firstSliceArray.size(); i++) { - if (firstSliceArray[i]) { pieSlices.emplace_back(firstSliceArray[i].get()); } - if (secondSliceArray[i]) { pieSlices.emplace_back(secondSliceArray[i].get()); } + if (firstSliceArray[i]) { + pieSlices.emplace_back(firstSliceArray[i].get()); + } + if (secondSliceArray[i]) { + pieSlices.emplace_back(secondSliceArray[i].get()); + } } } return pieSlices; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PieQuadrant::RealignPieSlices() { if ((m_RightPieSlices[0] && !m_LeftPieSlices[0]) || (m_RightPieSlices[1] && !m_LeftPieSlices[1])) { - for (const PieSlice *pieSliceToRealign : GetFlattenedPieSlices()) { + for (const PieSlice* pieSliceToRealign: GetFlattenedPieSlices()) { AddPieSlice(RemovePieSlice(pieSliceToRealign)); } } m_SlotsForPieSlices.fill(nullptr); - std::vector pieSlices = GetFlattenedPieSlices(true); + std::vector pieSlices = GetFlattenedPieSlices(true); int oddRoundedSliceCount = (2 * static_cast(pieSlices.size() / 2)) + 1; float angleOffset = NormalizeAngleBetween0And2PI(c_DirectionsToRadiansMap.at(m_Direction) - c_QuarterPI); int currentSlot = 0; - for (PieSlice *pieSlice : pieSlices) { + for (PieSlice* pieSlice: pieSlices) { int sliceSlotCount = 1; - if (oddRoundedSliceCount < c_PieQuadrantSlotCount && pieSlice == m_MiddlePieSlice.get()) { sliceSlotCount = (oddRoundedSliceCount == 1) ? c_PieQuadrantSlotCount : c_PieQuadrantSlotCount - 2; } + if (oddRoundedSliceCount < c_PieQuadrantSlotCount && pieSlice == m_MiddlePieSlice.get()) { + sliceSlotCount = (oddRoundedSliceCount == 1) ? c_PieQuadrantSlotCount : c_PieQuadrantSlotCount - 2; + } if ((currentSlot == 0 || m_SlotsForPieSlices.at(currentSlot - 1) == nullptr) && pieSlices.size() % 2 == 0) { currentSlot++; angleOffset = NormalizeAngleBetween0And2PI(angleOffset + c_PieSliceSlotSize); @@ -91,9 +105,9 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool PieQuadrant::AddPieSlice(PieSlice *pieSliceToAdd) { + bool PieQuadrant::AddPieSlice(PieSlice* pieSliceToAdd) { if (!pieSliceToAdd) { return false; } @@ -106,7 +120,7 @@ namespace RTE { bool bothSidesEqual = ((!m_LeftPieSlices[0] && !m_RightPieSlices[0]) || (m_LeftPieSlices[0] && m_RightPieSlices[0])) && ((!m_LeftPieSlices[1] && !m_RightPieSlices[1]) || (m_LeftPieSlices[1] && m_RightPieSlices[1])); bool leftSideHasMoreSlices = !bothSidesEqual && ((m_LeftPieSlices[0] && !m_RightPieSlices[0]) || m_LeftPieSlices[1]); - std::array, 2> &sliceArrayToAddTo = leftSideHasMoreSlices ? m_RightPieSlices : m_LeftPieSlices; + std::array, 2>& sliceArrayToAddTo = leftSideHasMoreSlices ? m_RightPieSlices : m_LeftPieSlices; sliceArrayToAddTo[sliceArrayToAddTo[0] ? 1 : 0] = std::unique_ptr(pieSliceToAdd); sliceWasAdded = true; } @@ -114,22 +128,22 @@ namespace RTE { return sliceWasAdded; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - PieSlice * PieQuadrant::RemovePieSlice(const PieSlice *pieSliceToRemove) { + PieSlice* PieQuadrant::RemovePieSlice(const PieSlice* pieSliceToRemove) { if (pieSliceToRemove == m_MiddlePieSlice.get()) { return m_MiddlePieSlice.release(); } - for (std::unique_ptr &pieSlice : m_LeftPieSlices) { + for (std::unique_ptr& pieSlice: m_LeftPieSlices) { if (pieSliceToRemove == pieSlice.get()) { return pieSlice.release(); } } - for (std::unique_ptr &pieSlice : m_RightPieSlices) { + for (std::unique_ptr& pieSlice: m_RightPieSlices) { if (pieSliceToRemove == pieSlice.get()) { return pieSlice.release(); } } return nullptr; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/PieQuadrant.h b/Source/System/PieQuadrant.h index 9e94a8f4b..e3c666ed2 100644 --- a/Source/System/PieQuadrant.h +++ b/Source/System/PieQuadrant.h @@ -11,7 +11,6 @@ namespace RTE { class PieQuadrant { public: - static constexpr int c_PieQuadrantSlotCount = 5; //!< The maximum number of PieSlices a PieQuadrant can have. static constexpr float c_PieSliceSlotSize = c_HalfPI / static_cast(c_PieQuadrantSlotCount); //!< The size of one PieSlice slot in PieQuadrants. @@ -21,7 +20,7 @@ namespace RTE { std::unique_ptr m_MiddlePieSlice; //!< A unique_ptr to the middle PieSlice of this PieQuadrant. std::array, c_PieQuadrantSlotCount / 2> m_LeftPieSlices; //!< An array of unique_ptrs to the left side PieSlices of this PieQuadrant. std::array, c_PieQuadrantSlotCount / 2> m_RightPieSlices; //!< An array of unique_ptrs to the right side PieSlices of this PieQuadrant. - std::array m_SlotsForPieSlices; //!< An array representing the slots in this PieQuadrant, via pointers to the PieSlices filling each slot. + std::array m_SlotsForPieSlices; //!< An array representing the slots in this PieQuadrant, via pointers to the PieSlices filling each slot. #pragma region Creation /// @@ -35,7 +34,7 @@ namespace RTE { /// A reference to the PieQuadrant to deep copy. /// A pointer to the old original source to check. This is generally the PieMenu the reference quadrant belongs to. /// A pointer to the new original source to be set for PieSlices whose reference's original source is the old original source to check. This is generally the PieMenu this quadrant belongs to. - void Create(const PieQuadrant &reference, const Entity *oldOriginalPieSliceSourceToCheck, const Entity *newOriginalPieSliceSourceToSet); + void Create(const PieQuadrant& reference, const Entity* oldOriginalPieSliceSourceToCheck, const Entity* newOriginalPieSliceSourceToSet); #pragma endregion #pragma region Destruction @@ -50,7 +49,7 @@ namespace RTE { /// Gets whether or not this PieQuadrant contains the given PieSlice. /// /// Whether or not this PieQuadrant contains the given PieSlice. - bool ContainsPieSlice(const PieSlice *sliceToCheck) const { return sliceToCheck == m_MiddlePieSlice.get() || sliceToCheck == m_LeftPieSlices[0].get() || sliceToCheck == m_RightPieSlices[0].get() || sliceToCheck == m_LeftPieSlices[1].get() || sliceToCheck == m_RightPieSlices[1].get(); } + bool ContainsPieSlice(const PieSlice* sliceToCheck) const { return sliceToCheck == m_MiddlePieSlice.get() || sliceToCheck == m_LeftPieSlices[0].get() || sliceToCheck == m_RightPieSlices[0].get() || sliceToCheck == m_LeftPieSlices[1].get() || sliceToCheck == m_RightPieSlices[1].get(); } /// /// Gets a vector of non-owning pointers to the PieSlices in this PieQuadrant. @@ -58,7 +57,7 @@ namespace RTE { /// Alternatively it can go in CCW order, getting the outermost right slice and moving inwards through the middle and then left slices. /// /// Whether to get flattened slices in counter-clockwise order. Defaults to false. - std::vector GetFlattenedPieSlices(bool inCCWOrder = false) const; + std::vector GetFlattenedPieSlices(bool inCCWOrder = false) const; #pragma endregion #pragma region Concrete Methods @@ -70,25 +69,24 @@ namespace RTE { /// /// Adds the PieSlice to the quadrant. PieSlices are added to the middle, then the left side, then the right side so things fill evenly. Ownership IS transferred! /// - bool AddPieSlice(PieSlice *pieSliceToAdd); + bool AddPieSlice(PieSlice* pieSliceToAdd); /// /// Removes the passed in PieSlice from this PieQuadrant. Ownership IS transferred to the caller! /// /// The PieSlice to be removed from this PieQuadrant. Ownership IS transferred to the caller! - PieSlice * RemovePieSlice(const PieSlice *pieSliceToRemove); + PieSlice* RemovePieSlice(const PieSlice* pieSliceToRemove); #pragma endregion private: - /// /// Clears all the member variables of this PieQuadrant. /// void Clear(); // Disallow the use of some implicit methods. - PieQuadrant(const PieQuadrant &reference) = delete; - PieQuadrant & operator=(const PieQuadrant &rhs) = delete; + PieQuadrant(const PieQuadrant& reference) = delete; + PieQuadrant& operator=(const PieQuadrant& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/RTEError.cpp b/Source/System/RTEError.cpp index ecf27e547..4fc5c9d5f 100644 --- a/Source/System/RTEError.cpp +++ b/Source/System/RTEError.cpp @@ -20,7 +20,7 @@ namespace RTE { std::string RTEError::s_LastIgnoredAssertDescription = ""; std::source_location RTEError::s_LastIgnoredAssertLocation = {}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 /// @@ -29,7 +29,7 @@ namespace RTE { /// Even if we "translate" SE exceptions to C++ exceptions it's still ass and doesn't really work, so this is what it is and it is good enough. /// /// Struct containing information about the exception. This will be provided by the OS exception handler. - static LONG WINAPI RTEWindowsExceptionHandler([[maybe_unused]] EXCEPTION_POINTERS *exceptPtr) { + static LONG WINAPI RTEWindowsExceptionHandler([[maybe_unused]] EXCEPTION_POINTERS* exceptPtr) { // This sorta half-assedly works in x86 because exception handling is slightly different, but since the main target is x64 we can just not care about it. // Something something ESP. ESP is a guitar brand. #ifndef TARGET_MACHINE_X86 @@ -51,35 +51,55 @@ namespace RTE { }; // Returns a string with the type of the exception from the passed in code. - static auto getExceptionDescriptionFromCode = [](const DWORD &exceptCode) -> std::string { + static auto getExceptionDescriptionFromCode = [](const DWORD& exceptCode) -> std::string { switch (exceptCode) { - case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; - case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT"; - case EXCEPTION_DATATYPE_MISALIGNMENT: return "EXCEPTION_DATATYPE_MISALIGNMENT"; - case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; - case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT"; - case EXCEPTION_FLT_INVALID_OPERATION: return "EXCEPTION_FLT_INVALID_OPERATION"; - case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW"; - case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK"; - case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW"; - case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION"; - case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO"; - case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW"; - case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION"; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; - case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION"; - case EXCEPTION_SINGLE_STEP: return "EXCEPTION_SINGLE_STEP"; - case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW"; + case EXCEPTION_ACCESS_VIOLATION: + return "EXCEPTION_ACCESS_VIOLATION"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + case EXCEPTION_BREAKPOINT: + return "EXCEPTION_BREAKPOINT"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "EXCEPTION_DATATYPE_MISALIGNMENT"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "EXCEPTION_FLT_DENORMAL_OPERAND"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "EXCEPTION_FLT_INEXACT_RESULT"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "EXCEPTION_FLT_INVALID_OPERATION"; + case EXCEPTION_FLT_OVERFLOW: + return "EXCEPTION_FLT_OVERFLOW"; + case EXCEPTION_FLT_STACK_CHECK: + return "EXCEPTION_FLT_STACK_CHECK"; + case EXCEPTION_FLT_UNDERFLOW: + return "EXCEPTION_FLT_UNDERFLOW"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "EXCEPTION_ILLEGAL_INSTRUCTION"; + case EXCEPTION_IN_PAGE_ERROR: + return "EXCEPTION_IN_PAGE_ERROR"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "EXCEPTION_INT_DIVIDE_BY_ZERO"; + case EXCEPTION_INT_OVERFLOW: + return "EXCEPTION_INT_OVERFLOW"; + case EXCEPTION_INVALID_DISPOSITION: + return "EXCEPTION_INVALID_DISPOSITION"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; + case EXCEPTION_PRIV_INSTRUCTION: + return "EXCEPTION_PRIV_INSTRUCTION"; + case EXCEPTION_SINGLE_STEP: + return "EXCEPTION_SINGLE_STEP"; + case EXCEPTION_STACK_OVERFLOW: + return "EXCEPTION_STACK_OVERFLOW"; default: return "UNKNOWN EXCEPTION"; } }; // Attempts to get a symbol name from the exception address. - static auto getSymbolNameFromAddress = [](HANDLE &procHandle, const size_t &exceptAddr) { + static auto getSymbolNameFromAddress = [](HANDLE& procHandle, const size_t& exceptAddr) { if (SymInitialize(procHandle, nullptr, TRUE)) { SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); @@ -115,7 +135,8 @@ namespace RTE { std::string symbolNameAtAddress = getSymbolNameFromAddress(processHandle, exceptionAddress); RTEError::FormatFunctionSignature(symbolNameAtAddress); - exceptionDescription << getExceptionDescriptionFromCode(exceptionCode) << " at address 0x" << std::uppercase << std::hex << exceptionAddress << ".\n\n" << symbolNameAtAddress << std::endl; + exceptionDescription << getExceptionDescriptionFromCode(exceptionCode) << " at address 0x" << std::uppercase << std::hex << exceptionAddress << ".\n\n" + << symbolNameAtAddress << std::endl; RTEStackTrace stackTrace; @@ -125,7 +146,7 @@ namespace RTE { } #endif -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RTEError::SetExceptionHandlers() { // Basic handling for C++ exceptions. Doesn't give us much meaningful information. @@ -135,9 +156,9 @@ namespace RTE { if (currentException) { try { std::rethrow_exception(currentException); - } catch (const std::bad_exception &exception) { + } catch (const std::bad_exception& exception) { RTEError::UnhandledExceptionFunc("Unable to get exception description because: " + std::string(exception.what()) + ".\n"); - } catch (const std::exception &exception) { + } catch (const std::exception& exception) { RTEError::UnhandledExceptionFunc(std::string(exception.what()) + ".\n"); } } else { @@ -158,20 +179,23 @@ namespace RTE { #endif } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void RTEError::ShowMessageBox(const std::string &message) { + void RTEError::ShowMessageBox(const std::string& message) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "RTE Warning! (>_<)", message.c_str(), nullptr); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool RTEError::ShowAbortMessageBox(const std::string &message) { - enum AbortMessageButton { ButtonInvalid, ButtonExit, ButtonRestart }; + bool RTEError::ShowAbortMessageBox(const std::string& message) { + enum AbortMessageButton { + ButtonInvalid, + ButtonExit, + ButtonRestart + }; std::vector abortMessageBoxButtons = { - SDL_MessageBoxButtonData(SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, AbortMessageButton::ButtonExit, "OK") - }; + SDL_MessageBoxButtonData(SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, AbortMessageButton::ButtonExit, "OK")}; // Don't even show the restart button in debug builds. #ifdef RELEASE_BUILD @@ -182,14 +206,13 @@ namespace RTE { #endif SDL_MessageBoxData abortMessageBox = { - SDL_MESSAGEBOX_ERROR, - g_WindowMan.GetWindow(), - "RTE Aborted! (x_x)", - message.c_str(), - static_cast(abortMessageBoxButtons.size()), - abortMessageBoxButtons.data(), - nullptr - }; + SDL_MESSAGEBOX_ERROR, + g_WindowMan.GetWindow(), + "RTE Aborted! (x_x)", + message.c_str(), + static_cast(abortMessageBoxButtons.size()), + abortMessageBoxButtons.data(), + nullptr}; int pressedButton = AbortMessageButton::ButtonInvalid; SDL_ShowMessageBox(&abortMessageBox, &pressedButton); @@ -197,26 +220,29 @@ namespace RTE { return pressedButton == AbortMessageButton::ButtonRestart; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool RTEError::ShowAssertMessageBox(const std::string &message) { - enum AssertMessageButton { ButtonInvalid, ButtonAbort, ButtonIgnore, ButtonIgnoreAll }; + bool RTEError::ShowAssertMessageBox(const std::string& message) { + enum AssertMessageButton { + ButtonInvalid, + ButtonAbort, + ButtonIgnore, + ButtonIgnoreAll + }; std::vector assertMessageBoxButtons = { - SDL_MessageBoxButtonData(SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, AssertMessageButton::ButtonAbort, "Abort"), - SDL_MessageBoxButtonData(0, AssertMessageButton::ButtonIgnore, "Ignore"), - SDL_MessageBoxButtonData(0, AssertMessageButton::ButtonIgnoreAll, "Ignore All") - }; + SDL_MessageBoxButtonData(SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, AssertMessageButton::ButtonAbort, "Abort"), + SDL_MessageBoxButtonData(0, AssertMessageButton::ButtonIgnore, "Ignore"), + SDL_MessageBoxButtonData(0, AssertMessageButton::ButtonIgnoreAll, "Ignore All")}; SDL_MessageBoxData assertMessageBox = { - SDL_MESSAGEBOX_ERROR, - g_WindowMan.GetWindow(), - "RTE Assert! (x_x)", - message.c_str(), - static_cast(assertMessageBoxButtons.size()), - assertMessageBoxButtons.data(), - nullptr - }; + SDL_MESSAGEBOX_ERROR, + g_WindowMan.GetWindow(), + "RTE Assert! (x_x)", + message.c_str(), + static_cast(assertMessageBoxButtons.size()), + assertMessageBoxButtons.data(), + nullptr}; int pressedButton = AssertMessageButton::ButtonInvalid; SDL_ShowMessageBox(&assertMessageBox, &pressedButton); @@ -228,9 +254,9 @@ namespace RTE { return pressedButton == AssertMessageButton::ButtonAbort; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void RTEError::UnhandledExceptionFunc(const std::string &description, const std::string &callstack) { + void RTEError::UnhandledExceptionFunc(const std::string& description, const std::string& callstack) { s_CurrentlyAborting = true; std::string exceptionMessage = "Runtime Error due to unhandled exception!\n\n" + description; @@ -282,9 +308,9 @@ namespace RTE { AbortAction; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void RTEError::AbortFunc(const std::string &description, const std::source_location &srcLocation) { + void RTEError::AbortFunc(const std::string& description, const std::source_location& srcLocation) { s_CurrentlyAborting = true; if (!System::IsInExternalModuleValidationMode()) { @@ -349,9 +375,9 @@ namespace RTE { AbortAction; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void RTEError::AssertFunc(const std::string &description, const std::source_location &srcLocation) { + void RTEError::AssertFunc(const std::string& description, const std::source_location& srcLocation) { if (System::IsInExternalModuleValidationMode()) { AbortFunc(description, srcLocation); } @@ -369,8 +395,8 @@ namespace RTE { if (!s_IgnoreAllAsserts) { std::string assertMessage = - "Assertion in file '" + fileName + "', line " + lineNum + ",\nin function '" + funcName + "'\nbecause:\n\n" + description + "\n\n" - "You may choose to ignore this and crash immediately\nor at some unexpected point later on.\n\nProceed at your own risk!"; + "Assertion in file '" + fileName + "', line " + lineNum + ",\nin function '" + funcName + "'\nbecause:\n\n" + description + "\n\n" + "You may choose to ignore this and crash immediately\nor at some unexpected point later on.\n\nProceed at your own risk!"; if (ShowAssertMessageBox(assertMessage)) { AbortFunc(description, srcLocation); @@ -387,14 +413,14 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool RTEError::DumpAbortScreen() { int success = -1; if (glReadPixels != nullptr) { - int w ,h; + int w, h; SDL_GL_GetDrawableSize(g_WindowMan.GetWindow(), &w, &h); - if (!(w>0 && h>0)) { + if (!(w > 0 && h > 0)) { return false; } BITMAP* readBuffer = create_bitmap_ex(24, w, h); @@ -417,7 +443,7 @@ namespace RTE { return success == 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool RTEError::DumpAbortSave() { bool success = false; @@ -427,16 +453,14 @@ namespace RTE { return success; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void RTEError::FormatFunctionSignature(std::string &symbolName) { + void RTEError::FormatFunctionSignature(std::string& symbolName) { // TODO: Expand this with more dumb signatures, or make something that makes more sense. - static const std::array, 3> stlSigs {{ - {std::regex("( >)"), ">"}, - {std::regex("(std::basic_string,std::allocator>)"), "std::string"}, - {std::regex("(class ?std::basic_string,class ?std::allocator>)"), "std::string"} - }}; - for (const auto &[fullSig, simpleSig] : stlSigs) { + static const std::array, 3> stlSigs{{{std::regex("( >)"), ">"}, + {std::regex("(std::basic_string,std::allocator>)"), "std::string"}, + {std::regex("(class ?std::basic_string,class ?std::allocator>)"), "std::string"}}}; + for (const auto& [fullSig, simpleSig]: stlSigs) { symbolName = std::regex_replace(symbolName, fullSig, simpleSig); } for (size_t pos = 0;;) { @@ -450,4 +474,4 @@ namespace RTE { } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/RTEError.h b/Source/System/RTEError.h index a739540d1..28823a7c4 100644 --- a/Source/System/RTEError.h +++ b/Source/System/RTEError.h @@ -26,7 +26,6 @@ namespace RTE { class RTEError { public: - static bool s_CurrentlyAborting; //!< Flag to prevent a potential recursive fault while attempting to save the game when aborting. static bool s_IgnoreAllAsserts; //!< Whether to skip the assert dialog and just let everything burn at whatever point that happens. static std::string s_LastIgnoredAssertDescription; //!< The last ignored assert message. @@ -41,50 +40,49 @@ namespace RTE { /// Pops up a message box dialog in the OS. For debug purposes mostly. /// /// The string that the message box should display. - static void ShowMessageBox(const std::string &message); + static void ShowMessageBox(const std::string& message); /// /// Abort on unhandled exception function. Will try save the current game, to dump a screenshot, dump the console log and show an abort message. Then quit the program immediately. /// /// Message explaining the exception. /// The call stack in string form. - static void UnhandledExceptionFunc(const std::string &description, const std::string &callstack = ""); + static void UnhandledExceptionFunc(const std::string& description, const std::string& callstack = ""); /// /// Abort on Error function. Will try save the current game, to dump a screenshot, dump the console log and show an abort message. Then quit the program immediately. /// /// Message explaining the reason for aborting. /// std::source_location corresponding to the location of the call site. - [[noreturn]] static void AbortFunc(const std::string &description, const std::source_location &srcLocation); + [[noreturn]] static void AbortFunc(const std::string& description, const std::source_location& srcLocation); /// /// An assert, which will prompt to abort or ignore it. /// /// The description of the assertion. /// std::source_location corresponding to the location of the call site. - static void AssertFunc(const std::string &description, const std::source_location &srcLocation); + static void AssertFunc(const std::string& description, const std::source_location& srcLocation); /// /// Formats function signatures so they're slightly more sane. /// /// Reference to the function signature to format. - static void FormatFunctionSignature(std::string &funcSig); + static void FormatFunctionSignature(std::string& funcSig); private: - /// /// Pops up the abort message box dialog in the OS, notifying the user about a runtime error. /// /// The string that the message box should display. /// Whether to restart the game by launching a new instance, or proceed to exit. - static bool ShowAbortMessageBox(const std::string &message); + static bool ShowAbortMessageBox(const std::string& message); /// /// Pops up the assert message box dialog in the OS, notifying the user about a runtime error. /// /// The string that the message box should display. /// Whether to abort, or ignore the assert and continue execution. - static bool ShowAssertMessageBox(const std::string &message); + static bool ShowAssertMessageBox(const std::string& message); /// /// Saves the current frame to a file. @@ -100,13 +98,13 @@ namespace RTE { }; #define RTEAbort(description) \ - if (!RTEError::s_CurrentlyAborting) { \ - RTEError::AbortFunc(description, std::source_location::current()); \ + if (!RTEError::s_CurrentlyAborting) { \ + RTEError::AbortFunc(description, std::source_location::current()); \ } #define RTEAssert(expression, description) \ - if (!(expression)) { \ - RTEError::AssertFunc(description, std::source_location::current()); \ + if (!(expression)) { \ + RTEError::AssertFunc(description, std::source_location::current()); \ } -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/RTEStackTrace.cpp b/Source/System/RTEStackTrace.cpp index 500d7dab8..b47fb95b9 100644 --- a/Source/System/RTEStackTrace.cpp +++ b/Source/System/RTEStackTrace.cpp @@ -2,9 +2,9 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string RTEStackTrace::GetCallStackAsString(const HANDLE &handle, const CONTEXT *context) { + std::string RTEStackTrace::GetCallStackAsString(const HANDLE& handle, const CONTEXT* context) { m_CallstackStream.clear(); if (!handle || !context) { @@ -17,10 +17,10 @@ namespace RTE { return m_CallstackStream.str(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RTEStackTrace::OnOutput(LPCSTR text) { this->StackWalker::OnOutput(text); m_CallstackStream << text; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/RTEStackTrace.h b/Source/System/RTEStackTrace.h index 65c61adb5..dbc5d8bf4 100644 --- a/Source/System/RTEStackTrace.h +++ b/Source/System/RTEStackTrace.h @@ -12,12 +12,12 @@ namespace RTE { class RTEStackTrace : public StackWalker { public: - /// /// Constructor method used to instantiate an RTEStackTrace object in system memory and make it ready for use. /// /// - RTEStackTrace() : StackWalker() {} + RTEStackTrace() : + StackWalker() {} /// /// Destructor method used to clean up a RTEStackTrace object before deletion from system memory. @@ -30,10 +30,9 @@ namespace RTE { /// Handle to the current process. If none provided will get the current thread handle. /// Register data. If none provided will get it from the caller. /// A string with the call stack. - std::string GetCallStackAsString(const HANDLE &handle = nullptr, const CONTEXT *context = nullptr); + std::string GetCallStackAsString(const HANDLE& handle = nullptr, const CONTEXT* context = nullptr); protected: - /// /// Redirects the output string to the member string stream. /// @@ -41,12 +40,11 @@ namespace RTE { void OnOutput(LPCSTR text) override; private: - std::stringstream m_CallstackStream; //!< Call stack output stream. // Disallow the use of some implicit methods. - RTEStackTrace(const RTEStackTrace &reference) = delete; - RTEStackTrace & operator=(const RTEStackTrace &rhs) = delete; + RTEStackTrace(const RTEStackTrace& reference) = delete; + RTEStackTrace& operator=(const RTEStackTrace& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/RTETools.cpp b/Source/System/RTETools.cpp index ac944a311..efeef0812 100644 --- a/Source/System/RTETools.cpp +++ b/Source/System/RTETools.cpp @@ -2,12 +2,11 @@ #include "Vector.h" - namespace RTE { RandomGenerator g_RandomGenerator; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SeedRNG() { // Use a constant seed for determinism. @@ -20,17 +19,17 @@ namespace RTE { const uint64_t hugePrime = 18446744073709551557; uint64_t seedResult = 0; - for (char c : seedString) { + for (char c: seedString) { seedResult += static_cast(c) * hugePrime; } - + return static_cast(seedResult); }(); g_RandomGenerator.Seed(constSeed); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float LERP(float scaleStart, float scaleEnd, float startValue, float endValue, float progressScalar) { if (progressScalar <= scaleStart) { @@ -41,7 +40,7 @@ namespace RTE { return startValue + ((progressScalar - scaleStart) * ((endValue - startValue) / (scaleEnd - scaleStart))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float EaseIn(float start, float end, float progressScalar) { if (progressScalar <= 0) { @@ -53,7 +52,7 @@ namespace RTE { return (end - start) * (std::sin(-t * c_HalfPI) + 1) + start; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float EaseOut(float start, float end, float progressScalar) { if (progressScalar <= 0) { @@ -64,15 +63,15 @@ namespace RTE { return (end - start) * -std::sin(-progressScalar * c_HalfPI) + start; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float EaseInOut(float start, float end, float progressScalar) { return start * (2 * std::pow(progressScalar, 3) - 3 * std::pow(progressScalar, 2) + 1) + end * (3 * std::pow(progressScalar, 2) - 2 * std::pow(progressScalar, 3)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Clamp(float &value, float upperLimit, float lowerLimit) { + bool Clamp(float& value, float upperLimit, float lowerLimit) { // Straighten out the limits if (upperLimit < lowerLimit) { float temp = upperLimit; @@ -90,7 +89,7 @@ namespace RTE { return false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Limit(float value, float upperLimit, float lowerLimit) { // Straighten out the limits @@ -109,7 +108,7 @@ namespace RTE { return value; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float NormalizeAngleBetween0And2PI(float angle) { while (angle < 0) { @@ -118,7 +117,7 @@ namespace RTE { return (angle > c_TwoPI) ? fmodf(angle + c_TwoPI, c_TwoPI) : angle; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float NormalizeAngleBetweenNegativePIAndPI(float angle) { while (angle < 0) { @@ -127,7 +126,7 @@ namespace RTE { return (angle > c_PI) ? fmodf(angle + c_PI, c_TwoPI) - c_PI : angle; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AngleWithinRange(float angleToCheck, float startAngle, float endAngle) { angleToCheck = NormalizeAngleBetween0And2PI(angleToCheck); @@ -137,7 +136,7 @@ namespace RTE { return endAngle >= startAngle ? (angleToCheck >= startAngle && angleToCheck <= endAngle) : (angleToCheck >= startAngle || angleToCheck <= endAngle); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float ClampAngle(float angleToClamp, float startAngle, float endAngle) { angleToClamp = NormalizeAngleBetween0And2PI(angleToClamp); @@ -154,19 +153,19 @@ namespace RTE { return angleToClamp; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool WithinBox(const Vector &point, float left, float top, float right, float bottom) { + bool WithinBox(const Vector& point, float left, float top, float right, float bottom) { return point.m_X >= left && point.m_X < right && point.m_Y >= top && point.m_Y < bottom; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool WithinBox(const Vector &point, const Vector &boxPos, float width, float height) { + bool WithinBox(const Vector& point, const Vector& boxPos, float width, float height) { return point.m_X >= boxPos.m_X && point.m_X < (boxPos.m_X + width) && point.m_Y >= boxPos.m_Y && point.m_Y < (boxPos.m_Y + height); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string RoundFloatToPrecision(float input, int precision, int roundingMode) { if (roundingMode == 0) { @@ -202,16 +201,16 @@ namespace RTE { } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // From https://stackoverflow.com/a/66764681, under license https://creativecommons.org/licenses/by-sa/4.0/. Minor modifications - uint64_t Hash(const std::string &text) { + uint64_t Hash(const std::string& text) { constexpr uint64_t fnv_prime = 1099511628211ULL; constexpr uint64_t fnv_offset_basis = 14695981039346656037ULL; - + uint64_t hash = fnv_offset_basis; - - for(auto c: text) { + + for (auto c: text) { hash ^= c; hash *= fnv_prime; } @@ -219,9 +218,9 @@ namespace RTE { return hash; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string GetCaseInsensitiveFullPath(const std::string &fullPath) { + std::string GetCaseInsensitiveFullPath(const std::string& fullPath) { if (std::filesystem::exists(fullPath)) { return fullPath; } @@ -235,7 +234,7 @@ namespace RTE { // Iterate over all entries in the path part's directory, // to check if the path part is in there case insensitively - for (const std::filesystem::path &filesystemEntryPath : std::filesystem::directory_iterator(inspectedPath)) { + for (const std::filesystem::path& filesystemEntryPath: std::filesystem::directory_iterator(inspectedPath)) { if (StringsEqualCaseInsensitive(filesystemEntryPath.filename().generic_string(), relativeFilePathIterator->generic_string())) { inspectedPath = filesystemEntryPath; @@ -257,4 +256,4 @@ namespace RTE { return inspectedPath.generic_string(); } -} +} // namespace RTE diff --git a/Source/System/RTETools.h b/Source/System/RTETools.h index b69b4fdcb..e69f66454 100644 --- a/Source/System/RTETools.h +++ b/Source/System/RTETools.h @@ -10,7 +10,7 @@ namespace RTE { class Vector; - #pragma region Random Numbers +#pragma region Random Numbers class RandomGenerator { std::mt19937 m_RNG; //!< The random number generator used for all random functions. @@ -64,7 +64,9 @@ namespace RTE { /// Uniformly distributed random number in the range [min, max]. template typename std::enable_if::value, floatType>::type RandomNum(floatType min, floatType max) { - if (max < min) { std::swap(min, max); } + if (max < min) { + std::swap(min, max); + } return (std::uniform_real_distribution(floatType(0.0), std::nextafter(max - min, std::numeric_limits::max()))(m_RNG) + min); } @@ -76,12 +78,14 @@ namespace RTE { /// Uniformly distributed random number in the range [min, max]. template typename std::enable_if::value, intType>::type RandomNum(intType min, intType max) { - if (max < min) { std::swap(min, max); } + if (max < min) { + std::swap(min, max); + } return (std::uniform_int_distribution(intType(0), max - min)(m_RNG) + min); } }; - extern RandomGenerator g_RandomGenerator; //!< The global random number generator used in our simulation thread. + extern RandomGenerator g_RandomGenerator; //!< The global random number generator used in our simulation thread. /// /// Seed global the global random number generators. @@ -119,218 +123,219 @@ namespace RTE { typename std::enable_if::value, intType>::type RandomNum(intType min, intType max) { return g_RandomGenerator.RandomNum(min, max); } - #pragma endregion - +#pragma endregion - #pragma region Interpolation - /// - /// Simple Linear Interpolation, with an added bonus: scaleStart and scaleEnd let you define your scale, where 0 and 1 would be standard scale. - /// This scale is used to normalize your progressScalar value and LERP accordingly. - /// - /// The start of the scale to LERP along. - /// The end of the scale to LERP along. - /// The start value of your LERP. - /// The end value of your LERP. - /// How far your LERP has progressed. Automatically normalized through use of scaleStart and scaleEnd. - /// Interpolated value. - float LERP(float scaleStart, float scaleEnd, float startValue, float endValue, float progressScalar); +#pragma region Interpolation + /// + /// Simple Linear Interpolation, with an added bonus: scaleStart and scaleEnd let you define your scale, where 0 and 1 would be standard scale. + /// This scale is used to normalize your progressScalar value and LERP accordingly. + /// + /// The start of the scale to LERP along. + /// The end of the scale to LERP along. + /// The start value of your LERP. + /// The end value of your LERP. + /// How far your LERP has progressed. Automatically normalized through use of scaleStart and scaleEnd. + /// Interpolated value. + float LERP(float scaleStart, float scaleEnd, float startValue, float endValue, float progressScalar); - /// - /// Nonlinear ease-in interpolation. Starts slow. - /// - /// Start value. - /// End value. - /// Normalized positive progress scalar (0 - 1.0). - /// Interpolated value. - float EaseIn(float start, float end, float progressScalar); + /// + /// Nonlinear ease-in interpolation. Starts slow. + /// + /// Start value. + /// End value. + /// Normalized positive progress scalar (0 - 1.0). + /// Interpolated value. + float EaseIn(float start, float end, float progressScalar); - /// - /// Nonlinear ease-out interpolation. Slows down toward the end. - /// - /// Start value. - /// End value. - /// Normalized positive progress scalar (0 - 1.0). - /// Interpolated value. - float EaseOut(float start, float end, float progressScalar); + /// + /// Nonlinear ease-out interpolation. Slows down toward the end. + /// + /// Start value. + /// End value. + /// Normalized positive progress scalar (0 - 1.0). + /// Interpolated value. + float EaseOut(float start, float end, float progressScalar); - /// - /// Nonlinear ease-in-out interpolation. Slows down in the start and end. - /// - /// Start value. - /// End value. - /// Normalized positive progress scalar (0 - 1.0). - /// Interpolated value. - float EaseInOut(float start, float end, float progressScalar); - #pragma endregion - - #pragma region Clamping - /// - /// Clamps a value between two limit values. - /// - /// Value to clamp. - /// Upper limit of value. - /// Lower limit of value. - /// True if either limit is currently reached, False if not. - bool Clamp(float &value, float upperLimit, float lowerLimit); + /// + /// Nonlinear ease-in-out interpolation. Slows down in the start and end. + /// + /// Start value. + /// End value. + /// Normalized positive progress scalar (0 - 1.0). + /// Interpolated value. + float EaseInOut(float start, float end, float progressScalar); +#pragma endregion + +#pragma region Clamping + /// + /// Clamps a value between two limit values. + /// + /// Value to clamp. + /// Upper limit of value. + /// Lower limit of value. + /// True if either limit is currently reached, False if not. + bool Clamp(float& value, float upperLimit, float lowerLimit); - /// - /// Clamps a value between two limit values. - /// - /// Value to clamp. - /// Upper limit of value. - /// Lower limit of value. - /// Upper/Lower limit value if limit is currently reached, value between limits if not. - float Limit(float value, float upperLimit, float lowerLimit); - #pragma endregion - - #pragma region Rounding - /// - /// Rounds a float to a set fixed point precision (digits after decimal point) with option to always ceil or always floor the remainder. - /// - /// The input float to round. - /// The precision to round to, i.e. the number of digits after the decimal points. - /// Method of rounding to use. 0 for system default, 1 for floored remainder, 2 for ceiled remainder. - /// A string of the float, rounded and displayed to chosen precision. - std::string RoundFloatToPrecision(float input, int precision, int roundingMode = 0); + /// + /// Clamps a value between two limit values. + /// + /// Value to clamp. + /// Upper limit of value. + /// Lower limit of value. + /// Upper/Lower limit value if limit is currently reached, value between limits if not. + float Limit(float value, float upperLimit, float lowerLimit); +#pragma endregion + +#pragma region Rounding + /// + /// Rounds a float to a set fixed point precision (digits after decimal point) with option to always ceil or always floor the remainder. + /// + /// The input float to round. + /// The precision to round to, i.e. the number of digits after the decimal points. + /// Method of rounding to use. 0 for system default, 1 for floored remainder, 2 for ceiled remainder. + /// A string of the float, rounded and displayed to chosen precision. + std::string RoundFloatToPrecision(float input, int precision, int roundingMode = 0); - /// - /// Rounds an integer to the specified nearest multiple. - /// For example, if the arguments are 63 and 5, the returned value will be 65. - /// - /// The number to round to the nearest multiple. - /// The multiple to round to. - /// An integer rounded to the specified nearest multiple. - inline int RoundToNearestMultiple(int num, int multiple) { return static_cast(std::round(static_cast(num) / static_cast(multiple)) * static_cast(multiple)); } - #pragma endregion + /// + /// Rounds an integer to the specified nearest multiple. + /// For example, if the arguments are 63 and 5, the returned value will be 65. + /// + /// The number to round to the nearest multiple. + /// The multiple to round to. + /// An integer rounded to the specified nearest multiple. + inline int RoundToNearestMultiple(int num, int multiple) { return static_cast(std::round(static_cast(num) / static_cast(multiple)) * static_cast(multiple)); } +#pragma endregion - #pragma region Angle Helpers - /// - /// Returns a copy of the angle normalized so it's between 0 and 2PI. - /// - /// The angle to normalize, in radians. - /// The angle, normalized so it's between 0 and 2PI - float NormalizeAngleBetween0And2PI(float angle); +#pragma region Angle Helpers + /// + /// Returns a copy of the angle normalized so it's between 0 and 2PI. + /// + /// The angle to normalize, in radians. + /// The angle, normalized so it's between 0 and 2PI + float NormalizeAngleBetween0And2PI(float angle); - /// - /// Returns a copy of the angle normalized so it's between -PI and PI. - /// - /// The angle to normalize, in radians. - /// The angle, normalized so it's between -PI and PI - float NormalizeAngleBetweenNegativePIAndPI(float angle); + /// + /// Returns a copy of the angle normalized so it's between -PI and PI. + /// + /// The angle to normalize, in radians. + /// The angle, normalized so it's between -PI and PI + float NormalizeAngleBetweenNegativePIAndPI(float angle); - /// - /// Returns whether or not the angle to check is between the start and end angles. Note that, because of how angles work (when normalized), the start angle may be greater than the end angle. - /// - /// The angle to check, in radians. - /// The starting angle for the range. - /// The ending angle for the range. - /// Whether or not the angle to check is between the start and end angle. - bool AngleWithinRange(float angleToCheck, float startAngle, float endAngle); + /// + /// Returns whether or not the angle to check is between the start and end angles. Note that, because of how angles work (when normalized), the start angle may be greater than the end angle. + /// + /// The angle to check, in radians. + /// The starting angle for the range. + /// The ending angle for the range. + /// Whether or not the angle to check is between the start and end angle. + bool AngleWithinRange(float angleToCheck, float startAngle, float endAngle); - /// - /// Clamps the passed in angle between the specified lower and upper limits, in a CCW direction. - /// - /// The angle to clamp. - /// The lower limit for clamping. - /// The upper limit for clamping. - /// The angle, clamped between the start and end angle. - float ClampAngle(float angleToClamp, float startAngle, float endAngle); - #pragma endregion - - #pragma region Detection - /// - /// Tells whether a point is within a specified box. - /// - /// Vector position of the point we're checking. - /// Vector position of the box. - /// Width of the box. - /// Height of the box. - /// True if point is inside box bounds. - bool WithinBox(const Vector &point, const Vector &boxPos, float width, float height); + /// + /// Clamps the passed in angle between the specified lower and upper limits, in a CCW direction. + /// + /// The angle to clamp. + /// The lower limit for clamping. + /// The upper limit for clamping. + /// The angle, clamped between the start and end angle. + float ClampAngle(float angleToClamp, float startAngle, float endAngle); +#pragma endregion + +#pragma region Detection + /// + /// Tells whether a point is within a specified box. + /// + /// Vector position of the point we're checking. + /// Vector position of the box. + /// Width of the box. + /// Height of the box. + /// True if point is inside box bounds. + bool WithinBox(const Vector& point, const Vector& boxPos, float width, float height); - /// - /// Tells whether a point is within a specified box. - /// - /// Vector position of the point we're checking. - /// Position of box left plane (X start). - /// Position of box top plane (Y start). - /// Position of box right plane (X end). - /// Position of box bottom plane (Y end). - /// True if point is inside box bounds. - bool WithinBox(const Vector &point, float left, float top, float right, float bottom); - #pragma endregion - - #pragma region Conversion - /// - /// Returns a corrected angle value that can be used with Allegro fixed point math routines where 256 equals 360 degrees. - /// - /// The angle value to correct. In degrees. - /// A float with the represented angle as full rotations being 256. - inline float GetAllegroAngle(float angleDegrees) { return (angleDegrees / 360) * 256; } + /// + /// Tells whether a point is within a specified box. + /// + /// Vector position of the point we're checking. + /// Position of box left plane (X start). + /// Position of box top plane (Y start). + /// Position of box right plane (X end). + /// Position of box bottom plane (Y end). + /// True if point is inside box bounds. + bool WithinBox(const Vector& point, float left, float top, float right, float bottom); +#pragma endregion + +#pragma region Conversion + /// + /// Returns a corrected angle value that can be used with Allegro fixed point math routines where 256 equals 360 degrees. + /// + /// The angle value to correct. In degrees. + /// A float with the represented angle as full rotations being 256. + inline float GetAllegroAngle(float angleDegrees) { return (angleDegrees / 360) * 256; } - /// - /// Returns the given angle converted from degrees to radians. - /// - /// The angle in degrees to be converted. - /// The converted angle in radians. - inline float DegreesToRadians(float angleDegrees) { return angleDegrees / 180.0F * c_PI; } + /// + /// Returns the given angle converted from degrees to radians. + /// + /// The angle in degrees to be converted. + /// The converted angle in radians. + inline float DegreesToRadians(float angleDegrees) { return angleDegrees / 180.0F * c_PI; } - /// - /// Returns the given angle converted from radians to degrees. - /// - /// The angle in radians to be converted. - /// The converted angle in degrees. - inline float RadiansToDegrees(float angleRadians) { return angleRadians / c_PI * 180.0F; } - #pragma endregion + /// + /// Returns the given angle converted from radians to degrees. + /// + /// The angle in radians to be converted. + /// The converted angle in degrees. + inline float RadiansToDegrees(float angleRadians) { return angleRadians / c_PI * 180.0F; } +#pragma endregion - #pragma region Strings - /// - /// Checks whether two strings are equal when the casing is disregarded. - /// - /// First string. - /// Second string. - /// Whether the two strings are equal case insensitively. - inline bool StringsEqualCaseInsensitive(const std::string_view &strA, const std::string_view &strB) { return std::equal(strA.begin(), strA.end(), strB.begin(), strB.end(), [](char strAChar, char strBChar) { return std::tolower(strAChar) == std::tolower(strBChar); }); } +#pragma region Strings + /// + /// Checks whether two strings are equal when the casing is disregarded. + /// + /// First string. + /// Second string. + /// Whether the two strings are equal case insensitively. + inline bool StringsEqualCaseInsensitive(const std::string_view& strA, const std::string_view& strB) { + return std::equal(strA.begin(), strA.end(), strB.begin(), strB.end(), [](char strAChar, char strBChar) { return std::tolower(strAChar) == std::tolower(strBChar); }); + } - /// - /// If a file "foo/Bar.txt" exists, and this method is passed "FOO/BAR.TXT", then this method will return "foo/Bar.txt". - /// This method's purpose is to enable Linux to get the real path using a case-insensitive search. - /// The real path is used by the Lua file I/O handling methods to ensure full Windows compatibility. - /// - /// Path to case-insensitively translate to a real path. - /// The real path. If the path doesn't exist, it returns the fullPath argument with all the existing parent directories correctly capitalized. - std::string GetCaseInsensitiveFullPath(const std::string &fullPath); + /// + /// If a file "foo/Bar.txt" exists, and this method is passed "FOO/BAR.TXT", then this method will return "foo/Bar.txt". + /// This method's purpose is to enable Linux to get the real path using a case-insensitive search. + /// The real path is used by the Lua file I/O handling methods to ensure full Windows compatibility. + /// + /// Path to case-insensitively translate to a real path. + /// The real path. If the path doesn't exist, it returns the fullPath argument with all the existing parent directories correctly capitalized. + std::string GetCaseInsensitiveFullPath(const std::string& fullPath); - /// - /// Hashes a string in a cross-compiler/platform safe way (std::hash gives different results on different compilers). - /// - /// Text string to hash. - /// The hash result value. - uint64_t Hash(const std::string &text); - #pragma endregion + /// + /// Hashes a string in a cross-compiler/platform safe way (std::hash gives different results on different compilers). + /// + /// Text string to hash. + /// The hash result value. + uint64_t Hash(const std::string& text); +#pragma endregion - #pragma region Misc - /// - /// Convenience method that takes in a double pointer array and returns a std::vector with its contents, because pointers-to-pointers are the devil. The passed in array is deleted in the process so no need to delete it manually. - /// - /// The double pointer to convert to a std::vector. - /// The size of the double pointer array. - template std::vector ConvertDoublePointerToVectorOfPointers(Type **arrayOfType, size_t arraySize) { - std::unique_ptr doublePointerArray = std::unique_ptr(arrayOfType); - std::vector outputVector; - for (size_t i = 0; i < arraySize; ++i) { - outputVector.emplace_back(doublePointerArray[i]); - } - return outputVector; +#pragma region Misc + /// + /// Convenience method that takes in a double pointer array and returns a std::vector with its contents, because pointers-to-pointers are the devil. The passed in array is deleted in the process so no need to delete it manually. + /// + /// The double pointer to convert to a std::vector. + /// The size of the double pointer array. + template std::vector ConvertDoublePointerToVectorOfPointers(Type** arrayOfType, size_t arraySize) { + std::unique_ptr doublePointerArray = std::unique_ptr(arrayOfType); + std::vector outputVector; + for (size_t i = 0; i < arraySize; ++i) { + outputVector.emplace_back(doublePointerArray[i]); } + return outputVector; + } - /// - /// Returns the sign of the given input value. - /// - /// The sign as an integer -1, 0 or +1. - template int Sign(const Type &value) { - return (Type(0) < value) - (Type(0) > value); - } - #pragma endregion -} -#endif \ No newline at end of file + /// + /// Returns the sign of the given input value. + /// + /// The sign as an integer -1, 0 or +1. + template int Sign(const Type& value) { + return (Type(0) < value) - (Type(0) > value); + } +#pragma endregion +} // namespace RTE +#endif diff --git a/Source/System/Reader.cpp b/Source/System/Reader.cpp index a86a2c47d..bd204a003 100644 --- a/Source/System/Reader.cpp +++ b/Source/System/Reader.cpp @@ -5,7 +5,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Reader::Clear() { m_Stream = nullptr; @@ -26,24 +26,24 @@ namespace RTE { m_NonModulePath = false; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Reader::Reader(const std::string &fileName, bool overwrites, const ProgressCallback &progressCallback, bool failOK, bool nonModulePath) { + Reader::Reader(const std::string& fileName, bool overwrites, const ProgressCallback& progressCallback, bool failOK, bool nonModulePath) { Clear(); m_NonModulePath = nonModulePath; Create(fileName, overwrites, progressCallback, failOK); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Reader::Reader(std::unique_ptr &&stream, bool overwrites, const ProgressCallback &progressCallback, bool failOK) { + Reader::Reader(std::unique_ptr&& stream, bool overwrites, const ProgressCallback& progressCallback, bool failOK) { Clear(); Create(std::move(stream), overwrites, progressCallback, failOK); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Reader::Create(const std::string &fileName, bool overwrites, const ProgressCallback &progressCallback, bool failOK) { + int Reader::Create(const std::string& fileName, bool overwrites, const ProgressCallback& progressCallback, bool failOK) { if (fileName.empty()) { return -1; } @@ -65,15 +65,15 @@ namespace RTE { return Create(std::make_unique(m_FilePath), overwrites, progressCallback, failOK); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Reader::Create(std::unique_ptr &&stream, bool overwrites, const ProgressCallback &progressCallback, bool failOK) { + int Reader::Create(std::unique_ptr&& stream, bool overwrites, const ProgressCallback& progressCallback, bool failOK) { m_CanFail = failOK; m_Stream = std::move(stream); - if (!m_CanFail) { - RTEAssert(System::PathExistsCaseSensitive(m_FilePath) && m_Stream->good(), "Failed to open data file \"" + m_FilePath + "\"!"); + if (!m_CanFail) { + RTEAssert(System::PathExistsCaseSensitive(m_FilePath) && m_Stream->good(), "Failed to open data file \"" + m_FilePath + "\"!"); } m_OverwriteExisting = overwrites; @@ -81,19 +81,19 @@ namespace RTE { // Report that we're starting a new file m_ReportProgress = progressCallback; if (m_ReportProgress && m_Stream->good()) { - m_ReportProgress("\t" + m_FileName + " on line " + std::to_string(m_CurrentLine), true); + m_ReportProgress("\t" + m_FileName + " on line " + std::to_string(m_CurrentLine), true); } return m_Stream->good() ? 0 : -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Reader::GetReadModuleID() const { return (m_DataModuleID < 0) ? g_PresetMan.GetModuleID(m_DataModuleName) : m_DataModuleID; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Reader::WholeFileAsString() const { std::stringstream stringStream; @@ -101,7 +101,7 @@ namespace RTE { return stringStream.str(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Reader::ReadLine() { DiscardEmptySpace(); @@ -119,8 +119,12 @@ namespace RTE { break; } - if (m_Stream->eof()) { break; } - if (!m_Stream->good()) { ReportError("Stream failed for some reason"); } + if (m_Stream->eof()) { + break; + } + if (!m_Stream->good()) { + ReportError("Stream failed for some reason"); + } retString.append(1, temp); peek = static_cast(m_Stream->peek()); @@ -128,7 +132,7 @@ namespace RTE { return TrimString(retString); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Reader::ReadPropName() { DiscardEmptySpace(); @@ -152,10 +156,10 @@ namespace RTE { EndIncludeFile(); break; } - if (!m_Stream->good() || temp == -1) { + if (!m_Stream->good() || temp == -1) { ReportError("Stream failed for some reason"); - EndIncludeFile(); - break; + EndIncludeFile(); + break; } retString.append(1, temp); } @@ -179,7 +183,7 @@ namespace RTE { return retString; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Reader::ReadPropValue() { std::string fullLine = ReadLine(); @@ -188,7 +192,7 @@ namespace RTE { return TrimString(propValue); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Reader::NextProperty() { if (!DiscardEmptySpace() || m_EndOfStreams) { @@ -203,9 +207,9 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string Reader::TrimString(const std::string &stringToTrim) const { + std::string Reader::TrimString(const std::string& stringToTrim) const { if (stringToTrim.empty()) { return ""; } @@ -215,7 +219,7 @@ namespace RTE { return stringToTrim.substr(start, (end - start + 1)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Reader::DiscardEmptySpace() { char peek; @@ -231,17 +235,19 @@ namespace RTE { return EndIncludeFile(); } // Not end-of-file but still got junk back... something went to shit - if (peek == -1) { ReportError("Something went wrong reading the line; make sure it is providing the expected type"); } + if (peek == -1) { + ReportError("Something went wrong reading the line; make sure it is providing the expected type"); + } // Discard spaces if (peek == ' ') { leadingSpaceCount++; m_Stream->ignore(1); - // Discard tabs, and count them + // Discard tabs, and count them } else if (peek == '\t') { indent++; m_Stream->ignore(1); - // Discard newlines and reset the tab count for the new line, also count the lines + // Discard newlines and reset the tab count for the new line, also count the lines } else if (peek == '\n' || peek == '\r') { // So we don't count lines twice when there are both newline and carriage return at the end of lines if (peek == '\n') { @@ -256,14 +262,16 @@ namespace RTE { discardedLine = true; m_Stream->ignore(1); - // Comment line? + // Comment line? } else if (m_Stream->peek() == '/') { char temp = static_cast(m_Stream->get()); // Confirm that it's a comment line, if so discard it and continue if (m_Stream->peek() == '/') { - while (m_Stream->peek() != '\n' && m_Stream->peek() != '\r' && !m_Stream->eof()) { m_Stream->ignore(1); } - // Block comment + while (m_Stream->peek() != '\n' && m_Stream->peek() != '\r' && !m_Stream->eof()) { + m_Stream->ignore(1); + } + // Block comment } else if (m_Stream->peek() == '*') { int openBlockComments = 1; m_BlockCommentOpenTagLines.emplace(m_CurrentLine); @@ -271,7 +279,9 @@ namespace RTE { char temp2 = 0; while (openBlockComments > 0 && !m_Stream->eof()) { temp2 = static_cast(m_Stream->get()); - if (temp2 == '\n') { ++m_CurrentLine; } + if (temp2 == '\n') { + ++m_CurrentLine; + } // Find the matching close tag. if (!(temp2 == '*' && m_Stream->peek() == '/')) { @@ -292,7 +302,7 @@ namespace RTE { ReportError("File stream ended with an open block comment!\nCouldn't find closing tag for block comment opened on line " + std::to_string(m_BlockCommentOpenTagLines.top()) + ".\n"); } - // Not a comment, so it's data, so quit. + // Not a comment, so it's data, so quit. } else { m_Stream->putback(temp); break; @@ -304,31 +314,39 @@ namespace RTE { // This precaution enables us to use DiscardEmptySpace repeatedly without messing up the indentation tracking logic if (discardedLine) { - if (leadingSpaceCount > 0) { ReportError("Encountered space characters used for indentation where a tab character was expected!\nPlease make sure the preset definition structure is correct.\n"); } + if (leadingSpaceCount > 0) { + ReportError("Encountered space characters used for indentation where a tab character was expected!\nPlease make sure the preset definition structure is correct.\n"); + } // Get indentation difference from the last line of the last call to DiscardEmptySpace(), and the last line of this call to DiscardEmptySpace(). m_IndentDifference = indent - m_PreviousIndent; - if (m_IndentDifference > 1) { ReportError("Over indentation detected!\nPlease make sure the preset definition structure is correct.\n"); } + if (m_IndentDifference > 1) { + ReportError("Over indentation detected!\nPlease make sure the preset definition structure is correct.\n"); + } // Save the last tab count m_PreviousIndent = indent; } return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Reader::ReportError(const std::string &errorDesc) const { + void Reader::ReportError(const std::string& errorDesc) const { if (!m_CanFail) { RTEAbort(errorDesc + "\nError happened in " + m_FilePath + " at line " + std::to_string(m_CurrentLine) + "!"); } else { - if (m_ReportProgress) { m_ReportProgress(errorDesc + ", skipping!", true); } + if (m_ReportProgress) { + m_ReportProgress(errorDesc + ", skipping!", true); + } } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Reader::StartIncludeFile() { // Report that we're including a file - if (m_ReportProgress) { m_ReportProgress(m_ReportTabs + m_FileName + " on line " + std::to_string(m_CurrentLine) + " includes:", false); } + if (m_ReportProgress) { + m_ReportProgress(m_ReportTabs + m_FileName + " on line " + std::to_string(m_CurrentLine) + " includes:", false); + } // Get the file path from the current stream before pushing it into the StreamStack, otherwise we can't open a new stream after releasing it because we can't read. std::string includeFilePath = g_PresetMan.GetFullModulePath(ReadPropValue()); @@ -372,10 +390,12 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Reader::EndIncludeFile() { - if (m_ReportProgress) { m_ReportProgress(m_ReportTabs + m_FileName + " - done! " + static_cast(-42), false); } + if (m_ReportProgress) { + m_ReportProgress(m_ReportTabs + m_FileName + " - done! " + static_cast(-42), false); + } if (m_StreamStack.empty()) { m_EndOfStreams = true; @@ -405,4 +425,4 @@ namespace RTE { DiscardEmptySpace(); return true; } -} +} // namespace RTE diff --git a/Source/System/Reader.h b/Source/System/Reader.h index 8848d3f39..4e9d31542 100644 --- a/Source/System/Reader.h +++ b/Source/System/Reader.h @@ -11,7 +11,6 @@ namespace RTE { class Reader { public: - #pragma region Creation /// /// Constructor method used to instantiate a Reader object in system memory. Create() should be called before using the object. @@ -26,7 +25,7 @@ namespace RTE { /// A function pointer to a function that will be called and sent a string with information about the progress of this Reader's reading. /// Whether it's ok for the file to not be there, ie we're only trying to open, and if it's not there, then fail silently. /// Whether this Reader is reading from path that is not a DataModule and should just read it as provided. - Reader(const std::string &fileName, bool overwrites = false, const ProgressCallback &progressCallback = nullptr, bool failOK = false, bool nonModulePath = false); + Reader(const std::string& fileName, bool overwrites = false, const ProgressCallback& progressCallback = nullptr, bool failOK = false, bool nonModulePath = false); /// /// Constructor method used to instantiate a Reader object in system memory and make it ready for reading from the passed in file path. @@ -35,7 +34,7 @@ namespace RTE { /// Whether object definitions read here overwrite existing ones with the same names. /// A function pointer to a function that will be called and sent a string with information about the progress of this Reader's reading. /// Whether it's ok for the file to not be there, ie we're only trying to open, and if it's not there, then fail silently. - Reader(std::unique_ptr &&stream, bool overwrites = false, const ProgressCallback &progressCallback = nullptr, bool failOK = false); + Reader(std::unique_ptr&& stream, bool overwrites = false, const ProgressCallback& progressCallback = nullptr, bool failOK = false); /// /// Makes the Reader object ready for use. @@ -45,7 +44,7 @@ namespace RTE { /// A function pointer to a function that will be called and sent a string with information about the progress of this Reader's reading. /// Whether it's ok for the file to not be there, ie we're only trying to open, and if it's not there, then fail silently. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const std::string &fileName, bool overwrites = false, const ProgressCallback &progressCallback = nullptr, bool failOK = false); + int Create(const std::string& fileName, bool overwrites = false, const ProgressCallback& progressCallback = nullptr, bool failOK = false); /// /// Makes the Reader object ready for use. @@ -55,7 +54,7 @@ namespace RTE { /// A function pointer to a function that will be called and sent a string with information about the progress of this Reader's reading. /// Whether it's ok for the file to not be there, ie we're only trying to open, and if it's not there, then fail silently. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(std::unique_ptr &&stream, bool overwrites = false, const ProgressCallback &progressCallback = nullptr, bool failOK = false); + int Create(std::unique_ptr&& stream, bool overwrites = false, const ProgressCallback& progressCallback = nullptr, bool failOK = false); #pragma endregion #pragma region Getters and Setters @@ -63,7 +62,7 @@ namespace RTE { /// Gets the name of the DataModule this Reader is reading from. /// /// The name of the DataModule this reader is reading from. - const std::string & GetReadModuleName() const { return m_DataModuleName; } + const std::string& GetReadModuleName() const { return m_DataModuleName; } /// /// Gets the ID of the DataModule this Reader is reading from. If the ID is invalid, attempts to get a valid ID using the DataModule name. @@ -75,7 +74,7 @@ namespace RTE { /// Gets a pointer to the istream of this reader. /// /// A pointer to the istream object for this reader. - std::istream * GetStream() const { return m_Stream.get(); } + std::istream* GetStream() const { return m_Stream.get(); } /// /// Gets the path of the current file this reader is reading from. @@ -157,7 +156,7 @@ namespace RTE { /// /// String to remove whitespace from. /// The string that was passed in, sans whitespace in the front and end. - std::string TrimString(const std::string &stringToTrim) const; + std::string TrimString(const std::string& stringToTrim) const; /// /// Discards all whitespace, newlines and comment lines (which start with '//') so that the next thing to be read will be actual data. @@ -177,7 +176,7 @@ namespace RTE { /// Makes an error message box pop up for the user that tells them something went wrong with the reading, and where. /// /// The message describing what's wrong. - void ReportError(const std::string &errorDesc) const; + void ReportError(const std::string& errorDesc) const; #pragma endregion #pragma region Operator Overloads @@ -186,24 +185,74 @@ namespace RTE { /// /// A reference to the variable that will be filled by the extracted data. /// A Reader reference for further use in an expression. - Reader & operator>>(bool &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(char &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(unsigned char &var) { DiscardEmptySpace(); int temp; *m_Stream >> temp; var = temp; return *this; } - Reader & operator>>(short &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(unsigned short &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(int &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(unsigned int &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(long &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(unsigned long &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } + Reader& operator>>(bool& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(char& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(unsigned char& var) { + DiscardEmptySpace(); + int temp; + *m_Stream >> temp; + var = temp; + return *this; + } + Reader& operator>>(short& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(unsigned short& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(int& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(unsigned int& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(long& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(unsigned long& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } // Yeah, this is dumb - read as double and cast. // This is because, for whatever fucking reason, iostream can save out floats at a precision that it's then unable to read... - Reader & operator>>(float &var) { DiscardEmptySpace(); double var2; *m_Stream >> var2; var = static_cast(var2); return *this; } - Reader & operator>>(double &var) { DiscardEmptySpace(); *m_Stream >> var; return *this; } - Reader & operator>>(std::string &var) { var.assign(ReadLine()); return *this; } + Reader& operator>>(float& var) { + DiscardEmptySpace(); + double var2; + *m_Stream >> var2; + var = static_cast(var2); + return *this; + } + Reader& operator>>(double& var) { + DiscardEmptySpace(); + *m_Stream >> var; + return *this; + } + Reader& operator>>(std::string& var) { + var.assign(ReadLine()); + return *this; + } #pragma endregion protected: - /// /// A struct containing information from the currently used stream. /// @@ -211,10 +260,11 @@ namespace RTE { /// /// Constructor method used to instantiate a StreamInfo object in system memory. /// - StreamInfo(std::istream *stream, const std::string &filePath, int currentLine, int prevIndent) : Stream(stream), FilePath(filePath), CurrentLine(currentLine), PreviousIndent(prevIndent) {} + StreamInfo(std::istream* stream, const std::string& filePath, int currentLine, int prevIndent) : + Stream(stream), FilePath(filePath), CurrentLine(currentLine), PreviousIndent(prevIndent) {} // NOTE: These members are owned by the reader that owns this struct, so are not deleted when this is destroyed. - std::istream *Stream; //!< Currently used stream, is not on the StreamStack until a new stream is opened. + std::istream* Stream; //!< Currently used stream, is not on the StreamStack until a new stream is opened. std::string FilePath; //!< Currently used stream's filepath. int CurrentLine; //!< The line number the stream is on. int PreviousIndent; //!< Count of tabs encountered on the last line DiscardEmptySpace() discarded. @@ -251,7 +301,6 @@ namespace RTE { int m_ObjectEndings; private: - #pragma region Reading Operations /// /// When ReadPropName encounters the property name "IncludeFile", it will automatically call this function to get started reading on that file. @@ -274,8 +323,8 @@ namespace RTE { void Clear(); // Disallow the use of some implicit methods. - Reader(const Reader &reference) = delete; - Reader & operator=(const Reader &rhs) = delete; + Reader(const Reader& reference) = delete; + Reader& operator=(const Reader& rhs) = delete; }; -} +} // namespace RTE #endif diff --git a/Source/System/Semver200/Semver200_modifier.cpp b/Source/System/Semver200/Semver200_modifier.cpp index af9423ae3..11f4f45ce 100644 --- a/Source/System/Semver200/Semver200_modifier.cpp +++ b/Source/System/Semver200/Semver200_modifier.cpp @@ -72,4 +72,4 @@ namespace version { Version_data Semver200_modifier::reset_build(const Version_data& s, const Build_identifiers& b) const { return Version_data{ s.major, s.minor, s.patch, s.prerelease_ids, b }; } -} \ No newline at end of file +} diff --git a/Source/System/Semver200/semver200.h b/Source/System/Semver200/semver200.h index 813dbdb83..cb271e271 100644 --- a/Source/System/Semver200/semver200.h +++ b/Source/System/Semver200/semver200.h @@ -85,4 +85,4 @@ namespace version { : Basic_version{ v, Semver200_parser(), Semver200_comparator(), Semver200_modifier() } {} }; -} \ No newline at end of file +} diff --git a/Source/System/Semver200/version.h b/Source/System/Semver200/version.h index 97a8322e9..10fc0f176 100644 --- a/Source/System/Semver200/version.h +++ b/Source/System/Semver200/version.h @@ -1,4 +1,4 @@ -/* +/* The MIT License (MIT) Copyright (c) 2015 Marko Zivanovic diff --git a/Source/System/Serializable.cpp b/Source/System/Serializable.cpp index b79204de3..97f037661 100644 --- a/Source/System/Serializable.cpp +++ b/Source/System/Serializable.cpp @@ -2,15 +2,17 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Serializable::CreateSerializable(Reader &reader, bool checkType, bool doCreate, bool skipStartingObject) { + int Serializable::CreateSerializable(Reader& reader, bool checkType, bool doCreate, bool skipStartingObject) { if (checkType && reader.ReadPropValue() != GetClassName()) { reader.ReportError("Wrong type in Reader when passed to Serializable::Create()"); return -1; } - if (!skipStartingObject) { reader.StartObject(); } + if (!skipStartingObject) { + reader.StartObject(); + } while (reader.NextProperty()) { SetFormattedReaderPosition("in file " + reader.GetCurrentFilePath() + " on line " + reader.GetCurrentFileLine()); std::string propName = reader.ReadPropName(); @@ -24,39 +26,41 @@ namespace RTE { return doCreate ? Create() : 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Serializable::ReadProperty(const std::string_view &propName, Reader &reader) { + int Serializable::ReadProperty(const std::string_view& propName, Reader& reader) { reader.ReadPropValue(); reader.ReportError("Could not match property '" + std::string(propName) + "'!"); return -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Reader & operator>>(Reader &reader, Serializable &operand) { + Reader& operator>>(Reader& reader, Serializable& operand) { operand.Create(reader); return reader; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Reader & operator>>(Reader &reader, Serializable *operand) { - if (operand) { operand->Create(reader); } + Reader& operator>>(Reader& reader, Serializable* operand) { + if (operand) { + operand->Create(reader); + } return reader; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Writer & operator<<(Writer &writer, const Serializable &operand) { + Writer& operator<<(Writer& writer, const Serializable& operand) { operand.Save(writer); writer.ObjectEnd(); return writer; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Writer & operator<<(Writer &writer, const Serializable *operand) { + Writer& operator<<(Writer& writer, const Serializable* operand) { if (operand) { operand->Save(writer); writer.ObjectEnd(); @@ -65,4 +69,4 @@ namespace RTE { } return writer; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Serializable.h b/Source/System/Serializable.h index 7db7835db..4d7d59127 100644 --- a/Source/System/Serializable.h +++ b/Source/System/Serializable.h @@ -17,52 +17,57 @@ namespace RTE { class Serializable { public: - #pragma region Global Macro Definitions - /// - /// Convenience macro to cut down on duplicate ReadProperty and Save methods in classes that extend Serializable. - /// - #define SerializableOverrideMethods \ - int ReadProperty(const std::string_view &propName, Reader &reader) override; \ - int Save(Writer &writer) const override; - - /// - /// Convenience macro to cut down on duplicate GetClassName methods in non-poolable classes that extend Serializable. - /// - #define SerializableClassNameGetter \ - const std::string & GetClassName() const override { return c_ClassName; } - - #define StartPropertyList(failureCase) \ - static std::unordered_map sm_Properties; \ - static bool sm_Initialized = false; \ - int jmpAddress = sm_Initialized ? -1 : -2; \ - if (sm_Initialized) { \ - auto itr = sm_Properties.find(std::string(propName)); \ - if (itr == sm_Properties.end()) { \ - failureCase; \ - } else { \ - jmpAddress = itr->second; \ - } \ - } \ - switch (jmpAddress) { \ - case -1: break; \ - case -2: - - #define MatchForwards(propertyName) \ - sm_Properties[propertyName] = __COUNTER__ + 1; \ - case __COUNTER__: - - #define MatchProperty(propertyName,matchedFunction) \ - sm_Properties[propertyName] = __COUNTER__ + 1; \ - case __COUNTER__: if (sm_Initialized) { { matchedFunction }; break; }; - - #define EndPropertyList } \ - if (!sm_Initialized) { \ - sm_Initialized = true; \ - /* This was the initialization pass, now properly read the value by calling ourselves again */ \ - return ReadProperty(propName, reader); \ - } \ - return 0; +/// +/// Convenience macro to cut down on duplicate ReadProperty and Save methods in classes that extend Serializable. +/// +#define SerializableOverrideMethods \ + int ReadProperty(const std::string_view& propName, Reader& reader) override; \ + int Save(Writer& writer) const override; + +/// +/// Convenience macro to cut down on duplicate GetClassName methods in non-poolable classes that extend Serializable. +/// +#define SerializableClassNameGetter \ + const std::string& GetClassName() const override { return c_ClassName; } + +#define StartPropertyList(failureCase) \ + static std::unordered_map sm_Properties; \ + static bool sm_Initialized = false; \ + int jmpAddress = sm_Initialized ? -1 : -2; \ + if (sm_Initialized) { \ + auto itr = sm_Properties.find(std::string(propName)); \ + if (itr == sm_Properties.end()) { \ + failureCase; \ + } else { \ + jmpAddress = itr->second; \ + } \ + } \ + switch (jmpAddress) { \ + case -1: \ + break; \ + case -2: + +#define MatchForwards(propertyName) \ + sm_Properties[propertyName] = __COUNTER__ + 1; \ + case __COUNTER__: + +#define MatchProperty(propertyName, matchedFunction) \ + sm_Properties[propertyName] = __COUNTER__ + 1; \ + case __COUNTER__: \ + if (sm_Initialized) { \ + {matchedFunction}; \ + break; \ + }; + +#define EndPropertyList \ + } \ + if (!sm_Initialized) { \ + sm_Initialized = true; \ + /* This was the initialization pass, now properly read the value by calling ourselves again */ \ + return ReadProperty(propName, reader); \ + } \ + return 0; #pragma endregion @@ -86,7 +91,7 @@ namespace RTE { /// Whether to do any additional initialization of the object after reading in all the properties from the Reader. This is done by calling Create(). /// Whether there is a class name in the stream to check against to make sure the correct type is being read from the stream. /// Whether to do any additional initialization of the object after reading in all the properties from the Reader. This is done by calling Create(). /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - virtual int Create(Reader &reader, bool checkType = true, bool doCreate = true) { return CreateSerializable(reader, checkType, doCreate, false); } + virtual int Create(Reader& reader, bool checkType = true, bool doCreate = true) { return CreateSerializable(reader, checkType, doCreate, false); } #pragma endregion #pragma region Destruction @@ -122,21 +127,24 @@ namespace RTE { /// An error return value signaling whether the property was successfully read or not. /// 0 means it was read successfully, and any nonzero indicates that a property of that name could not be found in this or base classes. /// - virtual int ReadProperty(const std::string_view &propName, Reader &reader); + virtual int ReadProperty(const std::string_view& propName, Reader& reader); /// /// Saves the complete state of this Serializable to an output stream for later recreation with Create(istream &stream). /// /// A Writer that the Serializable will save itself to. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - virtual int Save(Writer &writer) const { writer.ObjectStart(GetClassName()); return 0; } + virtual int Save(Writer& writer) const { + writer.ObjectStart(GetClassName()); + return 0; + } /// /// Replaces backslashes with forward slashes in file paths to eliminate issues with cross-platform compatibility or invalid escape sequences. /// /// Reference to the file path string to correct slashes in. // TODO: Add a warning log entry if backslashes are found in a data path. Perhaps overwrite them in the ini file itself. - std::string CorrectBackslashesInPath(const std::string &pathToCorrect) const { return std::filesystem::path(pathToCorrect).generic_string(); } + std::string CorrectBackslashesInPath(const std::string& pathToCorrect) const { return std::filesystem::path(pathToCorrect).generic_string(); } #pragma endregion #pragma region Logging @@ -146,7 +154,7 @@ namespace RTE { /// This just acts as an abstract base for child classes to implement. /// /// A string containing the currently read file path and the line being read. - virtual void SetFormattedReaderPosition(const std::string &newPosition) {} + virtual void SetFormattedReaderPosition(const std::string& newPosition) {} #pragma endregion #pragma region Operator Overloads @@ -156,7 +164,7 @@ namespace RTE { /// A Reader reference as the left hand side operand. /// An Serializable reference as the right hand side operand. /// A Reader reference for further use in an expression. - friend Reader & operator>>(Reader &reader, Serializable &operand); + friend Reader& operator>>(Reader& reader, Serializable& operand); /// /// A Reader extraction operator for filling an Serializable from a Reader. @@ -164,7 +172,7 @@ namespace RTE { /// A Reader reference as the left hand side operand. /// An Serializable pointer as the right hand side operand. /// A Reader reference for further use in an expression. - friend Reader & operator>>(Reader &reader, Serializable *operand); + friend Reader& operator>>(Reader& reader, Serializable* operand); /// /// A Writer insertion operator for sending a Serializable to a Writer. @@ -172,7 +180,7 @@ namespace RTE { /// A Writer reference as the left hand side operand. /// A Serializable reference as the right hand side operand. /// A Writer reference for further use in an expression. - friend Writer & operator<<(Writer &writer, const Serializable &operand); + friend Writer& operator<<(Writer& writer, const Serializable& operand); /// /// A Writer insertion operator for sending a Serializable to a Writer. @@ -180,7 +188,7 @@ namespace RTE { /// A Writer reference as the left hand side operand. /// A Serializable pointer as the right hand side operand. /// A Writer reference for further use in an expression. - friend Writer &operator<<(Writer &writer, const Serializable *operand); + friend Writer& operator<<(Writer& writer, const Serializable* operand); #pragma endregion #pragma region Class Info @@ -188,15 +196,14 @@ namespace RTE { /// Gets the class name of this Serializable. /// /// A string with the friendly-formatted type name of this Serializable. - virtual const std::string & GetClassName() const = 0; + virtual const std::string& GetClassName() const = 0; #pragma endregion private: - /// /// Clears all the member variables of this Object, effectively resetting the members of this abstraction level only. /// void Clear() {} }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Shader.cpp b/Source/System/Shader.cpp index 3650f03fa..07c9b1381 100644 --- a/Source/System/Shader.cpp +++ b/Source/System/Shader.cpp @@ -12,21 +12,21 @@ namespace RTE { Shader::Shader() : m_ProgramID(0), m_TextureUniform(-1), m_ColorUniform(-1), m_TransformUniform(-1), m_ProjectionUniform(-1) {} -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Shader::Shader(const std::string &vertexFilename, const std::string &fragPath) : + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Shader::Shader(const std::string& vertexFilename, const std::string& fragPath) : m_ProgramID(glCreateProgram()), m_TextureUniform(-1), m_ColorUniform(-1), m_TransformUniform(-1), m_ProjectionUniform(-1) { Compile(vertexFilename, fragPath); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Shader::~Shader() { if (m_ProgramID) { GL_CHECK(glDeleteProgram(m_ProgramID)); } } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Shader::Compile(const std::string &vertexPath, const std::string &fragPath) { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool Shader::Compile(const std::string& vertexPath, const std::string& fragPath) { assert(m_ProgramID != 0); GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); @@ -59,55 +59,55 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Shader::Use() { GL_CHECK(glUseProgram(m_ProgramID)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - GLint Shader::GetUniformLocation(const std::string &name) { return glGetUniformLocation(m_ProgramID, name.c_str()); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + GLint Shader::GetUniformLocation(const std::string& name) { return glGetUniformLocation(m_ProgramID, name.c_str()); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetBool(const std::string &name, bool value) { GL_CHECK(glUniform1i(glGetUniformLocation(m_ProgramID, name.c_str()), static_cast(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetBool(const std::string& name, bool value) { GL_CHECK(glUniform1i(glGetUniformLocation(m_ProgramID, name.c_str()), static_cast(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetInt(const std::string &name, int value) { GL_CHECK(glUniform1i(glGetUniformLocation(m_ProgramID, name.c_str()), value)); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetInt(const std::string& name, int value) { GL_CHECK(glUniform1i(glGetUniformLocation(m_ProgramID, name.c_str()), value)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetFloat(const std::string &name, float value) { GL_CHECK(glUniform1f(glGetUniformLocation(m_ProgramID, name.c_str()), value)); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetFloat(const std::string& name, float value) { GL_CHECK(glUniform1f(glGetUniformLocation(m_ProgramID, name.c_str()), value)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetMatrix4f(const std::string &name, const glm::mat4 &value) { GL_CHECK(glUniformMatrix4fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetMatrix4f(const std::string& name, const glm::mat4& value) { GL_CHECK(glUniformMatrix4fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetVector2f(const std::string &name, const glm::vec2 &value) { GL_CHECK(glUniform2fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetVector2f(const std::string& name, const glm::vec2& value) { GL_CHECK(glUniform2fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetVector3f(const std::string &name, const glm::vec3 &value) { GL_CHECK(glUniform3fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetVector3f(const std::string& name, const glm::vec3& value) { GL_CHECK(glUniform3fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetVector4f(const std::string &name, const glm::vec4 &value) { GL_CHECK(glUniform4fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetVector4f(const std::string& name, const glm::vec4& value) { GL_CHECK(glUniform4fv(glGetUniformLocation(m_ProgramID, name.c_str()), 1, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Shader::SetBool(int32_t uniformLoc, bool value) { GL_CHECK(glUniform1i(uniformLoc, value)); } void Shader::SetInt(int32_t uniformLoc, int value) { GL_CHECK(glUniform1i(uniformLoc, value)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Shader::SetFloat(int32_t uniformLoc, float value) { GL_CHECK(glUniform1f(uniformLoc, value)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetMatrix4f(int32_t uniformLoc, const glm::mat4 &value) { GL_CHECK(glUniformMatrix4fv(uniformLoc, 1, GL_FALSE, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetMatrix4f(int32_t uniformLoc, const glm::mat4& value) { GL_CHECK(glUniformMatrix4fv(uniformLoc, 1, GL_FALSE, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetVector2f(int32_t uniformLoc, const glm::vec2 &value) { GL_CHECK(glUniform2fv(uniformLoc, 1, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetVector2f(int32_t uniformLoc, const glm::vec2& value) { GL_CHECK(glUniform2fv(uniformLoc, 1, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetVector3f(int32_t uniformLoc, const glm::vec3 &value) { GL_CHECK(glUniform3fv(uniformLoc, 1, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetVector3f(int32_t uniformLoc, const glm::vec3& value) { GL_CHECK(glUniform3fv(uniformLoc, 1, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::SetVector4f(int32_t uniformLoc, const glm::vec4 &value) { GL_CHECK(glUniform4fv(uniformLoc, 1, glm::value_ptr(value))); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::SetVector4f(int32_t uniformLoc, const glm::vec4& value) { GL_CHECK(glUniform4fv(uniformLoc, 1, glm::value_ptr(value))); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool Shader::CompileShader(GLuint shaderID, const std::string &filename, std::string &error) { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool Shader::CompileShader(GLuint shaderID, const std::string& filename, std::string& error) { if (!System::PathExistsCaseSensitive(filename)) { error += "File " + filename + " doesn't exist."; return false; @@ -120,7 +120,7 @@ namespace RTE { std::string dataString = dataStream.str(); - const char *data = dataString.c_str(); + const char* data = dataString.c_str(); GL_CHECK(glShaderSource(shaderID, 1, &data, nullptr)); GL_CHECK(glCompileShader(shaderID)); @@ -140,7 +140,7 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Shader::Link(GLuint vtxShader, GLuint fragShader) { GL_CHECK(glAttachShader(m_ProgramID, vtxShader)); GL_CHECK(glAttachShader(m_ProgramID, fragShader)); @@ -155,8 +155,8 @@ namespace RTE { return true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Shader::ApplyDefaultUniforms(){ + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Shader::ApplyDefaultUniforms() { Use(); SetInt("rteTexture", 0); SetInt("rtePalette", 1); @@ -164,4 +164,4 @@ namespace RTE { SetMatrix4f("rteTransform", glm::mat4(1)); SetMatrix4f("rteProjection", glm::mat4(1)); } -} // namespace RTE \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Shader.h b/Source/System/Shader.h index 5c351f047..e731b405c 100644 --- a/Source/System/Shader.h +++ b/Source/System/Shader.h @@ -7,23 +7,22 @@ namespace RTE { class Shader { public: - - /// + /// /// Constructs an empty shader program, which can be initialized using `Shader::Compile` /// Shader(); - - /// + + /// /// Constructs a Shader from vertex shader file and fragment shader file. /// /// /// Filepath to the vertex shader file. /// /// - /// Filepath to the fragment shader file. + /// Filepath to the fragment shader file. /// - Shader(const std::string &vertexFilename, const std::string &fragPath); - + Shader(const std::string& vertexFilename, const std::string& fragPath); + /// /// Destructor. /// @@ -38,7 +37,7 @@ namespace RTE { /// /// Filepath to the fragment shader /// - bool Compile(const std::string &vertexFilename, const std::string &fragPath); + bool Compile(const std::string& vertexFilename, const std::string& fragPath); void Use(); #pragma region Uniform handling @@ -51,7 +50,7 @@ namespace RTE { /// /// A GLint containing the location of the requested uniform. /// - int32_t GetUniformLocation(const std::string &name); + int32_t GetUniformLocation(const std::string& name); /// /// Set a boolean uniform value in the active program by name. @@ -62,7 +61,7 @@ namespace RTE { /// /// The boolean value to set the uniform to. /// - void SetBool(const std::string &name, bool value); + void SetBool(const std::string& name, bool value); /// /// Set an integer uniform value in the active program by name. @@ -73,7 +72,7 @@ namespace RTE { /// /// The integer value to set the uniform to. /// - void SetInt(const std::string &name, int value); + void SetInt(const std::string& name, int value); /// /// Set a float uniform value in the active program by name. @@ -84,7 +83,7 @@ namespace RTE { /// /// The float value to set the uniform to. /// - void SetFloat(const std::string &name, float value); + void SetFloat(const std::string& name, float value); /// /// Set a float mat4 uniform value in the active program by name. @@ -95,7 +94,7 @@ namespace RTE { /// /// The float mat4 value to set the uniform to. /// - void SetMatrix4f(const std::string &name, const glm::mat4 &value); + void SetMatrix4f(const std::string& name, const glm::mat4& value); /// /// Set a float vec2 uniform value in the active program by name. @@ -106,7 +105,7 @@ namespace RTE { /// /// The float vec2 value to set the uniform to. /// - void SetVector2f(const std::string &name, const glm::vec2 &value); + void SetVector2f(const std::string& name, const glm::vec2& value); /// /// Set a float vec3 uniform value in the active program by name. @@ -117,7 +116,7 @@ namespace RTE { /// /// The float vec3 value to set the uniform to. /// - void SetVector3f(const std::string &name, const glm::vec3 &value); + void SetVector3f(const std::string& name, const glm::vec3& value); /// /// Set a float vec4 uniform value in the active program by name. @@ -128,7 +127,7 @@ namespace RTE { /// /// The float vec4 value to set the uniform to. /// - void SetVector4f(const std::string &name, const glm::vec4 &value); + void SetVector4f(const std::string& name, const glm::vec4& value); /// /// Set a boolean uniform value in the active program by location. @@ -172,7 +171,7 @@ namespace RTE { /// /// The float mat4 value to set the uniform to. /// - static void SetMatrix4f(int32_t uniformLoc, const glm::mat4 &value); + static void SetMatrix4f(int32_t uniformLoc, const glm::mat4& value); /// /// Set a float vec2 uniform value in the active program by location. @@ -183,7 +182,7 @@ namespace RTE { /// /// The float vec2 value to set the uniform to. /// - static void SetVector2f(int32_t uniformLoc, const glm::vec2 &value); + static void SetVector2f(int32_t uniformLoc, const glm::vec2& value); /// /// Set a float vec3 uniform value in the active program by location. @@ -194,7 +193,7 @@ namespace RTE { /// /// The float vec3 value to set the uniform to. /// - static void SetVector3f(int32_t uniformLoc, const glm::vec3 &value); + static void SetVector3f(int32_t uniformLoc, const glm::vec3& value); /// /// Set a float vec4 uniform value in the active program by location. @@ -205,7 +204,7 @@ namespace RTE { /// /// The float vec4 value to set the uniform to. /// - static void SetVector4f(int32_t uniformLoc, const glm::vec4 &value); + static void SetVector4f(int32_t uniformLoc, const glm::vec4& value); #pragma endregion #pragma region Engine Defined Uniforms @@ -269,9 +268,9 @@ namespace RTE { /// /// Whether compilation was successful. /// - bool CompileShader(uint32_t shaderID, const std::string &data, std::string &error); + bool CompileShader(uint32_t shaderID, const std::string& data, std::string& error); - /// + /// /// Links a shader program from a vertex and fragment shader. /// /// diff --git a/Source/System/Singleton.h b/Source/System/Singleton.h index 26d5e567e..36e886d13 100644 --- a/Source/System/Singleton.h +++ b/Source/System/Singleton.h @@ -17,7 +17,6 @@ namespace RTE { class Singleton { public: - /// /// Destructor method used to clean up a Singleton object before deletion. /// @@ -27,7 +26,7 @@ namespace RTE { /// Returns the sole instance of this Singleton. /// /// A reference to the sole instance of this Singleton. - inline static Type & Instance() { return *s_Instance; } + inline static Type& Instance() { return *s_Instance; } /// /// Constructs this Singleton. @@ -35,21 +34,19 @@ namespace RTE { inline static void Construct() { s_Instance = new Type(); } protected: - /// /// Constructor method used to instantiate a Singleton object. /// Singleton() { RTEAssert(!s_Instance, "Trying to create a second instance of a Singleton!"); } private: - - static Type *s_Instance; //!< Pointer to instance of this singleton. + static Type* s_Instance; //!< Pointer to instance of this singleton. // Disallow the use of some implicit methods. - Singleton(const Singleton &reference) = delete; - Singleton & operator=(const Singleton &rhs) = delete; + Singleton(const Singleton& reference) = delete; + Singleton& operator=(const Singleton& rhs) = delete; }; - template Type * Singleton::s_Instance = nullptr; -} -#endif \ No newline at end of file + template Type* Singleton::s_Instance = nullptr; +} // namespace RTE +#endif diff --git a/Source/System/SpatialPartitionGrid.cpp b/Source/System/SpatialPartitionGrid.cpp index 51abbfb40..bc32a5919 100644 --- a/Source/System/SpatialPartitionGrid.cpp +++ b/Source/System/SpatialPartitionGrid.cpp @@ -6,7 +6,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SpatialPartitionGrid::Clear() { m_Width = 0; @@ -19,7 +19,7 @@ namespace RTE { m_UsedCellIds.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int SpatialPartitionGrid::Create(int width, int height, int cellSize) { m_Width = width / cellSize; @@ -32,9 +32,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int SpatialPartitionGrid::Create(const SpatialPartitionGrid &reference) { + int SpatialPartitionGrid::Create(const SpatialPartitionGrid& reference) { m_Width = reference.m_Width; m_Height = reference.m_Height; m_CellSize = reference.m_CellSize; @@ -44,15 +44,15 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SpatialPartitionGrid::Reset() { - const Activity *activity = g_ActivityMan.GetActivity(); + const Activity* activity = g_ActivityMan.GetActivity(); RTEAssert(activity, "Tried to reset spatial partition grid with no running Activity!"); for (int team = Activity::NoTeam; team < Activity::MaxTeamCount; ++team) { if (team == Activity::NoTeam || activity->TeamActive(team)) { - for (int usedCellId : m_UsedCellIds) { + for (int usedCellId: m_UsedCellIds) { m_Cells[team + 1][usedCellId].clear(); m_PhysicsCells[team + 1][usedCellId].clear(); } @@ -62,13 +62,13 @@ namespace RTE { m_UsedCellIds.clear(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void SpatialPartitionGrid::Add(const IntRect &rect, const MovableObject &mo) { - const Activity *activity = g_ActivityMan.GetActivity(); + void SpatialPartitionGrid::Add(const IntRect& rect, const MovableObject& mo) { + const Activity* activity = g_ActivityMan.GetActivity(); RTEAssert(activity, "Tried to add to spatial partition grid with no running Activity!"); - const MovableObject &rootParentMo = *mo.GetRootParent(); + const MovableObject& rootParentMo = *mo.GetRootParent(); int topLeftCellX = rect.m_Left / m_CellSize; int topLeftCellY = rect.m_Top / m_CellSize; int bottomRightCellX = rect.m_Right / m_CellSize; @@ -104,7 +104,7 @@ namespace RTE { } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector SpatialPartitionGrid::GetMOsInBox(const Box &box, int ignoreTeam, bool getsHitByMOsOnly) const { + std::vector SpatialPartitionGrid::GetMOsInBox(const Box& box, int ignoreTeam, bool getsHitByMOsOnly) const { RTEAssert(ignoreTeam >= Activity::NoTeam && ignoreTeam < Activity::MaxTeamCount, "Invalid ignoreTeam given to SpatialPartitioningGrid::GetMOsInBox()!"); std::unordered_set potentialMOIDs; @@ -118,11 +118,11 @@ namespace RTE { int bottomRightCellY = static_cast(std::floor(bottomRight.m_Y / static_cast(m_CellSize))); // Note - GetCellIdForCellCoords accounts for wrapping automatically, so we don't have to deal with it here. - auto &cells = getsHitByMOsOnly ? m_PhysicsCells : m_Cells; + auto& cells = getsHitByMOsOnly ? m_PhysicsCells : m_Cells; for (int x = topLeftCellX; x <= bottomRightCellX; x++) { for (int y = topLeftCellY; y <= bottomRightCellY; y++) { - const std::vector &moidsInCell = cells[ignoreTeam + 1][GetCellIdForCellCoords(x, y)]; - for (MOID moid : moidsInCell) { + const std::vector& moidsInCell = cells[ignoreTeam + 1][GetCellIdForCellCoords(x, y)]; + for (MOID moid: moidsInCell) { potentialMOIDs.insert(moid); } } @@ -131,10 +131,10 @@ namespace RTE { std::list wrappedBoxes; g_SceneMan.WrapBox(box, wrappedBoxes); - std::vector MOList; - for (MOID moid : potentialMOIDs) { - MovableObject *mo = g_MovableMan.GetMOFromID(moid); - if (mo && std::any_of(wrappedBoxes.begin(), wrappedBoxes.end(), [&mo](const Box &wrappedBox) { return wrappedBox.IsWithinBox(mo->GetPos()); })) { + std::vector MOList; + for (MOID moid: potentialMOIDs) { + MovableObject* mo = g_MovableMan.GetMOFromID(moid); + if (mo && std::any_of(wrappedBoxes.begin(), wrappedBoxes.end(), [&mo](const Box& wrappedBox) { return wrappedBox.IsWithinBox(mo->GetPos()); })) { MOList.push_back(mo); } } @@ -142,9 +142,9 @@ namespace RTE { return MOList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::vector SpatialPartitionGrid::GetMOsInRadius(const Vector ¢er, float radius, int ignoreTeam, bool getsHitByMOsOnly) const { + std::vector SpatialPartitionGrid::GetMOsInRadius(const Vector& center, float radius, int ignoreTeam, bool getsHitByMOsOnly) const { RTEAssert(ignoreTeam >= Activity::NoTeam && ignoreTeam < Activity::MaxTeamCount, "Invalid ignoreTeam given to SpatialPartitioningGrid::GetMOsInRadius()!"); std::unordered_set potentialMOIDs; @@ -155,19 +155,19 @@ namespace RTE { int bottomRightCellY = static_cast(std::floor((center.m_Y + radius) / static_cast(m_CellSize))); // Note - GetCellIdForCellCoords accounts for wrapping automatically, so we don't have to deal with it here. - auto &cells = getsHitByMOsOnly ? m_PhysicsCells : m_Cells; + auto& cells = getsHitByMOsOnly ? m_PhysicsCells : m_Cells; for (int x = topLeftCellX; x <= bottomRightCellX; x++) { for (int y = topLeftCellY; y <= bottomRightCellY; y++) { - const std::vector &moidsInCell = cells[ignoreTeam + 1][GetCellIdForCellCoords(x, y)]; - for (MOID moid : moidsInCell) { + const std::vector& moidsInCell = cells[ignoreTeam + 1][GetCellIdForCellCoords(x, y)]; + for (MOID moid: moidsInCell) { potentialMOIDs.insert(moid); } } } - std::vector MOList; - for (MOID moid : potentialMOIDs) { - MovableObject *mo = g_MovableMan.GetMOFromID(moid); + std::vector MOList; + for (MOID moid: potentialMOIDs) { + MovableObject* mo = g_MovableMan.GetMOFromID(moid); if (mo && !g_SceneMan.ShortestDistance(center, mo->GetPos()).MagnitudeIsGreaterThan(radius)) { MOList.push_back(mo); } @@ -176,9 +176,9 @@ namespace RTE { return MOList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::vector & SpatialPartitionGrid::GetMOIDsAtPosition(int x, int y, int ignoreTeam, bool getsHitByMOsOnly) const { + const std::vector& SpatialPartitionGrid::GetMOIDsAtPosition(int x, int y, int ignoreTeam, bool getsHitByMOsOnly) const { int cellX = x / m_CellSize; int cellY = y / m_CellSize; @@ -187,11 +187,11 @@ namespace RTE { // So let's sanity check this shit. ignoreTeam = ignoreTeam < Activity::NoTeam || ignoreTeam >= Activity::MaxTeamCount ? Activity::NoTeam : ignoreTeam; - auto &cells = getsHitByMOsOnly ? m_PhysicsCells : m_Cells; + auto& cells = getsHitByMOsOnly ? m_PhysicsCells : m_Cells; return cells[ignoreTeam + 1][GetCellIdForCellCoords(cellX, cellY)]; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int SpatialPartitionGrid::GetCellIdForCellCoords(int cellX, int cellY) const { // We act like we wrap, even if the Scene doesn't. The only cost is some duplicate collision checks, but that's a minor cost to pay :) @@ -205,4 +205,4 @@ namespace RTE { } return (wrappedY * m_Width) + wrappedX; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/SpatialPartitionGrid.h b/Source/System/SpatialPartitionGrid.h index 9cadcf772..937aad172 100644 --- a/Source/System/SpatialPartitionGrid.h +++ b/Source/System/SpatialPartitionGrid.h @@ -1,7 +1,7 @@ #ifndef _RTESPATIALPARTITIONGRID_ #define _RTESPATIALPARTITIONGRID_ -//TODO Move Team enum into Constants so we can avoid including Activity here. +// TODO Move Team enum into Constants so we can avoid including Activity here. #include "Activity.h" #include "Constants.h" @@ -20,7 +20,6 @@ namespace RTE { class SpatialPartitionGrid { public: - #pragma region Creation /// /// Constructor method used to instantiate a SpatialPartitionGrid object. @@ -30,7 +29,10 @@ namespace RTE { /// /// Constructor method used to instantiate a SpatialPartitionGrid object. /// - SpatialPartitionGrid(int width, int height, int cellSize) { Clear(); Create(width, height, cellSize); } + SpatialPartitionGrid(int width, int height, int cellSize) { + Clear(); + Create(width, height, cellSize); + } /// /// Makes the SpatialPartitionGrid object ready for use. @@ -43,7 +45,7 @@ namespace RTE { /// /// A reference to the SpatialPartitionGrid to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const SpatialPartitionGrid &reference); + int Create(const SpatialPartitionGrid& reference); #pragma endregion #pragma region Grid Management @@ -57,7 +59,7 @@ namespace RTE { /// /// A rectangle defining the space the MovableObject takes up. /// The MovableObject to add. - void Add(const IntRect &rect, const MovableObject &mo); + void Add(const IntRect& rect, const MovableObject& mo); /// /// Gets a vector of pointers to all MovableObjects within the given Box, who aren't of the ignored team. @@ -66,7 +68,7 @@ namespace RTE { /// The team to ignore when getting MovableObjects. /// Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. /// A vector of pointers to all MovableObjects within the given Box, who aren't of the ignored team. - std::vector GetMOsInBox(const Box &box, int ignoreTeam, bool getsHitByMOsOnly) const; + std::vector GetMOsInBox(const Box& box, int ignoreTeam, bool getsHitByMOsOnly) const; /// /// Get a vector of pointers to all the MovableObjects within the specified radius of the given center point, who aren't of the ignored team. @@ -76,7 +78,7 @@ namespace RTE { /// The team to ignore when getting MovableObjects. /// Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. /// A vector of pointers to all the MovableObjects within the specified radius of the given center point, who aren't of the ignored team. - std::vector GetMOsInRadius(const Vector ¢er, float radius, int ignoreTeam, bool getsHitByMOsOnly) const; + std::vector GetMOsInRadius(const Vector& center, float radius, int ignoreTeam, bool getsHitByMOsOnly) const; /// /// Gets the MOIDs that are potentially overlapping the given X and Y Scene coordinates. @@ -86,11 +88,10 @@ namespace RTE { /// The team to ignore when getting MOIDs. /// Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. /// A vector of MOIDs that are potentially overlapping the x and y coordinates. - const std::vector & GetMOIDsAtPosition(int x, int y, int ignoreTeam, bool getsHitByMOsOnly) const; + const std::vector& GetMOIDsAtPosition(int x, int y, int ignoreTeam, bool getsHitByMOsOnly) const; #pragma endregion private: - int m_Width; //!< The width of the SpatialPartitionGrid, in cells. int m_Height; //!< The height of the SpatialPartitionGrid, in cells. int m_CellSize; //!< The size of each of the SpatialPartitionGrid's cells, in pixels. @@ -116,7 +117,7 @@ namespace RTE { void Clear(); // Disallow the use of an implicit method. - SpatialPartitionGrid(const SpatialPartitionGrid &reference) = delete; + SpatialPartitionGrid(const SpatialPartitionGrid& reference) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/StackWalker/LICENSE b/Source/System/StackWalker/LICENSE index 269dd6b2a..43fd8dba3 100644 --- a/Source/System/StackWalker/LICENSE +++ b/Source/System/StackWalker/LICENSE @@ -22,4 +22,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Source/System/StandardIncludes.cpp b/Source/System/StandardIncludes.cpp index 5df50ad00..ed9ce3edb 100644 --- a/Source/System/StandardIncludes.cpp +++ b/Source/System/StandardIncludes.cpp @@ -1,2 +1,2 @@ // This source file generates the precompiled header out of "StandardIncludes.h" - DO NOT REMOVE -#include "StandardIncludes.h" \ No newline at end of file +#include "StandardIncludes.h" diff --git a/Source/System/StandardIncludes.h b/Source/System/StandardIncludes.h index e31b8f8a2..929636a98 100644 --- a/Source/System/StandardIncludes.h +++ b/Source/System/StandardIncludes.h @@ -93,7 +93,7 @@ namespace std { /// Custom std::hash specialization to allow using std::array as key in hash table based containers. /// template struct hash> { - size_t operator()(const array &arr) const { + size_t operator()(const array& arr) const { hash hasher; size_t outHash = 0; for (size_t i = 0; i < Size; ++i) { @@ -103,5 +103,5 @@ namespace std { return outHash; } }; -} +} // namespace std #endif diff --git a/Source/System/System.cpp b/Source/System/System.cpp index 76eedacdb..30fc6465d 100644 --- a/Source/System/System.cpp +++ b/Source/System/System.cpp @@ -1,4 +1,4 @@ -#include "System.h" +#include "System.h" #include "RTETools.h" #include "unzip.h" @@ -31,11 +31,11 @@ namespace RTE { const std::string System::s_UserdataDirectory = "Userdata/"; const std::string System::s_ModulePackageExtension = ".rte"; const std::string System::s_ZippedModulePackageExtension = ".zip"; - const std::unordered_set System::s_SupportedExtensions = { ".ini", ".txt", ".lua", ".cfg", ".bmp", ".png", ".jpg", ".jpeg", ".wav", ".ogg", ".mp3", ".flac" }; + const std::unordered_set System::s_SupportedExtensions = {".ini", ".txt", ".lua", ".cfg", ".bmp", ".png", ".jpg", ".jpeg", ".wav", ".ogg", ".mp3", ".flac"}; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void System::Initialize(const char *thisExePathAndName) { + void System::Initialize(const char* thisExePathAndName) { s_ThisExePathAndName = std::filesystem::path(thisExePathAndName).generic_string(); s_WorkingDirectory = std::filesystem::current_path().generic_string(); @@ -49,54 +49,61 @@ namespace RTE { } // Get the URL of the application bundle CFURLRef bundleURL = CFBundleCopyBundleURL(mainBundle); - + if (!bundleURL) { RTEAbort("Could not copy App Bundle URL, the bundle does not exist!") } // Convert the URL to a C string char pathBuffer[PATH_MAX]; - if (CFURLGetFileSystemRepresentation(bundleURL, true, (UInt8 *)pathBuffer, sizeof(pathBuffer))) { + if (CFURLGetFileSystemRepresentation(bundleURL, true, (UInt8*)pathBuffer, sizeof(pathBuffer))) { // bundlePath now contains the path to the application bundle as a C string auto bundlePath = std::filesystem::path(pathBuffer); - + if (std::filesystem::exists(bundlePath) && bundlePath.extension() == ".app") { auto workingDirPath = bundlePath.parent_path(); std::filesystem::current_path(workingDirPath); s_WorkingDirectory = workingDirPath.generic_string(); } - + } else { CFRelease(bundleURL); RTEAbort("Could not write App Bundle URL to a readable representation! The bundle path may exceed the local PATH_MAX.") } // Release the CFURL object CFRelease(bundleURL); - - + #endif - if (s_WorkingDirectory.back() != '/') { s_WorkingDirectory.append("/"); } + if (s_WorkingDirectory.back() != '/') { + s_WorkingDirectory.append("/"); + } - if (!PathExistsCaseSensitive(s_WorkingDirectory + s_ScreenshotDirectory)) { MakeDirectory(s_WorkingDirectory + s_ScreenshotDirectory); } - if (!PathExistsCaseSensitive(s_WorkingDirectory + s_ModDirectory)) { MakeDirectory(s_WorkingDirectory + s_ModDirectory); } - if (!PathExistsCaseSensitive(s_WorkingDirectory + s_UserdataDirectory)) { MakeDirectory(s_WorkingDirectory + s_UserdataDirectory); } + if (!PathExistsCaseSensitive(s_WorkingDirectory + s_ScreenshotDirectory)) { + MakeDirectory(s_WorkingDirectory + s_ScreenshotDirectory); + } + if (!PathExistsCaseSensitive(s_WorkingDirectory + s_ModDirectory)) { + MakeDirectory(s_WorkingDirectory + s_ModDirectory); + } + if (!PathExistsCaseSensitive(s_WorkingDirectory + s_UserdataDirectory)) { + MakeDirectory(s_WorkingDirectory + s_UserdataDirectory); + } #ifdef _WIN32 // Consider Settings.ini not existing as first time boot, then create quick launch files if they are missing. if (!std::filesystem::exists(s_WorkingDirectory + s_UserdataDirectory + "Settings.ini")) { std::array, 7> quickLaunchFiles = {{ - { "Launch Actor Editor.bat", R"(start "" "Cortex Command.exe" -editor "ActorEditor")" }, - { "Launch Area Editor.bat", R"(start "" "Cortex Command.exe" -editor "AreaEditor")" }, - { "Launch Assembly Editor.bat", R"(start "" "Cortex Command.exe" -editor "AssemblyEditor")" }, - { "Launch Gib Editor.bat", R"(start "" "Cortex Command.exe" -editor "GibEditor")" }, - { "Launch Scene Editor.bat", R"(start "" "Cortex Command.exe" -editor "SceneEditor")" }, + {"Launch Actor Editor.bat", R"(start "" "Cortex Command.exe" -editor "ActorEditor")"}, + {"Launch Area Editor.bat", R"(start "" "Cortex Command.exe" -editor "AreaEditor")"}, + {"Launch Assembly Editor.bat", R"(start "" "Cortex Command.exe" -editor "AssemblyEditor")"}, + {"Launch Gib Editor.bat", R"(start "" "Cortex Command.exe" -editor "GibEditor")"}, + {"Launch Scene Editor.bat", R"(start "" "Cortex Command.exe" -editor "SceneEditor")"}, #ifdef TARGET_MACHINE_X86 - { "Start Dedicated Server x86.bat", R"(start "" "Cortex Command x86.exe" -server 8000)" }, + {"Start Dedicated Server x86.bat", R"(start "" "Cortex Command x86.exe" -server 8000)"}, #else - { "Start Dedicated Server.bat", R"(start "" "Cortex Command.exe" -server 8000)" }, + {"Start Dedicated Server.bat", R"(start "" "Cortex Command.exe" -server 8000)"}, #endif }}; - for (const auto &[fileName, fileContent] : quickLaunchFiles) { + for (const auto& [fileName, fileContent]: quickLaunchFiles) { if (std::filesystem::path filePath = s_WorkingDirectory + fileName; !std::filesystem::exists(filePath)) { std::ofstream fileStream(filePath); fileStream << fileContent; @@ -107,9 +114,9 @@ namespace RTE { #endif } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool System::MakeDirectory(const std::string &pathToMake) { + bool System::MakeDirectory(const std::string& pathToMake) { bool createResult = std::filesystem::create_directory(pathToMake); if (createResult) { std::filesystem::permissions(pathToMake, std::filesystem::perms::owner_all | std::filesystem::perms::group_read | std::filesystem::perms::group_exec | std::filesystem::perms::others_read | std::filesystem::perms::others_exec, std::filesystem::perm_options::add); @@ -117,13 +124,13 @@ namespace RTE { return createResult; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool System::PathExistsCaseSensitive(const std::string &pathToCheck) { + bool System::PathExistsCaseSensitive(const std::string& pathToCheck) { // Use Hash for compiler independent hashing. if (s_CaseSensitive) { if (s_WorkingTree.empty()) { - for (const std::filesystem::directory_entry &directoryEntry : std::filesystem::recursive_directory_iterator(s_WorkingDirectory, std::filesystem::directory_options::follow_directory_symlink)) { + for (const std::filesystem::directory_entry& directoryEntry: std::filesystem::recursive_directory_iterator(s_WorkingDirectory, std::filesystem::directory_options::follow_directory_symlink)) { s_WorkingTree.emplace_back(Hash(directoryEntry.path().generic_string().substr(s_WorkingDirectory.length()))); } } @@ -138,7 +145,7 @@ namespace RTE { return std::filesystem::exists(pathToCheck); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void System::EnableLoggingToCLI() { #ifdef _WIN32 @@ -160,10 +167,12 @@ namespace RTE { s_LogToCLI = true; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void System::PrintLoadingToCLI(const std::string &reportString, bool newItem) { - if (newItem) { std::cout << std::endl; } + void System::PrintLoadingToCLI(const std::string& reportString, bool newItem) { + if (newItem) { + std::cout << std::endl; + } // Overwrite current line std::cout << "\r"; size_t startPos = 0; @@ -200,9 +209,9 @@ namespace RTE { std::cout << unicodedOutput << std::flush; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void System::PrintToCLI(const std::string &stringToPrint) { + void System::PrintToCLI(const std::string& stringToPrint) { #if _LINUX_OR_MACOSX_ std::string outputString = stringToPrint; // Color the words ERROR: and SYSTEM: red @@ -224,9 +233,9 @@ namespace RTE { #endif } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string System::ExtractZippedDataModule(const std::string &zippedModulePath) { + std::string System::ExtractZippedDataModule(const std::string& zippedModulePath) { std::string zippedModuleName = System::GetModDirectory() + std::filesystem::path(zippedModulePath).filename().generic_string(); unzFile zippedModule = unzOpen(zippedModuleName.c_str()); @@ -235,7 +244,9 @@ namespace RTE { if (!zippedModule) { bool makeDirResult = false; - if (!std::filesystem::exists(s_WorkingDirectory + "_FailedExtract")) { makeDirResult = MakeDirectory(s_WorkingDirectory + "_FailedExtract"); } + if (!std::filesystem::exists(s_WorkingDirectory + "_FailedExtract")) { + makeDirResult = MakeDirectory(s_WorkingDirectory + "_FailedExtract"); + } if (makeDirResult) { extractionProgressReport << "Failed to extract Data module from: " + zippedModuleName + " - Moving zip file to failed extract directory!\n"; std::filesystem::rename(s_WorkingDirectory + zippedModuleName, s_WorkingDirectory + "_FailedExtract/" + zippedModuleName); @@ -309,8 +320,10 @@ namespace RTE { if (unzOpenCurrentFile(zippedModule) != UNZ_OK) { extractionProgressReport << "\tSkipped file: " + zippedModuleName + " - Could not open file!\n"; } else { - FILE *outputFile = fopen(outputFileName.c_str(), "wb"); - if (outputFile == nullptr) { extractionProgressReport << "\tSkipped file: " + outputFileName + " - Could not open/create destination file!\n"; } + FILE* outputFile = fopen(outputFileName.c_str(), "wb"); + if (outputFile == nullptr) { + extractionProgressReport << "\tSkipped file: " + outputFileName + " - Could not open/create destination file!\n"; + } // Write the entire file out, reading in buffer size chunks and spitting them out to the output stream. bool abortWrite = false; @@ -323,7 +336,7 @@ namespace RTE { if (bytesRead < 0) { extractionProgressReport << "\tSkipped file: " + outputFileName + " - File is empty or corrupt!\n"; abortWrite = true; - // Sanity check how damn big this file we're writing is becoming. could prevent zip bomb exploits: http://en.wikipedia.org/wiki/Zip_bomb + // Sanity check how damn big this file we're writing is becoming. could prevent zip bomb exploits: http://en.wikipedia.org/wiki/Zip_bomb } else if (totalBytesRead >= s_MaxUnzippedFileSize) { extractionProgressReport << "\tSkipped file: " + outputFileName + " - File is too large, extract it manually!\n"; abortWrite = true; @@ -332,7 +345,7 @@ namespace RTE { break; } fwrite(fileBuffer.data(), bytesRead, 1, outputFile); - // Keep going while bytes are still being read (0 means end of file). + // Keep going while bytes are still being read (0 means end of file). } while (bytesRead > 0 && outputFile); fclose(outputFile); @@ -356,19 +369,19 @@ namespace RTE { return extractionProgressReport.str(); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int System::ASCIIFileContainsString(const std::string &filePath, const std::string_view &findString) { + int System::ASCIIFileContainsString(const std::string& filePath, const std::string_view& findString) { std::ifstream inputStream(filePath, std::ios::binary); if (!inputStream.is_open()) { return -1; } else { size_t fileSize = static_cast(std::filesystem::file_size(filePath)); std::vector rawData(fileSize); - inputStream.read(reinterpret_cast(&rawData[0]), fileSize); + inputStream.read(reinterpret_cast(&rawData[0]), fileSize); inputStream.close(); return (std::search(rawData.begin(), rawData.end(), findString.begin(), findString.end()) != rawData.end()) ? 0 : 1; } } -} +} // namespace RTE diff --git a/Source/System/System.h b/Source/System/System.h index e92afefd3..ea19eaf2e 100644 --- a/Source/System/System.h +++ b/Source/System/System.h @@ -9,13 +9,12 @@ namespace RTE { class System { public: - #pragma region Creation /// /// Store the current working directory and create any missing subdirectories. /// /// The path and name of this executable. - static void Initialize(const char *thisExePathAndName); + static void Initialize(const char* thisExePathAndName); #pragma endregion #pragma region Program Termination @@ -42,56 +41,56 @@ namespace RTE { /// Gets the absolute path to this executable. /// /// Absolute path to this executable. - static const std::string & GetThisExePathAndName() { return s_ThisExePathAndName; } + static const std::string& GetThisExePathAndName() { return s_ThisExePathAndName; } /// /// Gets the current working directory. /// /// Absolute path to current working directory. - static const std::string & GetWorkingDirectory() { return s_WorkingDirectory; } + static const std::string& GetWorkingDirectory() { return s_WorkingDirectory; } /// /// Gets the game data directory name. /// /// Folder name of the game data directory. - static const std::string & GetDataDirectory() { return s_DataDirectory; } + static const std::string& GetDataDirectory() { return s_DataDirectory; } /// /// Gets the screenshot directory name. /// /// Folder name of the screenshots directory. - static const std::string & GetScreenshotDirectory() { return s_ScreenshotDirectory; } + static const std::string& GetScreenshotDirectory() { return s_ScreenshotDirectory; } /// /// Gets the mod directory name. /// /// Folder name of the mod directory. - static const std::string & GetModDirectory() { return s_ModDirectory; } + static const std::string& GetModDirectory() { return s_ModDirectory; } /// /// Gets the userdata directory name. /// /// Folder name of the userdata directory. - static const std::string & GetUserdataDirectory() { return s_UserdataDirectory; } + static const std::string& GetUserdataDirectory() { return s_UserdataDirectory; } /// /// Gets the extension that determines a directory/file is an RTE module. /// /// String containing the RTE module extension. - static const std::string & GetModulePackageExtension() { return s_ModulePackageExtension; } + static const std::string& GetModulePackageExtension() { return s_ModulePackageExtension; } /// /// Gets the extension that determines a file is a zipped RTE module. /// /// String containing the zipped RTE module extension. - static const std::string & GetZippedModulePackageExtension() { return s_ZippedModulePackageExtension; } + static const std::string& GetZippedModulePackageExtension() { return s_ZippedModulePackageExtension; } /// /// Create a directory. /// /// Path to create. /// Returns 0 if successful. - static bool MakeDirectory(const std::string &pathToMake); + static bool MakeDirectory(const std::string& pathToMake); #pragma endregion #pragma region Filesystem @@ -112,10 +111,10 @@ namespace RTE { /// /// The path to check. /// Whether the file exists. - static bool PathExistsCaseSensitive(const std::string &pathToCheck); + static bool PathExistsCaseSensitive(const std::string& pathToCheck); #pragma endregion -#pragma region Command-Line Interface +#pragma region Command - Line Interface /// /// Tells whether printing loading progress report and console to command-line is enabled or not. /// @@ -130,13 +129,13 @@ namespace RTE { /// /// Prints the loading progress report to command-line. /// - static void PrintLoadingToCLI(const std::string &reportString, bool newItem = false); + static void PrintLoadingToCLI(const std::string& reportString, bool newItem = false); /// /// Prints console output to command-line. /// /// - static void PrintToCLI(const std::string &stringToPrint); + static void PrintToCLI(const std::string& stringToPrint); #pragma endregion #pragma region Archived DataModule Handling @@ -145,7 +144,7 @@ namespace RTE { /// /// Path to the module to extract. /// A string containing the progress report of the extraction. - static std::string ExtractZippedDataModule(const std::string &zippedModulePath); + static std::string ExtractZippedDataModule(const std::string& zippedModulePath); #pragma endregion #pragma region Module Validation @@ -166,7 +165,7 @@ namespace RTE { /// Fires up the default browser for the current OS on a specific URL. /// /// A string with the URL to send the browser to. - static void OpenBrowserToURL(const std::string_view &goToURL) { std::system(std::string("start ").append(goToURL).c_str()); } + static void OpenBrowserToURL(const std::string_view& goToURL) { std::system(std::string("start ").append(goToURL).c_str()); } /// /// Searches through an ASCII file on disk for a specific string and tells whether it was found or not. @@ -174,11 +173,10 @@ namespace RTE { /// The path to the ASCII file to search. /// The exact string to look for. Case sensitive! /// 0 if the string was found in the file or 1 if not. -1 if the file was inaccessible. - static int ASCIIFileContainsString(const std::string & filePath, const std::string_view & findString); + static int ASCIIFileContainsString(const std::string& filePath, const std::string_view& findString); #pragma endregion private: - static bool s_Quit; //!< Whether the user requested program termination through GUI or the window close button. static bool s_LogToCLI; //!< Bool to tell whether to print the loading log and anything specified with PrintToCLI to command-line or not. static bool s_ExternalModuleValidation; //!< Whether to run the program in a special mode where it will immediately quit without any messages after either successful loading of all modules or aborting during loading. For use by an external tool. @@ -200,5 +198,5 @@ namespace RTE { static constexpr int s_FileBufferSize = 8192; //!< Buffer to hold data read from the zip file. static constexpr int s_MaxUnzippedFileSize = 104857600; //!< Maximum size of single file being extracted from zip archive (100MiB). }; -} +} // namespace RTE #endif diff --git a/Source/System/Timer.cpp b/Source/System/Timer.cpp index b367e7711..e022708dd 100644 --- a/Source/System/Timer.cpp +++ b/Source/System/Timer.cpp @@ -2,7 +2,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Timer::Clear() { m_StartRealTime = g_TimerMan.GetRealTickCount(); @@ -11,14 +11,14 @@ namespace RTE { m_SimTimeLimit = -1; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Timer::Create() { m_TicksPerMS = static_cast(g_TimerMan.GetTicksPerSecond()) * 0.001; return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Timer::Create(double simTimeLimit, double elapsedSimTime) { m_TicksPerMS = static_cast(g_TimerMan.GetTicksPerSecond()) * 0.001; @@ -29,9 +29,9 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Timer::Create(const Timer &reference) { + int Timer::Create(const Timer& reference) { m_StartRealTime = reference.m_StartRealTime; m_StartSimTime = reference.m_StartSimTime; m_RealTimeLimit = reference.m_RealTimeLimit; @@ -39,4 +39,4 @@ namespace RTE { m_TicksPerMS = static_cast(g_TimerMan.GetTicksPerSecond()) * 0.001; return 0; } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Timer.h b/Source/System/Timer.h index 814ac87eb..50091118b 100644 --- a/Source/System/Timer.h +++ b/Source/System/Timer.h @@ -11,31 +11,42 @@ namespace RTE { class Timer { public: - #pragma region Creation /// /// Constructor method used to instantiate a Timer object. /// - Timer() { Clear(); Create(); } + Timer() { + Clear(); + Create(); + } /// /// Constructor method used to instantiate a Timer object with a set sim time elapsed. /// /// A unsigned long defining this Timer's sim time limit in ms. - Timer(double simTimeLimit) { Clear(); Create(simTimeLimit); } + Timer(double simTimeLimit) { + Clear(); + Create(simTimeLimit); + } /// /// Constructor method used to instantiate a Timer object with a set sim time elapsed. /// /// A unsigned long defining this Timer's sim time limit in ms. /// A unsigned long defining the amount of time (in ms) that this Timer should start with elapsed. - Timer(double simTimeLimit, double elapsedSimTime) { Clear(); Create(simTimeLimit, elapsedSimTime); } + Timer(double simTimeLimit, double elapsedSimTime) { + Clear(); + Create(simTimeLimit, elapsedSimTime); + } /// /// Copy constructor method used to instantiate a Timer object identical to an already existing one. /// /// A Timer object which is passed in by reference. - Timer(const Timer &reference) { Clear(); Create(reference); } + Timer(const Timer& reference) { + Clear(); + Create(reference); + } /// /// Makes the Timer object ready for use. @@ -63,7 +74,7 @@ namespace RTE { /// /// A reference to the Timer to deep copy. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const Timer &reference); + int Create(const Timer& reference); #pragma endregion #pragma region Destruction @@ -71,7 +82,10 @@ namespace RTE { /// Resets the timer so that the elapsed time is 0 ms. /// // TODO: Figure out why calling Clear() here breaks time. - void Reset() { m_StartRealTime = g_TimerMan.GetRealTickCount(); m_StartSimTime = g_TimerMan.GetSimTickCount(); } + void Reset() { + m_StartRealTime = g_TimerMan.GetRealTickCount(); + m_StartSimTime = g_TimerMan.GetSimTickCount(); + } #pragma endregion #pragma region Real Time @@ -301,8 +315,6 @@ namespace RTE { #pragma endregion protected: - - double m_TicksPerMS; //!< Ticks per MS. int64_t m_StartRealTime; //!< Absolute tick count when this was started in real time. @@ -312,11 +324,10 @@ namespace RTE { int64_t m_SimTimeLimit; //!< Tick count, relative to the start time, when this should indicate end or expired in simulation time. private: - /// /// Clears all the member variables of this Timer, effectively resetting the members of this abstraction level only. /// void Clear(); }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/System/Vector.cpp b/Source/System/Vector.cpp index 0412f14ca..6a825e07e 100644 --- a/Source/System/Vector.cpp +++ b/Source/System/Vector.cpp @@ -6,20 +6,20 @@ namespace RTE { const std::string Vector::c_ClassName = "Vector"; -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Vector::ReadProperty(const std::string_view &propName, Reader &reader) { + int Vector::ReadProperty(const std::string_view& propName, Reader& reader) { StartPropertyList(return Serializable::ReadProperty(propName, reader)); - + MatchProperty("X", { reader >> m_X; }); MatchProperty("Y", { reader >> m_Y; }); - + EndPropertyList; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Vector::Save(Writer &writer) const { + int Vector::Save(Writer& writer) const { Serializable::Save(writer); writer.NewPropertyWithValue("X", m_X); @@ -27,4 +27,4 @@ namespace RTE { return 0; } -} +} // namespace RTE diff --git a/Source/System/Vector.h b/Source/System/Vector.h index cb2e28f7d..d91fb772c 100644 --- a/Source/System/Vector.h +++ b/Source/System/Vector.h @@ -6,7 +6,10 @@ namespace RTE { - enum Axes { X = 0, Y = 1 }; + enum Axes { + X = 0, + Y = 1 + }; /// /// A useful 2D float vector. @@ -14,7 +17,6 @@ namespace RTE { class Vector : public Serializable { public: - SerializableClassNameGetter; SerializableOverrideMethods; @@ -32,14 +34,18 @@ namespace RTE { /// /// Float defining the initial X value of this Vector. /// Float defining the initial Y value of this Vector. - inline Vector(const float inputX, const float inputY) : m_X(inputX), m_Y(inputY) {}; + inline Vector(const float inputX, const float inputY) : + m_X(inputX), m_Y(inputY){}; #pragma endregion #pragma region Destruction /// /// Sets both the X and Y of this Vector to zero. /// - inline void Reset() override { m_X = 0.0F; m_Y = 0.0F; } + inline void Reset() override { + m_X = 0.0F; + m_Y = 0.0F; + } #pragma endregion #pragma region Getters and Setters @@ -54,7 +60,10 @@ namespace RTE { /// /// A float value that the X value will be set to. /// Vector reference to this after the operation. - inline Vector & SetX(const float newX) { m_X = newX; return *this; } + inline Vector& SetX(const float newX) { + m_X = newX; + return *this; + } /// /// Gets the Y value of this Vector. @@ -67,7 +76,10 @@ namespace RTE { /// /// A float value that the Y value will be set to. /// Vector reference to this after the operation. - inline Vector & SetY(const float newY) { m_Y = newY; return *this; } + inline Vector& SetY(const float newY) { + m_Y = newY; + return *this; + } /// /// Sets both the X and Y values of this Vector. @@ -75,7 +87,11 @@ namespace RTE { /// A float value that the X value will be set to. /// A float value that the Y value will be set to. /// Vector reference to this after the operation. - inline Vector & SetXY(const float newX, const float newY) { m_X = newX; m_Y = newY; return *this; } + inline Vector& SetXY(const float newX, const float newY) { + m_X = newX; + m_Y = newY; + return *this; + } /// /// Gets the absolute largest of the two elements. Will always be positive. @@ -101,7 +117,10 @@ namespace RTE { /// /// Whether or not to flip the X element or not. /// Vector reference to this after the operation. - inline Vector & FlipX(const bool flipX = true) { *this = GetXFlipped(flipX); return *this; } + inline Vector& FlipX(const bool flipX = true) { + *this = GetXFlipped(flipX); + return *this; + } /// /// Gets a Vector identical to this except that its Y component is flipped. @@ -115,7 +134,10 @@ namespace RTE { /// /// Whether or not to flip the Y element or not. /// Vector reference to this after the operation. - inline Vector & FlipY(const bool flipY = true) { *this = GetYFlipped(flipY); return *this; } + inline Vector& FlipY(const bool flipY = true) { + *this = GetYFlipped(flipY); + return *this; + } /// /// Indicates whether the X component of this Vector is 0. @@ -140,7 +162,7 @@ namespace RTE { /// /// The Vector to compare with. /// Whether the X and Y components of this Vector each have opposite signs to their corresponding components of a passed in Vector. - inline bool IsOpposedTo(const Vector &opp) const { return ((XIsZero() && opp.XIsZero()) || (std::signbit(m_X) != std::signbit(opp.m_X))) && ((YIsZero() && opp.YIsZero()) || (std::signbit(m_Y) != std::signbit(opp.m_Y))); } + inline bool IsOpposedTo(const Vector& opp) const { return ((XIsZero() && opp.XIsZero()) || (std::signbit(m_X) != std::signbit(opp.m_X))) && ((YIsZero() && opp.YIsZero()) || (std::signbit(m_Y) != std::signbit(opp.m_Y))); } #pragma endregion #pragma region Magnitude @@ -175,7 +197,7 @@ namespace RTE { /// /// A float value that the magnitude will be set to. /// Vector reference to this after the operation. - inline Vector & SetMagnitude(const float newMag) { + inline Vector& SetMagnitude(const float newMag) { if (IsZero()) { SetXY(newMag, 0.0F); } else { @@ -189,9 +211,13 @@ namespace RTE { /// /// A float value that the magnitude will be capped by. /// Vector reference to this after the operation. - inline Vector & CapMagnitude(const float capMag) { - if (capMag == 0.0F) { Reset(); } - if (MagnitudeIsGreaterThan(capMag)) { SetMagnitude(capMag); } + inline Vector& CapMagnitude(const float capMag) { + if (capMag == 0.0F) { + Reset(); + } + if (MagnitudeIsGreaterThan(capMag)) { + SetMagnitude(capMag); + } return *this; } @@ -201,8 +227,10 @@ namespace RTE { /// A float value that defines the lower limit for the magnitude of this Vector. /// A float value that defines the upper limit for the magnitude of this Vector. /// A reference to this after the change. - inline Vector & ClampMagnitude(float lowerMagnitudeLimit, float upperMagnitudeLimit) { - if (upperMagnitudeLimit < lowerMagnitudeLimit) { std::swap(upperMagnitudeLimit, lowerMagnitudeLimit); } + inline Vector& ClampMagnitude(float lowerMagnitudeLimit, float upperMagnitudeLimit) { + if (upperMagnitudeLimit < lowerMagnitudeLimit) { + std::swap(upperMagnitudeLimit, lowerMagnitudeLimit); + } if (upperMagnitudeLimit == 0.0F && lowerMagnitudeLimit == 0.0F) { Reset(); } else if (MagnitudeIsLessThan(lowerMagnitudeLimit)) { @@ -223,7 +251,10 @@ namespace RTE { /// Scales this vector to have the same direction but a magnitude of 1.0. /// /// Vector reference to this after the operation. - inline Vector & Normalize() { *this = GetNormalized(); return *this; } + inline Vector& Normalize() { + *this = GetNormalized(); + return *this; + } #pragma endregion #pragma region Rotation @@ -231,7 +262,10 @@ namespace RTE { /// Get this Vector's absolute angle in radians. e.g: when x = 1, y = 0, the value returned here will be 0. x = 0, y = 1 yields -pi/2 here. /// /// The absolute angle in radians, in the interval [-0.5 pi, 1.5 pi). - inline float GetAbsRadAngle() const { const float radAngle = -std::atan2(m_Y, m_X); return (radAngle < -c_HalfPI) ? (radAngle + c_TwoPI) : radAngle; } + inline float GetAbsRadAngle() const { + const float radAngle = -std::atan2(m_Y, m_X); + return (radAngle < -c_HalfPI) ? (radAngle + c_TwoPI) : radAngle; + } /// /// Sets this Vector's absolute angle in radians. @@ -269,7 +303,10 @@ namespace RTE { /// /// The angle in radians to rotate by. Positive angles rotate counter-clockwise, and negative angles clockwise. /// Vector reference to this after the operation. - inline Vector & RadRotate(const float angle) { *this = GetRadRotatedCopy(angle); return *this; } + inline Vector& RadRotate(const float angle) { + *this = GetRadRotatedCopy(angle); + return *this; + } /// /// Returns a copy of this Vector, rotated relatively by an angle in degrees. @@ -283,14 +320,17 @@ namespace RTE { /// /// The angle in degrees to rotate by. Positive angles rotate counter-clockwise, and negative angles clockwise. /// Vector reference to this after the operation. - inline Vector & DegRotate(const float angle) { *this = GetDegRotatedCopy(angle); return *this; } + inline Vector& DegRotate(const float angle) { + *this = GetDegRotatedCopy(angle); + return *this; + } /// /// Set this Vector to an absolute rotation based on the absolute rotation of another Vector. /// /// The reference Vector whose absolute angle from positive X (0 degrees) this Vector will be rotated to. /// Vector reference to this after the operation. - inline Vector & AbsRotateTo(const Vector &refVector) { return RadRotate(refVector.GetAbsRadAngle() - GetAbsRadAngle()); } + inline Vector& AbsRotateTo(const Vector& refVector) { return RadRotate(refVector.GetAbsRadAngle() - GetAbsRadAngle()); } /// /// Returns a Vector that is perpendicular to this, rotated PI/2. @@ -302,7 +342,10 @@ namespace RTE { /// Makes this vector perpendicular to its previous state, rotated PI/2. Much faster than RadRotate by PI/2. /// /// Vector reference to this after the operation. - inline Vector & Perpendicularize() { *this = GetPerpendicular(); return *this; } + inline Vector& Perpendicularize() { + *this = GetPerpendicular(); + return *this; + } #pragma endregion #pragma region Rounding @@ -310,25 +353,38 @@ namespace RTE { /// Rounds the X and Y values of this Vector upwards. E.g. 0.49 -> 0.0 and 0.5 -> 1.0. /// /// Vector reference to this after the operation. - inline Vector & Round() { *this = GetRounded(); return *this; } + inline Vector& Round() { + *this = GetRounded(); + return *this; + } /// /// Sets the X and Y of this Vector to the nearest half value. E.g. 1.0 -> 1.5 and 0.9 -> 0.5. /// /// Vector reference to this after the operation. - inline Vector & ToHalf() { m_X = std::round(m_X * 2) / 2; m_Y = std::round(m_Y * 2) / 2; return *this; } + inline Vector& ToHalf() { + m_X = std::round(m_X * 2) / 2; + m_Y = std::round(m_Y * 2) / 2; + return *this; + } /// /// Sets the X and Y of this Vector to the greatest integers that are not greater than their original values. E.g. -1.02 becomes -2.0. /// /// Vector reference to this after the operation. - inline Vector & Floor() { *this = GetFloored(); return *this; } + inline Vector& Floor() { + *this = GetFloored(); + return *this; + } /// /// Sets the X and Y of this Vector to the lowest integers that are not less than their original values. E.g. -1.02 becomes -1.0. /// /// Vector reference to this after the operation. - inline Vector & Ceiling() { *this = GetCeilinged(); return *this; } + inline Vector& Ceiling() { + *this = GetCeilinged(); + return *this; + } /// /// Returns a rounded copy of this Vector. Does not alter this Vector. @@ -391,14 +447,14 @@ namespace RTE { /// /// The Vector which will be the right hand side operand of the dot product operation. /// The resulting dot product scalar float. - inline float Dot(const Vector &rhs) const { return (m_X * rhs.m_X) + (m_Y * rhs.m_Y); } + inline float Dot(const Vector& rhs) const { return (m_X * rhs.m_X) + (m_Y * rhs.m_Y); } /// /// Returns the 2D cross product of this Vector and the passed in Vector. This is really the area of the parallelogram that the two vectors form. /// /// The Vector which will be the right hand side operand of the cross product operation. /// The resulting 2D cross product parallelogram area. - inline float Cross(const Vector &rhs) const { return (m_X * rhs.m_Y) - (rhs.m_X * m_Y); } + inline float Cross(const Vector& rhs) const { return (m_X * rhs.m_Y) - (rhs.m_X * m_Y); } #pragma endregion #pragma region Operator Overloads @@ -407,7 +463,11 @@ namespace RTE { /// /// A Vector reference. /// A reference to the changed Vector. - inline Vector & operator=(const Vector &rhs) { m_X = rhs.m_X; m_Y = rhs.m_Y; return *this; } + inline Vector& operator=(const Vector& rhs) { + m_X = rhs.m_X; + m_Y = rhs.m_Y; + return *this; + } /// /// Unary negation overload for single Vectors. @@ -421,7 +481,7 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// A boolean indicating whether the two operands are equal or not. - inline friend bool operator==(const Vector &lhs, const Vector &rhs) { return lhs.m_X == rhs.m_X && lhs.m_Y == rhs.m_Y; } + inline friend bool operator==(const Vector& lhs, const Vector& rhs) { return lhs.m_X == rhs.m_X && lhs.m_Y == rhs.m_Y; } /// /// An inequality operator for testing if any two Vectors are unequal. @@ -429,7 +489,7 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// A boolean indicating whether the two operands are unequal or not. - inline friend bool operator!=(const Vector &lhs, const Vector &rhs) { return !(lhs == rhs); } + inline friend bool operator!=(const Vector& lhs, const Vector& rhs) { return !(lhs == rhs); } /// /// A stream insertion operator for sending a Vector to an output stream. @@ -437,7 +497,10 @@ namespace RTE { /// An ostream reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// An ostream reference for further use in an expression. - inline friend std::ostream & operator<<(std::ostream &stream, const Vector &operand) { stream << "{" << operand.m_X << ", " << operand.m_Y << "}"; return stream; } + inline friend std::ostream& operator<<(std::ostream& stream, const Vector& operand) { + stream << "{" << operand.m_X << ", " << operand.m_Y << "}"; + return stream; + } /// /// Addition operator overload for Vectors. @@ -445,7 +508,7 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// The resulting Vector. - inline friend Vector operator+(const Vector &lhs, const Vector &rhs) { return Vector(lhs.m_X + rhs.m_X, lhs.m_Y + rhs.m_Y); } + inline friend Vector operator+(const Vector& lhs, const Vector& rhs) { return Vector(lhs.m_X + rhs.m_X, lhs.m_Y + rhs.m_Y); } /// /// Subtraction operator overload for Vectors. @@ -453,14 +516,14 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// The resulting Vector. - inline friend Vector operator-(const Vector &lhs, const Vector &rhs) { return Vector(lhs.m_X - rhs.m_X, lhs.m_Y - rhs.m_Y); } + inline friend Vector operator-(const Vector& lhs, const Vector& rhs) { return Vector(lhs.m_X - rhs.m_X, lhs.m_Y - rhs.m_Y); } /// /// Multiplication operator overload for a Vector and a float. /// /// A float reference as the right hand side operand. /// The resulting Vector. - inline Vector operator*(const float &rhs) const { return Vector(m_X * rhs, m_Y * rhs); } + inline Vector operator*(const float& rhs) const { return Vector(m_X * rhs, m_Y * rhs); } /// /// Multiplication operator overload for Vectors. @@ -468,14 +531,14 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// The resulting Vector. - inline friend Vector operator*(const Vector &lhs, const Vector &rhs) { return Vector(lhs.m_X * rhs.m_X, lhs.m_Y * rhs.m_Y); } + inline friend Vector operator*(const Vector& lhs, const Vector& rhs) { return Vector(lhs.m_X * rhs.m_X, lhs.m_Y * rhs.m_Y); } /// /// Division operator overload for a Vector and a float. /// /// A float reference as the right hand side operand. /// The resulting Vector. - Vector operator/(const float &rhs) const { return (rhs != 0) ? Vector(m_X / rhs, m_Y / rhs) : Vector(0, 0); } + Vector operator/(const float& rhs) const { return (rhs != 0) ? Vector(m_X / rhs, m_Y / rhs) : Vector(0, 0); } /// /// Division operator overload for Vectors. @@ -483,7 +546,7 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// The resulting Vector. - inline friend Vector operator/(const Vector &lhs, const Vector &rhs) { return (rhs.m_X != 0 && rhs.m_Y != 0) ? Vector(lhs.m_X / rhs.m_X, lhs.m_Y / rhs.m_Y) : Vector(0, 0); } + inline friend Vector operator/(const Vector& lhs, const Vector& rhs) { return (rhs.m_X != 0 && rhs.m_Y != 0) ? Vector(lhs.m_X / rhs.m_X, lhs.m_Y / rhs.m_Y) : Vector(0, 0); } /// /// Self-addition operator overload for Vectors. @@ -491,7 +554,11 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// A reference to the resulting Vector (the left one). - inline friend Vector & operator+=(Vector &lhs, const Vector &rhs) { lhs.m_X += rhs.m_X; lhs.m_Y += rhs.m_Y; return lhs; } + inline friend Vector& operator+=(Vector& lhs, const Vector& rhs) { + lhs.m_X += rhs.m_X; + lhs.m_Y += rhs.m_Y; + return lhs; + } /// /// Self-subtraction operator overload for Vectors. @@ -499,14 +566,22 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// A reference to the resulting Vector (the left one). - inline friend Vector & operator-=(Vector &lhs, const Vector &rhs) { lhs.m_X -= rhs.m_X; lhs.m_Y -= rhs.m_Y; return lhs; } + inline friend Vector& operator-=(Vector& lhs, const Vector& rhs) { + lhs.m_X -= rhs.m_X; + lhs.m_Y -= rhs.m_Y; + return lhs; + } /// /// Self-multiplication operator overload for a Vector and a float. /// /// A float reference as the right hand side operand. /// A reference to the resulting Vector. - inline Vector & operator*=(const float &rhs) { m_X *= rhs; m_Y *= rhs; return *this; } + inline Vector& operator*=(const float& rhs) { + m_X *= rhs; + m_Y *= rhs; + return *this; + } /// /// Self-multiplication operator overload for Vectors. @@ -514,14 +589,24 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// A reference to the resulting Vector (the left one). - inline friend Vector & operator*=(Vector &lhs, const Vector &rhs) { lhs.m_X *= rhs.m_X; lhs.m_Y *= rhs.m_Y; return lhs; } + inline friend Vector& operator*=(Vector& lhs, const Vector& rhs) { + lhs.m_X *= rhs.m_X; + lhs.m_Y *= rhs.m_Y; + return lhs; + } /// /// self-division operator overload for a Vector and a float. /// /// A float reference as the right hand side operand. /// A reference to the resulting Vector. - inline Vector & operator/=(const float &rhs) { if (rhs != 0) { m_X /= rhs; m_Y /= rhs; } return *this; } + inline Vector& operator/=(const float& rhs) { + if (rhs != 0) { + m_X /= rhs; + m_Y /= rhs; + } + return *this; + } /// /// Self-division operator overload for Vectors. @@ -529,26 +614,29 @@ namespace RTE { /// A Vector reference as the left hand side operand. /// A Vector reference as the right hand side operand. /// A reference to the resulting Vector (the left one). - inline friend Vector & operator/=(Vector &lhs, const Vector &rhs) { lhs.m_X /= rhs.m_X; lhs.m_Y /= rhs.m_Y; return lhs; } + inline friend Vector& operator/=(Vector& lhs, const Vector& rhs) { + lhs.m_X /= rhs.m_X; + lhs.m_Y /= rhs.m_Y; + return lhs; + } /// /// Array subscripting to access either the X or Y element of this Vector. /// /// An int index indicating which element is requested (X = 0, Y = 1). /// The requested element. - inline const float & operator[](const int &rhs) const { return (rhs == 0) ? m_X : m_Y; } + inline const float& operator[](const int& rhs) const { return (rhs == 0) ? m_X : m_Y; } /// /// Array subscripting to access either the X or Y element of this Vector. /// /// An int index indicating which element is requested (X = 0, Y = 1). /// The requested element. - inline float & operator[](const int &rhs) { return (rhs == 0) ? m_X : m_Y; } + inline float& operator[](const int& rhs) { return (rhs == 0) ? m_X : m_Y; } #pragma endregion private: - static const std::string c_ClassName; //!< A string with the friendly-formatted type name of this. }; -} +} // namespace RTE #endif diff --git a/Source/System/Writer.cpp b/Source/System/Writer.cpp index 81be0b518..fce6a592c 100644 --- a/Source/System/Writer.cpp +++ b/Source/System/Writer.cpp @@ -5,7 +5,7 @@ namespace RTE { -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Writer::Clear() { m_Stream = nullptr; @@ -15,23 +15,23 @@ namespace RTE { m_IndentCount = 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Writer::Writer(const std::string &fileName, bool append, bool createDir) { - Clear(); + Writer::Writer(const std::string& fileName, bool append, bool createDir) { + Clear(); Create(fileName, append, createDir); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Writer::Writer(std::unique_ptr &&stream) { + Writer::Writer(std::unique_ptr&& stream) { Clear(); Create(std::move(stream)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Writer::Create(const std::string &fileName, bool append, bool createDir) { + int Writer::Create(const std::string& fileName, bool append, bool createDir) { m_FilePath = fileName; // Extract filename and folder path @@ -39,8 +39,8 @@ namespace RTE { m_FileName = m_FilePath.substr(slashPos + 1); m_FolderPath = m_FilePath.substr(0, slashPos + 1); - if (createDir && !std::filesystem::exists(System::GetWorkingDirectory() + m_FolderPath)) { - System::MakeDirectory(System::GetWorkingDirectory() + m_FolderPath); + if (createDir && !std::filesystem::exists(System::GetWorkingDirectory() + m_FolderPath)) { + System::MakeDirectory(System::GetWorkingDirectory() + m_FolderPath); } auto ofStream = std::make_unique(fileName, append ? (std::ios::out | std::ios::app | std::ios::ate) : (std::ios::out | std::ios::trunc)); @@ -48,9 +48,9 @@ namespace RTE { return Create(std::move(ofStream)); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - int Writer::Create(std::unique_ptr &&stream) { + int Writer::Create(std::unique_ptr&& stream) { m_Stream = std::move(stream); if (!m_Stream->good()) { return -1; @@ -59,12 +59,14 @@ namespace RTE { return 0; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Writer::NewLine(bool toIndent, int lineCount) const { for (int lines = 0; lines < lineCount; ++lines) { *m_Stream << "\n"; - if (toIndent) { *m_Stream << std::string(m_IndentCount, '\t'); } + if (toIndent) { + *m_Stream << std::string(m_IndentCount, '\t'); + } } } -} \ No newline at end of file +} // namespace RTE diff --git a/Source/System/Writer.h b/Source/System/Writer.h index 939cfba63..3f2b9dcfe 100644 --- a/Source/System/Writer.h +++ b/Source/System/Writer.h @@ -9,7 +9,6 @@ namespace RTE { class Writer { public: - #pragma region Creation /// /// Constructor method used to instantiate a Writer object in system memory. Create() should be called before using the object. @@ -22,13 +21,13 @@ namespace RTE { /// Path to the file to open for writing. If the directory doesn't exist the stream will fail to open. /// Whether to append to the file if it exists, or to overwrite it. /// Whether to create the directory path to the file name before attempting to open the stream, in case it doesn't exist. - Writer(const std::string &fileName, bool append = false, bool createDir = false); + Writer(const std::string& fileName, bool append = false, bool createDir = false); /// /// Constructor method used to instantiate a Writer object in system memory and make it ready for writing to the passed in file path. /// /// Stream to write to. - Writer(std::unique_ptr &&stream); + Writer(std::unique_ptr&& stream); /// /// Makes the Writer object ready for use. @@ -37,14 +36,14 @@ namespace RTE { /// Whether to append to the file if it exists, or to overwrite it. /// Whether to create the directory path to the file name before attempting to open the stream, in case it doesn't exist. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(const std::string &fileName, bool append = false, bool createDir = false); + int Create(const std::string& fileName, bool append = false, bool createDir = false); /// /// Makes the Writer object ready for use. /// /// Stream to write to. /// An error return value signaling success or any particular failure. Anything below 0 is an error signal. - int Create(std::unique_ptr &&stream); + int Create(std::unique_ptr&& stream); #pragma endregion #pragma region Getters @@ -72,12 +71,20 @@ namespace RTE { /// Used to specify the start of an object to be written. /// /// The class name of the object about to be written. - void ObjectStart(const std::string &className) { *m_Stream << className; ++m_IndentCount; } + void ObjectStart(const std::string& className) { + *m_Stream << className; + ++m_IndentCount; + } /// /// Used to specify the end of an object that has just been written. /// - void ObjectEnd() { --m_IndentCount; if (m_IndentCount == 0) { NewLine(false, 2); } } + void ObjectEnd() { + --m_IndentCount; + if (m_IndentCount == 0) { + NewLine(false, 2); + } + } /// /// Creates a new line that can be properly indented. @@ -91,27 +98,39 @@ namespace RTE { /// /// The text string to write to the new line. /// Whether to indent the new line or not. - void NewLineString(const std::string &textString, bool toIndent = true) const { NewLine(toIndent); *m_Stream << textString; } + void NewLineString(const std::string& textString, bool toIndent = true) const { + NewLine(toIndent); + *m_Stream << textString; + } /// /// Creates a new line and fills it with slashes to create a divider line for INI. /// /// Whether to indent the new line or not. /// The length of the divider (number of slashes). - void NewDivider(bool toIndent = true, int dividerLength = 72) const { NewLine(toIndent); *m_Stream << std::string(dividerLength, '/'); } + void NewDivider(bool toIndent = true, int dividerLength = 72) const { + NewLine(toIndent); + *m_Stream << std::string(dividerLength, '/'); + } /// /// Creates a new line and writes the name of the property in preparation to writing it's value. /// /// The name of the property to be written. - void NewProperty(const std::string &propName) const { NewLine(); *m_Stream << propName + " = "; } + void NewProperty(const std::string& propName) const { + NewLine(); + *m_Stream << propName + " = "; + } /// /// Creates a new line and writes the name of the specified property, followed by its set value. /// /// The name of the property to be written. /// The value of the property. - template void NewPropertyWithValue(const std::string &propName, const Type &propValue) { NewProperty(propName); *this << propValue; } + template void NewPropertyWithValue(const std::string& propName, const Type& propValue) { + NewProperty(propName); + *this << propValue; + } /// /// Marks that there is a null reference to an object here. @@ -129,7 +148,10 @@ namespace RTE { /// /// Flushes and closes the output stream of this Writer. This happens automatically at destruction but needs to be called manually if a written file must be read from in the same scope. /// - void EndWrite() { m_Stream->flush(); m_Stream.reset(); } + void EndWrite() { + m_Stream->flush(); + m_Stream.reset(); + } #pragma endregion #pragma region Operator Overloads @@ -138,25 +160,70 @@ namespace RTE { /// /// A reference to the variable that will be written to the ostream. /// A Writer reference for further use in an expression. - Writer & operator<<(const bool &var) { *m_Stream << var; return *this; } - Writer & operator<<(const char &var) { *m_Stream << var; return *this; } - Writer & operator<<(const unsigned char &var) { int temp = var; *m_Stream << temp; return *this; } - Writer & operator<<(const short &var) { *m_Stream << var; return *this; } - Writer & operator<<(const unsigned short &var) { *m_Stream << var; return *this; } - Writer & operator<<(const int &var) { *m_Stream << var; return *this; } - Writer & operator<<(const unsigned int &var) { *m_Stream << var; return *this; } - Writer & operator<<(const long &var) { *m_Stream << var; return *this; } - Writer & operator<<(const long long &var) { *m_Stream << var; return *this; } - Writer & operator<<(const unsigned long &var) { *m_Stream << var; return *this; } - Writer & operator<<(const unsigned long long &var) { *m_Stream << var; return *this; } - Writer & operator<<(const float &var) { *m_Stream << var; return *this; } - Writer & operator<<(const double &var) { *m_Stream << var; return *this; } - Writer & operator<<(const char *var) { *m_Stream << var; return *this; } - Writer & operator<<(const std::string &var) { *m_Stream << var; return *this; } + Writer& operator<<(const bool& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const char& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const unsigned char& var) { + int temp = var; + *m_Stream << temp; + return *this; + } + Writer& operator<<(const short& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const unsigned short& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const int& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const unsigned int& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const long& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const long long& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const unsigned long& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const unsigned long long& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const float& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const double& var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const char* var) { + *m_Stream << var; + return *this; + } + Writer& operator<<(const std::string& var) { + *m_Stream << var; + return *this; + } #pragma endregion protected: - std::unique_ptr m_Stream; //!< Stream used for writing. std::string m_FilePath; //!< Currently used stream's filepath. std::string m_FolderPath; //!< Only the path to the folder that we are writing a file in, excluding the filename. @@ -164,15 +231,14 @@ namespace RTE { int m_IndentCount; //!< Indentation counter. private: - /// /// Clears all the member variables of this Writer, effectively resetting the members of this abstraction level only. /// void Clear(); // Disallow the use of some implicit methods. - Writer(const Writer &reference) = delete; - Writer & operator=(const Writer &rhs) = delete; + Writer(const Writer& reference) = delete; + Writer& operator=(const Writer& rhs) = delete; }; -} -#endif \ No newline at end of file +} // namespace RTE +#endif diff --git a/Source/meson.build b/Source/meson.build index af44e7b0f..5e1f233cc 100644 --- a/Source/meson.build +++ b/Source/meson.build @@ -19,4 +19,4 @@ subdir('GUI') subdir('Lua') subdir('Managers') subdir('Menus') -subdir('System') \ No newline at end of file +subdir('System')